@fragments-sdk/cli 0.14.3 → 0.15.1
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/README.md +0 -3
- package/dist/{ai-client-I6MDWNYA.js → ai-client-LSLQGOMM.js} +1 -2
- package/dist/bin.js +4745 -3817
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-TXFCEDOC.js → chunk-2WXKALIG.js} +2 -2
- package/dist/{chunk-I34BC3CU.js → chunk-32LIWN2P.js} +1006 -3
- package/dist/chunk-32LIWN2P.js.map +1 -0
- package/dist/chunk-5JF26E55.js +1255 -0
- package/dist/chunk-5JF26E55.js.map +1 -0
- package/dist/{chunk-APTQIBS5.js → chunk-6SQPP47U.js} +153 -1342
- package/dist/chunk-6SQPP47U.js.map +1 -0
- package/dist/chunk-7DZC4YEV.js +294 -0
- package/dist/chunk-7DZC4YEV.js.map +1 -0
- package/dist/{chunk-PJT5IZ37.js → chunk-BJE3425I.js} +19 -52
- package/dist/{chunk-PJT5IZ37.js.map → chunk-BJE3425I.js.map} +1 -1
- package/dist/{chunk-55KERLWL.js → chunk-HQ6A6DTV.js} +1587 -1073
- package/dist/chunk-HQ6A6DTV.js.map +1 -0
- package/dist/chunk-MHIBEEW4.js +511 -0
- package/dist/chunk-MHIBEEW4.js.map +1 -0
- package/dist/{chunk-5A6X2Y73.js → chunk-ONUP6Z4W.js} +25 -13
- package/dist/chunk-ONUP6Z4W.js.map +1 -0
- package/dist/chunk-QCN35LJU.js +630 -0
- package/dist/chunk-QCN35LJU.js.map +1 -0
- package/dist/chunk-T47OLCSF.js +36 -0
- package/dist/chunk-T47OLCSF.js.map +1 -0
- package/dist/codebase-scanner-MQHUZC2G.js +21 -0
- package/dist/converter-7XM3Y6NJ.js +33 -0
- package/dist/converter-7XM3Y6NJ.js.map +1 -0
- package/dist/core/index.js +43 -2
- package/dist/create-IH4R45GE.js +806 -0
- package/dist/create-IH4R45GE.js.map +1 -0
- package/dist/{generate-RYWIPDN2.js → generate-PVOLUAAC.js} +4 -6
- package/dist/{generate-RYWIPDN2.js.map → generate-PVOLUAAC.js.map} +1 -1
- package/dist/govern-scan-OYFZYOQW.js +413 -0
- package/dist/govern-scan-OYFZYOQW.js.map +1 -0
- package/dist/index.d.ts +4 -23
- package/dist/index.js +15 -14
- package/dist/index.js.map +1 -1
- package/dist/{init-WRUSW7R5.js → init-SSGUSP7Z.js} +131 -129
- package/dist/init-SSGUSP7Z.js.map +1 -0
- package/dist/{init-cloud-REQ3XLHO.js → init-cloud-3DNKPWFB.js} +30 -5
- package/dist/{init-cloud-REQ3XLHO.js.map → init-cloud-3DNKPWFB.js.map} +1 -1
- package/dist/mcp-bin.js +5 -37
- package/dist/mcp-bin.js.map +1 -1
- package/dist/node-37AUE74M.js +65 -0
- package/dist/push-contracts-WY32TFP6.js +84 -0
- package/dist/push-contracts-WY32TFP6.js.map +1 -0
- package/dist/scan-PKSYSTRR.js +15 -0
- package/dist/{scan-generate-TFZVL3BT.js → scan-generate-VY27PIOX.js} +340 -52
- package/dist/scan-generate-VY27PIOX.js.map +1 -0
- package/dist/scanner-4KZNOXAK.js +12 -0
- package/dist/{service-HKJ6B7P7.js → service-QJGWUIVL.js} +41 -30
- package/dist/{snapshot-C5DYIGIV.js → snapshot-WIJMEIFT.js} +2 -3
- package/dist/{snapshot-C5DYIGIV.js.map → snapshot-WIJMEIFT.js.map} +1 -1
- package/dist/{static-viewer-DUVC4UIM.js → static-viewer-7QIBQZRC.js} +3 -4
- package/dist/static-viewer-7QIBQZRC.js.map +1 -0
- package/dist/{test-JW7JIDFG.js → test-64Z5BKBA.js} +4 -7
- package/dist/{test-JW7JIDFG.js.map → test-64Z5BKBA.js.map} +1 -1
- package/dist/token-normalizer-TEPOVBPV.js +312 -0
- package/dist/token-normalizer-TEPOVBPV.js.map +1 -0
- package/dist/token-parser-32KOIOFN.js +22 -0
- package/dist/token-parser-32KOIOFN.js.map +1 -0
- package/dist/{tokens-KE73G5JC.js → tokens-NZWFQIAB.js} +10 -9
- package/dist/{tokens-KE73G5JC.js.map → tokens-NZWFQIAB.js.map} +1 -1
- package/dist/tokens-generate-5JQSJ27E.js +85 -0
- package/dist/tokens-generate-5JQSJ27E.js.map +1 -0
- package/dist/tokens-push-HY3KO36V.js +148 -0
- package/dist/tokens-push-HY3KO36V.js.map +1 -0
- package/package.json +8 -6
- package/src/bin.ts +300 -48
- package/src/commands/__fixtures__/shadcn-label-wrapper/package.json +7 -0
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/label.contract.json +42 -0
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/label.tsx +11 -0
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/primitive.contract.json +20 -0
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/primitive.tsx +14 -0
- package/src/commands/__fixtures__/shadcn-label-wrapper/tsconfig.app.json +23 -0
- package/src/commands/__tests__/build-freshness.test.ts +231 -0
- package/src/commands/__tests__/create.test.ts +71 -0
- package/src/commands/__tests__/drift-sync.test.ts +1 -1
- package/src/commands/__tests__/govern.test.ts +258 -0
- package/src/commands/__tests__/init.test.ts +113 -0
- package/src/commands/__tests__/scan-generate.test.ts +189 -70
- package/src/commands/__tests__/verify.test.ts +91 -0
- package/src/commands/build.ts +54 -1
- package/src/commands/context.ts +1 -1
- package/src/commands/create.ts +536 -0
- package/src/commands/discover.ts +151 -0
- package/src/commands/doctor.ts +3 -2
- package/src/commands/enhance.ts +3 -1
- package/src/commands/govern-scan.ts +565 -0
- package/src/commands/govern.ts +67 -4
- package/src/commands/init-cloud.ts +32 -4
- package/src/commands/init.ts +152 -28
- package/src/commands/inspect.ts +290 -0
- package/src/commands/migrate-contract.ts +85 -0
- package/src/commands/push-contracts.ts +112 -0
- package/src/commands/scan-generate.ts +439 -51
- package/src/commands/scan.ts +14 -0
- package/src/commands/setup.ts +27 -50
- package/src/commands/sync.ts +2 -2
- package/src/commands/tokens-generate.ts +113 -0
- package/src/commands/tokens-push.ts +199 -0
- package/src/commands/verify.ts +195 -1
- package/src/core/__fixtures__/shadcn-input/input.tsx +7 -0
- package/src/core/__fixtures__/shadcn-input/tsconfig.json +14 -0
- package/src/core/__fixtures__/shadcn-label/label.tsx +11 -0
- package/src/core/__fixtures__/shadcn-label/primitive.tsx +14 -0
- package/src/core/__fixtures__/shadcn-label/tsconfig.json +14 -0
- package/src/core/__fixtures__/shadcn-radix-label/label.tsx +11 -0
- package/src/core/__fixtures__/shadcn-radix-label/node_modules/radix-ui/index.d.ts +12 -0
- package/src/core/__fixtures__/shadcn-radix-label/tsconfig.json +14 -0
- package/src/core/__tests__/contract-parity.test.ts +316 -0
- package/src/core/__tests__/token-resolver.test.ts +1 -1
- package/src/core/component-extractor.test.ts +40 -1
- package/src/core/config.ts +2 -1
- package/src/core/discovery.ts +13 -2
- package/src/core/drift-verifier.ts +123 -0
- package/src/core/extractor-adapter.ts +80 -0
- package/src/index.ts +3 -3
- package/src/mcp/__tests__/projectFields.test.ts +1 -1
- package/src/mcp/utils.ts +1 -50
- package/src/migrate/converter.ts +3 -3
- package/src/migrate/fragment-to-contract.ts +253 -0
- package/src/migrate/report.ts +1 -1
- package/src/scripts/token-benchmark.ts +121 -0
- package/src/service/__tests__/props-extractor.test.ts +94 -0
- package/src/service/__tests__/token-normalizer.test.ts +690 -0
- package/src/service/ast-utils.ts +4 -23
- package/src/service/babel-config.ts +23 -0
- package/src/service/enhance/converter.ts +61 -0
- package/src/service/enhance/props-extractor.ts +25 -8
- package/src/service/enhance/scanner.ts +5 -24
- package/src/service/index.ts +8 -0
- package/src/service/snippet-validation.ts +9 -3
- package/src/service/tailwind-v4-parser.ts +314 -0
- package/src/service/token-normalizer.ts +510 -0
- package/src/service/token-parser.ts +56 -0
- package/src/setup.ts +10 -39
- package/src/shared/index.ts +1 -0
- package/src/shared/project-fields.ts +46 -0
- package/src/theme/__tests__/component-contrast.test.ts +2 -2
- package/src/theme/__tests__/serializer.test.ts +1 -1
- package/src/theme/generator.ts +16 -1
- package/src/theme/schema.ts +8 -0
- package/src/theme/serializer.ts +13 -9
- package/src/theme/types.ts +8 -0
- package/src/validators.ts +1 -2
- package/src/viewer/__tests__/viewer-integration.test.ts +8 -8
- package/src/viewer/style-utils.ts +27 -412
- package/src/viewer/vite-plugin.ts +2 -2
- package/dist/chunk-55KERLWL.js.map +0 -1
- package/dist/chunk-5A6X2Y73.js.map +0 -1
- package/dist/chunk-APTQIBS5.js.map +0 -1
- package/dist/chunk-EYXVAMEX.js +0 -626
- package/dist/chunk-EYXVAMEX.js.map +0 -1
- package/dist/chunk-I34BC3CU.js.map +0 -1
- package/dist/chunk-LOYS64QS.js +0 -2453
- package/dist/chunk-LOYS64QS.js.map +0 -1
- package/dist/chunk-Z7EY4VHE.js +0 -50
- package/dist/chunk-ZKTFKHWN.js +0 -324
- package/dist/chunk-ZKTFKHWN.js.map +0 -1
- package/dist/discovery-VDANZAJ2.js +0 -28
- package/dist/init-WRUSW7R5.js.map +0 -1
- package/dist/sass.node-4XJK6YBF.js +0 -130708
- package/dist/sass.node-4XJK6YBF.js.map +0 -1
- package/dist/scan-YJHQIRKG.js +0 -14
- package/dist/scan-generate-TFZVL3BT.js.map +0 -1
- package/dist/viewer-2TZS3NDL.js +0 -2730
- package/dist/viewer-2TZS3NDL.js.map +0 -1
- package/src/build.ts +0 -612
- package/src/commands/dev.ts +0 -107
- package/src/core/auto-props.ts +0 -464
- package/src/core/component-extractor.ts +0 -1030
- package/src/core/token-resolver.ts +0 -155
- /package/dist/{ai-client-I6MDWNYA.js.map → ai-client-LSLQGOMM.js.map} +0 -0
- /package/dist/{chunk-TXFCEDOC.js.map → chunk-2WXKALIG.js.map} +0 -0
- /package/dist/{chunk-Z7EY4VHE.js.map → codebase-scanner-MQHUZC2G.js.map} +0 -0
- /package/dist/{discovery-VDANZAJ2.js.map → node-37AUE74M.js.map} +0 -0
- /package/dist/{scan-YJHQIRKG.js.map → scan-PKSYSTRR.js.map} +0 -0
- /package/dist/{service-HKJ6B7P7.js.map → scanner-4KZNOXAK.js.map} +0 -0
- /package/dist/{static-viewer-DUVC4UIM.js.map → service-QJGWUIVL.js.map} +0 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
parseColor
|
|
4
|
+
} from "./chunk-32LIWN2P.js";
|
|
5
|
+
|
|
6
|
+
// src/service/token-normalizer.ts
|
|
7
|
+
import { existsSync } from "fs";
|
|
8
|
+
import { resolve } from "path";
|
|
9
|
+
import { createJiti } from "jiti";
|
|
10
|
+
function normalizeCSSVarTokens(tokens) {
|
|
11
|
+
return tokens.map((token) => ({
|
|
12
|
+
name: token.name,
|
|
13
|
+
value: token.resolvedValue,
|
|
14
|
+
category: token.category,
|
|
15
|
+
source: "css-var",
|
|
16
|
+
originalName: token.name,
|
|
17
|
+
theme: token.theme
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
var TAILWIND_CATEGORY_MAP = {
|
|
21
|
+
colors: "color",
|
|
22
|
+
backgroundColor: "color",
|
|
23
|
+
textColor: "color",
|
|
24
|
+
borderColor: "color",
|
|
25
|
+
fill: "color",
|
|
26
|
+
stroke: "color",
|
|
27
|
+
accentColor: "color",
|
|
28
|
+
ringColor: "color",
|
|
29
|
+
outlineColor: "color",
|
|
30
|
+
spacing: "spacing",
|
|
31
|
+
margin: "spacing",
|
|
32
|
+
padding: "spacing",
|
|
33
|
+
gap: "spacing",
|
|
34
|
+
space: "spacing",
|
|
35
|
+
inset: "spacing",
|
|
36
|
+
fontSize: "typography",
|
|
37
|
+
fontFamily: "typography",
|
|
38
|
+
fontWeight: "typography",
|
|
39
|
+
lineHeight: "typography",
|
|
40
|
+
letterSpacing: "typography",
|
|
41
|
+
borderRadius: "radius",
|
|
42
|
+
borderWidth: "border",
|
|
43
|
+
boxShadow: "shadow",
|
|
44
|
+
width: "sizing",
|
|
45
|
+
height: "sizing",
|
|
46
|
+
maxWidth: "sizing",
|
|
47
|
+
maxHeight: "sizing",
|
|
48
|
+
minWidth: "sizing",
|
|
49
|
+
minHeight: "sizing",
|
|
50
|
+
size: "sizing",
|
|
51
|
+
zIndex: "z-index",
|
|
52
|
+
animation: "animation",
|
|
53
|
+
transitionDuration: "animation",
|
|
54
|
+
transitionTimingFunction: "animation",
|
|
55
|
+
transitionDelay: "animation"
|
|
56
|
+
};
|
|
57
|
+
function normalizeTailwindTheme(theme, options = {}) {
|
|
58
|
+
const { source = "tailwind", defaultTheme = "default" } = options;
|
|
59
|
+
const tokens = [];
|
|
60
|
+
for (const [themeKey, themeValue] of Object.entries(theme)) {
|
|
61
|
+
const category = TAILWIND_CATEGORY_MAP[themeKey];
|
|
62
|
+
if (!category || themeValue == null || typeof themeValue === "function") {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (typeof themeValue !== "object") {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
flattenThemeValue(
|
|
69
|
+
themeValue,
|
|
70
|
+
themeKey,
|
|
71
|
+
category,
|
|
72
|
+
source,
|
|
73
|
+
defaultTheme,
|
|
74
|
+
tokens
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
return tokens;
|
|
78
|
+
}
|
|
79
|
+
function flattenThemeValue(obj, prefix, category, source, theme, out) {
|
|
80
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
81
|
+
const path = key === "DEFAULT" ? prefix : `${prefix}.${key}`;
|
|
82
|
+
if (value == null || typeof value === "function") {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (typeof value === "string") {
|
|
86
|
+
out.push({
|
|
87
|
+
name: path,
|
|
88
|
+
value,
|
|
89
|
+
category,
|
|
90
|
+
source,
|
|
91
|
+
originalName: path,
|
|
92
|
+
theme
|
|
93
|
+
});
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (typeof value === "number") {
|
|
97
|
+
out.push({
|
|
98
|
+
name: path,
|
|
99
|
+
value: String(value),
|
|
100
|
+
category,
|
|
101
|
+
source,
|
|
102
|
+
originalName: path,
|
|
103
|
+
theme
|
|
104
|
+
});
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (Array.isArray(value)) {
|
|
108
|
+
const resolved = resolveArrayValue(value, category);
|
|
109
|
+
if (resolved !== null) {
|
|
110
|
+
out.push({
|
|
111
|
+
name: path,
|
|
112
|
+
value: resolved,
|
|
113
|
+
category,
|
|
114
|
+
source,
|
|
115
|
+
originalName: path,
|
|
116
|
+
theme
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (typeof value === "object") {
|
|
122
|
+
flattenThemeValue(
|
|
123
|
+
value,
|
|
124
|
+
path,
|
|
125
|
+
category,
|
|
126
|
+
source,
|
|
127
|
+
theme,
|
|
128
|
+
out
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function resolveArrayValue(value, category) {
|
|
134
|
+
if (value.length === 0) return null;
|
|
135
|
+
if (category === "typography" && value.every((v) => typeof v === "string")) {
|
|
136
|
+
return value.join(", ");
|
|
137
|
+
}
|
|
138
|
+
if (typeof value[0] === "string") {
|
|
139
|
+
return value[0];
|
|
140
|
+
}
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
function deepMerge(base, override) {
|
|
144
|
+
const result = { ...base };
|
|
145
|
+
for (const [key, value] of Object.entries(override)) {
|
|
146
|
+
const existing = result[key];
|
|
147
|
+
if (existing && typeof existing === "object" && !Array.isArray(existing) && value && typeof value === "object" && !Array.isArray(value)) {
|
|
148
|
+
result[key] = deepMerge(
|
|
149
|
+
existing,
|
|
150
|
+
value
|
|
151
|
+
);
|
|
152
|
+
} else {
|
|
153
|
+
result[key] = value;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
async function loadTailwindConfig(configPath) {
|
|
159
|
+
const absolutePath = resolve(configPath);
|
|
160
|
+
if (!existsSync(absolutePath)) {
|
|
161
|
+
throw new Error(`Tailwind config not found: ${absolutePath}`);
|
|
162
|
+
}
|
|
163
|
+
const jiti = createJiti(absolutePath);
|
|
164
|
+
const mod = await jiti.import(absolutePath);
|
|
165
|
+
const config = mod.default ?? mod;
|
|
166
|
+
if (!config || typeof config !== "object") {
|
|
167
|
+
throw new Error(
|
|
168
|
+
`Tailwind config at ${absolutePath} does not export a valid object`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
const configObj = config;
|
|
172
|
+
const theme = configObj.theme ?? {};
|
|
173
|
+
const extend = theme.extend ?? {};
|
|
174
|
+
const merged = {};
|
|
175
|
+
for (const [key, value] of Object.entries(theme)) {
|
|
176
|
+
if (key !== "extend") {
|
|
177
|
+
merged[key] = value;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
for (const [key, value] of Object.entries(extend)) {
|
|
181
|
+
const existing = merged[key];
|
|
182
|
+
if (existing && typeof existing === "object" && !Array.isArray(existing) && value && typeof value === "object" && !Array.isArray(value)) {
|
|
183
|
+
merged[key] = deepMerge(
|
|
184
|
+
existing,
|
|
185
|
+
value
|
|
186
|
+
);
|
|
187
|
+
} else {
|
|
188
|
+
merged[key] = value;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return normalizeTailwindTheme(merged);
|
|
192
|
+
}
|
|
193
|
+
var TAILWIND_CONFIG_FILENAMES = [
|
|
194
|
+
"tailwind.config.ts",
|
|
195
|
+
"tailwind.config.js",
|
|
196
|
+
"tailwind.config.mjs",
|
|
197
|
+
"tailwind.config.cjs"
|
|
198
|
+
];
|
|
199
|
+
function findTailwindConfig(projectRoot) {
|
|
200
|
+
for (const filename of TAILWIND_CONFIG_FILENAMES) {
|
|
201
|
+
const fullPath = resolve(projectRoot, filename);
|
|
202
|
+
if (existsSync(fullPath)) {
|
|
203
|
+
return fullPath;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
var NormalizedTokenLookup = class {
|
|
209
|
+
byName = /* @__PURE__ */ new Map();
|
|
210
|
+
byValue = /* @__PURE__ */ new Map();
|
|
211
|
+
constructor(tokens) {
|
|
212
|
+
for (const token of tokens) {
|
|
213
|
+
const dt = normalizedToDesignToken(token);
|
|
214
|
+
this.byName.set(token.name, dt);
|
|
215
|
+
const normalizedValue = normalizeForLookup(token.value);
|
|
216
|
+
const existing = this.byValue.get(normalizedValue) || [];
|
|
217
|
+
existing.push(token.name);
|
|
218
|
+
this.byValue.set(normalizedValue, existing);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
findByValue(value, theme) {
|
|
222
|
+
const normalized = normalizeForLookup(value);
|
|
223
|
+
const names = this.byValue.get(normalized) || [];
|
|
224
|
+
if (theme && names.length > 0) {
|
|
225
|
+
return names.filter((name) => {
|
|
226
|
+
const token = this.byName.get(name);
|
|
227
|
+
return token?.theme === theme || token?.theme === "default";
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
return names;
|
|
231
|
+
}
|
|
232
|
+
getToken(name) {
|
|
233
|
+
return this.byName.get(name);
|
|
234
|
+
}
|
|
235
|
+
calculateUsageSummary(styleDiffs, theme = "default") {
|
|
236
|
+
const hardcodedProperties = [];
|
|
237
|
+
let usingTokens = 0;
|
|
238
|
+
let hardcoded = 0;
|
|
239
|
+
let implicitMatches = 0;
|
|
240
|
+
for (const diff of styleDiffs) {
|
|
241
|
+
const figmaTokens = this.findByValue(diff.figma, theme);
|
|
242
|
+
const renderedTokens = this.findByValue(diff.rendered, theme);
|
|
243
|
+
const figmaToken = figmaTokens.length > 0 ? figmaTokens[0] : void 0;
|
|
244
|
+
const renderedToken = renderedTokens.length > 0 ? renderedTokens[0] : void 0;
|
|
245
|
+
const isHardcoded = !!figmaToken && !renderedToken;
|
|
246
|
+
if (renderedToken) {
|
|
247
|
+
usingTokens++;
|
|
248
|
+
} else if (isHardcoded) {
|
|
249
|
+
hardcoded++;
|
|
250
|
+
hardcodedProperties.push({
|
|
251
|
+
...diff,
|
|
252
|
+
figmaToken,
|
|
253
|
+
renderedToken,
|
|
254
|
+
isHardcoded: true
|
|
255
|
+
});
|
|
256
|
+
} else if (diff.match && figmaToken) {
|
|
257
|
+
implicitMatches++;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
const totalProperties = styleDiffs.length;
|
|
261
|
+
const compliancePercent = totalProperties > 0 ? Math.round(
|
|
262
|
+
(usingTokens + implicitMatches) / totalProperties * 100
|
|
263
|
+
) : 100;
|
|
264
|
+
return {
|
|
265
|
+
totalProperties,
|
|
266
|
+
usingTokens,
|
|
267
|
+
hardcoded,
|
|
268
|
+
implicitMatches,
|
|
269
|
+
compliancePercent,
|
|
270
|
+
hardcodedProperties
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
function createTokenLookup(tokens) {
|
|
275
|
+
return new NormalizedTokenLookup(tokens);
|
|
276
|
+
}
|
|
277
|
+
function normalizedToDesignToken(token) {
|
|
278
|
+
return {
|
|
279
|
+
name: token.name,
|
|
280
|
+
rawValue: token.value,
|
|
281
|
+
resolvedValue: token.value,
|
|
282
|
+
category: token.category,
|
|
283
|
+
level: 2,
|
|
284
|
+
referenceChain: [],
|
|
285
|
+
sourceFile: token.source,
|
|
286
|
+
theme: token.theme,
|
|
287
|
+
selector: token.source === "css-var" ? ":root" : ""
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function normalizeForLookup(value) {
|
|
291
|
+
let normalized = value.toLowerCase().trim();
|
|
292
|
+
if (looksLikeColor(normalized)) {
|
|
293
|
+
const rgb = parseColor(value);
|
|
294
|
+
if (rgb) {
|
|
295
|
+
normalized = `#${[rgb.r, rgb.g, rgb.b].map((x) => x.toString(16).padStart(2, "0")).join("")}`;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
normalized = normalized.replace(/\s+/g, " ");
|
|
299
|
+
return normalized;
|
|
300
|
+
}
|
|
301
|
+
function looksLikeColor(value) {
|
|
302
|
+
return value.startsWith("#") || value.startsWith("rgb") || value.startsWith("hsl");
|
|
303
|
+
}
|
|
304
|
+
export {
|
|
305
|
+
NormalizedTokenLookup,
|
|
306
|
+
createTokenLookup,
|
|
307
|
+
findTailwindConfig,
|
|
308
|
+
loadTailwindConfig,
|
|
309
|
+
normalizeCSSVarTokens,
|
|
310
|
+
normalizeTailwindTheme
|
|
311
|
+
};
|
|
312
|
+
//# sourceMappingURL=token-normalizer-TEPOVBPV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/service/token-normalizer.ts"],"sourcesContent":["/**\n * Token Normalizer\n *\n * One normalization layer that produces NormalizedToken[] regardless of source:\n * - CSS custom properties (from token-parser.ts)\n * - Tailwind theme tokens (from tailwind.config.{js,ts,mjs,cjs})\n *\n * Also provides NormalizedTokenLookup implementing the core TokenLookup\n * interface so the canonical comparison engine can consume any token source.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { createJiti } from \"jiti\";\nimport { parseColor } from \"@fragments-sdk/core\";\nimport type {\n DesignToken,\n EnhancedStyleDiffItem,\n NormalizedToken,\n TokenCategory,\n TokenLookup,\n TokenUsageSummary,\n} from \"@fragments-sdk/core\";\n\n// ─── CSS Custom Property Normalization ───────────────────────────────────────\n\n/**\n * Convert parsed DesignToken[] (CSS custom properties) to NormalizedToken[].\n */\nexport function normalizeCSSVarTokens(tokens: DesignToken[]): NormalizedToken[] {\n return tokens.map((token) => ({\n name: token.name,\n value: token.resolvedValue,\n category: token.category,\n source: \"css-var\" as const,\n originalName: token.name,\n theme: token.theme,\n }));\n}\n\n// ─── Tailwind Theme Normalization ────────────────────────────────────────────\n\n/**\n * Tailwind theme key → NormalizedToken category mapping.\n * Only keys that map to meaningful token categories are listed.\n */\nconst TAILWIND_CATEGORY_MAP: Record<string, TokenCategory> = {\n colors: \"color\",\n backgroundColor: \"color\",\n textColor: \"color\",\n borderColor: \"color\",\n fill: \"color\",\n stroke: \"color\",\n accentColor: \"color\",\n ringColor: \"color\",\n outlineColor: \"color\",\n\n spacing: \"spacing\",\n margin: \"spacing\",\n padding: \"spacing\",\n gap: \"spacing\",\n space: \"spacing\",\n inset: \"spacing\",\n\n fontSize: \"typography\",\n fontFamily: \"typography\",\n fontWeight: \"typography\",\n lineHeight: \"typography\",\n letterSpacing: \"typography\",\n\n borderRadius: \"radius\",\n\n borderWidth: \"border\",\n\n boxShadow: \"shadow\",\n\n width: \"sizing\",\n height: \"sizing\",\n maxWidth: \"sizing\",\n maxHeight: \"sizing\",\n minWidth: \"sizing\",\n minHeight: \"sizing\",\n size: \"sizing\",\n\n zIndex: \"z-index\",\n\n animation: \"animation\",\n transitionDuration: \"animation\",\n transitionTimingFunction: \"animation\",\n transitionDelay: \"animation\",\n};\n\n/**\n * Convert a Tailwind theme object into NormalizedToken[].\n *\n * Handles:\n * - Flat values: `{ primary: '#0051c2' }` → `colors.primary`\n * - Nested values: `{ blue: { 50: '#eff6ff', 500: '#3b82f6' } }` → `colors.blue.50`\n * - DEFAULT key: `{ blue: { DEFAULT: '#3b82f6' } }` → `colors.blue`\n * - Array values for fontFamily: `{ sans: ['Inter', 'sans-serif'] }` → joined\n * - Tuple values for fontSize: `{ sm: ['14px', { lineHeight: '20px' }] }` → first element\n */\nexport function normalizeTailwindTheme(\n theme: Record<string, unknown>,\n options: {\n /** Source identifier (default: \"tailwind\") */\n source?: string;\n /** Theme name (default: \"default\") */\n defaultTheme?: string;\n } = {}\n): NormalizedToken[] {\n const { source = \"tailwind\", defaultTheme = \"default\" } = options;\n const tokens: NormalizedToken[] = [];\n\n for (const [themeKey, themeValue] of Object.entries(theme)) {\n const category = TAILWIND_CATEGORY_MAP[themeKey];\n if (!category || themeValue == null || typeof themeValue === \"function\") {\n continue;\n }\n\n if (typeof themeValue !== \"object\") {\n continue;\n }\n\n flattenThemeValue(\n themeValue as Record<string, unknown>,\n themeKey,\n category,\n source,\n defaultTheme,\n tokens\n );\n }\n\n return tokens;\n}\n\n/**\n * Recursively flatten a Tailwind theme value object into NormalizedToken entries.\n */\nfunction flattenThemeValue(\n obj: Record<string, unknown>,\n prefix: string,\n category: TokenCategory,\n source: string,\n theme: string,\n out: NormalizedToken[]\n): void {\n for (const [key, value] of Object.entries(obj)) {\n // Build the path, collapsing DEFAULT to the parent\n const path = key === \"DEFAULT\" ? prefix : `${prefix}.${key}`;\n\n if (value == null || typeof value === \"function\") {\n continue;\n }\n\n // String value → leaf token\n if (typeof value === \"string\") {\n out.push({\n name: path,\n value,\n category,\n source,\n originalName: path,\n theme,\n });\n continue;\n }\n\n // Number value → convert to string\n if (typeof value === \"number\") {\n out.push({\n name: path,\n value: String(value),\n category,\n source,\n originalName: path,\n theme,\n });\n continue;\n }\n\n // Array value → handle fontFamily (join) and fontSize tuples (first element)\n if (Array.isArray(value)) {\n const resolved = resolveArrayValue(value, category);\n if (resolved !== null) {\n out.push({\n name: path,\n value: resolved,\n category,\n source,\n originalName: path,\n theme,\n });\n }\n continue;\n }\n\n // Nested object → recurse\n if (typeof value === \"object\") {\n flattenThemeValue(\n value as Record<string, unknown>,\n path,\n category,\n source,\n theme,\n out\n );\n }\n }\n}\n\n/**\n * Resolve an array theme value to a string.\n * - fontFamily: ['Inter', 'sans-serif'] → 'Inter, sans-serif'\n * - fontSize: ['14px', { lineHeight: '20px' }] → '14px'\n */\nfunction resolveArrayValue(\n value: unknown[],\n category: TokenCategory\n): string | null {\n if (value.length === 0) return null;\n\n // fontFamily arrays: join with comma\n if (category === \"typography\" && value.every((v) => typeof v === \"string\")) {\n return value.join(\", \");\n }\n\n // fontSize tuples: [size, config] — take the first element\n if (typeof value[0] === \"string\") {\n return value[0];\n }\n\n return null;\n}\n\n/**\n * Recursively deep-merge two objects. Values in `override` take precedence.\n * Nested plain objects are merged recursively; arrays and primitives are replaced.\n */\nfunction deepMerge(\n base: Record<string, unknown>,\n override: Record<string, unknown>,\n): Record<string, unknown> {\n const result = { ...base };\n for (const [key, value] of Object.entries(override)) {\n const existing = result[key];\n if (\n existing &&\n typeof existing === \"object\" &&\n !Array.isArray(existing) &&\n value &&\n typeof value === \"object\" &&\n !Array.isArray(value)\n ) {\n result[key] = deepMerge(\n existing as Record<string, unknown>,\n value as Record<string, unknown>,\n );\n } else {\n result[key] = value;\n }\n }\n return result;\n}\n\n/**\n * Load a Tailwind config file and extract normalized tokens from its theme.\n *\n * Supports tailwind.config.{js,ts,mjs,cjs} via jiti.\n * Reads both `theme` and `theme.extend` (extend values are merged).\n */\nexport async function loadTailwindConfig(\n configPath: string\n): Promise<NormalizedToken[]> {\n const absolutePath = resolve(configPath);\n\n if (!existsSync(absolutePath)) {\n throw new Error(`Tailwind config not found: ${absolutePath}`);\n }\n\n const jiti = createJiti(absolutePath);\n const mod = await jiti.import(absolutePath);\n const config = (mod as { default?: unknown }).default ?? mod;\n\n if (!config || typeof config !== \"object\") {\n throw new Error(\n `Tailwind config at ${absolutePath} does not export a valid object`\n );\n }\n\n const configObj = config as Record<string, unknown>;\n const theme = (configObj.theme ?? {}) as Record<string, unknown>;\n\n // Merge base theme with extend overrides\n const extend = (theme.extend ?? {}) as Record<string, unknown>;\n const merged: Record<string, unknown> = {};\n\n // Copy base theme keys (except 'extend')\n for (const [key, value] of Object.entries(theme)) {\n if (key !== \"extend\") {\n merged[key] = value;\n }\n }\n\n // Deep merge extend values on top (preserves nested tokens like colors.blue.50)\n for (const [key, value] of Object.entries(extend)) {\n const existing = merged[key];\n if (\n existing &&\n typeof existing === \"object\" &&\n !Array.isArray(existing) &&\n value &&\n typeof value === \"object\" &&\n !Array.isArray(value)\n ) {\n merged[key] = deepMerge(\n existing as Record<string, unknown>,\n value as Record<string, unknown>,\n );\n } else {\n merged[key] = value;\n }\n }\n\n return normalizeTailwindTheme(merged);\n}\n\n// ─── Tailwind Config Discovery ───────────────────────────────────────────────\n\nconst TAILWIND_CONFIG_FILENAMES = [\n \"tailwind.config.ts\",\n \"tailwind.config.js\",\n \"tailwind.config.mjs\",\n \"tailwind.config.cjs\",\n];\n\n/**\n * Find a Tailwind config file in the given directory.\n */\nexport function findTailwindConfig(projectRoot: string): string | null {\n for (const filename of TAILWIND_CONFIG_FILENAMES) {\n const fullPath = resolve(projectRoot, filename);\n if (existsSync(fullPath)) {\n return fullPath;\n }\n }\n return null;\n}\n\n// ─── NormalizedTokenLookup ───────────────────────────────────────────────────\n\n/**\n * Implements the core TokenLookup interface over NormalizedToken[].\n *\n * This is the single adapter that lets the canonical comparison engine\n * consume tokens from any source (CSS vars, Tailwind, DTCG, Figma).\n */\nexport class NormalizedTokenLookup implements TokenLookup {\n private byName = new Map<string, DesignToken>();\n private byValue = new Map<string, string[]>();\n\n constructor(tokens: NormalizedToken[]) {\n for (const token of tokens) {\n const dt = normalizedToDesignToken(token);\n this.byName.set(token.name, dt);\n\n const normalizedValue = normalizeForLookup(token.value);\n const existing = this.byValue.get(normalizedValue) || [];\n existing.push(token.name);\n this.byValue.set(normalizedValue, existing);\n }\n }\n\n findByValue(value: string, theme?: string): string[] {\n const normalized = normalizeForLookup(value);\n const names = this.byValue.get(normalized) || [];\n\n if (theme && names.length > 0) {\n return names.filter((name) => {\n const token = this.byName.get(name);\n return token?.theme === theme || token?.theme === \"default\";\n });\n }\n\n return names;\n }\n\n getToken(name: string): DesignToken | undefined {\n return this.byName.get(name);\n }\n\n calculateUsageSummary(\n styleDiffs: Array<{\n property: string;\n figma: string;\n rendered: string;\n match: boolean;\n }>,\n theme = \"default\"\n ): TokenUsageSummary {\n const hardcodedProperties: EnhancedStyleDiffItem[] = [];\n let usingTokens = 0;\n let hardcoded = 0;\n let implicitMatches = 0;\n\n for (const diff of styleDiffs) {\n const figmaTokens = this.findByValue(diff.figma, theme);\n const renderedTokens = this.findByValue(diff.rendered, theme);\n\n const figmaToken = figmaTokens.length > 0 ? figmaTokens[0] : undefined;\n const renderedToken =\n renderedTokens.length > 0 ? renderedTokens[0] : undefined;\n const isHardcoded = !!figmaToken && !renderedToken;\n\n if (renderedToken) {\n usingTokens++;\n } else if (isHardcoded) {\n hardcoded++;\n hardcodedProperties.push({\n ...diff,\n figmaToken,\n renderedToken,\n isHardcoded: true,\n } as EnhancedStyleDiffItem);\n } else if (diff.match && figmaToken) {\n implicitMatches++;\n }\n }\n\n const totalProperties = styleDiffs.length;\n const compliancePercent =\n totalProperties > 0\n ? Math.round(\n ((usingTokens + implicitMatches) / totalProperties) * 100\n )\n : 100;\n\n return {\n totalProperties,\n usingTokens,\n hardcoded,\n implicitMatches,\n compliancePercent,\n hardcodedProperties,\n };\n }\n}\n\n// ─── Factory ─────────────────────────────────────────────────────────────────\n\n/**\n * Create a TokenLookup from NormalizedToken[].\n * Convenience factory for the most common use case.\n */\nexport function createTokenLookup(tokens: NormalizedToken[]): TokenLookup {\n return new NormalizedTokenLookup(tokens);\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\n/**\n * Convert a NormalizedToken to a DesignToken for TokenLookup compatibility.\n * Fills source-specific fields with sensible defaults.\n */\nfunction normalizedToDesignToken(token: NormalizedToken): DesignToken {\n return {\n name: token.name,\n rawValue: token.value,\n resolvedValue: token.value,\n category: token.category,\n level: 2,\n referenceChain: [],\n sourceFile: token.source,\n theme: token.theme,\n selector: token.source === \"css-var\" ? \":root\" : \"\",\n };\n}\n\n/**\n * Normalize a value for consistent reverse lookup.\n * Matches the normalization logic in TokenRegistryManager for parity.\n */\nfunction normalizeForLookup(value: string): string {\n let normalized = value.toLowerCase().trim();\n\n // Normalize color formats to lowercase hex\n if (looksLikeColor(normalized)) {\n const rgb = parseColor(value);\n if (rgb) {\n normalized = `#${[rgb.r, rgb.g, rgb.b]\n .map((x) => x.toString(16).padStart(2, \"0\"))\n .join(\"\")}`;\n }\n }\n\n normalized = normalized.replace(/\\s+/g, \" \");\n return normalized;\n}\n\n/**\n * Check if a value looks like a color.\n */\nfunction looksLikeColor(value: string): boolean {\n return (\n value.startsWith(\"#\") ||\n value.startsWith(\"rgb\") ||\n value.startsWith(\"hsl\")\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
containsTailwindV4Theme,
|
|
4
|
+
hexToRgb,
|
|
5
|
+
normalizeColor,
|
|
6
|
+
parseRgb,
|
|
7
|
+
parseTailwindV4File,
|
|
8
|
+
parseTokenFile,
|
|
9
|
+
parseTokenFiles,
|
|
10
|
+
rgbToHex
|
|
11
|
+
} from "./chunk-MHIBEEW4.js";
|
|
12
|
+
export {
|
|
13
|
+
containsTailwindV4Theme,
|
|
14
|
+
hexToRgb,
|
|
15
|
+
normalizeColor,
|
|
16
|
+
parseRgb,
|
|
17
|
+
parseTailwindV4File,
|
|
18
|
+
parseTokenFile,
|
|
19
|
+
parseTokenFiles,
|
|
20
|
+
rgbToHex
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=token-parser-32KOIOFN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
|
|
2
|
+
import "./chunk-6SQPP47U.js";
|
|
3
|
+
import "./chunk-D2CDBRNU.js";
|
|
2
4
|
import {
|
|
3
5
|
loadConfig
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-ZKTFKHWN.js";
|
|
6
|
-
import {
|
|
7
|
-
parseTokenFiles
|
|
8
|
-
} from "./chunk-APTQIBS5.js";
|
|
9
|
-
import "./chunk-D2CDBRNU.js";
|
|
6
|
+
} from "./chunk-HQ6A6DTV.js";
|
|
10
7
|
import {
|
|
11
8
|
BRAND
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import
|
|
9
|
+
} from "./chunk-32LIWN2P.js";
|
|
10
|
+
import {
|
|
11
|
+
parseTokenFiles
|
|
12
|
+
} from "./chunk-MHIBEEW4.js";
|
|
13
|
+
import "./chunk-QCN35LJU.js";
|
|
14
|
+
import "./chunk-7DZC4YEV.js";
|
|
14
15
|
|
|
15
16
|
// src/commands/tokens.ts
|
|
16
17
|
import pc from "picocolors";
|
|
@@ -172,4 +173,4 @@ export {
|
|
|
172
173
|
tokens_default as default,
|
|
173
174
|
tokens
|
|
174
175
|
};
|
|
175
|
-
//# sourceMappingURL=tokens-
|
|
176
|
+
//# sourceMappingURL=tokens-NZWFQIAB.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/tokens.ts"],"sourcesContent":["/**\n * CLI Tokens Command\n *\n * Discover and list design tokens from CSS/SCSS files.\n *\n * Usage:\n * fragments tokens # List all tokens\n * fragments tokens --json # Output as JSON\n * fragments tokens --categories # Group by category\n * fragments tokens --theme dark # Filter by theme\n */\n\nimport pc from \"picocolors\";\nimport { BRAND } from \"../core/index.js\";\nimport type { DesignToken, TokenCategory, TokenConfig } from \"../core/index.js\";\nimport { loadConfig } from \"../core/node.js\";\nimport { parseTokenFiles, createTokenRegistry } from \"../service/index.js\";\n\nexport interface TokensCommandOptions {\n config?: string;\n json?: boolean;\n categories?: boolean;\n theme?: string;\n category?: string;\n verbose?: boolean;\n}\n\nexport interface TokensCommandResult {\n success: boolean;\n tokenCount: number;\n errors: string[];\n}\n\n/**\n * Run the tokens command\n */\nexport async function tokens(\n options: TokensCommandOptions\n): Promise<TokensCommandResult> {\n const errors: string[] = [];\n\n try {\n console.log(pc.cyan(`\\n${BRAND.name} Token Discovery\\n`));\n\n // Load config\n const { config, configDir } = await loadConfig(options.config);\n\n // Check for token configuration\n if (!config.tokens || !config.tokens.include || config.tokens.include.length === 0) {\n console.log(pc.yellow(\"No token configuration found.\\n\"));\n console.log(pc.dim(\"Add 'tokens' config to fragments.config.ts:\"));\n console.log(pc.dim(`\n tokens: {\n include: ['src/styles/theme.scss', 'src/styles/variables.css'],\n themeSelectors: {\n ':root': 'default',\n '[data-theme=\"dark\"]': 'dark',\n },\n },\n`));\n return { success: false, tokenCount: 0, errors: [\"No token configuration\"] };\n }\n\n console.log(pc.dim(`Scanning files: ${config.tokens.include.join(\", \")}\\n`));\n\n // Parse token files\n const parseResult = await parseTokenFiles(config.tokens, configDir);\n\n if (parseResult.errors.length > 0) {\n console.log(pc.yellow(\"Parse errors:\"));\n for (const err of parseResult.errors) {\n console.log(pc.red(` ${err.file}: ${err.message}`));\n errors.push(`${err.file}: ${err.message}`);\n }\n console.log();\n }\n\n if (parseResult.warnings.length > 0 && options.verbose) {\n console.log(pc.yellow(\"Warnings:\"));\n for (const warning of parseResult.warnings) {\n console.log(pc.dim(` ${warning}`));\n }\n console.log();\n }\n\n let tokens = parseResult.tokens;\n\n // Filter by theme if specified\n if (options.theme) {\n tokens = tokens.filter(\n (t) => t.theme === options.theme || t.theme === \"default\"\n );\n }\n\n // Filter by category if specified\n if (options.category) {\n tokens = tokens.filter((t) => t.category === options.category);\n }\n\n if (tokens.length === 0) {\n console.log(pc.yellow(\"No tokens found.\\n\"));\n console.log(pc.dim(\"Make sure your CSS files contain CSS custom properties (--token-name: value;)\"));\n return { success: true, tokenCount: 0, errors };\n }\n\n // Output based on format\n if (options.json) {\n outputJson(tokens, parseResult.parseTimeMs);\n } else if (options.categories) {\n outputByCategory(tokens, parseResult.parseTimeMs);\n } else {\n outputList(tokens, parseResult.parseTimeMs, options.verbose);\n }\n\n return { success: true, tokenCount: tokens.length, errors };\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Unknown error\";\n console.error(pc.red(\"Error:\"), message);\n errors.push(message);\n return { success: false, tokenCount: 0, errors };\n }\n}\n\n/**\n * Output tokens as JSON\n */\nfunction outputJson(tokens: DesignToken[], parseTimeMs: number): void {\n const output = {\n tokens,\n meta: {\n totalTokens: tokens.length,\n parseTimeMs,\n discoveredAt: new Date().toISOString(),\n },\n };\n\n console.log(JSON.stringify(output, null, 2));\n}\n\n/**\n * Output tokens grouped by category\n */\nfunction outputByCategory(tokens: DesignToken[], parseTimeMs: number): void {\n // Group by category\n const byCategory = new Map<TokenCategory, DesignToken[]>();\n\n for (const token of tokens) {\n const list = byCategory.get(token.category) || [];\n list.push(token);\n byCategory.set(token.category, list);\n }\n\n // Sort categories alphabetically\n const categories = Array.from(byCategory.keys()).sort();\n\n for (const category of categories) {\n const categoryTokens = byCategory.get(category) || [];\n console.log(pc.bold(`${category} (${categoryTokens.length})`));\n console.log(pc.dim(\"─\".repeat(40)));\n\n for (const token of categoryTokens.slice(0, 10)) {\n const levelLabel = token.level === 1 ? \"base\" : token.level === 2 ? \"semantic\" : \"component\";\n console.log(` ${pc.cyan(token.name)}`);\n console.log(` ${pc.dim(\"Value:\")} ${token.resolvedValue}`);\n console.log(` ${pc.dim(\"Level:\")} ${levelLabel} ${pc.dim(`(${token.theme})`)}`);\n }\n\n if (categoryTokens.length > 10) {\n console.log(pc.dim(` ... and ${categoryTokens.length - 10} more`));\n }\n console.log();\n }\n\n // Summary\n console.log(pc.dim(\"─\".repeat(40)));\n console.log(pc.green(`✓ Found ${tokens.length} token(s) in ${categories.length} categories`));\n console.log(pc.dim(` Parsed in ${parseTimeMs.toFixed(1)}ms\\n`));\n}\n\n/**\n * Output tokens as a simple list\n */\nfunction outputList(tokens: DesignToken[], parseTimeMs: number, verbose?: boolean): void {\n // Group by theme first\n const byTheme = new Map<string, DesignToken[]>();\n\n for (const token of tokens) {\n const list = byTheme.get(token.theme) || [];\n list.push(token);\n byTheme.set(token.theme, list);\n }\n\n const themes = Array.from(byTheme.keys()).sort();\n\n for (const theme of themes) {\n const themeTokens = byTheme.get(theme) || [];\n\n if (themes.length > 1) {\n console.log(pc.bold(`Theme: ${theme} (${themeTokens.length} tokens)`));\n console.log(pc.dim(\"─\".repeat(50)));\n }\n\n // Sort tokens by name\n themeTokens.sort((a, b) => a.name.localeCompare(b.name));\n\n // Table header\n console.log(\n pc.dim(\n `${\"Token Name\".padEnd(32)} ${\"Value\".padEnd(20)} ${\"Category\".padEnd(12)}`\n )\n );\n console.log(pc.dim(\"─\".repeat(70)));\n\n const displayTokens = verbose ? themeTokens : themeTokens.slice(0, 30);\n\n for (const token of displayTokens) {\n const name = token.name.length > 30 ? token.name.slice(0, 27) + \"...\" : token.name;\n const value = token.resolvedValue.length > 18 ? token.resolvedValue.slice(0, 15) + \"...\" : token.resolvedValue;\n\n console.log(\n `${pc.cyan(name.padEnd(32))} ${value.padEnd(20)} ${pc.dim(token.category.padEnd(12))}`\n );\n }\n\n if (!verbose && themeTokens.length > 30) {\n console.log(pc.dim(`\\n ... and ${themeTokens.length - 30} more (use --verbose to show all)`));\n }\n\n console.log();\n }\n\n // Summary\n console.log(pc.dim(\"─\".repeat(50)));\n console.log(pc.green(`✓ Found ${tokens.length} token(s)`));\n\n // Category breakdown\n const categoryCounts: Record<string, number> = {};\n for (const token of tokens) {\n categoryCounts[token.category] = (categoryCounts[token.category] || 0) + 1;\n }\n\n const breakdown = Object.entries(categoryCounts)\n .sort((a, b) => b[1] - a[1])\n .map(([cat, count]) => `${cat}: ${count}`)\n .join(\", \");\n\n console.log(pc.dim(` ${breakdown}`));\n console.log(pc.dim(` Parsed in ${parseTimeMs.toFixed(1)}ms\\n`));\n}\n\nexport default tokens;\n"],"mappings":"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","names":["tokens"]}
|
|
1
|
+
{"version":3,"sources":["../src/commands/tokens.ts"],"sourcesContent":["/**\n * CLI Tokens Command\n *\n * Discover and list design tokens from CSS/SCSS files.\n *\n * Usage:\n * fragments tokens # List all tokens\n * fragments tokens --json # Output as JSON\n * fragments tokens --categories # Group by category\n * fragments tokens --theme dark # Filter by theme\n */\n\nimport pc from \"picocolors\";\nimport { BRAND } from \"../core/index.js\";\nimport type { DesignToken, TokenCategory, TokenConfig } from \"../core/index.js\";\nimport { loadConfig } from \"../core/node.js\";\nimport { parseTokenFiles, createTokenRegistry } from \"../service/index.js\";\n\nexport interface TokensCommandOptions {\n config?: string;\n json?: boolean;\n categories?: boolean;\n theme?: string;\n category?: string;\n verbose?: boolean;\n}\n\nexport interface TokensCommandResult {\n success: boolean;\n tokenCount: number;\n errors: string[];\n}\n\n/**\n * Run the tokens command\n */\nexport async function tokens(\n options: TokensCommandOptions\n): Promise<TokensCommandResult> {\n const errors: string[] = [];\n\n try {\n console.log(pc.cyan(`\\n${BRAND.name} Token Discovery\\n`));\n\n // Load config\n const { config, configDir } = await loadConfig(options.config);\n\n // Check for token configuration\n if (!config.tokens || !config.tokens.include || config.tokens.include.length === 0) {\n console.log(pc.yellow(\"No token configuration found.\\n\"));\n console.log(pc.dim(\"Add 'tokens' config to fragments.config.ts:\"));\n console.log(pc.dim(`\n tokens: {\n include: ['src/styles/theme.scss', 'src/styles/variables.css'],\n themeSelectors: {\n ':root': 'default',\n '[data-theme=\"dark\"]': 'dark',\n },\n },\n`));\n return { success: false, tokenCount: 0, errors: [\"No token configuration\"] };\n }\n\n console.log(pc.dim(`Scanning files: ${config.tokens.include.join(\", \")}\\n`));\n\n // Parse token files\n const parseResult = await parseTokenFiles(config.tokens, configDir);\n\n if (parseResult.errors.length > 0) {\n console.log(pc.yellow(\"Parse errors:\"));\n for (const err of parseResult.errors) {\n console.log(pc.red(` ${err.file}: ${err.message}`));\n errors.push(`${err.file}: ${err.message}`);\n }\n console.log();\n }\n\n if (parseResult.warnings.length > 0 && options.verbose) {\n console.log(pc.yellow(\"Warnings:\"));\n for (const warning of parseResult.warnings) {\n console.log(pc.dim(` ${warning}`));\n }\n console.log();\n }\n\n let tokens = parseResult.tokens;\n\n // Filter by theme if specified\n if (options.theme) {\n tokens = tokens.filter(\n (t) => t.theme === options.theme || t.theme === \"default\"\n );\n }\n\n // Filter by category if specified\n if (options.category) {\n tokens = tokens.filter((t) => t.category === options.category);\n }\n\n if (tokens.length === 0) {\n console.log(pc.yellow(\"No tokens found.\\n\"));\n console.log(pc.dim(\"Make sure your CSS files contain CSS custom properties (--token-name: value;)\"));\n return { success: true, tokenCount: 0, errors };\n }\n\n // Output based on format\n if (options.json) {\n outputJson(tokens, parseResult.parseTimeMs);\n } else if (options.categories) {\n outputByCategory(tokens, parseResult.parseTimeMs);\n } else {\n outputList(tokens, parseResult.parseTimeMs, options.verbose);\n }\n\n return { success: true, tokenCount: tokens.length, errors };\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Unknown error\";\n console.error(pc.red(\"Error:\"), message);\n errors.push(message);\n return { success: false, tokenCount: 0, errors };\n }\n}\n\n/**\n * Output tokens as JSON\n */\nfunction outputJson(tokens: DesignToken[], parseTimeMs: number): void {\n const output = {\n tokens,\n meta: {\n totalTokens: tokens.length,\n parseTimeMs,\n discoveredAt: new Date().toISOString(),\n },\n };\n\n console.log(JSON.stringify(output, null, 2));\n}\n\n/**\n * Output tokens grouped by category\n */\nfunction outputByCategory(tokens: DesignToken[], parseTimeMs: number): void {\n // Group by category\n const byCategory = new Map<TokenCategory, DesignToken[]>();\n\n for (const token of tokens) {\n const list = byCategory.get(token.category) || [];\n list.push(token);\n byCategory.set(token.category, list);\n }\n\n // Sort categories alphabetically\n const categories = Array.from(byCategory.keys()).sort();\n\n for (const category of categories) {\n const categoryTokens = byCategory.get(category) || [];\n console.log(pc.bold(`${category} (${categoryTokens.length})`));\n console.log(pc.dim(\"─\".repeat(40)));\n\n for (const token of categoryTokens.slice(0, 10)) {\n const levelLabel = token.level === 1 ? \"base\" : token.level === 2 ? \"semantic\" : \"component\";\n console.log(` ${pc.cyan(token.name)}`);\n console.log(` ${pc.dim(\"Value:\")} ${token.resolvedValue}`);\n console.log(` ${pc.dim(\"Level:\")} ${levelLabel} ${pc.dim(`(${token.theme})`)}`);\n }\n\n if (categoryTokens.length > 10) {\n console.log(pc.dim(` ... and ${categoryTokens.length - 10} more`));\n }\n console.log();\n }\n\n // Summary\n console.log(pc.dim(\"─\".repeat(40)));\n console.log(pc.green(`✓ Found ${tokens.length} token(s) in ${categories.length} categories`));\n console.log(pc.dim(` Parsed in ${parseTimeMs.toFixed(1)}ms\\n`));\n}\n\n/**\n * Output tokens as a simple list\n */\nfunction outputList(tokens: DesignToken[], parseTimeMs: number, verbose?: boolean): void {\n // Group by theme first\n const byTheme = new Map<string, DesignToken[]>();\n\n for (const token of tokens) {\n const list = byTheme.get(token.theme) || [];\n list.push(token);\n byTheme.set(token.theme, list);\n }\n\n const themes = Array.from(byTheme.keys()).sort();\n\n for (const theme of themes) {\n const themeTokens = byTheme.get(theme) || [];\n\n if (themes.length > 1) {\n console.log(pc.bold(`Theme: ${theme} (${themeTokens.length} tokens)`));\n console.log(pc.dim(\"─\".repeat(50)));\n }\n\n // Sort tokens by name\n themeTokens.sort((a, b) => a.name.localeCompare(b.name));\n\n // Table header\n console.log(\n pc.dim(\n `${\"Token Name\".padEnd(32)} ${\"Value\".padEnd(20)} ${\"Category\".padEnd(12)}`\n )\n );\n console.log(pc.dim(\"─\".repeat(70)));\n\n const displayTokens = verbose ? themeTokens : themeTokens.slice(0, 30);\n\n for (const token of displayTokens) {\n const name = token.name.length > 30 ? token.name.slice(0, 27) + \"...\" : token.name;\n const value = token.resolvedValue.length > 18 ? token.resolvedValue.slice(0, 15) + \"...\" : token.resolvedValue;\n\n console.log(\n `${pc.cyan(name.padEnd(32))} ${value.padEnd(20)} ${pc.dim(token.category.padEnd(12))}`\n );\n }\n\n if (!verbose && themeTokens.length > 30) {\n console.log(pc.dim(`\\n ... and ${themeTokens.length - 30} more (use --verbose to show all)`));\n }\n\n console.log();\n }\n\n // Summary\n console.log(pc.dim(\"─\".repeat(50)));\n console.log(pc.green(`✓ Found ${tokens.length} token(s)`));\n\n // Category breakdown\n const categoryCounts: Record<string, number> = {};\n for (const token of tokens) {\n categoryCounts[token.category] = (categoryCounts[token.category] || 0) + 1;\n }\n\n const breakdown = Object.entries(categoryCounts)\n .sort((a, b) => b[1] - a[1])\n .map(([cat, count]) => `${cat}: ${count}`)\n .join(\", \");\n\n console.log(pc.dim(` ${breakdown}`));\n console.log(pc.dim(` Parsed in ${parseTimeMs.toFixed(1)}ms\\n`));\n}\n\nexport default tokens;\n"],"mappings":"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","names":["tokens"]}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
|
|
2
|
+
import "./chunk-D2CDBRNU.js";
|
|
3
|
+
import {
|
|
4
|
+
generateCSSCustomProperties,
|
|
5
|
+
generateFigmaVariables,
|
|
6
|
+
generateSCSSVariables,
|
|
7
|
+
generateTailwindConfig
|
|
8
|
+
} from "./chunk-32LIWN2P.js";
|
|
9
|
+
|
|
10
|
+
// src/commands/tokens-generate.ts
|
|
11
|
+
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
12
|
+
import { resolve, dirname, basename, extname } from "path";
|
|
13
|
+
import pc from "picocolors";
|
|
14
|
+
var VALID_FORMATS = /* @__PURE__ */ new Set(["css", "scss", "tailwind", "figma"]);
|
|
15
|
+
async function tokensGenerate(options) {
|
|
16
|
+
const { from, format, out, prefix, selector, verbose } = options;
|
|
17
|
+
const formats = format.split(",").map((f) => f.trim().toLowerCase());
|
|
18
|
+
const invalidFormats = formats.filter((f) => !VALID_FORMATS.has(f));
|
|
19
|
+
if (invalidFormats.length > 0) {
|
|
20
|
+
console.error(pc.red(`Invalid format(s): ${invalidFormats.join(", ")}`));
|
|
21
|
+
console.error(`Valid formats: ${[...VALID_FORMATS].join(", ")}`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
const sourcePath = resolve(process.cwd(), from);
|
|
25
|
+
let content;
|
|
26
|
+
try {
|
|
27
|
+
content = await readFile(sourcePath, "utf-8");
|
|
28
|
+
} catch {
|
|
29
|
+
console.error(pc.red(`Could not read file: ${sourcePath}`));
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
let tokens;
|
|
33
|
+
try {
|
|
34
|
+
tokens = JSON.parse(content);
|
|
35
|
+
} catch {
|
|
36
|
+
console.error(pc.red(`Invalid JSON in: ${sourcePath}`));
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
const outDir = out ? resolve(process.cwd(), out) : dirname(sourcePath);
|
|
40
|
+
await mkdir(outDir, { recursive: true });
|
|
41
|
+
const baseName = basename(from, extname(from)).replace(/\.tokens$/, "");
|
|
42
|
+
for (const fmt of formats) {
|
|
43
|
+
let output;
|
|
44
|
+
let fileName;
|
|
45
|
+
switch (fmt) {
|
|
46
|
+
case "css": {
|
|
47
|
+
output = generateCSSCustomProperties(tokens, { prefix, selector });
|
|
48
|
+
fileName = `${baseName}.css`;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
case "scss": {
|
|
52
|
+
output = generateSCSSVariables(tokens, { prefix });
|
|
53
|
+
fileName = `_${baseName}.scss`;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
case "tailwind": {
|
|
57
|
+
const config = generateTailwindConfig(tokens);
|
|
58
|
+
output = `// Auto-generated Tailwind config from DTCG tokens
|
|
59
|
+
// Do not edit directly
|
|
60
|
+
export default ${JSON.stringify(config, null, 2)};
|
|
61
|
+
`;
|
|
62
|
+
fileName = `tailwind.tokens.js`;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
case "figma": {
|
|
66
|
+
const collections = generateFigmaVariables(tokens);
|
|
67
|
+
output = JSON.stringify(collections, null, 2);
|
|
68
|
+
fileName = `${baseName}.figma-variables.json`;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
default:
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const outputPath = resolve(outDir, fileName);
|
|
75
|
+
await writeFile(outputPath, output, "utf-8");
|
|
76
|
+
if (verbose) {
|
|
77
|
+
console.log(pc.green(` \u2713 ${fmt}`), pc.dim(outputPath));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
console.log(pc.green(`Generated ${formats.length} output(s) from ${from}`));
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
tokensGenerate
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=tokens-generate-5JQSJ27E.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/tokens-generate.ts"],"sourcesContent":["/**\n * fragments tokens generate — Generate CSS, SCSS, Tailwind, or Figma output\n * from a DTCG .tokens.json source file.\n */\n\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { resolve, dirname, basename, extname } from 'node:path';\nimport pc from 'picocolors';\nimport {\n generateCSSCustomProperties,\n generateSCSSVariables,\n generateTailwindConfig,\n generateFigmaVariables,\n} from '../core/index.js';\nimport type { DTCGTokenFile } from '../core/index.js';\n\nexport interface TokensGenerateOptions {\n /** Path to DTCG .tokens.json source file */\n from: string;\n /** Output formats (comma-separated: css, scss, tailwind, figma) */\n format: string;\n /** Output directory */\n out?: string;\n /** Token name prefix */\n prefix?: string;\n /** CSS selector for custom properties (default: ':root') */\n selector?: string;\n /** Verbose output */\n verbose?: boolean;\n}\n\ntype OutputFormat = 'css' | 'scss' | 'tailwind' | 'figma';\n\nconst VALID_FORMATS = new Set<OutputFormat>(['css', 'scss', 'tailwind', 'figma']);\n\nexport async function tokensGenerate(options: TokensGenerateOptions): Promise<void> {\n const { from, format, out, prefix, selector, verbose } = options;\n\n // Parse formats\n const formats = format.split(',').map((f) => f.trim().toLowerCase()) as OutputFormat[];\n const invalidFormats = formats.filter((f) => !VALID_FORMATS.has(f));\n if (invalidFormats.length > 0) {\n console.error(pc.red(`Invalid format(s): ${invalidFormats.join(', ')}`));\n console.error(`Valid formats: ${[...VALID_FORMATS].join(', ')}`);\n process.exit(1);\n }\n\n // Read source file\n const sourcePath = resolve(process.cwd(), from);\n let content: string;\n try {\n content = await readFile(sourcePath, 'utf-8');\n } catch {\n console.error(pc.red(`Could not read file: ${sourcePath}`));\n process.exit(1);\n }\n\n let tokens: DTCGTokenFile;\n try {\n tokens = JSON.parse(content) as DTCGTokenFile;\n } catch {\n console.error(pc.red(`Invalid JSON in: ${sourcePath}`));\n process.exit(1);\n }\n\n // Determine output directory\n const outDir = out ? resolve(process.cwd(), out) : dirname(sourcePath);\n await mkdir(outDir, { recursive: true });\n\n const baseName = basename(from, extname(from)).replace(/\\.tokens$/, '');\n\n // Generate each format\n for (const fmt of formats) {\n let output: string;\n let fileName: string;\n\n switch (fmt) {\n case 'css': {\n output = generateCSSCustomProperties(tokens, { prefix, selector });\n fileName = `${baseName}.css`;\n break;\n }\n case 'scss': {\n output = generateSCSSVariables(tokens, { prefix });\n fileName = `_${baseName}.scss`;\n break;\n }\n case 'tailwind': {\n const config = generateTailwindConfig(tokens);\n output = `// Auto-generated Tailwind config from DTCG tokens\\n// Do not edit directly\\nexport default ${JSON.stringify(config, null, 2)};\\n`;\n fileName = `tailwind.tokens.js`;\n break;\n }\n case 'figma': {\n const collections = generateFigmaVariables(tokens);\n output = JSON.stringify(collections, null, 2);\n fileName = `${baseName}.figma-variables.json`;\n break;\n }\n default:\n continue;\n }\n\n const outputPath = resolve(outDir, fileName);\n await writeFile(outputPath, output, 'utf-8');\n\n if (verbose) {\n console.log(pc.green(` ✓ ${fmt}`), pc.dim(outputPath));\n }\n }\n\n console.log(pc.green(`Generated ${formats.length} output(s) from ${from}`));\n}\n"],"mappings":";;;;;;;;;;AAKA,SAAS,UAAU,WAAW,aAAa;AAC3C,SAAS,SAAS,SAAS,UAAU,eAAe;AACpD,OAAO,QAAQ;AA0Bf,IAAM,gBAAgB,oBAAI,IAAkB,CAAC,OAAO,QAAQ,YAAY,OAAO,CAAC;AAEhF,eAAsB,eAAe,SAA+C;AAClF,QAAM,EAAE,MAAM,QAAQ,KAAK,QAAQ,UAAU,QAAQ,IAAI;AAGzD,QAAM,UAAU,OAAO,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC;AACnE,QAAM,iBAAiB,QAAQ,OAAO,CAAC,MAAM,CAAC,cAAc,IAAI,CAAC,CAAC;AAClE,MAAI,eAAe,SAAS,GAAG;AAC7B,YAAQ,MAAM,GAAG,IAAI,sBAAsB,eAAe,KAAK,IAAI,CAAC,EAAE,CAAC;AACvE,YAAQ,MAAM,kBAAkB,CAAC,GAAG,aAAa,EAAE,KAAK,IAAI,CAAC,EAAE;AAC/D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,aAAa,QAAQ,QAAQ,IAAI,GAAG,IAAI;AAC9C,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,SAAS,YAAY,OAAO;AAAA,EAC9C,QAAQ;AACN,YAAQ,MAAM,GAAG,IAAI,wBAAwB,UAAU,EAAE,CAAC;AAC1D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,OAAO;AAAA,EAC7B,QAAQ;AACN,YAAQ,MAAM,GAAG,IAAI,oBAAoB,UAAU,EAAE,CAAC;AACtD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,SAAS,MAAM,QAAQ,QAAQ,IAAI,GAAG,GAAG,IAAI,QAAQ,UAAU;AACrE,QAAM,MAAM,QAAQ,EAAE,WAAW,KAAK,CAAC;AAEvC,QAAM,WAAW,SAAS,MAAM,QAAQ,IAAI,CAAC,EAAE,QAAQ,aAAa,EAAE;AAGtE,aAAW,OAAO,SAAS;AACzB,QAAI;AACJ,QAAI;AAEJ,YAAQ,KAAK;AAAA,MACX,KAAK,OAAO;AACV,iBAAS,4BAA4B,QAAQ,EAAE,QAAQ,SAAS,CAAC;AACjE,mBAAW,GAAG,QAAQ;AACtB;AAAA,MACF;AAAA,MACA,KAAK,QAAQ;AACX,iBAAS,sBAAsB,QAAQ,EAAE,OAAO,CAAC;AACjD,mBAAW,IAAI,QAAQ;AACvB;AAAA,MACF;AAAA,MACA,KAAK,YAAY;AACf,cAAM,SAAS,uBAAuB,MAAM;AAC5C,iBAAS;AAAA;AAAA,iBAA+F,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AACvI,mBAAW;AACX;AAAA,MACF;AAAA,MACA,KAAK,SAAS;AACZ,cAAM,cAAc,uBAAuB,MAAM;AACjD,iBAAS,KAAK,UAAU,aAAa,MAAM,CAAC;AAC5C,mBAAW,GAAG,QAAQ;AACtB;AAAA,MACF;AAAA,MACA;AACE;AAAA,IACJ;AAEA,UAAM,aAAa,QAAQ,QAAQ,QAAQ;AAC3C,UAAM,UAAU,YAAY,QAAQ,OAAO;AAE3C,QAAI,SAAS;AACX,cAAQ,IAAI,GAAG,MAAM,YAAO,GAAG,EAAE,GAAG,GAAG,IAAI,UAAU,CAAC;AAAA,IACxD;AAAA,EACF;AAEA,UAAQ,IAAI,GAAG,MAAM,aAAa,QAAQ,MAAM,mBAAmB,IAAI,EAAE,CAAC;AAC5E;","names":[]}
|