@fragments-sdk/cli 0.7.2 → 0.7.3

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.
Files changed (64) hide show
  1. package/dist/bin.js +20 -16
  2. package/dist/bin.js.map +1 -1
  3. package/dist/chunk-D34Q6A7S.js +266 -0
  4. package/dist/chunk-D34Q6A7S.js.map +1 -0
  5. package/dist/chunk-EKLMXTWU.js +80 -0
  6. package/dist/chunk-EKLMXTWU.js.map +1 -0
  7. package/dist/{chunk-GHYYFAQN.js → chunk-P33AKQJW.js} +1 -76
  8. package/dist/chunk-P33AKQJW.js.map +1 -0
  9. package/dist/{chunk-7KUSBMI4.js → chunk-QPY4DUFB.js} +174 -45
  10. package/dist/chunk-QPY4DUFB.js.map +1 -0
  11. package/dist/{chunk-DH4ETVSM.js → chunk-R2YH7NLN.js} +9 -7
  12. package/dist/{chunk-DH4ETVSM.js.map → chunk-R2YH7NLN.js.map} +1 -1
  13. package/dist/{chunk-3T6QL7IY.js → chunk-R6IZZSE7.js} +23 -275
  14. package/dist/chunk-R6IZZSE7.js.map +1 -0
  15. package/dist/{chunk-DQHWLAUV.js → chunk-TOIE7VXF.js} +2 -2
  16. package/dist/{chunk-OOGTG5FM.js → chunk-UXLGIGSX.js} +56 -2
  17. package/dist/chunk-UXLGIGSX.js.map +1 -0
  18. package/dist/{chunk-GKX2HPZ6.js → chunk-YMPGYEWK.js} +9 -3
  19. package/dist/chunk-YMPGYEWK.js.map +1 -0
  20. package/dist/chunk-Z7EY4VHE.js +50 -0
  21. package/dist/{core-UQXZTBFZ.js → core-3NMNCLFW.js} +8 -5
  22. package/dist/discovery-AKGA6CJD.js +28 -0
  23. package/dist/{generate-GP6ZLAQB.js → generate-JAUEHKK7.js} +7 -4
  24. package/dist/{generate-GP6ZLAQB.js.map → generate-JAUEHKK7.js.map} +1 -1
  25. package/dist/index.js +15 -11
  26. package/dist/index.js.map +1 -1
  27. package/dist/{init-W72WBSU2.js → init-DZQOT54X.js} +6 -4
  28. package/dist/{init-W72WBSU2.js.map → init-DZQOT54X.js.map} +1 -1
  29. package/dist/mcp-bin.js +5 -3
  30. package/dist/mcp-bin.js.map +1 -1
  31. package/dist/sass.node-4XJK6YBF.js +130708 -0
  32. package/dist/sass.node-4XJK6YBF.js.map +1 -0
  33. package/dist/scan-OJRCVKK2.js +15 -0
  34. package/dist/{service-PVGTYUKX.js → service-CFFBHW4X.js} +6 -4
  35. package/dist/service-CFFBHW4X.js.map +1 -0
  36. package/dist/{static-viewer-KILKIVN7.js → static-viewer-VA2JXSCX.js} +6 -4
  37. package/dist/static-viewer-VA2JXSCX.js.map +1 -0
  38. package/dist/{test-3YRYQRGV.js → test-O7DZNKDC.js} +8 -4
  39. package/dist/{test-3YRYQRGV.js.map → test-O7DZNKDC.js.map} +1 -1
  40. package/dist/{tokens-IXSQHPQK.js → tokens-N7THFD6J.js} +10 -7
  41. package/dist/{tokens-IXSQHPQK.js.map → tokens-N7THFD6J.js.map} +1 -1
  42. package/dist/{viewer-K42REJU2.js → viewer-QTR7QJMM.js} +390 -25
  43. package/dist/viewer-QTR7QJMM.js.map +1 -0
  44. package/package.json +1 -1
  45. package/src/build.ts +57 -5
  46. package/src/core/__tests__/token-resolver.test.ts +82 -0
  47. package/src/core/token-parser.ts +102 -0
  48. package/src/core/token-resolver.ts +155 -0
  49. package/src/service/__tests__/patch-generator.test.ts +2 -2
  50. package/src/service/patch-generator.ts +8 -1
  51. package/src/viewer/render-utils.ts +141 -0
  52. package/src/viewer/vite-plugin.ts +381 -23
  53. package/dist/chunk-3T6QL7IY.js.map +0 -1
  54. package/dist/chunk-7KUSBMI4.js.map +0 -1
  55. package/dist/chunk-GHYYFAQN.js.map +0 -1
  56. package/dist/chunk-GKX2HPZ6.js.map +0 -1
  57. package/dist/chunk-OOGTG5FM.js.map +0 -1
  58. package/dist/scan-V54HWRDY.js +0 -12
  59. package/dist/viewer-K42REJU2.js.map +0 -1
  60. /package/dist/{chunk-DQHWLAUV.js.map → chunk-TOIE7VXF.js.map} +0 -0
  61. /package/dist/{core-UQXZTBFZ.js.map → chunk-Z7EY4VHE.js.map} +0 -0
  62. /package/dist/{scan-V54HWRDY.js.map → core-3NMNCLFW.js.map} +0 -0
  63. /package/dist/{service-PVGTYUKX.js.map → discovery-AKGA6CJD.js.map} +0 -0
  64. /package/dist/{static-viewer-KILKIVN7.js.map → scan-OJRCVKK2.js.map} +0 -0
