@fragments-sdk/cli 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +106 -0
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +4783 -0
- package/dist/bin.js.map +1 -0
- package/dist/chunk-4FDQSGKX.js +786 -0
- package/dist/chunk-4FDQSGKX.js.map +1 -0
- package/dist/chunk-7H2MMGYG.js +369 -0
- package/dist/chunk-7H2MMGYG.js.map +1 -0
- package/dist/chunk-BSCG3IP7.js +619 -0
- package/dist/chunk-BSCG3IP7.js.map +1 -0
- package/dist/chunk-LY2CFFPY.js +898 -0
- package/dist/chunk-LY2CFFPY.js.map +1 -0
- package/dist/chunk-MUZ6CM66.js +6636 -0
- package/dist/chunk-MUZ6CM66.js.map +1 -0
- package/dist/chunk-OAENNG3G.js +1489 -0
- package/dist/chunk-OAENNG3G.js.map +1 -0
- package/dist/chunk-XHNKNI6J.js +235 -0
- package/dist/chunk-XHNKNI6J.js.map +1 -0
- package/dist/core-DWKLGY4N.js +68 -0
- package/dist/core-DWKLGY4N.js.map +1 -0
- package/dist/generate-4LQNJ7SX.js +249 -0
- package/dist/generate-4LQNJ7SX.js.map +1 -0
- package/dist/index.d.ts +775 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/init-EMVI47QG.js +416 -0
- package/dist/init-EMVI47QG.js.map +1 -0
- package/dist/mcp-bin.d.ts +1 -0
- package/dist/mcp-bin.js +1117 -0
- package/dist/mcp-bin.js.map +1 -0
- package/dist/scan-4YPRF7FV.js +12 -0
- package/dist/scan-4YPRF7FV.js.map +1 -0
- package/dist/service-QSZMZJBJ.js +208 -0
- package/dist/service-QSZMZJBJ.js.map +1 -0
- package/dist/static-viewer-MIPGZ4Z7.js +12 -0
- package/dist/static-viewer-MIPGZ4Z7.js.map +1 -0
- package/dist/test-SQ5ZHXWU.js +1067 -0
- package/dist/test-SQ5ZHXWU.js.map +1 -0
- package/dist/tokens-HSGMYK64.js +173 -0
- package/dist/tokens-HSGMYK64.js.map +1 -0
- package/dist/viewer-YRF4SQE4.js +11101 -0
- package/dist/viewer-YRF4SQE4.js.map +1 -0
- package/package.json +107 -0
- package/src/ai.ts +266 -0
- package/src/analyze.ts +265 -0
- package/src/bin.ts +916 -0
- package/src/build.ts +248 -0
- package/src/commands/a11y.ts +302 -0
- package/src/commands/add.ts +313 -0
- package/src/commands/audit.ts +195 -0
- package/src/commands/baseline.ts +221 -0
- package/src/commands/build.ts +144 -0
- package/src/commands/compare.ts +337 -0
- package/src/commands/context.ts +107 -0
- package/src/commands/dev.ts +107 -0
- package/src/commands/enhance.ts +858 -0
- package/src/commands/generate.ts +391 -0
- package/src/commands/init.ts +531 -0
- package/src/commands/link/figma.ts +645 -0
- package/src/commands/link/index.ts +10 -0
- package/src/commands/link/storybook.ts +267 -0
- package/src/commands/list.ts +49 -0
- package/src/commands/metrics.ts +114 -0
- package/src/commands/reset.ts +242 -0
- package/src/commands/scan.ts +537 -0
- package/src/commands/storygen.ts +207 -0
- package/src/commands/tokens.ts +251 -0
- package/src/commands/validate.ts +93 -0
- package/src/commands/verify.ts +215 -0
- package/src/core/composition.test.ts +262 -0
- package/src/core/composition.ts +255 -0
- package/src/core/config.ts +84 -0
- package/src/core/constants.ts +111 -0
- package/src/core/context.ts +380 -0
- package/src/core/defineSegment.ts +137 -0
- package/src/core/discovery.ts +337 -0
- package/src/core/figma.ts +263 -0
- package/src/core/fragment-types.ts +214 -0
- package/src/core/generators/context.ts +389 -0
- package/src/core/generators/index.ts +23 -0
- package/src/core/generators/registry.ts +364 -0
- package/src/core/generators/typescript-extractor.ts +374 -0
- package/src/core/importAnalyzer.ts +217 -0
- package/src/core/index.ts +149 -0
- package/src/core/loader.ts +155 -0
- package/src/core/node.ts +63 -0
- package/src/core/parser.ts +551 -0
- package/src/core/previewLoader.ts +172 -0
- package/src/core/schema/fragment.schema.json +189 -0
- package/src/core/schema/registry.schema.json +137 -0
- package/src/core/schema.ts +182 -0
- package/src/core/storyAdapter.test.ts +571 -0
- package/src/core/storyAdapter.ts +761 -0
- package/src/core/token-types.ts +287 -0
- package/src/core/types.ts +754 -0
- package/src/diff.ts +323 -0
- package/src/index.ts +43 -0
- package/src/mcp/__tests__/projectFields.test.ts +130 -0
- package/src/mcp/bin.ts +36 -0
- package/src/mcp/index.ts +8 -0
- package/src/mcp/server.ts +1310 -0
- package/src/mcp/utils.ts +54 -0
- package/src/mcp-bin.ts +36 -0
- package/src/migrate/__tests__/argTypes/argTypes.test.ts +189 -0
- package/src/migrate/__tests__/args/args.test.ts +452 -0
- package/src/migrate/__tests__/meta/meta.test.ts +198 -0
- package/src/migrate/__tests__/stories/stories.test.ts +278 -0
- package/src/migrate/__tests__/utils/utils.test.ts +371 -0
- package/src/migrate/__tests__/values/values.test.ts +303 -0
- package/src/migrate/bin.ts +108 -0
- package/src/migrate/converter.ts +658 -0
- package/src/migrate/detect.ts +196 -0
- package/src/migrate/index.ts +45 -0
- package/src/migrate/migrate.ts +163 -0
- package/src/migrate/parser.ts +1136 -0
- package/src/migrate/report.ts +624 -0
- package/src/migrate/types.ts +169 -0
- package/src/screenshot.ts +249 -0
- package/src/service/__tests__/ast-utils.test.ts +426 -0
- package/src/service/__tests__/enhance-scanner.test.ts +200 -0
- package/src/service/__tests__/figma/figma.test.ts +652 -0
- package/src/service/__tests__/metrics-store.test.ts +409 -0
- package/src/service/__tests__/patch-generator.test.ts +186 -0
- package/src/service/__tests__/props-extractor.test.ts +365 -0
- package/src/service/__tests__/token-registry.test.ts +267 -0
- package/src/service/analytics.ts +659 -0
- package/src/service/ast-utils.ts +444 -0
- package/src/service/browser-pool.ts +339 -0
- package/src/service/capture.ts +267 -0
- package/src/service/diff.ts +279 -0
- package/src/service/enhance/aggregator.ts +489 -0
- package/src/service/enhance/cache.ts +275 -0
- package/src/service/enhance/codebase-scanner.ts +357 -0
- package/src/service/enhance/context-generator.ts +529 -0
- package/src/service/enhance/doc-extractor.ts +523 -0
- package/src/service/enhance/index.ts +131 -0
- package/src/service/enhance/props-extractor.ts +665 -0
- package/src/service/enhance/scanner.ts +445 -0
- package/src/service/enhance/storybook-parser.ts +552 -0
- package/src/service/enhance/types.ts +346 -0
- package/src/service/enhance/variant-renderer.ts +479 -0
- package/src/service/figma.ts +1008 -0
- package/src/service/index.ts +249 -0
- package/src/service/metrics-store.ts +333 -0
- package/src/service/patch-generator.ts +349 -0
- package/src/service/report.ts +854 -0
- package/src/service/storage.ts +401 -0
- package/src/service/token-fixes.ts +281 -0
- package/src/service/token-parser.ts +504 -0
- package/src/service/token-registry.ts +721 -0
- package/src/service/utils.ts +172 -0
- package/src/setup.ts +241 -0
- package/src/shared/command-wrapper.ts +81 -0
- package/src/shared/dev-server-client.ts +199 -0
- package/src/shared/index.ts +8 -0
- package/src/shared/segment-loader.ts +59 -0
- package/src/shared/types.ts +147 -0
- package/src/static-viewer.ts +715 -0
- package/src/test/discovery.ts +172 -0
- package/src/test/index.ts +281 -0
- package/src/test/reporters/console.ts +194 -0
- package/src/test/reporters/json.ts +190 -0
- package/src/test/reporters/junit.ts +186 -0
- package/src/test/runner.ts +598 -0
- package/src/test/types.ts +245 -0
- package/src/test/watch.ts +200 -0
- package/src/validators.ts +152 -0
- package/src/viewer/__tests__/jsx-parser.test.ts +502 -0
- package/src/viewer/__tests__/render-utils.test.ts +232 -0
- package/src/viewer/__tests__/style-utils.test.ts +404 -0
- package/src/viewer/bin.ts +86 -0
- package/src/viewer/cli/health.ts +256 -0
- package/src/viewer/cli/index.ts +33 -0
- package/src/viewer/cli/scan.ts +124 -0
- package/src/viewer/cli/utils.ts +174 -0
- package/src/viewer/components/AccessibilityPanel.tsx +1404 -0
- package/src/viewer/components/ActionCapture.tsx +172 -0
- package/src/viewer/components/ActionsPanel.tsx +371 -0
- package/src/viewer/components/App.tsx +638 -0
- package/src/viewer/components/BottomPanel.tsx +224 -0
- package/src/viewer/components/CodePanel.tsx +589 -0
- package/src/viewer/components/CommandPalette.tsx +336 -0
- package/src/viewer/components/ComponentGraph.tsx +394 -0
- package/src/viewer/components/ComponentHeader.tsx +85 -0
- package/src/viewer/components/ContractPanel.tsx +234 -0
- package/src/viewer/components/ErrorBoundary.tsx +85 -0
- package/src/viewer/components/FigmaEmbed.tsx +231 -0
- package/src/viewer/components/FragmentEditor.tsx +485 -0
- package/src/viewer/components/HealthDashboard.tsx +452 -0
- package/src/viewer/components/HmrStatusIndicator.tsx +71 -0
- package/src/viewer/components/Icons.tsx +417 -0
- package/src/viewer/components/InteractionsPanel.tsx +720 -0
- package/src/viewer/components/IsolatedPreviewFrame.tsx +321 -0
- package/src/viewer/components/IsolatedRender.tsx +111 -0
- package/src/viewer/components/KeyboardShortcutsHelp.tsx +89 -0
- package/src/viewer/components/LandingPage.tsx +441 -0
- package/src/viewer/components/Layout.tsx +22 -0
- package/src/viewer/components/LeftSidebar.tsx +391 -0
- package/src/viewer/components/MultiViewportPreview.tsx +429 -0
- package/src/viewer/components/PreviewArea.tsx +404 -0
- package/src/viewer/components/PreviewFrameHost.tsx +310 -0
- package/src/viewer/components/PreviewPane.tsx +150 -0
- package/src/viewer/components/PreviewToolbar.tsx +176 -0
- package/src/viewer/components/PropsEditor.tsx +512 -0
- package/src/viewer/components/PropsTable.tsx +98 -0
- package/src/viewer/components/RelationsSection.tsx +57 -0
- package/src/viewer/components/ResizablePanel.tsx +328 -0
- package/src/viewer/components/RightSidebar.tsx +118 -0
- package/src/viewer/components/ScreenshotButton.tsx +90 -0
- package/src/viewer/components/Sidebar.tsx +169 -0
- package/src/viewer/components/SkeletonLoader.tsx +156 -0
- package/src/viewer/components/StoryRenderer.tsx +128 -0
- package/src/viewer/components/ThemeProvider.tsx +96 -0
- package/src/viewer/components/Toast.tsx +67 -0
- package/src/viewer/components/TokenStylePanel.tsx +708 -0
- package/src/viewer/components/UsageSection.tsx +95 -0
- package/src/viewer/components/VariantMatrix.tsx +350 -0
- package/src/viewer/components/VariantRenderer.tsx +131 -0
- package/src/viewer/components/VariantTabs.tsx +84 -0
- package/src/viewer/components/ViewportSelector.tsx +165 -0
- package/src/viewer/components/_future/CreatePage.tsx +836 -0
- package/src/viewer/composition-renderer.ts +381 -0
- package/src/viewer/constants/index.ts +1 -0
- package/src/viewer/constants/ui.ts +185 -0
- package/src/viewer/entry.tsx +299 -0
- package/src/viewer/hooks/index.ts +2 -0
- package/src/viewer/hooks/useA11yCache.ts +383 -0
- package/src/viewer/hooks/useA11yService.ts +498 -0
- package/src/viewer/hooks/useActions.ts +138 -0
- package/src/viewer/hooks/useAppState.ts +124 -0
- package/src/viewer/hooks/useFigmaIntegration.ts +132 -0
- package/src/viewer/hooks/useHmrStatus.ts +109 -0
- package/src/viewer/hooks/useKeyboardShortcuts.ts +222 -0
- package/src/viewer/hooks/usePreviewBridge.ts +347 -0
- package/src/viewer/hooks/useScrollSpy.ts +78 -0
- package/src/viewer/hooks/useUrlState.ts +330 -0
- package/src/viewer/hooks/useViewSettings.ts +125 -0
- package/src/viewer/index.html +28 -0
- package/src/viewer/index.ts +14 -0
- package/src/viewer/intelligence/healthReport.ts +505 -0
- package/src/viewer/intelligence/styleDrift.ts +340 -0
- package/src/viewer/intelligence/usageScanner.ts +309 -0
- package/src/viewer/jsx-parser.ts +485 -0
- package/src/viewer/postcss.config.js +6 -0
- package/src/viewer/preview-frame-entry.tsx +25 -0
- package/src/viewer/preview-frame.html +109 -0
- package/src/viewer/render-template.html +68 -0
- package/src/viewer/render-utils.ts +170 -0
- package/src/viewer/server.ts +276 -0
- package/src/viewer/style-utils.ts +414 -0
- package/src/viewer/styles/globals.css +355 -0
- package/src/viewer/tailwind.config.js +37 -0
- package/src/viewer/types/a11y.ts +197 -0
- package/src/viewer/utils/a11y-fixes.ts +471 -0
- package/src/viewer/utils/actionExport.ts +372 -0
- package/src/viewer/utils/colorSchemes.ts +201 -0
- package/src/viewer/utils/detectRelationships.ts +256 -0
- package/src/viewer/vite-plugin.ts +2143 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patch Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates unified diff patches to fix token compliance issues.
|
|
5
|
+
* Takes style comparison results and produces patches that replace
|
|
6
|
+
* hardcoded CSS values with design token references.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { EnhancedStyleDiffItem, TokenUsageSummary } from "../core/index.js";
|
|
10
|
+
import { TokenRegistryManager } from "./token-registry.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A patch represents a file modification in unified diff format
|
|
14
|
+
*/
|
|
15
|
+
export interface Patch {
|
|
16
|
+
/** File path relative to project root */
|
|
17
|
+
file: string;
|
|
18
|
+
|
|
19
|
+
/** Unified diff content */
|
|
20
|
+
diff: string;
|
|
21
|
+
|
|
22
|
+
/** Line number where the change starts */
|
|
23
|
+
lineNumber?: number;
|
|
24
|
+
|
|
25
|
+
/** Type of style syntax being modified */
|
|
26
|
+
styleType: "inline" | "styled-components" | "emotion" | "css-module" | "css";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Result of patch generation for a component
|
|
31
|
+
*/
|
|
32
|
+
export interface PatchGenerationResult {
|
|
33
|
+
/** Generated patches */
|
|
34
|
+
patches: Patch[];
|
|
35
|
+
|
|
36
|
+
/** Human-readable summary */
|
|
37
|
+
summary: string;
|
|
38
|
+
|
|
39
|
+
/** Number of hardcoded values that could be fixed */
|
|
40
|
+
fixableCount: number;
|
|
41
|
+
|
|
42
|
+
/** Number of hardcoded values that couldn't be fixed (no matching token) */
|
|
43
|
+
unfixableCount: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Options for patch generation
|
|
48
|
+
*/
|
|
49
|
+
export interface PatchGenerationOptions {
|
|
50
|
+
/** Source file path (if known from segment metadata) */
|
|
51
|
+
sourceFile?: string;
|
|
52
|
+
|
|
53
|
+
/** Style type hint */
|
|
54
|
+
styleType?: Patch["styleType"];
|
|
55
|
+
|
|
56
|
+
/** Number of context lines to include in diff (default: 3) */
|
|
57
|
+
contextLines?: number;
|
|
58
|
+
|
|
59
|
+
/** Theme context for token matching */
|
|
60
|
+
theme?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Generate token patches for a component's hardcoded styles
|
|
65
|
+
*
|
|
66
|
+
* @param componentName - Name of the component
|
|
67
|
+
* @param styleDiffs - Style comparison results with rendered vs figma values
|
|
68
|
+
* @param registry - Token registry for token lookup
|
|
69
|
+
* @param options - Generation options
|
|
70
|
+
*/
|
|
71
|
+
export function generateTokenPatches(
|
|
72
|
+
componentName: string,
|
|
73
|
+
styleDiffs: Array<{
|
|
74
|
+
property: string;
|
|
75
|
+
figma: string;
|
|
76
|
+
rendered: string;
|
|
77
|
+
match: boolean;
|
|
78
|
+
}>,
|
|
79
|
+
registry: TokenRegistryManager,
|
|
80
|
+
options: PatchGenerationOptions = {}
|
|
81
|
+
): PatchGenerationResult {
|
|
82
|
+
const { theme = "default", contextLines = 3 } = options;
|
|
83
|
+
|
|
84
|
+
// Get token usage summary with hardcoded properties
|
|
85
|
+
const summary = registry.calculateUsageSummary(styleDiffs, theme);
|
|
86
|
+
|
|
87
|
+
if (summary.hardcodedProperties.length === 0) {
|
|
88
|
+
return {
|
|
89
|
+
patches: [],
|
|
90
|
+
summary: `No hardcoded values found in ${componentName}. Token compliance is at ${summary.compliancePercent}%.`,
|
|
91
|
+
fixableCount: 0,
|
|
92
|
+
unfixableCount: 0,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const patches: Patch[] = [];
|
|
97
|
+
let fixableCount = 0;
|
|
98
|
+
let unfixableCount = 0;
|
|
99
|
+
|
|
100
|
+
// Group fixes by file (if we have file info)
|
|
101
|
+
const fixesByFile = new Map<string, EnhancedStyleDiffItem[]>();
|
|
102
|
+
|
|
103
|
+
for (const item of summary.hardcodedProperties) {
|
|
104
|
+
if (!item.suggestedFix) {
|
|
105
|
+
unfixableCount++;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
fixableCount++;
|
|
110
|
+
|
|
111
|
+
// For now, group under the source file or a placeholder
|
|
112
|
+
const file = options.sourceFile || `${componentName}.tsx`;
|
|
113
|
+
const existing = fixesByFile.get(file) || [];
|
|
114
|
+
existing.push(item);
|
|
115
|
+
fixesByFile.set(file, existing);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Generate patches for each file
|
|
119
|
+
for (const [file, fixes] of fixesByFile) {
|
|
120
|
+
const patch = generateUnifiedDiff(file, fixes, options);
|
|
121
|
+
if (patch) {
|
|
122
|
+
patches.push(patch);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Generate summary
|
|
127
|
+
const summaryLines: string[] = [];
|
|
128
|
+
summaryLines.push(`Token Patch Summary for ${componentName}:`);
|
|
129
|
+
summaryLines.push(`- Compliance: ${summary.compliancePercent}%`);
|
|
130
|
+
summaryLines.push(`- Fixable issues: ${fixableCount}`);
|
|
131
|
+
if (unfixableCount > 0) {
|
|
132
|
+
summaryLines.push(`- Unfixable issues: ${unfixableCount} (no matching token found)`);
|
|
133
|
+
}
|
|
134
|
+
summaryLines.push(`- Patches generated: ${patches.length}`);
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
patches,
|
|
138
|
+
summary: summaryLines.join("\n"),
|
|
139
|
+
fixableCount,
|
|
140
|
+
unfixableCount,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Generate a unified diff for a set of fixes in a single file
|
|
146
|
+
*/
|
|
147
|
+
function generateUnifiedDiff(
|
|
148
|
+
file: string,
|
|
149
|
+
fixes: EnhancedStyleDiffItem[],
|
|
150
|
+
options: PatchGenerationOptions
|
|
151
|
+
): Patch | null {
|
|
152
|
+
if (fixes.length === 0) return null;
|
|
153
|
+
|
|
154
|
+
const { styleType = detectStyleType(file) } = options;
|
|
155
|
+
const diffLines: string[] = [];
|
|
156
|
+
|
|
157
|
+
// Diff header
|
|
158
|
+
diffLines.push(`--- a/${file}`);
|
|
159
|
+
diffLines.push(`+++ b/${file}`);
|
|
160
|
+
|
|
161
|
+
// Generate hunks for each fix
|
|
162
|
+
// In a real implementation, we'd read the actual file and generate proper diffs
|
|
163
|
+
// For now, we generate synthetic diffs showing the transformation
|
|
164
|
+
for (const fix of fixes) {
|
|
165
|
+
if (!fix.suggestedFix) continue;
|
|
166
|
+
|
|
167
|
+
const cssProperty = toCssProperty(fix.property);
|
|
168
|
+
const hunk = generateHunk(cssProperty, fix.rendered, fix.suggestedFix, styleType);
|
|
169
|
+
diffLines.push(...hunk);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
file,
|
|
174
|
+
diff: diffLines.join("\n"),
|
|
175
|
+
styleType,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Generate a diff hunk for a single property fix
|
|
181
|
+
*/
|
|
182
|
+
function generateHunk(
|
|
183
|
+
cssProperty: string,
|
|
184
|
+
currentValue: string,
|
|
185
|
+
suggestedFix: NonNullable<EnhancedStyleDiffItem["suggestedFix"]>,
|
|
186
|
+
styleType: Patch["styleType"]
|
|
187
|
+
): string[] {
|
|
188
|
+
const lines: string[] = [];
|
|
189
|
+
|
|
190
|
+
// The hunk format depends on the style type
|
|
191
|
+
switch (styleType) {
|
|
192
|
+
case "inline":
|
|
193
|
+
// React inline style: { backgroundColor: '#0051c2' }
|
|
194
|
+
const camelProp = toCamelCase(cssProperty);
|
|
195
|
+
lines.push(`@@ -1,1 +1,1 @@ inline style`);
|
|
196
|
+
lines.push(`- ${camelProp}: '${currentValue}',`);
|
|
197
|
+
lines.push(`+ ${camelProp}: 'var(${suggestedFix.tokenName})',`);
|
|
198
|
+
break;
|
|
199
|
+
|
|
200
|
+
case "styled-components":
|
|
201
|
+
case "emotion":
|
|
202
|
+
// CSS-in-JS: background-color: #0051c2;
|
|
203
|
+
lines.push(`@@ -1,1 +1,1 @@ ${styleType}`);
|
|
204
|
+
lines.push(`- ${cssProperty}: ${currentValue};`);
|
|
205
|
+
lines.push(`+ ${cssProperty}: var(${suggestedFix.tokenName});`);
|
|
206
|
+
break;
|
|
207
|
+
|
|
208
|
+
case "css-module":
|
|
209
|
+
case "css":
|
|
210
|
+
default:
|
|
211
|
+
// Plain CSS: background-color: #0051c2;
|
|
212
|
+
lines.push(`@@ -1,1 +1,1 @@ css`);
|
|
213
|
+
lines.push(`- ${cssProperty}: ${currentValue};`);
|
|
214
|
+
lines.push(`+ ${cssProperty}: var(${suggestedFix.tokenName});`);
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return lines;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Detect the style type from file extension and name
|
|
223
|
+
*/
|
|
224
|
+
function detectStyleType(file: string): Patch["styleType"] {
|
|
225
|
+
if (file.endsWith(".css")) return "css";
|
|
226
|
+
if (file.endsWith(".module.css") || file.endsWith(".module.scss")) return "css-module";
|
|
227
|
+
if (file.includes("styled") || file.includes("emotion")) return "styled-components";
|
|
228
|
+
// Default to inline for TSX/JSX files
|
|
229
|
+
if (file.endsWith(".tsx") || file.endsWith(".jsx")) return "inline";
|
|
230
|
+
return "css";
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Convert camelCase to kebab-case
|
|
235
|
+
*/
|
|
236
|
+
function toCssProperty(prop: string): string {
|
|
237
|
+
return prop.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Convert kebab-case to camelCase
|
|
242
|
+
*/
|
|
243
|
+
function toCamelCase(prop: string): string {
|
|
244
|
+
return prop.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Generate patches for CSS-in-JS patterns
|
|
249
|
+
*
|
|
250
|
+
* Handles common patterns:
|
|
251
|
+
* - styled-components: styled.div`...`
|
|
252
|
+
* - emotion: css`...` or css={{...}}
|
|
253
|
+
* - inline: style={{...}}
|
|
254
|
+
*/
|
|
255
|
+
export function generateCSSInJSPatches(
|
|
256
|
+
sourceCode: string,
|
|
257
|
+
fixes: Array<{
|
|
258
|
+
property: string;
|
|
259
|
+
currentValue: string;
|
|
260
|
+
tokenName: string;
|
|
261
|
+
}>,
|
|
262
|
+
options: { fileName?: string } = {}
|
|
263
|
+
): Patch[] {
|
|
264
|
+
const patches: Patch[] = [];
|
|
265
|
+
const fileName = options.fileName || "component.tsx";
|
|
266
|
+
|
|
267
|
+
for (const fix of fixes) {
|
|
268
|
+
// Find the property in source code
|
|
269
|
+
const cssProperty = toCssProperty(fix.property);
|
|
270
|
+
const camelProperty = toCamelCase(cssProperty);
|
|
271
|
+
|
|
272
|
+
// Try to find inline style pattern: propertyName: 'value' or propertyName: "value"
|
|
273
|
+
const inlinePattern = new RegExp(
|
|
274
|
+
`(${camelProperty}\\s*:\\s*)(['"]?)${escapeRegExp(fix.currentValue)}\\2`,
|
|
275
|
+
"g"
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
// Try to find CSS pattern: property-name: value;
|
|
279
|
+
const cssPattern = new RegExp(
|
|
280
|
+
`(${cssProperty}\\s*:\\s*)${escapeRegExp(fix.currentValue)}(\\s*;)`,
|
|
281
|
+
"g"
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
let match;
|
|
285
|
+
const lines = sourceCode.split("\n");
|
|
286
|
+
|
|
287
|
+
// Check inline style pattern
|
|
288
|
+
for (let i = 0; i < lines.length; i++) {
|
|
289
|
+
const line = lines[i];
|
|
290
|
+
|
|
291
|
+
if (inlinePattern.test(line)) {
|
|
292
|
+
const newLine = line.replace(
|
|
293
|
+
inlinePattern,
|
|
294
|
+
`$1'var(${fix.tokenName})'`
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
patches.push({
|
|
298
|
+
file: fileName,
|
|
299
|
+
diff: generateLineDiff(fileName, i + 1, line, newLine),
|
|
300
|
+
lineNumber: i + 1,
|
|
301
|
+
styleType: "inline",
|
|
302
|
+
});
|
|
303
|
+
} else if (cssPattern.test(line)) {
|
|
304
|
+
const newLine = line.replace(
|
|
305
|
+
cssPattern,
|
|
306
|
+
`$1var(${fix.tokenName})$2`
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
patches.push({
|
|
310
|
+
file: fileName,
|
|
311
|
+
diff: generateLineDiff(fileName, i + 1, line, newLine),
|
|
312
|
+
lineNumber: i + 1,
|
|
313
|
+
styleType: "css",
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Reset regex state
|
|
318
|
+
inlinePattern.lastIndex = 0;
|
|
319
|
+
cssPattern.lastIndex = 0;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return patches;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Generate a unified diff for a single line change
|
|
328
|
+
*/
|
|
329
|
+
function generateLineDiff(
|
|
330
|
+
file: string,
|
|
331
|
+
lineNumber: number,
|
|
332
|
+
oldLine: string,
|
|
333
|
+
newLine: string
|
|
334
|
+
): string {
|
|
335
|
+
return [
|
|
336
|
+
`--- a/${file}`,
|
|
337
|
+
`+++ b/${file}`,
|
|
338
|
+
`@@ -${lineNumber},1 +${lineNumber},1 @@`,
|
|
339
|
+
`-${oldLine}`,
|
|
340
|
+
`+${newLine}`,
|
|
341
|
+
].join("\n");
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Escape special regex characters
|
|
346
|
+
*/
|
|
347
|
+
function escapeRegExp(string: string): string {
|
|
348
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
349
|
+
}
|