From a603aea8e869e1a6ea0cc9e32df9bfee7b5103b2 Mon Sep 17 00:00:00 2001 From: Jeremy Walton Date: Thu, 5 Feb 2026 15:36:21 -0500 Subject: [PATCH 1/2] extract it --- src/index.ts | 32 +----- src/tools/replace-hard-coded-values-tool.ts | 111 ++++++++++++++++++++ 2 files changed, 115 insertions(+), 28 deletions(-) create mode 100644 src/tools/replace-hard-coded-values-tool.ts diff --git a/src/index.ts b/src/index.ts index d072ac7..d713d6a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,7 +14,7 @@ import { z } from 'zod'; import { designTokens } from './optics-data.js'; import { generateTheme } from './tools/theme-generator.js'; import { validateTokenUsage, formatValidationReport } from './tools/validate.js'; -import { replaceHardCodedValues, formatReplacementSuggestions } from './tools/replace.js'; + import { checkTokenContrast, formatContrastResult } from './tools/accessibility.js'; import { suggestTokenMigration, formatMigrationSuggestions } from './tools/migration.js'; import { generateComponentScaffold, formatScaffoldOutput } from './tools/scaffold.js'; @@ -43,6 +43,7 @@ import ListComponentsTool from './tools/list-components-tool.js' import GetComponentInfoTool from './tools/get-component-info-tool.js'; import GetComponentTokensTool from './tools/get-component-tokens-tool.js'; import SearchDocumentationTool from './tools/search-documentation-tool.js'; +import ReplaceHardCodedValuesTool from './tools/replace-hard-coded-values-tool.js'; /** * Create and configure the MCP server @@ -187,7 +188,8 @@ const tools = [ new ListComponentsTool(), new GetComponentInfoTool(), new GetComponentTokensTool(), - new SearchDocumentationTool() + new SearchDocumentationTool(), + new ReplaceHardCodedValuesTool() ] tools.forEach((tool) => { @@ -273,33 +275,7 @@ server.registerTool( } ); -/** - * Tool: Replace Hard-Coded Values - */ -server.registerTool( - 'replace_hard_coded_values', - { - title: 'Replace Hard-Coded Values', - description: 'Replace hard-coded values with design tokens', - inputSchema: { - code: z.string().describe('Code containing hard-coded values'), - autofix: z.boolean().optional().describe('Whether to automatically fix the code (default: false)'), - }, - }, - async ({ code, autofix }) => { - const result = replaceHardCodedValues(code, designTokens, autofix ?? false); - const formatted = formatReplacementSuggestions(result); - return { - content: [ - { - type: 'text', - text: formatted, - }, - ], - }; - } -); /** * Tool: Check Contrast diff --git a/src/tools/replace-hard-coded-values-tool.ts b/src/tools/replace-hard-coded-values-tool.ts new file mode 100644 index 0000000..e682977 --- /dev/null +++ b/src/tools/replace-hard-coded-values-tool.ts @@ -0,0 +1,111 @@ +import { z } from 'zod' +import Tool from './tool.js' +import { designTokens, type DesignToken } from '../optics-data.js' +import { extractAllValues, findMatchingToken } from '../utils/css-parser.js' + +interface ReplacementSuggestion { + original: string + replacement: string + tokenName: string + property?: string +} + +interface ReplacementResult { + originalCode: string + fixedCode: string + replacements: ReplacementSuggestion[] + replacementCount: number +} + +class ReplaceHardCodedValuesTool extends Tool { + name = 'replace_hard_coded_values' + title = 'Replace Hard-Coded Values' + description = 'Replace hard-coded values with design tokens' + + inputSchema = { + code: z.string().describe('Code containing hard-coded values'), + autofix: z.boolean().optional().describe('Whether to automatically fix the code (default: false)'), + } + + async handler(args: any): Promise { + const { code, autofix } = args + const result = this.replaceHardCodedValues(code, designTokens, autofix ?? false) + return this.formatReplacementSuggestions(result) + } + + private replaceHardCodedValues( + code: string, + tokens: DesignToken[], + autofix: boolean = false + ): ReplacementResult { + const extractedValues = extractAllValues(code) + const replacements: ReplacementSuggestion[] = [] + let fixedCode = code + + for (const value of extractedValues) { + const matchingToken = findMatchingToken(value.value, tokens) + + if (matchingToken) { + const replacement = `var(--${matchingToken})` + replacements.push({ + original: value.value, + replacement, + tokenName: matchingToken, + property: value.property, + }) + + if (autofix) { + fixedCode = fixedCode.replace( + new RegExp(this.escapeRegex(value.value), 'g'), + replacement + ) + } + } + } + + return { + originalCode: code, + fixedCode: autofix ? fixedCode : code, + replacements, + replacementCount: replacements.length, + } + } + + private escapeRegex(str: string): string { + return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + } + + private formatReplacementSuggestions(result: ReplacementResult): string { + const lines: string[] = [ + '# Token Replacement Suggestions', + '', + `**Replacements Found**: ${result.replacementCount}`, + '', + ] + + if (result.replacements.length > 0) { + lines.push('## Suggested Replacements') + lines.push('') + + for (const rep of result.replacements) { + lines.push(`- Replace \`${rep.original}\` with \`${rep.replacement}\``) + lines.push(` Token: ${rep.tokenName}`) + if (rep.property) lines.push(` Property: ${rep.property}`) + lines.push('') + } + + if (result.fixedCode !== result.originalCode) { + lines.push('## Fixed Code') + lines.push('```css') + lines.push(result.fixedCode) + lines.push('```') + } + } else { + lines.push('✓ No replacements needed!') + } + + return lines.join('\n') + } +} + +export default ReplaceHardCodedValuesTool From d83a7c7dbf875a0ef62db1acaaeb6849837f36d3 Mon Sep 17 00:00:00 2001 From: Jeremy Walton Date: Thu, 5 Feb 2026 15:38:44 -0500 Subject: [PATCH 2/2] Remove old tool --- src/tools/replace.ts | 101 ------------------------------------------- 1 file changed, 101 deletions(-) delete mode 100644 src/tools/replace.ts diff --git a/src/tools/replace.ts b/src/tools/replace.ts deleted file mode 100644 index 1a57179..0000000 --- a/src/tools/replace.ts +++ /dev/null @@ -1,101 +0,0 @@ -/** - * Token replacement tool - * Replaces hard-coded values with design tokens - */ - -import { DesignToken } from '../optics-data.js'; -import { extractAllValues, findMatchingToken } from '../utils/css-parser.js'; - -export interface ReplacementSuggestion { - original: string; - replacement: string; - tokenName: string; - property?: string; -} - -export interface ReplacementResult { - originalCode: string; - fixedCode: string; - replacements: ReplacementSuggestion[]; - replacementCount: number; -} - -/** - * Replace hard-coded values with tokens - */ -export function replaceHardCodedValues( - code: string, - tokens: DesignToken[], - autofix: boolean = false -): ReplacementResult { - const extractedValues = extractAllValues(code); - const replacements: ReplacementSuggestion[] = []; - let fixedCode = code; - - for (const value of extractedValues) { - const matchingToken = findMatchingToken(value.value, tokens); - - if (matchingToken) { - const replacement = `var(--${matchingToken})`; - replacements.push({ - original: value.value, - replacement, - tokenName: matchingToken, - property: value.property - }); - - if (autofix) { - fixedCode = fixedCode.replace( - new RegExp(escapeRegex(value.value), 'g'), - replacement - ); - } - } - } - - return { - originalCode: code, - fixedCode: autofix ? fixedCode : code, - replacements, - replacementCount: replacements.length - }; -} - -function escapeRegex(str: string): string { - return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); -} - -/** - * Format replacement suggestions - */ -export function formatReplacementSuggestions(result: ReplacementResult): string { - const lines: string[] = [ - '# Token Replacement Suggestions', - '', - `**Replacements Found**: ${result.replacementCount}`, - '' - ]; - - if (result.replacements.length > 0) { - lines.push('## Suggested Replacements'); - lines.push(''); - - for (const rep of result.replacements) { - lines.push(`- Replace \`${rep.original}\` with \`${rep.replacement}\``); - lines.push(` Token: ${rep.tokenName}`); - if (rep.property) lines.push(` Property: ${rep.property}`); - lines.push(''); - } - - if (result.fixedCode !== result.originalCode) { - lines.push('## Fixed Code'); - lines.push('```css'); - lines.push(result.fixedCode); - lines.push('```'); - } - } else { - lines.push('✓ No replacements needed!'); - } - - return lines.join('\n'); -}