@@ -1,4 +1,17 @@
1
1
  import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
2
+ import {
3
+ generateContextMd,
4
+ generateRegistry,
5
+ loadFragmentFile,
6
+ parseFragmentFile
7
+ } from "./chunk-R6IZZSE7.js";
8
+ import {
9
+ discoverBlockFiles,
10
+ discoverComponentFiles,
11
+ discoverFragmentFiles,
12
+ discoverTokenFiles,
13
+ extractComponentName
14
+ } from "./chunk-D34Q6A7S.js";
2
15
  import {
3
16
  BrowserPool,
4
17
  CaptureEngine,
@@ -8,27 +21,18 @@ import {
8
21
  formatMs,
9
22
  generateHtmlReport,
10
23
  getGrade
11
- } from "./chunk-GKX2HPZ6.js";
12
- import {
13
- discoverBlockFiles,
14
- discoverComponentFiles,
15
- discoverFragmentFiles,
16
- discoverTokenFiles,
17
- extractComponentName,
18
- generateContextMd,
19
- generateRegistry,
20
- loadFragmentFile,
21
- parseFragmentFile
22
- } from "./chunk-3T6QL7IY.js";
24
+ } from "./chunk-YMPGYEWK.js";
23
25
  import {
24
26
  compileBlock,
25
27
  parseTokenFile
26
- } from "./chunk-OOGTG5FM.js";
28
+ } from "./chunk-UXLGIGSX.js";
27
29
  import {
28
- BRAND,
29
- DEFAULTS,
30
30
  fragmentDefinitionSchema
31
- } from "./chunk-GHYYFAQN.js";
31
+ } from "./chunk-P33AKQJW.js";
32
+ import {
33
+ BRAND,
34
+ DEFAULTS
35
+ } from "./chunk-EKLMXTWU.js";
32
36
 
33
37
  // src/validators.ts
