@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,721 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token Registry
|
|
3
|
+
*
|
|
4
|
+
* Manages design tokens in memory with fast lookup capabilities:
|
|
5
|
+
* - By name: O(1) lookup
|
|
6
|
+
* - By value (reverse): O(1) lookup
|
|
7
|
+
* - By theme: O(1) lookup
|
|
8
|
+
* - By category: O(1) lookup
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type {
|
|
12
|
+
DesignToken,
|
|
13
|
+
TokenRegistry,
|
|
14
|
+
TokenRegistryMeta,
|
|
15
|
+
TokenCategory,
|
|
16
|
+
TokenConfig,
|
|
17
|
+
TokenMatchRequest,
|
|
18
|
+
TokenMatchResult,
|
|
19
|
+
EnhancedStyleDiffItem,
|
|
20
|
+
TokenUsageSummary,
|
|
21
|
+
} from "../core/index.js";
|
|
22
|
+
import { parseTokenFiles, normalizeColor, hexToRgb, parseRgb } from "./token-parser.js";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Token Registry Manager
|
|
26
|
+
*
|
|
27
|
+
* Singleton-style manager for design tokens with initialization,
|
|
28
|
+
* lookup, and matching capabilities.
|
|
29
|
+
*/
|
|
30
|
+
export class TokenRegistryManager {
|
|
31
|
+
private registry: TokenRegistry | null = null;
|
|
32
|
+
private initPromise: Promise<void> | null = null;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Initialize the registry by parsing token files
|
|
36
|
+
*/
|
|
37
|
+
async initialize(
|
|
38
|
+
config: TokenConfig,
|
|
39
|
+
projectRoot: string
|
|
40
|
+
): Promise<TokenRegistry> {
|
|
41
|
+
// If already initializing, wait for that
|
|
42
|
+
if (this.initPromise) {
|
|
43
|
+
await this.initPromise;
|
|
44
|
+
return this.registry!;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// If already initialized, return existing
|
|
48
|
+
if (this.registry) {
|
|
49
|
+
return this.registry;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.initPromise = this.doInitialize(config, projectRoot);
|
|
53
|
+
await this.initPromise;
|
|
54
|
+
this.initPromise = null;
|
|
55
|
+
|
|
56
|
+
return this.registry!;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private async doInitialize(
|
|
60
|
+
config: TokenConfig,
|
|
61
|
+
projectRoot: string
|
|
62
|
+
): Promise<void> {
|
|
63
|
+
const startTime = performance.now();
|
|
64
|
+
|
|
65
|
+
// Parse all token files
|
|
66
|
+
const result = await parseTokenFiles(config, projectRoot);
|
|
67
|
+
|
|
68
|
+
// Build the registry
|
|
69
|
+
const byName = new Map<string, DesignToken>();
|
|
70
|
+
const byValue = new Map<string, string[]>();
|
|
71
|
+
const byTheme = new Map<string, DesignToken[]>();
|
|
72
|
+
const byCategory = new Map<TokenCategory, DesignToken[]>();
|
|
73
|
+
|
|
74
|
+
let circularRefs = 0;
|
|
75
|
+
let unresolvedRefs = 0;
|
|
76
|
+
|
|
77
|
+
for (const token of result.tokens) {
|
|
78
|
+
// Index by name
|
|
79
|
+
byName.set(token.name, token);
|
|
80
|
+
|
|
81
|
+
// Index by resolved value (reverse lookup)
|
|
82
|
+
const normalizedValue = this.normalizeForLookup(token.resolvedValue);
|
|
83
|
+
const existingTokens = byValue.get(normalizedValue) || [];
|
|
84
|
+
existingTokens.push(token.name);
|
|
85
|
+
byValue.set(normalizedValue, existingTokens);
|
|
86
|
+
|
|
87
|
+
// Index by theme
|
|
88
|
+
const themeTokens = byTheme.get(token.theme) || [];
|
|
89
|
+
themeTokens.push(token);
|
|
90
|
+
byTheme.set(token.theme, themeTokens);
|
|
91
|
+
|
|
92
|
+
// Index by category
|
|
93
|
+
const categoryTokens = byCategory.get(token.category) || [];
|
|
94
|
+
categoryTokens.push(token);
|
|
95
|
+
byCategory.set(token.category, categoryTokens);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Count issues from warnings
|
|
99
|
+
for (const warning of result.warnings) {
|
|
100
|
+
if (warning.includes("Circular")) circularRefs++;
|
|
101
|
+
if (warning.includes("Unresolved")) unresolvedRefs++;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const meta: TokenRegistryMeta = {
|
|
105
|
+
discoveredAt: new Date(),
|
|
106
|
+
sourceFiles: config.include,
|
|
107
|
+
totalTokens: result.tokens.length,
|
|
108
|
+
parseTimeMs: performance.now() - startTime,
|
|
109
|
+
circularRefs,
|
|
110
|
+
unresolvedRefs,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
this.registry = {
|
|
114
|
+
byName,
|
|
115
|
+
byValue,
|
|
116
|
+
byTheme,
|
|
117
|
+
byCategory,
|
|
118
|
+
meta,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get the current registry (throws if not initialized)
|
|
124
|
+
*/
|
|
125
|
+
getRegistry(): TokenRegistry {
|
|
126
|
+
if (!this.registry) {
|
|
127
|
+
throw new Error("Token registry not initialized. Call initialize() first.");
|
|
128
|
+
}
|
|
129
|
+
return this.registry;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Check if registry is initialized
|
|
134
|
+
*/
|
|
135
|
+
isInitialized(): boolean {
|
|
136
|
+
return this.registry !== null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Clear the registry (for re-initialization)
|
|
141
|
+
*/
|
|
142
|
+
clear(): void {
|
|
143
|
+
this.registry = null;
|
|
144
|
+
this.initPromise = null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Get a token by name
|
|
149
|
+
*/
|
|
150
|
+
getToken(name: string): DesignToken | undefined {
|
|
151
|
+
return this.registry?.byName.get(name);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Find tokens by resolved value (reverse lookup)
|
|
156
|
+
*
|
|
157
|
+
* This is the key feature: given a computed value like "#0051c2",
|
|
158
|
+
* find which design token(s) resolve to that value.
|
|
159
|
+
*/
|
|
160
|
+
findByValue(value: string, theme?: string): string[] {
|
|
161
|
+
if (!this.registry) return [];
|
|
162
|
+
|
|
163
|
+
const normalizedValue = this.normalizeForLookup(value);
|
|
164
|
+
const tokenNames = this.registry.byValue.get(normalizedValue) || [];
|
|
165
|
+
|
|
166
|
+
// Filter by theme if specified
|
|
167
|
+
if (theme && tokenNames.length > 0) {
|
|
168
|
+
return tokenNames.filter((name) => {
|
|
169
|
+
const token = this.registry!.byName.get(name);
|
|
170
|
+
return token?.theme === theme || token?.theme === "default";
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return tokenNames;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Match a value to tokens with similarity scoring
|
|
179
|
+
*/
|
|
180
|
+
matchValue(request: TokenMatchRequest): TokenMatchResult {
|
|
181
|
+
const { value, propertyType, theme } = request;
|
|
182
|
+
const exactMatches: DesignToken[] = [];
|
|
183
|
+
const closeMatches: Array<{ token: DesignToken; similarity: number }> = [];
|
|
184
|
+
|
|
185
|
+
if (!this.registry) {
|
|
186
|
+
return { exactMatches, closeMatches, found: false };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const normalizedValue = this.normalizeForLookup(value);
|
|
190
|
+
|
|
191
|
+
// Find exact matches
|
|
192
|
+
const exactNames = this.registry.byValue.get(normalizedValue) || [];
|
|
193
|
+
for (const name of exactNames) {
|
|
194
|
+
const token = this.registry.byName.get(name);
|
|
195
|
+
if (token) {
|
|
196
|
+
// Filter by theme if specified
|
|
197
|
+
if (!theme || token.theme === theme || token.theme === "default") {
|
|
198
|
+
exactMatches.push(token);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// For colors, find close matches
|
|
204
|
+
if (propertyType === "color" || this.looksLikeColor(value)) {
|
|
205
|
+
const targetRgb = this.parseColorToRgb(value);
|
|
206
|
+
if (targetRgb) {
|
|
207
|
+
// Get all color tokens
|
|
208
|
+
const colorTokens = this.registry.byCategory.get("color") || [];
|
|
209
|
+
|
|
210
|
+
for (const token of colorTokens) {
|
|
211
|
+
// Skip if already an exact match
|
|
212
|
+
if (exactMatches.includes(token)) continue;
|
|
213
|
+
|
|
214
|
+
// Filter by theme
|
|
215
|
+
if (theme && token.theme !== theme && token.theme !== "default") {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const tokenRgb = this.parseColorToRgb(token.resolvedValue);
|
|
220
|
+
if (tokenRgb) {
|
|
221
|
+
const similarity = this.colorSimilarity(targetRgb, tokenRgb);
|
|
222
|
+
if (similarity > 0.9) {
|
|
223
|
+
// 90% similar
|
|
224
|
+
closeMatches.push({ token, similarity });
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Sort by similarity descending
|
|
230
|
+
closeMatches.sort((a, b) => b.similarity - a.similarity);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
exactMatches,
|
|
236
|
+
closeMatches: closeMatches.slice(0, 5), // Top 5 close matches
|
|
237
|
+
found: exactMatches.length > 0 || closeMatches.length > 0,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Get all tokens for a theme
|
|
243
|
+
*/
|
|
244
|
+
getTokensByTheme(theme: string): DesignToken[] {
|
|
245
|
+
return this.registry?.byTheme.get(theme) || [];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get all tokens in a category
|
|
250
|
+
*/
|
|
251
|
+
getTokensByCategory(category: TokenCategory): DesignToken[] {
|
|
252
|
+
return this.registry?.byCategory.get(category) || [];
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Get all tokens
|
|
257
|
+
*/
|
|
258
|
+
getAllTokens(): DesignToken[] {
|
|
259
|
+
if (!this.registry) return [];
|
|
260
|
+
return Array.from(this.registry.byName.values());
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Get registry metadata
|
|
265
|
+
*/
|
|
266
|
+
getMeta(): TokenRegistryMeta | undefined {
|
|
267
|
+
return this.registry?.meta;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Enhance a style diff with token information
|
|
272
|
+
*/
|
|
273
|
+
enhanceStyleDiff(
|
|
274
|
+
figmaValue: string,
|
|
275
|
+
renderedValue: string,
|
|
276
|
+
property: string,
|
|
277
|
+
theme = "default"
|
|
278
|
+
): Partial<EnhancedStyleDiffItem> {
|
|
279
|
+
const figmaTokens = this.findByValue(figmaValue, theme);
|
|
280
|
+
const renderedTokens = this.findByValue(renderedValue, theme);
|
|
281
|
+
|
|
282
|
+
const figmaToken = figmaTokens.length > 0 ? figmaTokens[0] : undefined;
|
|
283
|
+
const renderedToken = renderedTokens.length > 0 ? renderedTokens[0] : undefined;
|
|
284
|
+
|
|
285
|
+
// Determine if this is a hardcoded value
|
|
286
|
+
// Hardcoded = Figma matches a token, but rendered doesn't use a token
|
|
287
|
+
const isHardcoded = !!figmaToken && !renderedToken;
|
|
288
|
+
|
|
289
|
+
let suggestedFix: EnhancedStyleDiffItem["suggestedFix"] | undefined;
|
|
290
|
+
|
|
291
|
+
if (isHardcoded && figmaToken) {
|
|
292
|
+
const token = this.getToken(figmaToken);
|
|
293
|
+
if (token) {
|
|
294
|
+
const cssProperty = this.toCssProperty(property);
|
|
295
|
+
suggestedFix = {
|
|
296
|
+
tokenName: figmaToken,
|
|
297
|
+
tokenValue: token.resolvedValue,
|
|
298
|
+
codeFix: `${cssProperty}: var(${figmaToken});`,
|
|
299
|
+
confidence: 0.9,
|
|
300
|
+
reason: `Figma uses token ${figmaToken} (${token.resolvedValue}). Replace hardcoded value with token for consistency.`,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return {
|
|
306
|
+
figmaToken,
|
|
307
|
+
renderedToken,
|
|
308
|
+
isHardcoded,
|
|
309
|
+
suggestedFix,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Calculate token usage summary for a set of style comparisons
|
|
315
|
+
*/
|
|
316
|
+
calculateUsageSummary(
|
|
317
|
+
styleDiffs: Array<{
|
|
318
|
+
property: string;
|
|
319
|
+
figma: string;
|
|
320
|
+
rendered: string;
|
|
321
|
+
match: boolean;
|
|
322
|
+
}>,
|
|
323
|
+
theme = "default"
|
|
324
|
+
): TokenUsageSummary {
|
|
325
|
+
const hardcodedProperties: EnhancedStyleDiffItem[] = [];
|
|
326
|
+
let usingTokens = 0;
|
|
327
|
+
let hardcoded = 0;
|
|
328
|
+
let implicitMatches = 0;
|
|
329
|
+
|
|
330
|
+
for (const diff of styleDiffs) {
|
|
331
|
+
const enhanced = this.enhanceStyleDiff(
|
|
332
|
+
diff.figma,
|
|
333
|
+
diff.rendered,
|
|
334
|
+
diff.property,
|
|
335
|
+
theme
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
if (enhanced.renderedToken) {
|
|
339
|
+
usingTokens++;
|
|
340
|
+
} else if (enhanced.isHardcoded) {
|
|
341
|
+
hardcoded++;
|
|
342
|
+
hardcodedProperties.push({
|
|
343
|
+
...diff,
|
|
344
|
+
...enhanced,
|
|
345
|
+
isHardcoded: true,
|
|
346
|
+
} as EnhancedStyleDiffItem);
|
|
347
|
+
} else if (diff.match && enhanced.figmaToken) {
|
|
348
|
+
// Values match and Figma uses a token, but rendered doesn't explicitly use token
|
|
349
|
+
implicitMatches++;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const totalProperties = styleDiffs.length;
|
|
354
|
+
const compliancePercent =
|
|
355
|
+
totalProperties > 0
|
|
356
|
+
? Math.round(((usingTokens + implicitMatches) / totalProperties) * 100)
|
|
357
|
+
: 100;
|
|
358
|
+
|
|
359
|
+
return {
|
|
360
|
+
totalProperties,
|
|
361
|
+
usingTokens,
|
|
362
|
+
hardcoded,
|
|
363
|
+
implicitMatches,
|
|
364
|
+
compliancePercent,
|
|
365
|
+
hardcodedProperties,
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Find closest matching tokens for a value that doesn't match exactly
|
|
371
|
+
*
|
|
372
|
+
* @param value - The value to find close matches for
|
|
373
|
+
* @param category - Optional category to filter by (color, spacing, sizing, etc.)
|
|
374
|
+
* @param options - Matching options
|
|
375
|
+
* @returns Array of close matches sorted by distance with confidence scores
|
|
376
|
+
*/
|
|
377
|
+
findClosestToken(
|
|
378
|
+
value: string,
|
|
379
|
+
category?: TokenCategory,
|
|
380
|
+
options: {
|
|
381
|
+
/** Maximum numeric difference for spacing/sizing (default: 4px) */
|
|
382
|
+
numericThreshold?: number;
|
|
383
|
+
/** Maximum color difference using Delta E (default: 5) */
|
|
384
|
+
colorDeltaE?: number;
|
|
385
|
+
/** Maximum results to return (default: 5) */
|
|
386
|
+
limit?: number;
|
|
387
|
+
/** Theme to filter by */
|
|
388
|
+
theme?: string;
|
|
389
|
+
} = {}
|
|
390
|
+
): Array<{ token: DesignToken; distance: number; confidence: number }> {
|
|
391
|
+
if (!this.registry) return [];
|
|
392
|
+
|
|
393
|
+
const {
|
|
394
|
+
numericThreshold = 4,
|
|
395
|
+
colorDeltaE = 5,
|
|
396
|
+
limit = 5,
|
|
397
|
+
theme,
|
|
398
|
+
} = options;
|
|
399
|
+
|
|
400
|
+
const results: Array<{ token: DesignToken; distance: number; confidence: number }> = [];
|
|
401
|
+
|
|
402
|
+
// Determine value type
|
|
403
|
+
const isColor = this.looksLikeColor(value);
|
|
404
|
+
const numericValue = this.parseNumericValue(value);
|
|
405
|
+
const isNumeric = numericValue !== null;
|
|
406
|
+
|
|
407
|
+
// Get tokens to search through
|
|
408
|
+
let candidates: DesignToken[];
|
|
409
|
+
if (category) {
|
|
410
|
+
candidates = this.registry.byCategory.get(category) || [];
|
|
411
|
+
} else if (isColor) {
|
|
412
|
+
candidates = this.registry.byCategory.get("color") || [];
|
|
413
|
+
} else if (isNumeric) {
|
|
414
|
+
// Search through spacing, sizing, and radius tokens
|
|
415
|
+
candidates = [
|
|
416
|
+
...(this.registry.byCategory.get("spacing") || []),
|
|
417
|
+
...(this.registry.byCategory.get("sizing") || []),
|
|
418
|
+
...(this.registry.byCategory.get("radius") || []),
|
|
419
|
+
];
|
|
420
|
+
} else {
|
|
421
|
+
// Search all tokens
|
|
422
|
+
candidates = Array.from(this.registry.byName.values());
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Filter by theme if specified
|
|
426
|
+
if (theme) {
|
|
427
|
+
candidates = candidates.filter(
|
|
428
|
+
(t) => t.theme === theme || t.theme === "default"
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// Calculate distances
|
|
433
|
+
if (isColor) {
|
|
434
|
+
const targetRgb = this.parseColorToRgb(value);
|
|
435
|
+
if (targetRgb) {
|
|
436
|
+
for (const token of candidates) {
|
|
437
|
+
const tokenRgb = this.parseColorToRgb(token.resolvedValue);
|
|
438
|
+
if (!tokenRgb) continue;
|
|
439
|
+
|
|
440
|
+
// Calculate Delta E (CIE76 approximation using RGB)
|
|
441
|
+
const deltaE = this.calculateDeltaE(targetRgb, tokenRgb);
|
|
442
|
+
|
|
443
|
+
if (deltaE <= colorDeltaE) {
|
|
444
|
+
// Confidence inversely proportional to deltaE
|
|
445
|
+
const confidence = Math.max(0, 1 - deltaE / colorDeltaE);
|
|
446
|
+
results.push({ token, distance: deltaE, confidence });
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
} else if (isNumeric) {
|
|
451
|
+
for (const token of candidates) {
|
|
452
|
+
const tokenNumeric = this.parseNumericValue(token.resolvedValue);
|
|
453
|
+
if (tokenNumeric === null) continue;
|
|
454
|
+
|
|
455
|
+
const distance = Math.abs(numericValue - tokenNumeric);
|
|
456
|
+
|
|
457
|
+
if (distance <= numericThreshold) {
|
|
458
|
+
// Confidence inversely proportional to distance
|
|
459
|
+
const confidence = Math.max(0, 1 - distance / numericThreshold);
|
|
460
|
+
results.push({ token, distance, confidence });
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Sort by distance ascending (closest first)
|
|
466
|
+
results.sort((a, b) => a.distance - b.distance);
|
|
467
|
+
|
|
468
|
+
return results.slice(0, limit);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Serialize registry for JSON export
|
|
473
|
+
*/
|
|
474
|
+
toJSON(): {
|
|
475
|
+
tokens: DesignToken[];
|
|
476
|
+
meta: TokenRegistryMeta;
|
|
477
|
+
} {
|
|
478
|
+
if (!this.registry) {
|
|
479
|
+
return { tokens: [], meta: this.createEmptyMeta() };
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
return {
|
|
483
|
+
tokens: Array.from(this.registry.byName.values()),
|
|
484
|
+
meta: this.registry.meta,
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// ----- Private helpers -----
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Normalize a value for consistent lookup
|
|
492
|
+
*/
|
|
493
|
+
private normalizeForLookup(value: string): string {
|
|
494
|
+
// Lowercase
|
|
495
|
+
let normalized = value.toLowerCase().trim();
|
|
496
|
+
|
|
497
|
+
// Normalize color formats
|
|
498
|
+
if (this.looksLikeColor(normalized)) {
|
|
499
|
+
const rgb = this.parseColorToRgb(value);
|
|
500
|
+
if (rgb) {
|
|
501
|
+
// Convert to lowercase hex for consistent lookup
|
|
502
|
+
normalized = `#${[rgb.r, rgb.g, rgb.b]
|
|
503
|
+
.map((x) => x.toString(16).padStart(2, "0"))
|
|
504
|
+
.join("")}`;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Normalize whitespace
|
|
509
|
+
normalized = normalized.replace(/\s+/g, " ");
|
|
510
|
+
|
|
511
|
+
return normalized;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Check if a value looks like a color
|
|
516
|
+
*/
|
|
517
|
+
private looksLikeColor(value: string): boolean {
|
|
518
|
+
return (
|
|
519
|
+
value.startsWith("#") ||
|
|
520
|
+
value.startsWith("rgb") ||
|
|
521
|
+
value.startsWith("hsl") ||
|
|
522
|
+
/^(transparent|white|black|red|blue|green|yellow|orange|purple|pink|gray|grey)$/i.test(
|
|
523
|
+
value
|
|
524
|
+
)
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Parse any color format to RGB
|
|
530
|
+
*/
|
|
531
|
+
private parseColorToRgb(
|
|
532
|
+
color: string
|
|
533
|
+
): { r: number; g: number; b: number } | null {
|
|
534
|
+
// Handle named colors
|
|
535
|
+
const namedColors: Record<string, { r: number; g: number; b: number }> = {
|
|
536
|
+
white: { r: 255, g: 255, b: 255 },
|
|
537
|
+
black: { r: 0, g: 0, b: 0 },
|
|
538
|
+
transparent: { r: 0, g: 0, b: 0 },
|
|
539
|
+
red: { r: 255, g: 0, b: 0 },
|
|
540
|
+
green: { r: 0, g: 128, b: 0 },
|
|
541
|
+
blue: { r: 0, g: 0, b: 255 },
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
const lower = color.toLowerCase().trim();
|
|
545
|
+
if (namedColors[lower]) {
|
|
546
|
+
return namedColors[lower];
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Handle hex
|
|
550
|
+
if (color.startsWith("#")) {
|
|
551
|
+
return hexToRgb(color);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Handle rgb/rgba
|
|
555
|
+
if (color.startsWith("rgb")) {
|
|
556
|
+
const parsed = parseRgb(color);
|
|
557
|
+
if (parsed) {
|
|
558
|
+
return { r: parsed.r, g: parsed.g, b: parsed.b };
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
return null;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Calculate color similarity (0-1)
|
|
567
|
+
*/
|
|
568
|
+
private colorSimilarity(
|
|
569
|
+
c1: { r: number; g: number; b: number },
|
|
570
|
+
c2: { r: number; g: number; b: number }
|
|
571
|
+
): number {
|
|
572
|
+
// Use simple Euclidean distance in RGB space
|
|
573
|
+
const maxDist = Math.sqrt(255 ** 2 * 3);
|
|
574
|
+
const dist = Math.sqrt(
|
|
575
|
+
(c1.r - c2.r) ** 2 + (c1.g - c2.g) ** 2 + (c1.b - c2.b) ** 2
|
|
576
|
+
);
|
|
577
|
+
|
|
578
|
+
return 1 - dist / maxDist;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Convert camelCase property to kebab-case CSS property
|
|
583
|
+
*/
|
|
584
|
+
private toCssProperty(prop: string): string {
|
|
585
|
+
return prop.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Create empty metadata
|
|
590
|
+
*/
|
|
591
|
+
private createEmptyMeta(): TokenRegistryMeta {
|
|
592
|
+
return {
|
|
593
|
+
discoveredAt: new Date(),
|
|
594
|
+
sourceFiles: [],
|
|
595
|
+
totalTokens: 0,
|
|
596
|
+
parseTimeMs: 0,
|
|
597
|
+
circularRefs: 0,
|
|
598
|
+
unresolvedRefs: 0,
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Parse a numeric value from a CSS value string
|
|
604
|
+
* Handles px, rem, em, % and bare numbers
|
|
605
|
+
*/
|
|
606
|
+
private parseNumericValue(value: string): number | null {
|
|
607
|
+
const trimmed = value.trim().toLowerCase();
|
|
608
|
+
|
|
609
|
+
// Match numeric values with optional units
|
|
610
|
+
const match = trimmed.match(/^(-?\d*\.?\d+)(px|rem|em|%)?$/);
|
|
611
|
+
if (!match) return null;
|
|
612
|
+
|
|
613
|
+
const num = parseFloat(match[1]);
|
|
614
|
+
const unit = match[2];
|
|
615
|
+
|
|
616
|
+
// Convert to px for comparison
|
|
617
|
+
switch (unit) {
|
|
618
|
+
case "rem":
|
|
619
|
+
return num * 16; // Assume 16px base
|
|
620
|
+
case "em":
|
|
621
|
+
return num * 16; // Approximate
|
|
622
|
+
case "%":
|
|
623
|
+
return null; // Percentages are relative, skip
|
|
624
|
+
case "px":
|
|
625
|
+
default:
|
|
626
|
+
return num;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Calculate Delta E (CIE76) color difference
|
|
632
|
+
* Uses simplified RGB to Lab approximation
|
|
633
|
+
* Lower values = more similar (0 = identical, >5 = noticeably different)
|
|
634
|
+
*/
|
|
635
|
+
private calculateDeltaE(
|
|
636
|
+
c1: { r: number; g: number; b: number },
|
|
637
|
+
c2: { r: number; g: number; b: number }
|
|
638
|
+
): number {
|
|
639
|
+
// Convert RGB to Lab (simplified)
|
|
640
|
+
const lab1 = this.rgbToLab(c1);
|
|
641
|
+
const lab2 = this.rgbToLab(c2);
|
|
642
|
+
|
|
643
|
+
// CIE76 Delta E formula
|
|
644
|
+
return Math.sqrt(
|
|
645
|
+
Math.pow(lab2.l - lab1.l, 2) +
|
|
646
|
+
Math.pow(lab2.a - lab1.a, 2) +
|
|
647
|
+
Math.pow(lab2.b - lab1.b, 2)
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Convert RGB to Lab color space (simplified approximation)
|
|
653
|
+
*/
|
|
654
|
+
private rgbToLab(rgb: { r: number; g: number; b: number }): { l: number; a: number; b: number } {
|
|
655
|
+
// Normalize RGB values
|
|
656
|
+
let r = rgb.r / 255;
|
|
657
|
+
let g = rgb.g / 255;
|
|
658
|
+
let b = rgb.b / 255;
|
|
659
|
+
|
|
660
|
+
// Apply gamma correction
|
|
661
|
+
r = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
|
|
662
|
+
g = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
|
|
663
|
+
b = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
|
|
664
|
+
|
|
665
|
+
// Convert to XYZ
|
|
666
|
+
let x = (r * 0.4124564 + g * 0.3575761 + b * 0.1804375) / 0.95047;
|
|
667
|
+
let y = (r * 0.2126729 + g * 0.7151522 + b * 0.0721750);
|
|
668
|
+
let z = (r * 0.0193339 + g * 0.1191920 + b * 0.9503041) / 1.08883;
|
|
669
|
+
|
|
670
|
+
// Convert to Lab
|
|
671
|
+
x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + 16/116;
|
|
672
|
+
y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + 16/116;
|
|
673
|
+
z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + 16/116;
|
|
674
|
+
|
|
675
|
+
return {
|
|
676
|
+
l: (116 * y) - 16,
|
|
677
|
+
a: 500 * (x - y),
|
|
678
|
+
b: 200 * (y - z),
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* Shared singleton instance
|
|
685
|
+
*/
|
|
686
|
+
let sharedRegistry: TokenRegistryManager | null = null;
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Get or create the shared token registry
|
|
690
|
+
*/
|
|
691
|
+
export function getSharedTokenRegistry(): TokenRegistryManager {
|
|
692
|
+
if (!sharedRegistry) {
|
|
693
|
+
sharedRegistry = new TokenRegistryManager();
|
|
694
|
+
}
|
|
695
|
+
return sharedRegistry;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Initialize the shared registry
|
|
700
|
+
*/
|
|
701
|
+
export async function initializeSharedRegistry(
|
|
702
|
+
config: TokenConfig,
|
|
703
|
+
projectRoot: string
|
|
704
|
+
): Promise<TokenRegistry> {
|
|
705
|
+
return getSharedTokenRegistry().initialize(config, projectRoot);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* Clear the shared registry
|
|
710
|
+
*/
|
|
711
|
+
export function clearSharedRegistry(): void {
|
|
712
|
+
sharedRegistry?.clear();
|
|
713
|
+
sharedRegistry = null;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Create a standalone registry (not shared)
|
|
718
|
+
*/
|
|
719
|
+
export function createTokenRegistry(): TokenRegistryManager {
|
|
720
|
+
return new TokenRegistryManager();
|
|
721
|
+
}
|