@fragments-sdk/cli 0.6.0 → 0.7.0

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 (49) hide show
  1. package/dist/bin.js +294 -50
  2. package/dist/bin.js.map +1 -1
  3. package/dist/{chunk-D35RGPAG.js → chunk-7OPWMLOE.js} +435 -19
  4. package/dist/chunk-7OPWMLOE.js.map +1 -0
  5. package/dist/{chunk-SSLQXHNX.js → chunk-CVXKXVOY.js} +1 -1
  6. package/dist/{chunk-SSLQXHNX.js.map → chunk-CVXKXVOY.js.map} +1 -1
  7. package/dist/{chunk-Q7GOHVOK.js → chunk-TJ34N7C7.js} +39 -2
  8. package/dist/{chunk-Q7GOHVOK.js.map → chunk-TJ34N7C7.js.map} +1 -1
  9. package/dist/{chunk-F7ITZPDJ.js → chunk-XHUDJNN3.js} +2 -2
  10. package/dist/{core-SKRPJQZG.js → core-W2HYIQW6.js} +2 -2
  11. package/dist/{generate-7AF7WRVK.js → generate-LMTISDIJ.js} +3 -3
  12. package/dist/index.js +3 -3
  13. package/dist/{init-WKGDPYI4.js → init-7CHRKQ7P.js} +3 -3
  14. package/dist/mcp-bin.js +2 -2
  15. package/dist/{scan-K6JNMCGM.js → scan-WY23TJCP.js} +4 -4
  16. package/dist/{service-F3E4JJM7.js → service-T2L7VLTE.js} +2 -2
  17. package/dist/{static-viewer-4LQZ5AGA.js → static-viewer-GBR7YNF3.js} +2 -2
  18. package/dist/{test-CJDNJTPZ.js → test-OJRXNDO2.js} +2 -2
  19. package/dist/{tokens-JAJABYXP.js → tokens-3BWDESVM.js} +3 -3
  20. package/dist/{viewer-R3Q6WAMJ.js → viewer-SUFOISZM.js} +12 -12
  21. package/package.json +2 -2
  22. package/src/bin.ts +23 -0
  23. package/src/build.ts +43 -0
  24. package/src/commands/graph.ts +274 -0
  25. package/src/core/composition.ts +64 -1
  26. package/src/core/graph-extractor.test.ts +542 -0
  27. package/src/core/graph-extractor.ts +601 -0
  28. package/src/core/importAnalyzer.ts +5 -0
  29. package/src/viewer/components/App.tsx +128 -30
  30. package/src/viewer/components/Icons.tsx +53 -1
  31. package/src/viewer/components/Layout.tsx +7 -3
  32. package/src/viewer/components/LeftSidebar.tsx +65 -87
  33. package/src/viewer/components/PreviewFrameHost.tsx +30 -1
  34. package/src/viewer/components/PreviewToolbar.tsx +57 -10
  35. package/src/viewer/components/ViewportSelector.tsx +56 -45
  36. package/src/viewer/constants/ui.ts +4 -4
  37. package/src/viewer/preview-frame.html +22 -13
  38. package/src/viewer/styles/globals.css +42 -81
  39. package/dist/chunk-D35RGPAG.js.map +0 -1
  40. /package/dist/{chunk-F7ITZPDJ.js.map → chunk-XHUDJNN3.js.map} +0 -0
  41. /package/dist/{core-SKRPJQZG.js.map → core-W2HYIQW6.js.map} +0 -0
  42. /package/dist/{generate-7AF7WRVK.js.map → generate-LMTISDIJ.js.map} +0 -0
  43. /package/dist/{init-WKGDPYI4.js.map → init-7CHRKQ7P.js.map} +0 -0
  44. /package/dist/{scan-K6JNMCGM.js.map → scan-WY23TJCP.js.map} +0 -0
  45. /package/dist/{service-F3E4JJM7.js.map → service-T2L7VLTE.js.map} +0 -0
  46. /package/dist/{static-viewer-4LQZ5AGA.js.map → static-viewer-GBR7YNF3.js.map} +0 -0
  47. /package/dist/{test-CJDNJTPZ.js.map → test-OJRXNDO2.js.map} +0 -0
  48. /package/dist/{tokens-JAJABYXP.js.map → tokens-3BWDESVM.js.map} +0 -0
  49. /package/dist/{viewer-R3Q6WAMJ.js.map → viewer-SUFOISZM.js.map} +0 -0
