Skip to content

Commit c8ed654

Browse files
committed
refactor: streamline error handling and improve code consistency across tools
1 parent d41ea6a commit c8ed654

15 files changed

+184
-160
lines changed

src/tools/get-component-by-purpose.ts

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Tool } from '@modelcontextprotocol/sdk/types.js';
22
import { StorybookClient } from '../utils/storybook-client.js';
3-
import { handleError, formatSuccessResponse, handleErrorWithContext } from '../utils/error-handler.js';
3+
import { formatSuccessResponse, handleErrorWithContext } from '../utils/error-handler.js';
44
import { validateGetComponentByPurposeInput } from '../utils/validators.js';
55
import { ComponentByPurpose } from '../types/storybook.js';
66
import { applyPagination, formatPaginationMessage } from '../utils/pagination.js';
@@ -156,8 +156,9 @@ const PURPOSE_PATTERNS: Record<string, { patterns: RegExp[]; description: string
156156
};
157157

158158
export async function handleGetComponentByPurpose(input: any) {
159+
let validatedInput: any;
159160
try {
160-
const validatedInput = validateGetComponentByPurposeInput(input);
161+
validatedInput = validateGetComponentByPurposeInput(input);
161162
const purposeLower = validatedInput.purpose.toLowerCase();
162163
const client = new StorybookClient();
163164

@@ -180,24 +181,24 @@ export async function handleGetComponentByPurpose(input: any) {
180181
} else {
181182
// Create patterns from the purpose string
182183
const words = purposeLower.split(/\s+/);
183-
patterns = words.map(word => new RegExp(word, 'i'));
184+
patterns = words.map((word: string) => new RegExp(word, 'i'));
184185
description = `Components related to ${validatedInput.purpose}`;
185186
}
186187

187188
// Create filter function for purpose matching
188189
const filterFn = (story: any, componentName: string) => {
189190
const componentTitle = story.title || '';
190191
const storyName = story.name || story.story || '';
191-
192+
192193
return patterns.some(
193194
pattern =>
194195
pattern.test(componentTitle) || pattern.test(storyName) || pattern.test(componentName)
195196
);
196197
};
197198

198-
const componentMap = mapStoriesToComponents(stories, {
199+
const componentMap = mapStoriesToComponents(stories, {
199200
filterFn,
200-
useComponentKey: 'title'
201+
useComponentKey: 'title',
201202
});
202203
const allComponents = getComponentsArray(componentMap);
203204

@@ -221,12 +222,8 @@ export async function handleGetComponentByPurpose(input: any) {
221222

222223
return formatSuccessResponse(result, message);
223224
} catch (error) {
224-
return handleErrorWithContext(
225-
error,
226-
'get components by purpose',
227-
{
228-
resource: 'components by purpose'
229-
}
230-
);
225+
return handleErrorWithContext(error, 'get components by purpose', {
226+
resource: 'components by purpose',
227+
});
231228
}
232229
}

src/tools/get-component-html.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Tool } from '@modelcontextprotocol/sdk/types.js';
22
import { StorybookClient } from '../utils/storybook-client.js';
3-
import { handleError, formatSuccessResponse, handleErrorWithContext } from '../utils/error-handler.js';
3+
import { formatSuccessResponse, handleErrorWithContext } from '../utils/error-handler.js';
44
import { validateGetComponentHTMLInput } from '../utils/validators.js';
55
import { ComponentHTML } from '../types/storybook.js';
66
import { createTimeoutError } from '../utils/error-formatter.js';
@@ -29,12 +29,13 @@ export const getComponentHTMLTool: Tool = {
2929
};
3030

3131
export async function handleGetComponentHTML(input: any) {
32+
let validatedInput: any;
3233
try {
33-
const validatedInput = validateGetComponentHTMLInput(input);
34+
validatedInput = validateGetComponentHTMLInput(input);
3435
const client = new StorybookClient();
3536

3637
const timeout = getEnvironmentTimeout(OPERATION_TIMEOUTS.fetchComponentHTML);
37-
38+
3839
// Add timeout wrapper
3940
const timeoutPromise = new Promise((_, reject) => {
4041
setTimeout(() => {
@@ -65,13 +66,9 @@ export async function handleGetComponentHTML(input: any) {
6566
`Extracted HTML for component: ${validatedInput.componentId}`
6667
);
6768
} catch (error) {
68-
return handleErrorWithContext(
69-
error,
70-
'get component HTML',
71-
{
72-
storyId: validatedInput?.componentId,
73-
resource: 'component HTML'
74-
}
75-
);
69+
return handleErrorWithContext(error, 'get component HTML', {
70+
storyId: validatedInput?.componentId || 'unknown',
71+
resource: 'component HTML',
72+
});
7673
}
7774
}

src/tools/get-component-variants.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { Tool } from '@modelcontextprotocol/sdk/types.js';
22
import { StorybookClient } from '../utils/storybook-client.js';
3-
import { handleError, formatSuccessResponse, handleErrorWithContext } from '../utils/error-handler.js';
3+
import {
4+
handleError,
5+
formatSuccessResponse,
6+
handleErrorWithContext,
7+
} from '../utils/error-handler.js';
48
import { validateGetComponentVariantsInput } from '../utils/validators.js';
59
import { ComponentVariant } from '../types/storybook.js';
610
import { createNotFoundError } from '../utils/error-formatter.js';
@@ -23,8 +27,9 @@ export const getComponentVariantsTool: Tool = {
2327
};
2428

2529
export async function handleGetComponentVariants(input: any) {
30+
let validatedInput: any;
2631
try {
27-
const validatedInput = validateGetComponentVariantsInput(input);
32+
validatedInput = validateGetComponentVariantsInput(input);
2833
const client = new StorybookClient();
2934

3035
const storiesIndex = await client.fetchStoriesIndex();
@@ -60,10 +65,8 @@ export async function handleGetComponentVariants(input: any) {
6065
`Found ${variants.length} variants for component: ${validatedInput.componentName}`
6166
);
6267
} catch (error) {
63-
return handleErrorWithContext(
64-
error,
65-
'get component variants',
66-
{ componentName: validatedInput?.componentName }
67-
);
68+
return handleErrorWithContext(error, 'get component variants', {
69+
componentName: validatedInput?.componentName || 'unknown',
70+
});
6871
}
6972
}

src/tools/get-external-css.ts

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import { Tool } from '@modelcontextprotocol/sdk/types.js';
22
import { StorybookClient } from '../utils/storybook-client.js';
3-
import { handleError, formatSuccessResponse, handleErrorWithContext } from '../utils/error-handler.js';
3+
import { formatSuccessResponse, handleErrorWithContext } from '../utils/error-handler.js';
44
import { extractDesignTokens } from '../utils/html-parser.js';
55
import { DesignToken } from '../types/storybook.js';
6-
import { createSecurityError, createConnectionError, createTimeoutError } from '../utils/error-formatter.js';
6+
import {
7+
createSecurityError,
8+
createConnectionError,
9+
createTimeoutError,
10+
} from '../utils/error-formatter.js';
711
import { OPERATION_TIMEOUTS, getEnvironmentTimeout } from '../utils/timeout-constants.js';
812

913
interface GetExternalCSSInput {
@@ -158,8 +162,9 @@ async function makeAbsoluteUrl(url: string, baseUrl: string): Promise<string> {
158162
}
159163

160164
export async function handleGetExternalCSS(input: any) {
165+
let validatedInput: any;
161166
try {
162-
const validatedInput = validateGetExternalCSSInput(input);
167+
validatedInput = validateGetExternalCSSInput(input);
163168
const client = new StorybookClient();
164169
const baseUrl = client.getStorybookUrl();
165170

@@ -200,11 +205,7 @@ export async function handleGetExternalCSS(input: any) {
200205
);
201206
throw new Error(timeoutError.message);
202207
}
203-
const connectionError = createConnectionError(
204-
'fetch external CSS',
205-
absoluteUrl,
206-
error
207-
);
208+
const connectionError = createConnectionError('fetch external CSS', absoluteUrl, error);
208209
throw new Error(connectionError.message);
209210
} finally {
210211
clearTimeout(timeoutId);
@@ -273,14 +274,10 @@ export async function handleGetExternalCSS(input: any) {
273274

274275
return formatSuccessResponse(result, message);
275276
} catch (error) {
276-
return handleErrorWithContext(
277-
error,
278-
'get external CSS',
279-
{
280-
url: validatedInput?.cssUrl,
281-
resource: 'external CSS file'
282-
}
283-
);
277+
return handleErrorWithContext(error, 'get external CSS', {
278+
url: validatedInput?.cssUrl || 'unknown',
279+
resource: 'external CSS file',
280+
});
284281
}
285282
}
286283

src/tools/list-components.ts

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Tool } from '@modelcontextprotocol/sdk/types.js';
22
import { StorybookClient } from '../utils/storybook-client.js';
3-
import { handleError, formatSuccessResponse, handleErrorWithContext } from '../utils/error-handler.js';
3+
import { formatSuccessResponse, handleErrorWithContext } from '../utils/error-handler.js';
44
import { validateListComponentsInput } from '../utils/validators.js';
55
import { applyPagination, formatPaginationMessage } from '../utils/pagination.js';
66
import { mapStoriesToComponents, getComponentsArray } from '../utils/story-mapper.js';
@@ -31,8 +31,9 @@ export const listComponentsTool: Tool = {
3131
};
3232

3333
export async function handleListComponents(input: any) {
34+
let validatedInput: any;
3435
try {
35-
const validatedInput = validateListComponentsInput(input);
36+
validatedInput = validateListComponentsInput(input);
3637
const client = new StorybookClient();
3738

3839
const storiesIndex = await client.fetchStoriesIndex();
@@ -62,11 +63,13 @@ export async function handleListComponents(input: any) {
6263
);
6364
}
6465

65-
const filterFn = validatedInput.category && validatedInput.category !== 'all'
66-
? (story: any, componentName: string, category?: string) => category === validatedInput.category
67-
: undefined;
66+
const filterFn =
67+
validatedInput.category && validatedInput.category !== 'all'
68+
? (_story: any, _componentName: string, category?: string) =>
69+
category === validatedInput.category
70+
: undefined;
6871

69-
const componentMap = mapStoriesToComponents(storiesData, { filterFn });
72+
const componentMap = mapStoriesToComponents(storiesData, filterFn ? { filterFn } : {});
7073
const allComponents = getComponentsArray(componentMap);
7174

7275
// Apply pagination
@@ -83,13 +86,8 @@ export async function handleListComponents(input: any) {
8386

8487
return formatSuccessResponse(paginationResult.items, message);
8588
} catch (error) {
86-
return handleErrorWithContext(
87-
error,
88-
'list components',
89-
{
90-
resource: 'components list',
91-
category: validatedInput?.category
92-
}
93-
);
89+
return handleErrorWithContext(error, 'list components', {
90+
resource: 'components list',
91+
});
9492
}
9593
}

src/tools/search-components.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Tool } from '@modelcontextprotocol/sdk/types.js';
22
import { StorybookClient } from '../utils/storybook-client.js';
3-
import { handleError, formatSuccessResponse, handleErrorWithContext } from '../utils/error-handler.js';
3+
import { formatSuccessResponse, handleErrorWithContext } from '../utils/error-handler.js';
44
import { validateSearchComponentsInput } from '../utils/validators.js';
55
import { applyPagination, formatPaginationMessage } from '../utils/pagination.js';
66
import { mapStoriesToComponents, getComponentsArray } from '../utils/story-mapper.js';
@@ -49,12 +49,14 @@ export async function handleSearchComponents(input: any) {
4949
const storiesIndex = await client.fetchStoriesIndex();
5050
const stories = storiesIndex.stories || storiesIndex.entries || {};
5151

52-
const filterFn = (story: any, componentName: string, category?: string) => {
52+
const filterFn = (story: any, componentName: string, _category?: string) => {
5353
const storyTitle = story.title || '';
5454
const categoryParts = storyTitle.split('/').slice(0, -1);
5555
const storyCategory = categoryParts.length > 0 ? categoryParts.join('/') : undefined;
5656

57-
if (isWildcard) return true;
57+
if (isWildcard) {
58+
return true;
59+
}
5860

5961
switch (searchIn) {
6062
case 'name':
@@ -68,7 +70,7 @@ export async function handleSearchComponents(input: any) {
6870
return (
6971
componentName.toLowerCase().includes(query) ||
7072
storyTitle.toLowerCase().includes(query) ||
71-
Boolean(storyCategory && storyCategory.toLowerCase().includes(query))
73+
Boolean(storyCategory?.toLowerCase().includes(query))
7274
);
7375
}
7476
};
@@ -90,12 +92,8 @@ export async function handleSearchComponents(input: any) {
9092

9193
return formatSuccessResponse(paginationResult.items, message);
9294
} catch (error) {
93-
return handleErrorWithContext(
94-
error,
95-
'search components',
96-
{
97-
resource: 'component search results'
98-
}
99-
);
95+
return handleErrorWithContext(error, 'search components', {
96+
resource: 'component search results',
97+
});
10098
}
10199
}

src/utils/error-constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,4 @@ export const ERROR_MESSAGES = {
144144
brief: 'Security restriction encountered',
145145
suggestion: 'Check CORS and security policy configuration',
146146
},
147-
} as const;
147+
} as const;

0 commit comments

Comments
 (0)