Skip to content

Commit d83afa4

Browse files
Jeremy-Waltondallasbpeters
authored andcommitted
Extract the replace hard coded values tool (#26)
* extract it * Remove old tool
1 parent 10c01d4 commit d83afa4

3 files changed

Lines changed: 115 additions & 129 deletions

File tree

src/index.ts

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { z } from 'zod';
1414
import { designTokens } from './optics-data.js';
1515
import { generateTheme } from './tools/theme-generator.js';
1616
import { validateTokenUsage, formatValidationReport } from './tools/validate.js';
17-
import { replaceHardCodedValues, formatReplacementSuggestions } from './tools/replace.js';
17+
1818
import { checkTokenContrast, formatContrastResult } from './tools/accessibility.js';
1919
import { suggestTokenMigration, formatMigrationSuggestions } from './tools/migration.js';
2020
import { generateComponentScaffold, formatScaffoldOutput } from './tools/scaffold.js';
@@ -46,6 +46,7 @@ import ListComponentsTool from './tools/list-components-tool.js'
4646
import GetComponentInfoTool from './tools/get-component-info-tool.js';
4747
import GetComponentTokensTool from './tools/get-component-tokens-tool.js';
4848
import SearchDocumentationTool from './tools/search-documentation-tool.js';
49+
import ReplaceHardCodedValuesTool from './tools/replace-hard-coded-values-tool.js';
4950

5051
/**
5152
* Create and configure the MCP server
@@ -198,7 +199,8 @@ const tools = [
198199
new ListComponentsTool(),
199200
new GetComponentInfoTool(),
200201
new GetComponentTokensTool(),
201-
new SearchDocumentationTool()
202+
new SearchDocumentationTool(),
203+
new ReplaceHardCodedValuesTool()
202204
]
203205

204206
tools.forEach((tool) => {
@@ -284,33 +286,7 @@ server.registerTool(
284286
}
285287
);
286288

287-
/**
288-
* Tool: Replace Hard-Coded Values
289-
*/
290-
server.registerTool(
291-
'replace_hard_coded_values',
292-
{
293-
title: 'Replace Hard-Coded Values',
294-
description: 'Replace hard-coded values with design tokens',
295-
inputSchema: {
296-
code: z.string().describe('Code containing hard-coded values'),
297-
autofix: z.boolean().optional().describe('Whether to automatically fix the code (default: false)'),
298-
},
299-
},
300-
async ({ code, autofix }) => {
301-
const result = replaceHardCodedValues(code, designTokens, autofix ?? false);
302-
const formatted = formatReplacementSuggestions(result);
303289

304-
return {
305-
content: [
306-
{
307-
type: 'text',
308-
text: formatted,
309-
},
310-
],
311-
};
312-
}
313-
);
314290

315291
/**
316292
* Tool: Check Contrast
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { z } from 'zod'
2+
import Tool from './tool.js'
3+
import { designTokens, type DesignToken } from '../optics-data.js'
4+
import { extractAllValues, findMatchingToken } from '../utils/css-parser.js'
5+
6+
interface ReplacementSuggestion {
7+
original: string
8+
replacement: string
9+
tokenName: string
10+
property?: string
11+
}
12+
13+
interface ReplacementResult {
14+
originalCode: string
15+
fixedCode: string
16+
replacements: ReplacementSuggestion[]
17+
replacementCount: number
18+
}
19+
20+
class ReplaceHardCodedValuesTool extends Tool {
21+
name = 'replace_hard_coded_values'
22+
title = 'Replace Hard-Coded Values'
23+
description = 'Replace hard-coded values with design tokens'
24+
25+
inputSchema = {
26+
code: z.string().describe('Code containing hard-coded values'),
27+
autofix: z.boolean().optional().describe('Whether to automatically fix the code (default: false)'),
28+
}
29+
30+
async handler(args: any): Promise<string> {
31+
const { code, autofix } = args
32+
const result = this.replaceHardCodedValues(code, designTokens, autofix ?? false)
33+
return this.formatReplacementSuggestions(result)
34+
}
35+
36+
private replaceHardCodedValues(
37+
code: string,
38+
tokens: DesignToken[],
39+
autofix: boolean = false
40+
): ReplacementResult {
41+
const extractedValues = extractAllValues(code)
42+
const replacements: ReplacementSuggestion[] = []
43+
let fixedCode = code
44+
45+
for (const value of extractedValues) {
46+
const matchingToken = findMatchingToken(value.value, tokens)
47+
48+
if (matchingToken) {
49+
const replacement = `var(--${matchingToken})`
50+
replacements.push({
51+
original: value.value,
52+
replacement,
53+
tokenName: matchingToken,
54+
property: value.property,
55+
})
56+
57+
if (autofix) {
58+
fixedCode = fixedCode.replace(
59+
new RegExp(this.escapeRegex(value.value), 'g'),
60+
replacement
61+
)
62+
}
63+
}
64+
}
65+
66+
return {
67+
originalCode: code,
68+
fixedCode: autofix ? fixedCode : code,
69+
replacements,
70+
replacementCount: replacements.length,
71+
}
72+
}
73+
74+
private escapeRegex(str: string): string {
75+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
76+
}
77+
78+
private formatReplacementSuggestions(result: ReplacementResult): string {
79+
const lines: string[] = [
80+
'# Token Replacement Suggestions',
81+
'',
82+
`**Replacements Found**: ${result.replacementCount}`,
83+
'',
84+
]
85+
86+
if (result.replacements.length > 0) {
87+
lines.push('## Suggested Replacements')
88+
lines.push('')
89+
90+
for (const rep of result.replacements) {
91+
lines.push(`- Replace \`${rep.original}\` with \`${rep.replacement}\``)
92+
lines.push(` Token: ${rep.tokenName}`)
93+
if (rep.property) lines.push(` Property: ${rep.property}`)
94+
lines.push('')
95+
}
96+
97+
if (result.fixedCode !== result.originalCode) {
98+
lines.push('## Fixed Code')
99+
lines.push('```css')
100+
lines.push(result.fixedCode)
101+
lines.push('```')
102+
}
103+
} else {
104+
lines.push('✓ No replacements needed!')
105+
}
106+
107+
return lines.join('\n')
108+
}
109+
}
110+
111+
export default ReplaceHardCodedValuesTool

src/tools/replace.ts

Lines changed: 0 additions & 101 deletions
This file was deleted.

0 commit comments

Comments
 (0)