@@ -19,11 +19,11 @@ import {
19
19
  generateRegistry,
20
20
  loadSegmentFile,
21
21
  parseSegmentFile
22
- } from "./chunk-SSLQXHNX.js";
22
+ } from "./chunk-CVXKXVOY.js";
23
23
  import {
24
24
  compileBlock,
25
25
  parseTokenFile
26
- } from "./chunk-Q7GOHVOK.js";
26
+ } from "./chunk-TJ34N7C7.js";
27
27
  import {
28
28
  BRAND,
29
29
  DEFAULTS,
@@ -120,8 +120,8 @@ async function validateAll(config, configDir) {
120
120
 
121
121
  // src/build.ts
122
122
  import { readFile, writeFile, mkdir } from "fs/promises";
123
- import { resolve as resolve2, join as join2 } from "path";
124
- import { existsSync as existsSync2 } from "fs";
123
+ import { resolve as resolve3, join as join3 } from "path";
124
+ import { existsSync as existsSync3 } from "fs";
125
125
 
126
126
  // src/core/auto-props.ts
127
127
  import { existsSync, statSync } from "fs";
@@ -429,7 +429,391 @@ function extractCustomPropsFromComponentFile(componentFilePath, exportName) {
429
429
  };
430
430
  }
431
431
 
432
+ // src/core/graph-extractor.ts
433
+ import ts2 from "typescript";
434
+ import { readFileSync, existsSync as existsSync2 } from "fs";
435
+ import { join as join2 } from "path";
436
+ import { readdirSync } from "fs";
437
+ import { EDGE_TYPE_WEIGHTS, computeHealthFromData } from "@fragments-sdk/context/graph";
438
+ async function buildComponentGraph(segments, blocks, componentDir, options) {
439
+ const knownComponents = new Set(Object.keys(segments));
440
+ const allEdges = [];
441
+ const autoDetected = /* @__PURE__ */ new Map();
442
+ const warnings = [];
443
+ if (!options?.skipSourceAnalysis) {
444
+ const sourceEdges = extractImportAndHookEdges(componentDir, knownComponents);
445
+ allEdges.push(...sourceEdges);
446
+ const subComponentResults = extractSubComponents(componentDir, knownComponents);
447
+ for (const [name, subs] of subComponentResults) {
448
+ autoDetected.set(name, {
449
+ ...autoDetected.get(name),
450
+ subComponents: subs,
451
+ compositionPattern: subs.length > 0 ? "compound" : "simple"
452
+ });
453
+ }
454
+ }
455
+ const jsxEdges = extractJsxUsageEdges(segments, knownComponents);
456
+ allEdges.push(...jsxEdges);
457
+ const blockEdges = extractBlockEdges(blocks);
458
+ allEdges.push(...blockEdges);
459
+ const relationEdges = extractRelationEdges(segments);
460
+ allEdges.push(...relationEdges);
461
+ const requiredChildrenMap = inferRequiredChildren(segments, autoDetected);
462
+ for (const [name, children] of requiredChildrenMap) {
463
+ const existing = autoDetected.get(name) ?? {};
464
+ autoDetected.set(name, { ...existing, requiredChildren: children });
465
+ }
466
+ const patternsMap = generateCommonPatterns(segments, autoDetected);
467
+ for (const [name, patterns] of patternsMap) {
468
+ const existing = autoDetected.get(name) ?? {};
469
+ autoDetected.set(name, { ...existing, commonPatterns: patterns });
470
+ }
471
+ const mergedEdges = mergeAndDeduplicate(allEdges);
472
+ const nodes = Object.entries(segments).map(([name, segment]) => {
473
+ const detected = autoDetected.get(name);
474
+ return {
475
+ name,
476
+ category: segment.meta.category,
477
+ status: segment.meta.status ?? "stable",
478
+ compositionPattern: segment.ai?.compositionPattern ?? detected?.compositionPattern,
479
+ subComponents: segment.ai?.subComponents ?? detected?.subComponents
480
+ };
481
+ });
482
+ const blockIndex = /* @__PURE__ */ new Map();
483
+ for (const [blockName, block] of Object.entries(blocks)) {
484
+ for (const comp of block.components) {
485
+ const existing = blockIndex.get(comp);
486
+ if (existing) existing.push(blockName);
487
+ else blockIndex.set(comp, [blockName]);
488
+ }
489
+ }
490
+ const health = computeHealthFromData(nodes, mergedEdges, blockIndex);
491
+ for (const [name, segment] of Object.entries(segments)) {
492
+ const detected = autoDetected.get(name);
493
+ if (!detected) continue;
494
+ if (segment.ai?.subComponents && detected.subComponents) {
495
+ const declared = new Set(segment.ai.subComponents);
496
+ const found = new Set(detected.subComponents);
497
+ const missing = detected.subComponents.filter((s) => !declared.has(s));
498
+ const extra = segment.ai.subComponents.filter((s) => !found.has(s));
499
+ if (missing.length > 0) {
500
+ warnings.push(
501
+ `${name}: declares ${declared.size} subComponents but code has ${found.size}. Missing from declaration: ${missing.join(", ")}`
502
+ );
503
+ }
504
+ if (extra.length > 0) {
505
+ warnings.push(
506
+ `${name}: declares subComponents [${extra.join(", ")}] not found in Object.assign`
507
+ );
508
+ }
509
+ }
510
+ }
511
+ return {
512
+ graph: { nodes, edges: mergedEdges, health },
513
+ autoDetected,
514
+ warnings
515
+ };
516
+ }
517
+ function extractImportAndHookEdges(componentDir, knownComponents) {
518
+ const edges = [];
519
+ for (const componentName of knownComponents) {
520
+ const indexPath = findComponentIndex(componentDir, componentName);
521
+ if (!indexPath) continue;
522
+ let sourceText;
523
+ try {
524
+ sourceText = readFileSync(indexPath, "utf-8");
525
+ } catch {
526
+ continue;
527
+ }
528
+ const sourceFile = ts2.createSourceFile(
529
+ indexPath,
530
+ sourceText,
531
+ ts2.ScriptTarget.Latest,
532
+ true,
533
+ indexPath.endsWith(".tsx") ? ts2.ScriptKind.TSX : ts2.ScriptKind.TS
534
+ );
535
+ const visitNode = (node) => {
536
+ if (ts2.isImportDeclaration(node)) {
537
+ const moduleSpecifier = node.moduleSpecifier;
538
+ if (ts2.isStringLiteral(moduleSpecifier)) {
539
+ const importPath = moduleSpecifier.text;
540
+ if (importPath.startsWith(".") || importPath.startsWith("/")) {
541
+ const clause = node.importClause;
542
+ if (clause) {
543
+ if (clause.name && isPascalCase(clause.name.text) && knownComponents.has(clause.name.text)) {
544
+ edges.push({
545
+ source: componentName,
546
+ target: clause.name.text,
547
+ type: "imports",
548
+ weight: EDGE_TYPE_WEIGHTS["imports"],
549
+ provenance: `source:${componentName}/index.tsx`
550
+ });
551
+ }
552
+ if (clause.namedBindings && ts2.isNamedImports(clause.namedBindings)) {
553
+ for (const element of clause.namedBindings.elements) {
554
+ const name = element.name.text;
555
+ if (isPascalCase(name) && knownComponents.has(name) && name !== componentName) {
556
+ edges.push({
557
+ source: componentName,
558
+ target: name,
559
+ type: "imports",
560
+ weight: EDGE_TYPE_WEIGHTS["imports"],
561
+ provenance: `source:${componentName}/index.tsx`
562
+ });
563
+ }
564
+ }
565
+ }
566
+ }
567
+ }
568
+ }
569
+ }
570
+ if (ts2.isCallExpression(node) && ts2.isIdentifier(node.expression)) {
571
+ const callName = node.expression.text;
572
+ const hookMatch = callName.match(/^use([A-Z][a-zA-Z]*)$/);
573
+ if (hookMatch) {
574
+ const hookTarget = hookMatch[1];
575
+ if (knownComponents.has(hookTarget) && hookTarget !== componentName) {
576
+ edges.push({
577
+ source: componentName,
578
+ target: hookTarget,
579
+ type: "hook-depends",
580
+ weight: EDGE_TYPE_WEIGHTS["hook-depends"],
581
+ provenance: `source:${componentName}/index.tsx`
582
+ });
583
+ }
584
+ }
585
+ }
586
+ ts2.forEachChild(node, visitNode);
587
+ };
588
+ ts2.forEachChild(sourceFile, visitNode);
589
+ }
590
+ return edges;
591
+ }
592
+ function extractSubComponents(componentDir, knownComponents) {
593
+ const result = /* @__PURE__ */ new Map();
594
+ for (const componentName of knownComponents) {
595
+ const indexPath = findComponentIndex(componentDir, componentName);
596
+ if (!indexPath) continue;
597
+ let sourceText;
598
+ try {
599
+ sourceText = readFileSync(indexPath, "utf-8");
600
+ } catch {
601
+ continue;
602
+ }
603
+ if (!sourceText.includes("Object.assign")) continue;
604
+ const sourceFile = ts2.createSourceFile(
605
+ indexPath,
606
+ sourceText,
607
+ ts2.ScriptTarget.Latest,
608
+ true,
609
+ indexPath.endsWith(".tsx") ? ts2.ScriptKind.TSX : ts2.ScriptKind.TS
610
+ );
611
+ const subComponents = [];
612
+ const visitNode = (node) => {
613
+ if (ts2.isCallExpression(node) && ts2.isPropertyAccessExpression(node.expression) && ts2.isIdentifier(node.expression.expression) && node.expression.expression.text === "Object" && node.expression.name.text === "assign" && node.arguments.length >= 2) {
614
+ const propsArg = node.arguments[1];
615
+ if (ts2.isObjectLiteralExpression(propsArg)) {
616
+ for (const prop of propsArg.properties) {
617
+ if (ts2.isShorthandPropertyAssignment(prop)) {
618
+ subComponents.push(prop.name.text);
619
+ } else if (ts2.isPropertyAssignment(prop) && ts2.isIdentifier(prop.name)) {
620
+ subComponents.push(prop.name.text);
621
+ }
622
+ }
623
+ }
624
+ }
625
+ ts2.forEachChild(node, visitNode);
626
+ };
627
+ ts2.forEachChild(sourceFile, visitNode);
628
+ if (subComponents.length > 0) {
629
+ result.set(componentName, subComponents);
630
+ }
631
+ }
632
+ return result;
633
+ }
634
+ function extractJsxUsageEdges(segments, knownComponents) {
635
+ const edges = [];
636
+ const jsxTagRegex = /<([A-Z][a-zA-Z]*(?:\.[A-Z][a-zA-Z]*)?)/g;
637
+ for (const [name, segment] of Object.entries(segments)) {
638
+ const usedComponents = /* @__PURE__ */ new Set();
639
+ for (const variant of segment.variants) {
640
+ if (!variant.code) continue;
641
+ let match;
642
+ jsxTagRegex.lastIndex = 0;
643
+ while ((match = jsxTagRegex.exec(variant.code)) !== null) {
644
+ let tagName = match[1];
645
+ if (tagName.includes(".")) {
646
+ tagName = tagName.split(".")[0];
647
+ }
648
+ if (knownComponents.has(tagName) && tagName !== name) {
649
+ usedComponents.add(tagName);
650
+ }
651
+ }
652
+ }
653
+ for (const target of usedComponents) {
654
+ edges.push({
655
+ source: name,
656
+ target,
657
+ type: "renders",
658
+ weight: EDGE_TYPE_WEIGHTS["renders"],
659
+ provenance: `variant:${name}`
660
+ });
661
+ }
662
+ }
663
+ return edges;
664
+ }
665
+ function extractBlockEdges(blocks) {
666
+ const edges = [];
667
+ for (const [blockName, block] of Object.entries(blocks)) {
668
+ const components = block.components;
669
+ for (let i = 0; i < components.length; i++) {
670
+ for (let j = i + 1; j < components.length; j++) {
671
+ edges.push({
672
+ source: components[i],
673
+ target: components[j],
674
+ type: "composes",
675
+ weight: EDGE_TYPE_WEIGHTS["composes"],
676
+ provenance: `block:${blockName}`
677
+ });
678
+ }
679
+ }
680
+ }
681
+ return edges;
682
+ }
683
+ function extractRelationEdges(segments) {
684
+ const edges = [];
685
+ const relationToEdgeType = {
686
+ parent: "parent-of",
687
+ child: "parent-of",
688
+ // reversed: if A declares child B, edge is A parent-of B
689
+ composition: "composes",
690
+ alternative: "alternative-to",
691
+ sibling: "sibling-of"
692
+ };
693
+ for (const [name, segment] of Object.entries(segments)) {
694
+ if (!segment.relations) continue;
695
+ for (const rel of segment.relations) {
696
+ const edgeType = relationToEdgeType[rel.relationship];
697
+ if (!edgeType) continue;
698
+ let source;
699
+ let target;
700
+ if (rel.relationship === "parent") {
701
+ source = rel.component;
702
+ target = name;
703
+ } else {
704
+ source = name;
705
+ target = rel.component;
706
+ }
707
+ edges.push({
708
+ source,
709
+ target,
710
+ type: edgeType,
711
+ weight: EDGE_TYPE_WEIGHTS[edgeType],
712
+ note: rel.note,
713
+ provenance: "relation"
714
+ });
715
+ }
716
+ }
717
+ return edges;
718
+ }
719
+ function inferRequiredChildren(segments, autoDetected) {
720
+ const result = /* @__PURE__ */ new Map();
721
+ for (const [name, segment] of Object.entries(segments)) {
722
+ const detected = autoDetected.get(name);
723
+ const subs = detected?.subComponents ?? segment.ai?.subComponents;
724
+ if (!subs || subs.length === 0) continue;
725
+ const variantsWithCode = segment.variants.filter((v) => v.code);
726
+ if (variantsWithCode.length === 0) continue;
727
+ const required = [];
728
+ for (const sub of subs) {
729
+ const inAll = variantsWithCode.every((v) => {
730
+ const patterns = [
731
+ new RegExp(`<${name}\\.${sub}[\\s/>]`),
732
+ new RegExp(`<${sub}[\\s/>]`)
733
+ ];
734
+ return patterns.some((p) => p.test(v.code));
735
+ });
736
+ if (inAll) required.push(sub);
737
+ }
738
+ if (required.length > 0) {
739
+ result.set(name, required);
740
+ }
741
+ }
742
+ return result;
743
+ }
744
+ function generateCommonPatterns(segments, autoDetected) {
745
+ const result = /* @__PURE__ */ new Map();
746
+ for (const [name, segment] of Object.entries(segments)) {
747
+ const detected = autoDetected.get(name);
748
+ const subs = detected?.subComponents ?? segment.ai?.subComponents;
749
+ if (!subs || subs.length === 0) continue;
750
+ const firstVariant = segment.variants.find((v) => v.code);
751
+ if (!firstVariant?.code) continue;
752
+ const usedSubs = [];
753
+ for (const sub of subs) {
754
+ const patterns = [
755
+ new RegExp(`<${name}\\.${sub}`),
756
+ new RegExp(`<${sub}[\\s/>]`)
757
+ ];
758
+ if (patterns.some((p) => p.test(firstVariant.code))) {
759
+ usedSubs.push(sub);
760
+ }
761
+ }
762
+ if (usedSubs.length > 0) {
763
+ const pattern = `<${name}>
764
+ ${usedSubs.map((s) => ` <${name}.${s}>...</${name}.${s}>`).join("\n")}
765
+ </${name}>`;
766
+ result.set(name, [pattern]);
767
+ }
768
+ }
769
+ return result;
770
+ }
771
+ function mergeAndDeduplicate(edges) {
772
+ const edgeMap = /* @__PURE__ */ new Map();
773
+ for (const edge of edges) {
774
+ const key = `${edge.source}\u2192${edge.target}:${edge.type}`;
775
+ const existing = edgeMap.get(key);
776
+ if (!existing || edge.weight > existing.weight) {
777
+ edgeMap.set(key, edge);
778
+ }
779
+ }
780
+ return [...edgeMap.values()];
781
+ }
782
+ function isPascalCase(name) {
783
+ return /^[A-Z][a-zA-Z0-9]*$/.test(name);
784
+ }
785
+ function findComponentIndex(componentDir, componentName) {
786
+ const candidates = [
787
+ join2(componentDir, componentName, "index.tsx"),
788
+ join2(componentDir, componentName, "index.ts"),
789
+ join2(componentDir, componentName, `${componentName}.tsx`),
790
+ join2(componentDir, componentName, `${componentName}.ts`)
791
+ ];
792
+ for (const candidate of candidates) {
793
+ if (existsSync2(candidate)) {
794
+ return candidate;
795
+ }
796
+ }
797
+ try {
798
+ const entries = readdirSync(componentDir, { withFileTypes: true });
799
+ for (const entry of entries) {
800
+ if (entry.isDirectory() && entry.name === componentName) {
801
+ const subCandidates = [
802
+ join2(componentDir, entry.name, "index.tsx"),
803
+ join2(componentDir, entry.name, "index.ts")
804
+ ];
805
+ for (const sc of subCandidates) {
806
+ if (existsSync2(sc)) return sc;
807
+ }
808
+ }
809
+ }
810
+ } catch {
811
+ }
812
+ return null;
813
+ }
814
+
432
815
  // src/build.ts
816
+ import { serializeGraph } from "@fragments-sdk/context/graph";
433
817
  function normalizeParsedProps(parsedProps) {
434
818
  return Object.fromEntries(
435
819
  Object.entries(parsedProps).map(([name, prop]) => [
@@ -625,23 +1009,55 @@ async function buildSegments(config, configDir) {
625
1009
  } catch {
626
1010
  }
627
1011
  let packageName;
628
- const pkgJsonPath = resolve2(configDir, "package.json");
629
- if (existsSync2(pkgJsonPath)) {
1012
+ const pkgJsonPath = resolve3(configDir, "package.json");
1013
+ if (existsSync3(pkgJsonPath)) {
630
1014
  try {
631
1015
  const pkg = JSON.parse(await readFile(pkgJsonPath, "utf-8"));
632
1016
  if (pkg.name) packageName = pkg.name;
633
1017
  } catch {
634
1018
  }
635
1019
  }
1020
+ const componentDir = resolve3(configDir, "src", "components");
1021
+ let graphData;
1022
+ try {
1023
+ const graphResult = await buildComponentGraph(segments, blocks, componentDir);
1024
+ for (const [name, segment] of Object.entries(segments)) {
1025
+ const detected = graphResult.autoDetected.get(name);
1026
+ if (!detected) continue;
1027
+ if (!segment.ai) segment.ai = {};
1028
+ if (!segment.ai.subComponents && detected.subComponents) {
1029
+ segment.ai.subComponents = detected.subComponents;
1030
+ }
1031
+ if (!segment.ai.compositionPattern && detected.compositionPattern) {
1032
+ segment.ai.compositionPattern = detected.compositionPattern;
1033
+ }
1034
+ if (!segment.ai.commonPatterns && detected.commonPatterns) {
1035
+ segment.ai.commonPatterns = detected.commonPatterns;
1036
+ }
1037
+ if (!segment.ai.requiredChildren && detected.requiredChildren) {
1038
+ segment.ai.requiredChildren = detected.requiredChildren;
1039
+ }
1040
+ }
1041
+ for (const w of graphResult.warnings) {
1042
+ warnings.push({ file: "graph", warning: w });
1043
+ }
1044
+ graphData = serializeGraph(graphResult.graph);
1045
+ } catch (error) {
1046
+ warnings.push({
1047
+ file: "graph",
1048
+ warning: `Graph extraction failed: ${error instanceof Error ? error.message : String(error)}`
1049
+ });
1050
+ }
636
1051
  const output = {
637
1052
  version: "1.0.0",
638
1053
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
639
1054
  ...packageName && { packageName },
640
1055
  segments,
641
1056
  ...Object.keys(blocks).length > 0 && { blocks },
642
- ...tokens && { tokens }
1057
+ ...tokens && { tokens },
1058
+ ...graphData && { graph: graphData }
643
1059
  };
644
- const outputPath = resolve2(configDir, config.outFile ?? BRAND.outFile);
1060
+ const outputPath = resolve3(configDir, config.outFile ?? BRAND.outFile);
645
1061
  await writeFile(outputPath, JSON.stringify(output));
646
1062
  return {
647
1063
  success: errors.length === 0,
@@ -652,8 +1068,8 @@ async function buildSegments(config, configDir) {
652
1068
  };
653
1069
  }
654
1070
  async function buildFragmentsDir(config, configDir) {
655
- const fragmentsDir = join2(configDir, BRAND.dataDir);
656
- const componentsDir = join2(fragmentsDir, BRAND.componentsDir);
1071
+ const fragmentsDir = join3(configDir, BRAND.dataDir);
1072
+ const componentsDir = join3(fragmentsDir, BRAND.componentsDir);
657
1073
  await mkdir(fragmentsDir, { recursive: true });
658
1074
  await mkdir(componentsDir, { recursive: true });
659
1075
  const registryResult = await generateRegistry({
@@ -665,9 +1081,9 @@ async function buildFragmentsDir(config, configDir) {
665
1081
  });
666
1082
  const errors = [...registryResult.errors];
667
1083
  const warnings = [...registryResult.warnings];
668
- const indexPath = join2(fragmentsDir, "index.json");
1084
+ const indexPath = join3(fragmentsDir, "index.json");
669
1085
  await writeFile(indexPath, JSON.stringify(registryResult.index, null, 2));
670
- const registryPath = join2(fragmentsDir, BRAND.registryFile);
1086
+ const registryPath = join3(fragmentsDir, BRAND.registryFile);
671
1087
  await writeFile(registryPath, JSON.stringify(registryResult.registry, null, 2));
672
1088
  const contextResult = generateContextMd(registryResult.registry, {
673
1089
  format: "markdown",
@@ -679,7 +1095,7 @@ async function buildFragmentsDir(config, configDir) {
679
1095
  code: false
680
1096
  }
681
1097
  });
682
- const contextPath = join2(fragmentsDir, BRAND.contextFile);
1098
+ const contextPath = join3(fragmentsDir, BRAND.contextFile);
683
1099
  await writeFile(contextPath, contextResult.content);
684
1100
  return {
685
1101
  success: errors.length === 0,
@@ -1032,9 +1448,9 @@ ${BRAND.name} Diff
1032
1448
  }
1033
1449
 
1034
1450
  // src/analyze.ts
1035
- import { existsSync as existsSync3 } from "fs";
1451
+ import { existsSync as existsSync4 } from "fs";
1036
1452
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
1037
- import { join as join3, dirname as dirname2 } from "path";
1453
+ import { join as join4, dirname as dirname2 } from "path";
1038
1454
  import pc3 from "picocolors";
1039
1455
  async function runAnalyzeCommand(config, configDir, options = {}) {
1040
1456
  const format = options.format ?? "html";
@@ -1042,8 +1458,8 @@ async function runAnalyzeCommand(config, configDir, options = {}) {
1042
1458
  console.log(pc3.cyan(`
1043
1459
  ${BRAND.name} Analyzer
1044
1460
  `));
1045
- const segmentsPath = join3(configDir, config.outFile ?? "segments.json");
1046
- if (!existsSync3(segmentsPath)) {
1461
+ const segmentsPath = join4(configDir, config.outFile ?? "segments.json");
1462
+ if (!existsSync4(segmentsPath)) {
1047
1463
  console.log(pc3.red(`\u2717 No segments.json found. Run \`${BRAND.cliCommand} build\` first.
1048
1464
  `));
1049
1465
  return {
@@ -1138,7 +1554,7 @@ function colorizeScore(score) {
1138
1554
  }
1139
1555
  function getDefaultOutputPath(format, configDir) {
1140
1556
  const filename = format === "html" ? "segments-report.html" : "segments-report.json";
1141
- return join3(configDir, filename);
1557
+ return join4(configDir, filename);
1142
1558
  }
1143
1559
  async function openInBrowser(path) {
1144
1560
  const { platform } = await import("os");
@@ -1206,4 +1622,4 @@ export {
1206
1622
  runDiffCommand,
1207
1623
  runAnalyzeCommand
1208
1624
  };
1209
- //# sourceMappingURL=chunk-D35RGPAG.js.map
1625
+ //# sourceMappingURL=chunk-7OPWMLOE.js.map