34
38
  async function validateSchema(config, configDir) {
@@ -120,18 +124,110 @@ async function validateAll(config, configDir) {
120
124
 
121
125
  // src/build.ts
122
126
  import { readFile, writeFile, mkdir } from "fs/promises";
123
- import { resolve as resolve3, join as join3 } from "path";
124
- import { existsSync as existsSync3 } from "fs";
127
+ import { resolve as resolve4, join as join3 } from "path";
128
+ import { existsSync as existsSync4 } from "fs";
129
+
130
+ // src/core/token-resolver.ts
131
+ import { resolve, dirname, basename } from "path";
132
+ import { existsSync, readdirSync } from "fs";
133
+ function roundRgbValues(value) {
134
+ return value.replace(
135
+ /rgb\(([^)]+)\)/g,
136
+ (_full, inner) => {
137
+ const parts = inner.split(",").map((p) => p.trim());
138
+ const rounded = parts.map((p) => {
139
+ const num = parseFloat(p);
140
+ return isNaN(num) ? p : String(Math.round(num));
141
+ });
142
+ return `rgb(${rounded.join(", ")})`;
143
+ }
144
+ ).replace(
145
+ /rgba\(([^)]+)\)/g,
146
+ (_full, inner) => {
147
+ const parts = inner.split(",").map((p) => p.trim());
148
+ const rounded = parts.map((p, i) => {
149
+ if (i >= 3) return p;
150
+ const num = parseFloat(p);
151
+ return isNaN(num) ? p : String(Math.round(num));
152
+ });
153
+ return `rgba(${rounded.join(", ")})`;
154
+ }
155
+ );
156
+ }
157
+ async function resolveTokensWithSass(unresolvedTokens, tokensDir) {
158
+ const resolvedMap = /* @__PURE__ */ new Map();
159
+ const needsResolution = unresolvedTokens.filter(
160
+ (t) => t.value.includes("#{") || t.value.includes("$")
161
+ );
162
+ if (needsResolution.length === 0) {
163
+ return resolvedMap;
164
+ }
165
+ try {
166
+ const sass = await import("./sass.node-4XJK6YBF.js");
167
+ const variablesPath = findVariablesFile(tokensDir);
168
+ if (!variablesPath) {
169
+ return resolvedMap;
170
+ }
171
+ const fileName = basename(variablesPath);
172
+ const moduleName = fileName.replace(/^_/, "").replace(/\.scss$/, "");
173
+ const scssSource = `
174
+ @use '${moduleName}' as vars;
175
+ :root { @include vars.fui-css-variables; }
176
+ `;
177
+ const compiled = sass.compileString(scssSource, {
178
+ loadPaths: [tokensDir, dirname(tokensDir)],
179
+ style: "expanded",
180
+ // Suppress sass deprecation warnings during build
181
+ logger: { warn() {
182
+ }, debug() {
183
+ } }
184
+ });
185
+ const cssVarRegex = /(--[\w-]+)\s*:\s*([^;]+)/g;
186
+ let match;
187
+ const allResolved = /* @__PURE__ */ new Map();
188
+ while ((match = cssVarRegex.exec(compiled.css)) !== null) {
189
+ allResolved.set(match[1], roundRgbValues(match[2].trim()));
190
+ }
191
+ for (const token of needsResolution) {
192
+ const value = allResolved.get(token.name);
193
+ if (value !== void 0) {
194
+ resolvedMap.set(token.name, value);
195
+ }
196
+ }
197
+ } catch {
198
+ }
199
+ return resolvedMap;
200
+ }
201
+ function findVariablesFile(tokensDir) {
202
+ const candidates = ["_variables.scss", "variables.scss"];
203
+ for (const name of candidates) {
204
+ const path = resolve(tokensDir, name);
205
+ if (existsSync(path)) {
206
+ return path;
207
+ }
208
+ }
209
+ try {
210
+ const files = readdirSync(tokensDir).filter((f) => f.endsWith(".scss"));
211
+ for (const file of files) {
212
+ const path = resolve(tokensDir, file);
213
+ if (file.includes("variables") || file.includes("tokens")) {
214
+ return path;
215
+ }
216
+ }
217
+ } catch {
218
+ }
219
+ return null;
220
+ }
125
221
 
126
222
  // src/core/auto-props.ts
127
- import { existsSync, statSync } from "fs";
128
- import { dirname, extname, join, resolve } from "path";
223
+ import { existsSync as existsSync2, statSync } from "fs";
224
+ import { dirname as dirname2, extname, join, resolve as resolve2 } from "path";
129
225
  import ts from "typescript";
130
226
  function toPosixPath(filePath) {
131
227
  return filePath.replace(/\\/g, "/");
132
228
  }
