Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 4 additions & 28 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -187,7 +188,8 @@ const tools = [
new ListComponentsTool(),
new GetComponentInfoTool(),
new GetComponentTokensTool(),
new SearchDocumentationTool()
new SearchDocumentationTool(),
new ReplaceHardCodedValuesTool()
]

tools.forEach((tool) => {
Expand Down Expand Up @@ -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
Expand Down
111 changes: 111 additions & 0 deletions src/tools/replace-hard-coded-values-tool.ts
Original file line number Diff line number Diff line change
@@ -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<string> {
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
101 changes: 0 additions & 101 deletions src/tools/replace.ts

This file was deleted.