@fragments-sdk/cli 0.11.1 → 0.12.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/dist/ai-client-I6MDWNYA.js +21 -0
- package/dist/bin.js +275 -368
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-PW7QTQA6.js → chunk-4OC7FTJB.js} +2 -2
- package/dist/{chunk-HRFUSSZI.js → chunk-AM4MRTMN.js} +2 -2
- package/dist/{chunk-5G3VZH43.js → chunk-GVDSFQ4E.js} +281 -351
- package/dist/chunk-GVDSFQ4E.js.map +1 -0
- package/dist/chunk-JJ2VRTBU.js +626 -0
- package/dist/chunk-JJ2VRTBU.js.map +1 -0
- package/dist/{chunk-D5PYOXEI.js → chunk-LVWFOLUZ.js} +148 -13
- package/dist/{chunk-D5PYOXEI.js.map → chunk-LVWFOLUZ.js.map} +1 -1
- package/dist/{chunk-WXSR2II7.js → chunk-OQKMEFOS.js} +58 -6
- package/dist/chunk-OQKMEFOS.js.map +1 -0
- package/dist/chunk-SXTKFDCR.js +104 -0
- package/dist/chunk-SXTKFDCR.js.map +1 -0
- package/dist/chunk-T5OMVL7E.js +443 -0
- package/dist/chunk-T5OMVL7E.js.map +1 -0
- package/dist/{chunk-ZM4ZQZWZ.js → chunk-TPWGL2XS.js} +39 -37
- package/dist/chunk-TPWGL2XS.js.map +1 -0
- package/dist/{chunk-OQO55NKV.js → chunk-WFS63PCW.js} +85 -11
- package/dist/chunk-WFS63PCW.js.map +1 -0
- package/dist/core/index.js +9 -1
- package/dist/{discovery-NEOY4MPN.js → discovery-ZJQSXF56.js} +3 -3
- package/dist/{generate-FBHSXR3D.js → generate-RJFS2JWA.js} +4 -4
- package/dist/index.js +7 -6
- package/dist/index.js.map +1 -1
- package/dist/init-ZSX3NRCZ.js +636 -0
- package/dist/init-ZSX3NRCZ.js.map +1 -0
- package/dist/mcp-bin.js +2 -2
- package/dist/{scan-CJF2DOQW.js → scan-3PMCJ4RB.js} +6 -6
- package/dist/scan-generate-SYU4PYZD.js +1115 -0
- package/dist/scan-generate-SYU4PYZD.js.map +1 -0
- package/dist/{service-TQYWY65E.js → service-VMGNJZ42.js} +3 -3
- package/dist/{snapshot-SV2JOFZH.js → snapshot-XOISO2IS.js} +2 -2
- package/dist/{static-viewer-NUBFPKWH.js → static-viewer-5GXH2MGE.js} +3 -3
- package/dist/static-viewer-5GXH2MGE.js.map +1 -0
- package/dist/{test-Z5LVO724.js → test-SI4NSHQX.js} +4 -4
- package/dist/{tokens-CE46OTMD.js → tokens-T6SIVUT5.js} +5 -5
- package/dist/{viewer-DLLJIMCK.js → viewer-7ZEAFBVN.js} +13 -13
- package/package.json +4 -4
- package/src/ai-client.ts +156 -0
- package/src/bin.ts +44 -2
- package/src/build.ts +95 -33
- package/src/commands/__tests__/drift-sync.test.ts +252 -0
- package/src/commands/__tests__/scan-generate.test.ts +497 -45
- package/src/commands/enhance.ts +11 -35
- package/src/commands/init.ts +288 -260
- package/src/commands/scan-generate.ts +740 -139
- package/src/commands/scan.ts +37 -32
- package/src/commands/setup.ts +143 -52
- package/src/commands/sync.ts +357 -0
- package/src/commands/validate.ts +43 -1
- package/src/core/component-extractor.test.ts +282 -0
- package/src/core/component-extractor.ts +1030 -0
- package/src/core/discovery.ts +93 -7
- package/src/service/enhance/props-extractor.ts +235 -13
- package/src/validators.ts +236 -0
- package/dist/chunk-5G3VZH43.js.map +0 -1
- package/dist/chunk-OQO55NKV.js.map +0 -1
- package/dist/chunk-WXSR2II7.js.map +0 -1
- package/dist/chunk-ZM4ZQZWZ.js.map +0 -1
- package/dist/init-UFGK5TCN.js +0 -867
- package/dist/init-UFGK5TCN.js.map +0 -1
- package/dist/scan-generate-SJAN5MVI.js +0 -691
- package/dist/scan-generate-SJAN5MVI.js.map +0 -1
- package/src/ai.ts +0 -266
- package/src/commands/init-framework.ts +0 -414
- package/src/mcp/bin.ts +0 -36
- package/src/migrate/bin.ts +0 -114
- package/src/theme/index.ts +0 -77
- package/src/viewer/bin.ts +0 -86
- package/src/viewer/cli/health.ts +0 -256
- package/src/viewer/cli/index.ts +0 -33
- package/src/viewer/cli/scan.ts +0 -124
- package/src/viewer/cli/utils.ts +0 -174
- /package/dist/{discovery-NEOY4MPN.js.map → ai-client-I6MDWNYA.js.map} +0 -0
- /package/dist/{chunk-PW7QTQA6.js.map → chunk-4OC7FTJB.js.map} +0 -0
- /package/dist/{chunk-HRFUSSZI.js.map → chunk-AM4MRTMN.js.map} +0 -0
- /package/dist/{scan-CJF2DOQW.js.map → discovery-ZJQSXF56.js.map} +0 -0
- /package/dist/{generate-FBHSXR3D.js.map → generate-RJFS2JWA.js.map} +0 -0
- /package/dist/{service-TQYWY65E.js.map → scan-3PMCJ4RB.js.map} +0 -0
- /package/dist/{static-viewer-NUBFPKWH.js.map → service-VMGNJZ42.js.map} +0 -0
- /package/dist/{snapshot-SV2JOFZH.js.map → snapshot-XOISO2IS.js.map} +0 -0
- /package/dist/{test-Z5LVO724.js.map → test-SI4NSHQX.js.map} +0 -0
- /package/dist/{tokens-CE46OTMD.js.map → tokens-T6SIVUT5.js.map} +0 -0
- /package/dist/{viewer-DLLJIMCK.js.map → viewer-7ZEAFBVN.js.map} +0 -0
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
createComponentExtractor
|
|
4
|
+
} from "./chunk-JJ2VRTBU.js";
|
|
2
5
|
import {
|
|
3
6
|
generateContextMd,
|
|
4
7
|
generateRegistry,
|
|
5
8
|
loadFragmentFile,
|
|
6
9
|
parseFragmentFile
|
|
7
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-AM4MRTMN.js";
|
|
8
11
|
import {
|
|
9
12
|
discoverBlockFiles,
|
|
10
13
|
discoverComponentFiles,
|
|
11
14
|
discoverFragmentFiles,
|
|
12
15
|
discoverTokenFiles,
|
|
13
16
|
extractComponentName
|
|
14
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-OQKMEFOS.js";
|
|
15
18
|
import {
|
|
16
19
|
BrowserPool,
|
|
17
20
|
CaptureEngine,
|
|
@@ -21,7 +24,7 @@ import {
|
|
|
21
24
|
formatMs,
|
|
22
25
|
generateHtmlReport,
|
|
23
26
|
getGrade
|
|
24
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-LVWFOLUZ.js";
|
|
25
28
|
import {
|
|
26
29
|
BRAND,
|
|
27
30
|
DEFAULTS,
|
|
@@ -30,7 +33,7 @@ import {
|
|
|
30
33
|
fragmentDefinitionSchema,
|
|
31
34
|
parseTokenFile,
|
|
32
35
|
resolvePerformanceConfig
|
|
33
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-WFS63PCW.js";
|
|
34
37
|
|
|
35
38
|
// src/service/snippet-validation.ts
|
|
36
39
|
import ts from "typescript";
|
|
@@ -481,7 +484,52 @@ async function validateSnippetPolicy(config, configDir, options = {}) {
|
|
|
481
484
|
return toValidationResult(policy, issues);
|
|
482
485
|
}
|
|
483
486
|
|
|
487
|
+
// src/core/auto-props.ts
|
|
488
|
+
import { existsSync as existsSync2, statSync } from "fs";
|
|
489
|
+
import { dirname, extname, join as join2, resolve } from "path";
|
|
490
|
+
import ts2 from "typescript";
|
|
491
|
+
function isFile(filePath) {
|
|
492
|
+
if (!existsSync2(filePath)) return false;
|
|
493
|
+
try {
|
|
494
|
+
return statSync(filePath).isFile();
|
|
495
|
+
} catch {
|
|
496
|
+
return false;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
function resolveModulePath(basePath) {
|
|
500
|
+
const candidates = [];
|
|
501
|
+
const extension = extname(basePath);
|
|
502
|
+
if (extension) {
|
|
503
|
+
candidates.push(basePath);
|
|
504
|
+
} else {
|
|
505
|
+
candidates.push(
|
|
506
|
+
`${basePath}.tsx`,
|
|
507
|
+
`${basePath}.ts`,
|
|
508
|
+
`${basePath}.jsx`,
|
|
509
|
+
`${basePath}.js`,
|
|
510
|
+
join2(basePath, "index.tsx"),
|
|
511
|
+
join2(basePath, "index.ts"),
|
|
512
|
+
join2(basePath, "index.jsx"),
|
|
513
|
+
join2(basePath, "index.js")
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
for (const candidate of candidates) {
|
|
517
|
+
if (isFile(candidate)) {
|
|
518
|
+
return resolve(candidate);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return null;
|
|
522
|
+
}
|
|
523
|
+
function resolveComponentSourcePath(fragmentFileAbsolutePath, componentImportPath) {
|
|
524
|
+
if (!componentImportPath) return null;
|
|
525
|
+
if (!componentImportPath.startsWith(".")) return null;
|
|
526
|
+
const fragmentDir = dirname(fragmentFileAbsolutePath);
|
|
527
|
+
const basePath = resolve(fragmentDir, componentImportPath);
|
|
528
|
+
return resolveModulePath(basePath);
|
|
529
|
+
}
|
|
530
|
+
|
|
484
531
|
// src/validators.ts
|
|
532
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
485
533
|
async function validateSchema(config, configDir) {
|
|
486
534
|
const files = await discoverFragmentFiles(config, configDir);
|
|
487
535
|
const errors = [];
|
|
@@ -593,15 +641,162 @@ async function validateSnippets(config, configDir, options = {}) {
|
|
|
593
641
|
warnings: snippetResult.warnings
|
|
594
642
|
};
|
|
595
643
|
}
|
|
644
|
+
async function validateDrift(config, configDir, options = {}) {
|
|
645
|
+
const fragmentFiles = await discoverFragmentFiles(config, configDir);
|
|
646
|
+
const errors = [];
|
|
647
|
+
const warnings = [];
|
|
648
|
+
const reports = [];
|
|
649
|
+
if (fragmentFiles.length === 0) {
|
|
650
|
+
return { valid: true, errors, warnings, reports };
|
|
651
|
+
}
|
|
652
|
+
const extractor = createComponentExtractor(options.tsconfig);
|
|
653
|
+
try {
|
|
654
|
+
for (const file of fragmentFiles) {
|
|
655
|
+
try {
|
|
656
|
+
const fragment = await loadFragmentFile(file.absolutePath);
|
|
657
|
+
if (!fragment?.meta?.name) continue;
|
|
658
|
+
const fileContent = await readFile2(file.absolutePath, "utf-8");
|
|
659
|
+
const parsed = parseFragmentFile(fileContent, file.absolutePath);
|
|
660
|
+
if (!parsed.componentImport) continue;
|
|
661
|
+
const sourcePath = resolveComponentSourcePath(file.absolutePath, parsed.componentImport);
|
|
662
|
+
if (!sourcePath) continue;
|
|
663
|
+
const meta = extractor.extract(sourcePath, fragment.meta.name);
|
|
664
|
+
if (!meta) continue;
|
|
665
|
+
const drifts = diffProps(fragment.props, meta.props);
|
|
666
|
+
let compositionDrift = null;
|
|
667
|
+
const fragmentAi = fragment.ai;
|
|
668
|
+
if (meta.composition && !fragmentAi?.compositionPattern) {
|
|
669
|
+
compositionDrift = `Source has "${meta.composition.pattern}" composition but fragment has no ai.compositionPattern`;
|
|
670
|
+
} else if (!meta.composition && fragmentAi?.compositionPattern) {
|
|
671
|
+
compositionDrift = `Fragment declares "${fragmentAi.compositionPattern}" but source has no compound pattern`;
|
|
672
|
+
} else if (meta.composition && fragmentAi?.compositionPattern && meta.composition.pattern !== fragmentAi.compositionPattern) {
|
|
673
|
+
compositionDrift = `Composition pattern changed: fragment="${fragmentAi.compositionPattern}" source="${meta.composition.pattern}"`;
|
|
674
|
+
}
|
|
675
|
+
if (drifts.length > 0 || compositionDrift) {
|
|
676
|
+
const report2 = {
|
|
677
|
+
component: fragment.meta.name,
|
|
678
|
+
file: file.relativePath,
|
|
679
|
+
drifts,
|
|
680
|
+
compositionDrift
|
|
681
|
+
};
|
|
682
|
+
reports.push(report2);
|
|
683
|
+
for (const drift of drifts) {
|
|
684
|
+
if (drift.kind === "removed") {
|
|
685
|
+
errors.push({
|
|
686
|
+
file: file.relativePath,
|
|
687
|
+
message: `Prop "${drift.prop}" documented in fragment but removed from source`,
|
|
688
|
+
details: `Fragment: ${drift.fragment} | Source: (not found)`
|
|
689
|
+
});
|
|
690
|
+
} else if (drift.kind === "added") {
|
|
691
|
+
warnings.push({
|
|
692
|
+
file: file.relativePath,
|
|
693
|
+
message: `Prop "${drift.prop}" exists in source but not documented in fragment`
|
|
694
|
+
});
|
|
695
|
+
} else {
|
|
696
|
+
warnings.push({
|
|
697
|
+
file: file.relativePath,
|
|
698
|
+
message: `Prop "${drift.prop}" ${drift.kind.replace("_", " ")}: fragment=${drift.fragment} source=${drift.source}`
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
if (compositionDrift) {
|
|
703
|
+
warnings.push({
|
|
704
|
+
file: file.relativePath,
|
|
705
|
+
message: compositionDrift
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
} catch {
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
} finally {
|
|
713
|
+
extractor.dispose();
|
|
714
|
+
}
|
|
715
|
+
return {
|
|
716
|
+
valid: errors.length === 0,
|
|
717
|
+
errors,
|
|
718
|
+
warnings,
|
|
719
|
+
reports
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
function diffProps(fragmentProps, sourceProps) {
|
|
723
|
+
const drifts = [];
|
|
724
|
+
const localSourceProps = Object.fromEntries(
|
|
725
|
+
Object.entries(sourceProps).filter(([_, p]) => p.source === "local")
|
|
726
|
+
);
|
|
727
|
+
for (const [name, sourceProp] of Object.entries(localSourceProps)) {
|
|
728
|
+
if (!(name in fragmentProps)) {
|
|
729
|
+
drifts.push({
|
|
730
|
+
prop: name,
|
|
731
|
+
kind: "added",
|
|
732
|
+
source: sourceProp.type,
|
|
733
|
+
fragment: "(not documented)"
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
for (const [name, fragProp] of Object.entries(fragmentProps)) {
|
|
738
|
+
if (!(name in localSourceProps)) {
|
|
739
|
+
drifts.push({
|
|
740
|
+
prop: name,
|
|
741
|
+
kind: "removed",
|
|
742
|
+
source: "(not found)",
|
|
743
|
+
fragment: String(fragProp.type ?? "unknown")
|
|
744
|
+
});
|
|
745
|
+
continue;
|
|
746
|
+
}
|
|
747
|
+
const sourceProp = localSourceProps[name];
|
|
748
|
+
if (fragProp.type && fragProp.type !== sourceProp.typeKind) {
|
|
749
|
+
drifts.push({
|
|
750
|
+
prop: name,
|
|
751
|
+
kind: "type_changed",
|
|
752
|
+
source: sourceProp.typeKind,
|
|
753
|
+
fragment: String(fragProp.type)
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
if (fragProp.required !== void 0 && fragProp.required !== sourceProp.required) {
|
|
757
|
+
drifts.push({
|
|
758
|
+
prop: name,
|
|
759
|
+
kind: "required_changed",
|
|
760
|
+
source: String(sourceProp.required),
|
|
761
|
+
fragment: String(fragProp.required)
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
if (fragProp.values && sourceProp.values) {
|
|
765
|
+
const fragSet = new Set(fragProp.values);
|
|
766
|
+
const srcSet = new Set(sourceProp.values);
|
|
767
|
+
const added = sourceProp.values.filter((v) => !fragSet.has(v));
|
|
768
|
+
const removed = Array.from(fragProp.values).filter((v) => !srcSet.has(v));
|
|
769
|
+
if (added.length > 0 || removed.length > 0) {
|
|
770
|
+
drifts.push({
|
|
771
|
+
prop: name,
|
|
772
|
+
kind: "values_changed",
|
|
773
|
+
source: sourceProp.values.join(", "),
|
|
774
|
+
fragment: Array.from(fragProp.values).join(", ")
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
if (fragProp.default !== void 0 && sourceProp.default !== void 0) {
|
|
779
|
+
if (String(fragProp.default) !== sourceProp.default) {
|
|
780
|
+
drifts.push({
|
|
781
|
+
prop: name,
|
|
782
|
+
kind: "default_changed",
|
|
783
|
+
source: sourceProp.default,
|
|
784
|
+
fragment: String(fragProp.default)
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
return drifts;
|
|
790
|
+
}
|
|
596
791
|
|
|
597
792
|
// src/build.ts
|
|
598
|
-
import { readFile as
|
|
793
|
+
import { readFile as readFile3, writeFile, mkdir } from "fs/promises";
|
|
599
794
|
import { resolve as resolve5, join as join5 } from "path";
|
|
600
795
|
import { existsSync as existsSync6 } from "fs";
|
|
601
796
|
|
|
602
797
|
// src/core/token-resolver.ts
|
|
603
|
-
import { resolve, dirname, basename } from "path";
|
|
604
|
-
import { existsSync as
|
|
798
|
+
import { resolve as resolve2, dirname as dirname2, basename } from "path";
|
|
799
|
+
import { existsSync as existsSync3, readdirSync } from "fs";
|
|
605
800
|
function roundRgbValues(value) {
|
|
606
801
|
return value.replace(
|
|
607
802
|
/rgb\(([^)]+)\)/g,
|
|
@@ -647,7 +842,7 @@ async function resolveTokensWithSass(unresolvedTokens, tokensDir) {
|
|
|
647
842
|
:root { @include vars.fui-css-variables; }
|
|
648
843
|
`;
|
|
649
844
|
const compiled = sass.compileString(scssSource, {
|
|
650
|
-
loadPaths: [tokensDir,
|
|
845
|
+
loadPaths: [tokensDir, dirname2(tokensDir)],
|
|
651
846
|
style: "expanded",
|
|
652
847
|
// Suppress sass deprecation warnings during build
|
|
653
848
|
logger: { warn() {
|
|
@@ -673,15 +868,15 @@ async function resolveTokensWithSass(unresolvedTokens, tokensDir) {
|
|
|
673
868
|
function findVariablesFile(tokensDir) {
|
|
674
869
|
const candidates = ["_variables.scss", "variables.scss"];
|
|
675
870
|
for (const name of candidates) {
|
|
676
|
-
const path =
|
|
677
|
-
if (
|
|
871
|
+
const path = resolve2(tokensDir, name);
|
|
872
|
+
if (existsSync3(path)) {
|
|
678
873
|
return path;
|
|
679
874
|
}
|
|
680
875
|
}
|
|
681
876
|
try {
|
|
682
877
|
const files = readdirSync(tokensDir).filter((f) => f.endsWith(".scss"));
|
|
683
878
|
for (const file of files) {
|
|
684
|
-
const path =
|
|
879
|
+
const path = resolve2(tokensDir, file);
|
|
685
880
|
if (file.includes("variables") || file.includes("tokens")) {
|
|
686
881
|
return path;
|
|
687
882
|
}
|
|
@@ -691,312 +886,6 @@ function findVariablesFile(tokensDir) {
|
|
|
691
886
|
return null;
|
|
692
887
|
}
|
|
693
888
|
|
|
694
|
-
// src/core/auto-props.ts
|
|
695
|
-
import { existsSync as existsSync3, statSync } from "fs";
|
|
696
|
-
import { dirname as dirname2, extname, join as join2, resolve as resolve2 } from "path";
|
|
697
|
-
import ts2 from "typescript";
|
|
698
|
-
function toPosixPath(filePath) {
|
|
699
|
-
return filePath.replace(/\\/g, "/");
|
|
700
|
-
}
|
|
701
|
-
function isFile(filePath) {
|
|
702
|
-
if (!existsSync3(filePath)) return false;
|
|
703
|
-
try {
|
|
704
|
-
return statSync(filePath).isFile();
|
|
705
|
-
} catch {
|
|
706
|
-
return false;
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
function resolveModulePath(basePath) {
|
|
710
|
-
const candidates = [];
|
|
711
|
-
const extension = extname(basePath);
|
|
712
|
-
if (extension) {
|
|
713
|
-
candidates.push(basePath);
|
|
714
|
-
} else {
|
|
715
|
-
candidates.push(
|
|
716
|
-
`${basePath}.tsx`,
|
|
717
|
-
`${basePath}.ts`,
|
|
718
|
-
`${basePath}.jsx`,
|
|
719
|
-
`${basePath}.js`,
|
|
720
|
-
join2(basePath, "index.tsx"),
|
|
721
|
-
join2(basePath, "index.ts"),
|
|
722
|
-
join2(basePath, "index.jsx"),
|
|
723
|
-
join2(basePath, "index.js")
|
|
724
|
-
);
|
|
725
|
-
}
|
|
726
|
-
for (const candidate of candidates) {
|
|
727
|
-
if (isFile(candidate)) {
|
|
728
|
-
return resolve2(candidate);
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
return null;
|
|
732
|
-
}
|
|
733
|
-
function resolveComponentSourcePath(fragmentFileAbsolutePath, componentImportPath) {
|
|
734
|
-
if (!componentImportPath) return null;
|
|
735
|
-
if (!componentImportPath.startsWith(".")) return null;
|
|
736
|
-
const fragmentDir = dirname2(fragmentFileAbsolutePath);
|
|
737
|
-
const basePath = resolve2(fragmentDir, componentImportPath);
|
|
738
|
-
return resolveModulePath(basePath);
|
|
739
|
-
}
|
|
740
|
-
function collectTopLevelDeclarations(sourceFile) {
|
|
741
|
-
const typeDeclarations = /* @__PURE__ */ new Map();
|
|
742
|
-
const functionDeclarations = /* @__PURE__ */ new Map();
|
|
743
|
-
const variableDeclarations = /* @__PURE__ */ new Map();
|
|
744
|
-
for (const node of sourceFile.statements) {
|
|
745
|
-
if (ts2.isInterfaceDeclaration(node)) {
|
|
746
|
-
typeDeclarations.set(node.name.text, node);
|
|
747
|
-
continue;
|
|
748
|
-
}
|
|
749
|
-
if (ts2.isTypeAliasDeclaration(node)) {
|
|
750
|
-
typeDeclarations.set(node.name.text, node);
|
|
751
|
-
continue;
|
|
752
|
-
}
|
|
753
|
-
if (ts2.isFunctionDeclaration(node) && node.name) {
|
|
754
|
-
functionDeclarations.set(node.name.text, node);
|
|
755
|
-
continue;
|
|
756
|
-
}
|
|
757
|
-
if (ts2.isVariableStatement(node)) {
|
|
758
|
-
for (const declaration of node.declarationList.declarations) {
|
|
759
|
-
if (ts2.isIdentifier(declaration.name)) {
|
|
760
|
-
variableDeclarations.set(declaration.name.text, declaration);
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
return { typeDeclarations, functionDeclarations, variableDeclarations };
|
|
766
|
-
}
|
|
767
|
-
function readDefaultValue(expression) {
|
|
768
|
-
if (ts2.isStringLiteral(expression) || ts2.isNoSubstitutionTemplateLiteral(expression)) {
|
|
769
|
-
return expression.text;
|
|
770
|
-
}
|
|
771
|
-
if (ts2.isNumericLiteral(expression)) {
|
|
772
|
-
return Number(expression.text);
|
|
773
|
-
}
|
|
774
|
-
if (expression.kind === ts2.SyntaxKind.TrueKeyword) return true;
|
|
775
|
-
if (expression.kind === ts2.SyntaxKind.FalseKeyword) return false;
|
|
776
|
-
if (expression.kind === ts2.SyntaxKind.NullKeyword) return null;
|
|
777
|
-
if (ts2.isPrefixUnaryExpression(expression) && expression.operator === ts2.SyntaxKind.MinusToken && ts2.isNumericLiteral(expression.operand)) {
|
|
778
|
-
return -Number(expression.operand.text);
|
|
779
|
-
}
|
|
780
|
-
return void 0;
|
|
781
|
-
}
|
|
782
|
-
function extractDefaultValues(componentNode) {
|
|
783
|
-
const defaults = {};
|
|
784
|
-
if (!componentNode?.parameters?.length) return defaults;
|
|
785
|
-
const firstParam = componentNode.parameters[0];
|
|
786
|
-
if (!ts2.isObjectBindingPattern(firstParam.name)) return defaults;
|
|
787
|
-
for (const element of firstParam.name.elements) {
|
|
788
|
-
let propName = null;
|
|
789
|
-
if (element.propertyName) {
|
|
790
|
-
if (ts2.isIdentifier(element.propertyName) || ts2.isStringLiteral(element.propertyName)) {
|
|
791
|
-
propName = element.propertyName.text;
|
|
792
|
-
}
|
|
793
|
-
} else if (ts2.isIdentifier(element.name)) {
|
|
794
|
-
propName = element.name.text;
|
|
795
|
-
}
|
|
796
|
-
if (!propName || !element.initializer) continue;
|
|
797
|
-
const value = readDefaultValue(element.initializer);
|
|
798
|
-
if (value !== void 0) {
|
|
799
|
-
defaults[propName] = value;
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
return defaults;
|
|
803
|
-
}
|
|
804
|
-
function isNullishType(type) {
|
|
805
|
-
return (type.flags & ts2.TypeFlags.Null) !== 0 || (type.flags & ts2.TypeFlags.Undefined) !== 0 || (type.flags & ts2.TypeFlags.Void) !== 0;
|
|
806
|
-
}
|
|
807
|
-
function isBooleanLikeType(type) {
|
|
808
|
-
return (type.flags & ts2.TypeFlags.BooleanLike) !== 0 || type.flags === ts2.TypeFlags.BooleanLiteral;
|
|
809
|
-
}
|
|
810
|
-
function inferPropType(type, checker) {
|
|
811
|
-
const typeText = checker.typeToString(type, void 0, ts2.TypeFormatFlags.NoTruncation);
|
|
812
|
-
if (typeText.includes("ReactNode")) {
|
|
813
|
-
return { type: "node" };
|
|
814
|
-
}
|
|
815
|
-
if (typeText.includes("ReactElement") || typeText.includes("JSX.Element")) {
|
|
816
|
-
return { type: "element" };
|
|
817
|
-
}
|
|
818
|
-
if (type.getCallSignatures().length > 0) {
|
|
819
|
-
return { type: "function" };
|
|
820
|
-
}
|
|
821
|
-
if (checker.isArrayType(type) || checker.isTupleType(type)) {
|
|
822
|
-
return { type: "array" };
|
|
823
|
-
}
|
|
824
|
-
if (type.isUnion()) {
|
|
825
|
-
const nonNullableTypes = type.types.filter((unionType) => !isNullishType(unionType));
|
|
826
|
-
if (nonNullableTypes.length === 1) {
|
|
827
|
-
return inferPropType(nonNullableTypes[0], checker);
|
|
828
|
-
}
|
|
829
|
-
const stringLiteralValues = nonNullableTypes.filter((unionType) => (unionType.flags & ts2.TypeFlags.StringLiteral) !== 0).map((unionType) => unionType.value);
|
|
830
|
-
if (stringLiteralValues.length > 0 && stringLiteralValues.length === nonNullableTypes.length) {
|
|
831
|
-
return { type: "enum", values: stringLiteralValues };
|
|
832
|
-
}
|
|
833
|
-
if (nonNullableTypes.every((unionType) => isBooleanLikeType(unionType))) {
|
|
834
|
-
return { type: "boolean" };
|
|
835
|
-
}
|
|
836
|
-
return { type: "union" };
|
|
837
|
-
}
|
|
838
|
-
if ((type.flags & ts2.TypeFlags.StringLike) !== 0) {
|
|
839
|
-
return { type: "string" };
|
|
840
|
-
}
|
|
841
|
-
if ((type.flags & ts2.TypeFlags.NumberLike) !== 0) {
|
|
842
|
-
return { type: "number" };
|
|
843
|
-
}
|
|
844
|
-
if ((type.flags & ts2.TypeFlags.BooleanLike) !== 0) {
|
|
845
|
-
return { type: "boolean" };
|
|
846
|
-
}
|
|
847
|
-
if ((type.flags & ts2.TypeFlags.Object) !== 0) {
|
|
848
|
-
return { type: "object" };
|
|
849
|
-
}
|
|
850
|
-
return { type: "custom" };
|
|
851
|
-
}
|
|
852
|
-
function resolveComponentSignature(exportName, declarations, sourceFile) {
|
|
853
|
-
const visitedNames = /* @__PURE__ */ new Set();
|
|
854
|
-
const typeNodeFromFunction = (node) => ({
|
|
855
|
-
propsTypeNode: node.parameters[0]?.type ?? null,
|
|
856
|
-
componentNode: node
|
|
857
|
-
});
|
|
858
|
-
const resolveFromExpression = (expression) => {
|
|
859
|
-
if (ts2.isParenthesizedExpression(expression)) {
|
|
860
|
-
return resolveFromExpression(expression.expression);
|
|
861
|
-
}
|
|
862
|
-
if (ts2.isAsExpression(expression) || ts2.isTypeAssertionExpression(expression)) {
|
|
863
|
-
return resolveFromExpression(expression.expression);
|
|
864
|
-
}
|
|
865
|
-
if (ts2.isArrowFunction(expression) || ts2.isFunctionExpression(expression)) {
|
|
866
|
-
return typeNodeFromFunction(expression);
|
|
867
|
-
}
|
|
868
|
-
if (ts2.isIdentifier(expression)) {
|
|
869
|
-
return resolveFromIdentifier(expression.text);
|
|
870
|
-
}
|
|
871
|
-
if (ts2.isCallExpression(expression)) {
|
|
872
|
-
if (ts2.isPropertyAccessExpression(expression.expression) && expression.expression.name.text === "forwardRef") {
|
|
873
|
-
const forwardRefPropsType = expression.typeArguments?.[1] ?? null;
|
|
874
|
-
const innerArg = expression.arguments[0];
|
|
875
|
-
const inner = innerArg && (ts2.isArrowFunction(innerArg) || ts2.isFunctionExpression(innerArg)) ? typeNodeFromFunction(innerArg) : innerArg && ts2.isIdentifier(innerArg) ? resolveFromIdentifier(innerArg.text) : { propsTypeNode: null, componentNode: null };
|
|
876
|
-
return {
|
|
877
|
-
propsTypeNode: forwardRefPropsType ?? inner.propsTypeNode,
|
|
878
|
-
componentNode: inner.componentNode
|
|
879
|
-
};
|
|
880
|
-
}
|
|
881
|
-
if (ts2.isPropertyAccessExpression(expression.expression) && expression.expression.name.text === "memo" && expression.arguments[0]) {
|
|
882
|
-
return resolveFromExpression(expression.arguments[0]);
|
|
883
|
-
}
|
|
884
|
-
if (ts2.isPropertyAccessExpression(expression.expression) && expression.expression.expression.getText(sourceFile) === "Object" && expression.expression.name.text === "assign" && expression.arguments[0]) {
|
|
885
|
-
return resolveFromExpression(expression.arguments[0]);
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
return { propsTypeNode: null, componentNode: null };
|
|
889
|
-
};
|
|
890
|
-
const resolveFromVariable = (declaration) => {
|
|
891
|
-
if (declaration.type && ts2.isTypeReferenceNode(declaration.type) && declaration.type.typeArguments?.length) {
|
|
892
|
-
const typeName = declaration.type.typeName.getText(sourceFile);
|
|
893
|
-
if (typeName.includes("FC") || typeName.includes("FunctionComponent")) {
|
|
894
|
-
const componentNode = declaration.initializer && (ts2.isArrowFunction(declaration.initializer) || ts2.isFunctionExpression(declaration.initializer)) ? declaration.initializer : null;
|
|
895
|
-
return {
|
|
896
|
-
propsTypeNode: declaration.type.typeArguments[0] ?? null,
|
|
897
|
-
componentNode
|
|
898
|
-
};
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
if (declaration.initializer) {
|
|
902
|
-
return resolveFromExpression(declaration.initializer);
|
|
903
|
-
}
|
|
904
|
-
return { propsTypeNode: null, componentNode: null };
|
|
905
|
-
};
|
|
906
|
-
const resolveFromIdentifier = (name) => {
|
|
907
|
-
if (!name || visitedNames.has(name)) {
|
|
908
|
-
return { propsTypeNode: null, componentNode: null };
|
|
909
|
-
}
|
|
910
|
-
visitedNames.add(name);
|
|
911
|
-
const functionDeclaration = declarations.functionDeclarations.get(name);
|
|
912
|
-
if (functionDeclaration) {
|
|
913
|
-
return typeNodeFromFunction(functionDeclaration);
|
|
914
|
-
}
|
|
915
|
-
const variableDeclaration = declarations.variableDeclarations.get(name);
|
|
916
|
-
if (variableDeclaration) {
|
|
917
|
-
return resolveFromVariable(variableDeclaration);
|
|
918
|
-
}
|
|
919
|
-
return { propsTypeNode: null, componentNode: null };
|
|
920
|
-
};
|
|
921
|
-
return resolveFromIdentifier(exportName);
|
|
922
|
-
}
|
|
923
|
-
function extractCustomPropsFromComponentFile(componentFilePath, exportName) {
|
|
924
|
-
const warnings = [];
|
|
925
|
-
const resolvedPath = resolve2(componentFilePath);
|
|
926
|
-
if (!existsSync3(resolvedPath)) {
|
|
927
|
-
return {
|
|
928
|
-
props: {},
|
|
929
|
-
warnings: [`Component file not found: ${resolvedPath}`],
|
|
930
|
-
resolved: false
|
|
931
|
-
};
|
|
932
|
-
}
|
|
933
|
-
const compilerOptions = {
|
|
934
|
-
target: ts2.ScriptTarget.ESNext,
|
|
935
|
-
module: ts2.ModuleKind.ESNext,
|
|
936
|
-
moduleResolution: ts2.ModuleResolutionKind.Bundler,
|
|
937
|
-
jsx: ts2.JsxEmit.ReactJSX,
|
|
938
|
-
allowSyntheticDefaultImports: true,
|
|
939
|
-
esModuleInterop: true,
|
|
940
|
-
skipLibCheck: true,
|
|
941
|
-
strict: false,
|
|
942
|
-
noEmit: true
|
|
943
|
-
};
|
|
944
|
-
const program = ts2.createProgram([resolvedPath], compilerOptions);
|
|
945
|
-
const sourceFile = program.getSourceFile(resolvedPath);
|
|
946
|
-
if (!sourceFile) {
|
|
947
|
-
return {
|
|
948
|
-
props: {},
|
|
949
|
-
warnings: [`Unable to parse component source: ${resolvedPath}`],
|
|
950
|
-
resolved: false
|
|
951
|
-
};
|
|
952
|
-
}
|
|
953
|
-
const checker = program.getTypeChecker();
|
|
954
|
-
const declarations = collectTopLevelDeclarations(sourceFile);
|
|
955
|
-
const signature = resolveComponentSignature(exportName, declarations, sourceFile);
|
|
956
|
-
if (!signature.propsTypeNode) {
|
|
957
|
-
return {
|
|
958
|
-
props: {},
|
|
959
|
-
warnings: [`Unable to resolve props type for export: ${exportName}`],
|
|
960
|
-
resolved: false
|
|
961
|
-
};
|
|
962
|
-
}
|
|
963
|
-
const propsType = checker.getTypeFromTypeNode(signature.propsTypeNode);
|
|
964
|
-
const defaultValues = extractDefaultValues(signature.componentNode);
|
|
965
|
-
const sourceFilePath = toPosixPath(sourceFile.fileName);
|
|
966
|
-
const extractedProps = {};
|
|
967
|
-
for (const symbol of checker.getPropertiesOfType(propsType)) {
|
|
968
|
-
const propName = symbol.getName();
|
|
969
|
-
if (propName.startsWith("_") || propName.startsWith("$")) {
|
|
970
|
-
continue;
|
|
971
|
-
}
|
|
972
|
-
const declarationsForSymbol = symbol.getDeclarations() ?? [];
|
|
973
|
-
const localDeclarations = declarationsForSymbol.filter(
|
|
974
|
-
(declaration) => toPosixPath(declaration.getSourceFile().fileName) === sourceFilePath
|
|
975
|
-
);
|
|
976
|
-
if (localDeclarations.length === 0) {
|
|
977
|
-
continue;
|
|
978
|
-
}
|
|
979
|
-
const referenceNode = localDeclarations[0];
|
|
980
|
-
const inferredType = inferPropType(checker.getTypeOfSymbolAtLocation(symbol, referenceNode), checker);
|
|
981
|
-
const description = ts2.displayPartsToString(symbol.getDocumentationComment(checker)).trim();
|
|
982
|
-
extractedProps[propName] = {
|
|
983
|
-
type: inferredType.type,
|
|
984
|
-
description,
|
|
985
|
-
required: (symbol.getFlags() & ts2.SymbolFlags.Optional) === 0,
|
|
986
|
-
...inferredType.values && { values: inferredType.values },
|
|
987
|
-
...defaultValues[propName] !== void 0 && { default: defaultValues[propName] }
|
|
988
|
-
};
|
|
989
|
-
}
|
|
990
|
-
if (Object.keys(extractedProps).length === 0) {
|
|
991
|
-
warnings.push(`Resolved props type for ${exportName}, but no local custom props were found`);
|
|
992
|
-
}
|
|
993
|
-
return {
|
|
994
|
-
props: extractedProps,
|
|
995
|
-
warnings,
|
|
996
|
-
resolved: true
|
|
997
|
-
};
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
889
|
// src/core/graph-extractor.ts
|
|
1001
890
|
import ts3 from "typescript";
|
|
1002
891
|
import { readFileSync, existsSync as existsSync4 } from "fs";
|
|
@@ -1645,13 +1534,13 @@ function normalizeParsedProps(parsedProps) {
|
|
|
1645
1534
|
}
|
|
1646
1535
|
function mergeDocumentedAndAutoProps(documentedProps, autoProps) {
|
|
1647
1536
|
return Object.fromEntries(
|
|
1648
|
-
Object.keys(autoProps).map((name) => {
|
|
1537
|
+
Object.keys(autoProps).filter((name) => autoProps[name].source === "local" || name in documentedProps).map((name) => {
|
|
1649
1538
|
const documented = documentedProps[name];
|
|
1650
1539
|
const auto = autoProps[name];
|
|
1651
1540
|
return [
|
|
1652
1541
|
name,
|
|
1653
1542
|
{
|
|
1654
|
-
type: auto.
|
|
1543
|
+
type: auto.typeKind,
|
|
1655
1544
|
description: documented?.description ?? auto.description ?? "",
|
|
1656
1545
|
default: auto.default !== void 0 ? auto.default : documented?.default,
|
|
1657
1546
|
required: auto.required,
|
|
@@ -1662,14 +1551,37 @@ function mergeDocumentedAndAutoProps(documentedProps, autoProps) {
|
|
|
1662
1551
|
})
|
|
1663
1552
|
);
|
|
1664
1553
|
}
|
|
1554
|
+
function compilePropsSummary(props) {
|
|
1555
|
+
return Object.entries(props).filter(([_, p]) => p.source === "local").map(([name, prop]) => {
|
|
1556
|
+
let summary = name + ": ";
|
|
1557
|
+
if (prop.values && prop.values.length > 0) {
|
|
1558
|
+
summary += prop.values.join("|");
|
|
1559
|
+
} else {
|
|
1560
|
+
summary += prop.typeKind;
|
|
1561
|
+
}
|
|
1562
|
+
if (prop.default !== void 0) {
|
|
1563
|
+
summary += ` (default: ${prop.default})`;
|
|
1564
|
+
}
|
|
1565
|
+
if (prop.required) {
|
|
1566
|
+
summary += " (required)";
|
|
1567
|
+
}
|
|
1568
|
+
return summary;
|
|
1569
|
+
});
|
|
1570
|
+
}
|
|
1665
1571
|
async function buildFragments(config, configDir) {
|
|
1666
1572
|
const files = await discoverFragmentFiles(config, configDir);
|
|
1667
1573
|
const errors = [];
|
|
1668
1574
|
const warnings = [];
|
|
1669
1575
|
const fragments = {};
|
|
1576
|
+
const tsconfigCandidates = [
|
|
1577
|
+
resolve5(configDir, "tsconfig.json"),
|
|
1578
|
+
resolve5(configDir, "..", "tsconfig.json")
|
|
1579
|
+
];
|
|
1580
|
+
const tsconfigPath = tsconfigCandidates.find((p) => existsSync6(p));
|
|
1581
|
+
const extractor = createComponentExtractor(tsconfigPath);
|
|
1670
1582
|
for (const file of files) {
|
|
1671
1583
|
try {
|
|
1672
|
-
const content = await
|
|
1584
|
+
const content = await readFile3(file.absolutePath, "utf-8");
|
|
1673
1585
|
if (!content.includes("defineFragment")) {
|
|
1674
1586
|
warnings.push({
|
|
1675
1587
|
file: file.relativePath,
|
|
@@ -1695,34 +1607,32 @@ async function buildFragments(config, configDir) {
|
|
|
1695
1607
|
file.absolutePath,
|
|
1696
1608
|
parsed.componentImport
|
|
1697
1609
|
);
|
|
1610
|
+
let extractedMeta = null;
|
|
1698
1611
|
if (componentExportName && componentSourcePath) {
|
|
1699
|
-
|
|
1700
|
-
componentSourcePath,
|
|
1701
|
-
|
|
1702
|
-
);
|
|
1703
|
-
for (const warning of autoPropsResult.warnings) {
|
|
1704
|
-
warnings.push({ file: file.relativePath, warning });
|
|
1612
|
+
try {
|
|
1613
|
+
extractedMeta = extractor.extract(componentSourcePath, componentExportName);
|
|
1614
|
+
} catch {
|
|
1705
1615
|
}
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
const
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1616
|
+
if (extractedMeta) {
|
|
1617
|
+
const autoProps = extractedMeta.props;
|
|
1618
|
+
const hasAutoProps = Object.keys(autoProps).length > 0;
|
|
1619
|
+
if (hasAutoProps) {
|
|
1620
|
+
const removedDocumentedProps = Object.keys(documentedProps).filter(
|
|
1621
|
+
(propName) => !(propName in autoProps)
|
|
1622
|
+
);
|
|
1623
|
+
if (removedDocumentedProps.length > 0) {
|
|
1624
|
+
warnings.push({
|
|
1625
|
+
file: file.relativePath,
|
|
1626
|
+
warning: `Removed ${removedDocumentedProps.length} documented props not present in source API: ${removedDocumentedProps.join(", ")}`
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
mergedProps = mergeDocumentedAndAutoProps(documentedProps, autoProps);
|
|
1630
|
+
} else if (Object.keys(documentedProps).length > 0) {
|
|
1712
1631
|
warnings.push({
|
|
1713
1632
|
file: file.relativePath,
|
|
1714
|
-
warning:
|
|
1633
|
+
warning: "Auto-props extraction returned no props; falling back to documented props"
|
|
1715
1634
|
});
|
|
1716
1635
|
}
|
|
1717
|
-
mergedProps = mergeDocumentedAndAutoProps(
|
|
1718
|
-
documentedProps,
|
|
1719
|
-
autoPropsResult.props
|
|
1720
|
-
);
|
|
1721
|
-
} else if (autoPropsResult.resolved && !hasAutoProps && Object.keys(documentedProps).length > 0) {
|
|
1722
|
-
warnings.push({
|
|
1723
|
-
file: file.relativePath,
|
|
1724
|
-
warning: "Auto-props extraction returned no custom props; falling back to documented props"
|
|
1725
|
-
});
|
|
1726
1636
|
}
|
|
1727
1637
|
} else if (!componentExportName) {
|
|
1728
1638
|
warnings.push({
|
|
@@ -1735,6 +1645,23 @@ async function buildFragments(config, configDir) {
|
|
|
1735
1645
|
warning: `Unable to resolve component source path from import: ${parsed.componentImport ?? "unknown"}`
|
|
1736
1646
|
});
|
|
1737
1647
|
}
|
|
1648
|
+
let contract = parsed.contract;
|
|
1649
|
+
if (!contract?.propsSummary && extractedMeta) {
|
|
1650
|
+
const summary = compilePropsSummary(extractedMeta.props);
|
|
1651
|
+
if (summary.length > 0) {
|
|
1652
|
+
contract = { ...contract, propsSummary: summary };
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
let ai = parsed.ai;
|
|
1656
|
+
if (extractedMeta?.composition) {
|
|
1657
|
+
const comp = extractedMeta.composition;
|
|
1658
|
+
ai = {
|
|
1659
|
+
compositionPattern: comp.pattern,
|
|
1660
|
+
subComponents: comp.parts.map((p) => p.name),
|
|
1661
|
+
...ai
|
|
1662
|
+
// Manually authored ai fields take precedence
|
|
1663
|
+
};
|
|
1664
|
+
}
|
|
1738
1665
|
const compiled = {
|
|
1739
1666
|
filePath: file.relativePath,
|
|
1740
1667
|
meta: {
|
|
@@ -1766,10 +1693,10 @@ async function buildFragments(config, configDir) {
|
|
|
1766
1693
|
...v.figma && { figma: v.figma },
|
|
1767
1694
|
...v.args && { args: v.args }
|
|
1768
1695
|
})),
|
|
1769
|
-
// Include AI metadata
|
|
1770
|
-
...
|
|
1771
|
-
// Include contract metadata
|
|
1772
|
-
...
|
|
1696
|
+
// Include AI metadata (auto-enriched or manual)
|
|
1697
|
+
...ai && { ai },
|
|
1698
|
+
// Include contract metadata (auto-compiled or manual)
|
|
1699
|
+
...contract && { contract }
|
|
1773
1700
|
};
|
|
1774
1701
|
fragments[parsed.meta.name] = compiled;
|
|
1775
1702
|
} catch (error) {
|
|
@@ -1779,6 +1706,7 @@ async function buildFragments(config, configDir) {
|
|
|
1779
1706
|
});
|
|
1780
1707
|
}
|
|
1781
1708
|
}
|
|
1709
|
+
extractor.dispose();
|
|
1782
1710
|
const blocks = {};
|
|
1783
1711
|
try {
|
|
1784
1712
|
const blockFiles = await discoverBlockFiles(configDir, config.exclude);
|
|
@@ -1812,7 +1740,7 @@ async function buildFragments(config, configDir) {
|
|
|
1812
1740
|
let total = 0;
|
|
1813
1741
|
const fileContents = [];
|
|
1814
1742
|
for (const file of tokenFiles) {
|
|
1815
|
-
const content = await
|
|
1743
|
+
const content = await readFile3(file.absolutePath, "utf-8");
|
|
1816
1744
|
fileContents.push({ content, path: file.relativePath });
|
|
1817
1745
|
}
|
|
1818
1746
|
const allContent = fileContents.map((f) => f.content).join("\n");
|
|
@@ -1869,7 +1797,7 @@ async function buildFragments(config, configDir) {
|
|
|
1869
1797
|
const pkgJsonPath = resolve5(configDir, "package.json");
|
|
1870
1798
|
if (existsSync6(pkgJsonPath)) {
|
|
1871
1799
|
try {
|
|
1872
|
-
const pkg = JSON.parse(await
|
|
1800
|
+
const pkg = JSON.parse(await readFile3(pkgJsonPath, "utf-8"));
|
|
1873
1801
|
if (pkg.name) packageName = pkg.name;
|
|
1874
1802
|
} catch {
|
|
1875
1803
|
}
|
|
@@ -2344,7 +2272,7 @@ ${BRAND.name} Diff
|
|
|
2344
2272
|
|
|
2345
2273
|
// src/analyze.ts
|
|
2346
2274
|
import { existsSync as existsSync7 } from "fs";
|
|
2347
|
-
import { readFile as
|
|
2275
|
+
import { readFile as readFile4, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
2348
2276
|
import { join as join6, dirname as dirname4 } from "path";
|
|
2349
2277
|
import pc3 from "picocolors";
|
|
2350
2278
|
async function runAnalyzeCommand(config, configDir, options = {}) {
|
|
@@ -2363,7 +2291,7 @@ ${BRAND.name} Analyzer
|
|
|
2363
2291
|
};
|
|
2364
2292
|
}
|
|
2365
2293
|
console.log(pc3.dim("Analyzing design system...\n"));
|
|
2366
|
-
const content = await
|
|
2294
|
+
const content = await readFile4(fragmentsPath, "utf-8");
|
|
2367
2295
|
const data = JSON.parse(content);
|
|
2368
2296
|
const analytics = analyzeDesignSystem(data);
|
|
2369
2297
|
printConsoleSummary(analytics);
|
|
@@ -2508,10 +2436,12 @@ function createEmptyAnalytics() {
|
|
|
2508
2436
|
}
|
|
2509
2437
|
|
|
2510
2438
|
export {
|
|
2439
|
+
resolveComponentSourcePath,
|
|
2511
2440
|
validateSchema,
|
|
2512
2441
|
validateCoverage,
|
|
2513
2442
|
validateAll,
|
|
2514
2443
|
validateSnippets,
|
|
2444
|
+
validateDrift,
|
|
2515
2445
|
measureBundleSizes,
|
|
2516
2446
|
toPerformanceData,
|
|
2517
2447
|
buildFragments,
|
|
@@ -2520,4 +2450,4 @@ export {
|
|
|
2520
2450
|
runDiffCommand,
|
|
2521
2451
|
runAnalyzeCommand
|
|
2522
2452
|
};
|
|
2523
|
-
//# sourceMappingURL=chunk-
|
|
2453
|
+
//# sourceMappingURL=chunk-GVDSFQ4E.js.map
|