133
229
  function isFile(filePath) {
134
- if (!existsSync(filePath)) return false;
230
+ if (!existsSync2(filePath)) return false;
135
231
  try {
136
232
  return statSync(filePath).isFile();
137
233
  } catch {
@@ -157,7 +253,7 @@ function resolveModulePath(basePath) {
157
253
  }
158
254
  for (const candidate of candidates) {
159
255
  if (isFile(candidate)) {
160
- return resolve(candidate);
256
+ return resolve2(candidate);
161
257
  }
162
258
  }
163
259
  return null;
@@ -165,8 +261,8 @@ function resolveModulePath(basePath) {
165
261
  function resolveComponentSourcePath(fragmentFileAbsolutePath, componentImportPath) {
166
262
  if (!componentImportPath) return null;
167
263
  if (!componentImportPath.startsWith(".")) return null;
168
- const fragmentDir = dirname(fragmentFileAbsolutePath);
169
- const basePath = resolve(fragmentDir, componentImportPath);
264
+ const fragmentDir = dirname2(fragmentFileAbsolutePath);
265
+ const basePath = resolve2(fragmentDir, componentImportPath);
170
266
  return resolveModulePath(basePath);
171
267
  }
172
268
  function collectTopLevelDeclarations(sourceFile) {
@@ -354,8 +450,8 @@ function resolveComponentSignature(exportName, declarations, sourceFile) {
354
450
  }
355
451
  function extractCustomPropsFromComponentFile(componentFilePath, exportName) {
356
452
  const warnings = [];
357
- const resolvedPath = resolve(componentFilePath);
358
- if (!existsSync(resolvedPath)) {
453
+ const resolvedPath = resolve2(componentFilePath);
454
+ if (!existsSync2(resolvedPath)) {
359
455
  return {
360
456
  props: {},
361
457
  warnings: [`Component file not found: ${resolvedPath}`],
@@ -431,9 +527,9 @@ function extractCustomPropsFromComponentFile(componentFilePath, exportName) {
431
527
 
432
528
  // src/core/graph-extractor.ts
433
529
  import ts2 from "typescript";
434
- import { readFileSync, existsSync as existsSync2 } from "fs";
530
+ import { readFileSync, existsSync as existsSync3 } from "fs";
435
531
  import { join as join2 } from "path";
436
- import { readdirSync } from "fs";
532
+ import { readdirSync as readdirSync2 } from "fs";
437
533
  import { EDGE_TYPE_WEIGHTS, computeHealthFromData } from "@fragments-sdk/context/graph";
438
534
  async function buildComponentGraph(fragments, blocks, componentDir, options) {
439
535
  const knownComponents = new Set(Object.keys(fragments));
@@ -790,12 +886,12 @@ function findComponentIndex(componentDir, componentName) {
790
886
  join2(componentDir, componentName, `${componentName}.ts`)
791
887
  ];
792
888
  for (const candidate of candidates) {
793
- if (existsSync2(candidate)) {
889
+ if (existsSync3(candidate)) {
794
890
  return candidate;
795
891
  }
796
892
  }
797
893
  try {
798
- const entries = readdirSync(componentDir, { withFileTypes: true });
894
+ const entries = readdirSync2(componentDir, { withFileTypes: true });
799
895
  for (const entry of entries) {
800
896
  if (entry.isDirectory() && entry.name === componentName) {
801
897
  const subCandidates = [
@@ -803,7 +899,7 @@ function findComponentIndex(componentDir, componentName) {
803
899
  join2(componentDir, entry.name, "index.ts")
804
900
  ];
805
901
  for (const sc of subCandidates) {
806
- if (existsSync2(sc)) return sc;
902
+ if (existsSync3(sc)) return sc;
807
903
  }
808
904
  }
809
905
  }
@@ -988,38 +1084,71 @@ async function buildFragments(config, configDir) {
988
1084
  const mergedCategories = {};
989
1085
  let prefix = "--";
990
1086
  let total = 0;
1087
+ const fileContents = [];
991
1088
  for (const file of tokenFiles) {
992
1089
  const content = await readFile(file.absolutePath, "utf-8");
993
- const parsed = parseTokenFile(content, file.relativePath);
994
- prefix = parsed.prefix;
995
- total += parsed.total;
996
- for (const [cat, catTokens] of Object.entries(parsed.categories)) {
1090
+ fileContents.push({ content, path: file.relativePath });
1091
+ }
1092
+ const allContent = fileContents.map((f) => f.content).join("\n");
1093
+ for (const { content, path } of fileContents) {
1094
+ const parsed = parseTokenFile(allContent, path);
1095
+ const fileParsed = parseTokenFile(content, path);
1096
+ prefix = fileParsed.prefix;
1097
+ total += fileParsed.total;
1098
+ for (const [cat, catTokens] of Object.entries(fileParsed.categories)) {
997
1099
  if (!mergedCategories[cat]) {
998
1100
  mergedCategories[cat] = [];
999
1101
  }
1000
1102
  for (const t of catTokens) {
1001
1103
  if (!mergedCategories[cat].some((e) => e.name === t.name)) {
1002
- mergedCategories[cat].push({ name: t.name, ...t.value && { value: t.value }, description: t.description });
1104
+ const combinedToken = Object.values(parsed.categories).flat().find((ct) => ct.name === t.name);
1105
+ const resolvedValue = combinedToken?.resolvedValue ?? t.resolvedValue;
1106
+ mergedCategories[cat].push({
1107
+ name: t.name,
1108
+ ...resolvedValue ? { value: resolvedValue } : t.value ? { value: t.value } : {},
1109
+ description: t.description
1110
+ });
1003
1111
  }
1004
1112
  }
1005
1113
  }
1006
1114
  }
1007
1115
  if (total > 0) {
1116
+ const allTokens = Object.values(mergedCategories).flat();
1117
+ const unresolved = allTokens.filter(
1118
+ (t) => t.value && (t.value.includes("#{") || t.value.includes("$"))
1119
+ );
1120
+ if (unresolved.length > 0 && tokenFiles.length > 0) {
1121
+ const tokensDir = resolve4(configDir, tokenFiles[0].relativePath, "..");
1122
+ const sassResolved = await resolveTokensWithSass(
1123
+ unresolved,
1124
+ tokensDir
1125
+ );
1126
+ if (sassResolved.size > 0) {
1127
+ for (const catTokens of Object.values(mergedCategories)) {
1128
+ for (const token of catTokens) {
1129
+ const resolved = sassResolved.get(token.name);
1130
+ if (resolved && token.value && (token.value.includes("#{") || token.value.includes("$"))) {
1131
+ token.value = resolved;
1132
+ }
1133
+ }
1134
+ }
1135
+ }
1136
+ }
1008
1137
  tokens = { prefix, total, categories: mergedCategories };
1009
1138
  }
1010
1139
  }
1011
1140
  } catch {
1012
1141
  }
1013
1142
  let packageName;
1014
- const pkgJsonPath = resolve3(configDir, "package.json");
1015
- if (existsSync3(pkgJsonPath)) {
1143
+ const pkgJsonPath = resolve4(configDir, "package.json");
1144
+ if (existsSync4(pkgJsonPath)) {
1016
1145
  try {
1017
1146
  const pkg = JSON.parse(await readFile(pkgJsonPath, "utf-8"));
1018
1147
  if (pkg.name) packageName = pkg.name;
1019
1148
  } catch {
1020
1149
  }
1021
1150
  }
1022
- const componentDir = resolve3(configDir, "src", "components");
1151
+ const componentDir = resolve4(configDir, "src", "components");
1023
1152
  let graphData;
1024
1153
  try {
1025
1154
  const graphResult = await buildComponentGraph(fragments, blocks, componentDir);
@@ -1059,7 +1188,7 @@ async function buildFragments(config, configDir) {
1059
1188
  ...tokens && { tokens },
1060
1189
  ...graphData && { graph: graphData }
1061
1190
  };
1062
- const outputPath = resolve3(configDir, config.outFile ?? BRAND.outFile);
1191
+ const outputPath = resolve4(configDir, config.outFile ?? BRAND.outFile);
1063
1192
  await writeFile(outputPath, JSON.stringify(output));
1064
1193
  return {
1065
1194
  success: errors.length === 0,
@@ -1450,9 +1579,9 @@ ${BRAND.name} Diff
1450
1579
  }
1451
1580
 
1452
1581
  // src/analyze.ts
1453
- import { existsSync as existsSync4 } from "fs";
1582
+ import { existsSync as existsSync5 } from "fs";
1454
1583
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
1455
- import { join as join4, dirname as dirname2 } from "path";
1584
+ import { join as join4, dirname as dirname3 } from "path";
1456
1585
  import pc3 from "picocolors";
1457
1586
  async function runAnalyzeCommand(config, configDir, options = {}) {
1458
1587
  const format = options.format ?? "html";
@@ -1461,7 +1590,7 @@ async function runAnalyzeCommand(config, configDir, options = {}) {
1461
1590
  ${BRAND.name} Analyzer
1462
1591
  `));
1463
1592
  const fragmentsPath = join4(configDir, config.outFile ?? "fragments.json");
1464
- if (!existsSync4(fragmentsPath)) {
1593
+ if (!existsSync5(fragmentsPath)) {
1465
1594
  console.log(pc3.red(`\u2717 No fragments.json found. Run \`${BRAND.cliCommand} build\` first.
1466
1595
  `));
1467
1596
  return {
@@ -1477,7 +1606,7 @@ ${BRAND.name} Analyzer
1477
1606
  let outputPath;
1478
1607
  if (format === "html" || format === "json") {
1479
1608
  outputPath = options.output ?? getDefaultOutputPath(format, configDir);
1480
- await mkdir2(dirname2(outputPath), { recursive: true });
1609
+ await mkdir2(dirname3(outputPath), { recursive: true });
1481
1610
  if (format === "html") {
1482
1611
  const html = generateHtmlReport(analytics);
1483
1612
  await writeFile2(outputPath, html);
@@ -1624,4 +1753,4 @@ export {
1624
1753
  runDiffCommand,
1625
1754
  runAnalyzeCommand
1626
1755
  };
1627
- //# sourceMappingURL=chunk-7KUSBMI4.js.map
1756
+ //# sourceMappingURL=chunk-QPY4DUFB.js.map