@fragments-sdk/cli 0.14.2 → 0.15.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.
- package/README.md +0 -3
- package/dist/bin.js +4290 -3754
- 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-55KERLWL.js → chunk-65WSVDV5.js} +314 -89
- package/dist/chunk-65WSVDV5.js.map +1 -0
- package/dist/chunk-7DZC4YEV.js +294 -0
- package/dist/chunk-7DZC4YEV.js.map +1 -0
- package/dist/{chunk-LOYS64QS.js → chunk-7WHVW72L.js} +230 -19
- package/dist/chunk-7WHVW72L.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-5A6X2Y73.js → chunk-CZD3AD4Q.js} +12 -11
- package/dist/chunk-CZD3AD4Q.js.map +1 -0
- package/dist/{chunk-EYXVAMEX.js → chunk-MN3TJ3D5.js} +72 -3
- package/dist/chunk-MN3TJ3D5.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/{chunk-APTQIBS5.js → chunk-XJQ5BIWI.js} +144 -1049
- package/dist/chunk-XJQ5BIWI.js.map +1 -0
- package/dist/codebase-scanner-VOTPXRYW.js +22 -0
- package/dist/converter-JLINP7CJ.js +34 -0
- package/dist/converter-JLINP7CJ.js.map +1 -0
- package/dist/core/index.js +43 -1
- package/dist/{generate-RYWIPDN2.js → generate-A4FP5426.js} +3 -4
- package/dist/{generate-RYWIPDN2.js.map → generate-A4FP5426.js.map} +1 -1
- package/dist/govern-scan-UCBZR6D6.js +280 -0
- package/dist/govern-scan-UCBZR6D6.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +11 -11
- package/dist/{init-WRUSW7R5.js → init-HGSM35XA.js} +131 -128
- package/dist/init-HGSM35XA.js.map +1 -0
- package/dist/{init-cloud-REQ3XLHO.js → init-cloud-MQ6GRJAZ.js} +2 -2
- package/dist/mcp-bin.js +5 -36
- package/dist/mcp-bin.js.map +1 -1
- package/dist/scan-VNNKACG2.js +15 -0
- package/dist/{scan-generate-TFZVL3BT.js → scan-generate-TWRHNU5M.js} +335 -46
- package/dist/scan-generate-TWRHNU5M.js.map +1 -0
- package/dist/scanner-7LAZYPWZ.js +13 -0
- package/dist/{service-HKJ6B7P7.js → service-FHQU7YS7.js} +27 -23
- package/dist/{snapshot-C5DYIGIV.js → snapshot-KQEQ6XHL.js} +2 -2
- package/dist/{static-viewer-DUVC4UIM.js → static-viewer-63PG6FWY.js} +3 -3
- package/dist/static-viewer-63PG6FWY.js.map +1 -0
- package/dist/{test-JW7JIDFG.js → test-UQYUCZIS.js} +4 -6
- package/dist/{test-JW7JIDFG.js.map → test-UQYUCZIS.js.map} +1 -1
- package/dist/{tokens-KE73G5JC.js → tokens-6GYKDV6U.js} +6 -5
- package/dist/{tokens-KE73G5JC.js.map → tokens-6GYKDV6U.js.map} +1 -1
- package/dist/tokens-generate-VTZV5EEW.js +86 -0
- package/dist/tokens-generate-VTZV5EEW.js.map +1 -0
- package/package.json +6 -6
- package/src/bin.ts +210 -48
- package/src/build.ts +130 -6
- 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__/init.test.ts +113 -0
- package/src/commands/__tests__/scan-generate.test.ts +188 -69
- package/src/commands/__tests__/verify.test.ts +91 -0
- package/src/commands/discover.ts +151 -0
- package/src/commands/enhance.ts +3 -1
- package/src/commands/govern-scan.ts +386 -0
- package/src/commands/govern.ts +2 -2
- 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/scan-generate.ts +438 -50
- package/src/commands/scan.ts +1 -0
- package/src/commands/setup.ts +27 -50
- package/src/commands/tokens-generate.ts +113 -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/component-extractor.test.ts +39 -0
- package/src/core/component-extractor.ts +92 -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/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/snippet-validation.ts +9 -3
- package/src/service/token-normalizer.ts +510 -0
- package/src/shared/index.ts +1 -0
- package/src/shared/project-fields.ts +46 -0
- package/src/viewer/__tests__/viewer-integration.test.ts +8 -8
- package/src/viewer/preview-adapter.ts +116 -0
- 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.map +0 -1
- package/dist/chunk-I34BC3CU.js.map +0 -1
- package/dist/chunk-LOYS64QS.js.map +0 -1
- 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/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/commands/dev.ts +0 -107
- /package/dist/{chunk-TXFCEDOC.js.map → chunk-2WXKALIG.js.map} +0 -0
- /package/dist/{discovery-VDANZAJ2.js.map → codebase-scanner-VOTPXRYW.js.map} +0 -0
- /package/dist/{init-cloud-REQ3XLHO.js.map → init-cloud-MQ6GRJAZ.js.map} +0 -0
- /package/dist/{scan-YJHQIRKG.js.map → scan-VNNKACG2.js.map} +0 -0
- /package/dist/{service-HKJ6B7P7.js.map → scanner-7LAZYPWZ.js.map} +0 -0
- /package/dist/{static-viewer-DUVC4UIM.js.map → service-FHQU7YS7.js.map} +0 -0
- /package/dist/{snapshot-C5DYIGIV.js.map → snapshot-KQEQ6XHL.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/service/enhance/scanner.ts","../src/service/babel-config.ts"],"sourcesContent":["/**\n * AST Scanner for Component Usage Analysis\n *\n * Scans TypeScript/TSX files to find:\n * - Component imports (named, default, aliased)\n * - Component usages in JSX with props\n */\n\nimport { parse } from \"@babel/parser\";\nimport { BABEL_PARSER_OPTIONS } from \"../babel-config.js\";\nimport _traverse from \"@babel/traverse\";\nimport * as t from \"@babel/types\";\n\n// Handle CommonJS/ESM interop\nconst traverse = (_traverse as unknown as { default: typeof _traverse }).default || _traverse;\nimport { readFile } from \"node:fs/promises\";\nimport type {\n ComponentImport,\n ComponentUsage,\n UsageProps,\n} from \"./types.js\";\n\n\n/**\n * Scan a file for component imports\n *\n * Handles:\n * - Named imports: import { Button } from './Button'\n * - Default imports: import Button from './Button'\n * - Aliased imports: import { Button as Btn } from './Button'\n * - Namespace imports: import * as Components from './index'\n */\nexport async function scanFileForImports(\n filePath: string\n): Promise<ComponentImport[]> {\n const imports: ComponentImport[] = [];\n\n try {\n const sourceCode = await readFile(filePath, \"utf-8\");\n const ast = parse(sourceCode, BABEL_PARSER_OPTIONS);\n\n traverse(ast, {\n ImportDeclaration(path) {\n const source = path.node.source.value;\n const line = path.node.loc?.start.line ?? 0;\n\n for (const specifier of path.node.specifiers) {\n if (t.isImportSpecifier(specifier)) {\n // Named import: import { Button } from './Button'\n // or aliased: import { Button as Btn } from './Button'\n const importedName = t.isIdentifier(specifier.imported)\n ? specifier.imported.name\n : specifier.imported.value;\n const localName = specifier.local.name;\n\n // Only track PascalCase names (likely components)\n if (isPascalCase(importedName)) {\n imports.push({\n componentName: importedName,\n localName,\n source,\n isDefault: false,\n filePath,\n line,\n });\n }\n } else if (t.isImportDefaultSpecifier(specifier)) {\n // Default import: import Button from './Button'\n const localName = specifier.local.name;\n\n // Only track PascalCase names (likely components)\n if (isPascalCase(localName)) {\n imports.push({\n componentName: localName,\n localName,\n source,\n isDefault: true,\n filePath,\n line,\n });\n }\n }\n // Skip namespace imports for now (import * as X)\n }\n },\n });\n } catch (error) {\n // Return empty array for files with parse errors\n // Caller can check if empty means \"no imports\" or \"parse error\"\n console.warn(`Failed to parse ${filePath}:`, (error as Error).message);\n return [];\n }\n\n return imports;\n}\n\n/**\n * Scan a file for component usages in JSX\n *\n * @param filePath - File to scan\n * @param componentNames - Map of localName -> componentName for components to track\n */\nexport async function scanFileForUsages(\n filePath: string,\n componentNames: Map<string, string>\n): Promise<ComponentUsage[]> {\n const usages: ComponentUsage[] = [];\n\n try {\n const sourceCode = await readFile(filePath, \"utf-8\");\n const lines = sourceCode.split(\"\\n\");\n const ast = parse(sourceCode, BABEL_PARSER_OPTIONS);\n\n traverse(ast, {\n JSXOpeningElement(path) {\n const elementName = getJSXElementName(path.node.name);\n if (!elementName) return;\n\n // Check if this is a tracked component (by local name)\n const componentName = componentNames.get(elementName);\n if (!componentName) return;\n\n const loc = path.node.loc;\n if (!loc) return;\n\n // Extract props\n const props = extractProps(path.node.attributes);\n\n // Get surrounding context (3 lines before and after)\n const contextLines = getContextLines(lines, loc.start.line - 1, 3);\n\n // Check if conditionally rendered\n const isConditional = checkIfConditional(path);\n\n // Get parent element name\n const parentElement = getParentElementName(path);\n\n usages.push({\n componentName,\n filePath,\n line: loc.start.line,\n column: loc.start.column,\n props,\n context: contextLines,\n parentElement,\n hasSpreadProps: props.spreads.length > 0,\n isConditional,\n });\n },\n });\n } catch (error) {\n console.warn(`Failed to parse ${filePath}:`, (error as Error).message);\n return [];\n }\n\n return usages;\n}\n\n/**\n * Scan a file for both imports and usages in a single pass\n * More efficient for scanning many files\n */\nexport async function scanFile(\n filePath: string,\n trackedComponents?: Set<string>\n): Promise<{ imports: ComponentImport[]; usages: ComponentUsage[] }> {\n const imports: ComponentImport[] = [];\n const usages: ComponentUsage[] = [];\n\n try {\n const sourceCode = await readFile(filePath, \"utf-8\");\n const lines = sourceCode.split(\"\\n\");\n const ast = parse(sourceCode, BABEL_PARSER_OPTIONS);\n\n // Track local names to component names mapping within this file\n const localToComponent = new Map<string, string>();\n\n traverse(ast, {\n ImportDeclaration(path) {\n const source = path.node.source.value;\n const line = path.node.loc?.start.line ?? 0;\n\n for (const specifier of path.node.specifiers) {\n if (t.isImportSpecifier(specifier)) {\n const importedName = t.isIdentifier(specifier.imported)\n ? specifier.imported.name\n : specifier.imported.value;\n const localName = specifier.local.name;\n\n if (isPascalCase(importedName)) {\n // If we're tracking specific components, only add those\n if (!trackedComponents || trackedComponents.has(importedName)) {\n imports.push({\n componentName: importedName,\n localName,\n source,\n isDefault: false,\n filePath,\n line,\n });\n localToComponent.set(localName, importedName);\n }\n }\n } else if (t.isImportDefaultSpecifier(specifier)) {\n const localName = specifier.local.name;\n\n if (isPascalCase(localName)) {\n if (!trackedComponents || trackedComponents.has(localName)) {\n imports.push({\n componentName: localName,\n localName,\n source,\n isDefault: true,\n filePath,\n line,\n });\n localToComponent.set(localName, localName);\n }\n }\n }\n }\n },\n\n JSXOpeningElement(path) {\n const elementName = getJSXElementName(path.node.name);\n if (!elementName) return;\n\n // Check if this is a tracked component (by local name)\n const componentName = localToComponent.get(elementName);\n if (!componentName) return;\n\n const loc = path.node.loc;\n if (!loc) return;\n\n const props = extractProps(path.node.attributes);\n const contextLines = getContextLines(lines, loc.start.line - 1, 3);\n const isConditional = checkIfConditional(path);\n const parentElement = getParentElementName(path);\n\n usages.push({\n componentName,\n filePath,\n line: loc.start.line,\n column: loc.start.column,\n props,\n context: contextLines,\n parentElement,\n hasSpreadProps: props.spreads.length > 0,\n isConditional,\n });\n },\n });\n } catch (error) {\n console.warn(`Failed to parse ${filePath}:`, (error as Error).message);\n return { imports: [], usages: [] };\n }\n\n return { imports, usages };\n}\n\n/**\n * Check if a string is PascalCase (likely a component name)\n */\nfunction isPascalCase(str: string): boolean {\n return /^[A-Z][a-zA-Z0-9]*$/.test(str);\n}\n\n/**\n * Get the element name from a JSX element name node\n */\nfunction getJSXElementName(\n name: t.JSXIdentifier | t.JSXMemberExpression | t.JSXNamespacedName\n): string | null {\n if (t.isJSXIdentifier(name)) {\n return name.name;\n }\n if (t.isJSXMemberExpression(name)) {\n // Handle Component.SubComponent - return the full path\n const parts: string[] = [];\n let current: t.JSXMemberExpression | t.JSXIdentifier = name;\n while (t.isJSXMemberExpression(current)) {\n parts.unshift(current.property.name);\n current = current.object as t.JSXMemberExpression | t.JSXIdentifier;\n }\n if (t.isJSXIdentifier(current)) {\n parts.unshift(current.name);\n }\n return parts.join(\".\");\n }\n return null;\n}\n\n/**\n * Extract props from JSX attributes\n */\nfunction extractProps(\n attributes: (t.JSXAttribute | t.JSXSpreadAttribute)[]\n): UsageProps {\n const result: UsageProps = {\n static: {},\n dynamic: [],\n spreads: [],\n };\n\n for (const attr of attributes) {\n if (t.isJSXSpreadAttribute(attr)) {\n // {...props} or {...otherProps}\n if (t.isIdentifier(attr.argument)) {\n result.spreads.push(attr.argument.name);\n } else {\n result.spreads.push(\"(expression)\");\n }\n } else if (t.isJSXAttribute(attr)) {\n const propName = t.isJSXIdentifier(attr.name)\n ? attr.name.name\n : `${attr.name.namespace.name}:${attr.name.name.name}`;\n\n const value = attr.value;\n\n if (value === null) {\n // Boolean shorthand: <Button disabled />\n result.static[propName] = true;\n } else if (t.isStringLiteral(value)) {\n // String literal: <Button variant=\"primary\" />\n result.static[propName] = value.value;\n } else if (t.isJSXExpressionContainer(value)) {\n const expr = value.expression;\n\n if (t.isStringLiteral(expr)) {\n result.static[propName] = expr.value;\n } else if (t.isNumericLiteral(expr)) {\n result.static[propName] = expr.value;\n } else if (t.isBooleanLiteral(expr)) {\n result.static[propName] = expr.value;\n } else if (t.isTemplateLiteral(expr) && expr.expressions.length === 0) {\n // Static template literal: variant={`primary`}\n result.static[propName] = expr.quasis.map((q) => q.value.raw).join(\"\");\n } else {\n // Dynamic expression\n result.dynamic.push(propName);\n }\n }\n }\n }\n\n return result;\n}\n\n/**\n * Get surrounding context lines\n */\nfunction getContextLines(\n lines: string[],\n centerLine: number,\n radius: number\n): string {\n const start = Math.max(0, centerLine - radius);\n const end = Math.min(lines.length, centerLine + radius + 1);\n return lines.slice(start, end).join(\"\\n\");\n}\n\n/**\n * Check if JSX element is conditionally rendered\n */\nfunction checkIfConditional(path: babel.NodePath<t.JSXOpeningElement>): boolean {\n let current: babel.NodePath | null = path.parentPath;\n\n while (current) {\n // Check for {condition && <Component />}\n if (\n current.isLogicalExpression() &&\n current.node.operator === \"&&\"\n ) {\n return true;\n }\n\n // Check for {condition ? <Component /> : null}\n if (current.isConditionalExpression()) {\n return true;\n }\n\n // Check for ternary in JSX expression container\n if (\n current.isJSXExpressionContainer() &&\n current.parentPath?.isJSXElement()\n ) {\n const expr = current.node.expression;\n if (\n t.isLogicalExpression(expr) ||\n t.isConditionalExpression(expr)\n ) {\n return true;\n }\n }\n\n current = current.parentPath;\n }\n\n return false;\n}\n\n/**\n * Get the parent JSX element name\n */\nfunction getParentElementName(\n path: babel.NodePath<t.JSXOpeningElement>\n): string | undefined {\n let current: babel.NodePath | null = path.parentPath;\n const currentElementName = getJSXElementName(path.node.name);\n\n while (current) {\n if (current.isJSXElement()) {\n const opening = current.node.openingElement;\n const name = getJSXElementName(opening.name);\n if (name && name !== currentElementName) {\n return name;\n }\n }\n current = current.parentPath;\n }\n\n return undefined;\n}\n\n// Type import for babel NodePath\nimport type * as babel from \"@babel/traverse\";\n","/**\n * Shared Babel parser configuration for React/TypeScript files.\n */\n\nimport type { ParserOptions } from \"@babel/parser\";\n\nexport const BABEL_PARSER_OPTIONS: ParserOptions = {\n sourceType: \"module\",\n plugins: [\n \"jsx\",\n \"typescript\",\n [\"decorators\", { decoratorsBeforeExport: true }],\n \"classProperties\",\n \"classPrivateProperties\",\n \"classPrivateMethods\",\n \"exportDefaultFrom\",\n \"exportNamespaceFrom\",\n \"dynamicImport\",\n \"nullishCoalescingOperator\",\n \"optionalChaining\",\n \"objectRestSpread\",\n ],\n};\n"],"mappings":";;;AAQA,SAAS,aAAa;;;ACFf,IAAM,uBAAsC;AAAA,EACjD,YAAY;AAAA,EACZ,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA,CAAC,cAAc,EAAE,wBAAwB,KAAK,CAAC;AAAA,IAC/C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ADZA,OAAO,eAAe;AACtB,YAAY,OAAO;AAInB,SAAS,gBAAgB;AADzB,IAAM,WAAY,UAAuD,WAAW;AAkBpF,eAAsB,mBACpB,UAC4B;AAC5B,QAAM,UAA6B,CAAC;AAEpC,MAAI;AACF,UAAM,aAAa,MAAM,SAAS,UAAU,OAAO;AACnD,UAAM,MAAM,MAAM,YAAY,oBAAoB;AAElD,aAAS,KAAK;AAAA,MACZ,kBAAkB,MAAM;AACtB,cAAM,SAAS,KAAK,KAAK,OAAO;AAChC,cAAM,OAAO,KAAK,KAAK,KAAK,MAAM,QAAQ;AAE1C,mBAAW,aAAa,KAAK,KAAK,YAAY;AAC5C,cAAM,oBAAkB,SAAS,GAAG;AAGlC,kBAAM,eAAiB,eAAa,UAAU,QAAQ,IAClD,UAAU,SAAS,OACnB,UAAU,SAAS;AACvB,kBAAM,YAAY,UAAU,MAAM;AAGlC,gBAAI,aAAa,YAAY,GAAG;AAC9B,sBAAQ,KAAK;AAAA,gBACX,eAAe;AAAA,gBACf;AAAA,gBACA;AAAA,gBACA,WAAW;AAAA,gBACX;AAAA,gBACA;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF,WAAa,2BAAyB,SAAS,GAAG;AAEhD,kBAAM,YAAY,UAAU,MAAM;AAGlC,gBAAI,aAAa,SAAS,GAAG;AAC3B,sBAAQ,KAAK;AAAA,gBACX,eAAe;AAAA,gBACf;AAAA,gBACA;AAAA,gBACA,WAAW;AAAA,gBACX;AAAA,gBACA;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QAEF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AAGd,YAAQ,KAAK,mBAAmB,QAAQ,KAAM,MAAgB,OAAO;AACrE,WAAO,CAAC;AAAA,EACV;AAEA,SAAO;AACT;AAQA,eAAsB,kBACpB,UACA,gBAC2B;AAC3B,QAAM,SAA2B,CAAC;AAElC,MAAI;AACF,UAAM,aAAa,MAAM,SAAS,UAAU,OAAO;AACnD,UAAM,QAAQ,WAAW,MAAM,IAAI;AACnC,UAAM,MAAM,MAAM,YAAY,oBAAoB;AAElD,aAAS,KAAK;AAAA,MACZ,kBAAkB,MAAM;AACtB,cAAM,cAAc,kBAAkB,KAAK,KAAK,IAAI;AACpD,YAAI,CAAC,YAAa;AAGlB,cAAM,gBAAgB,eAAe,IAAI,WAAW;AACpD,YAAI,CAAC,cAAe;AAEpB,cAAM,MAAM,KAAK,KAAK;AACtB,YAAI,CAAC,IAAK;AAGV,cAAM,QAAQ,aAAa,KAAK,KAAK,UAAU;AAG/C,cAAM,eAAe,gBAAgB,OAAO,IAAI,MAAM,OAAO,GAAG,CAAC;AAGjE,cAAM,gBAAgB,mBAAmB,IAAI;AAG7C,cAAM,gBAAgB,qBAAqB,IAAI;AAE/C,eAAO,KAAK;AAAA,UACV;AAAA,UACA;AAAA,UACA,MAAM,IAAI,MAAM;AAAA,UAChB,QAAQ,IAAI,MAAM;AAAA,UAClB;AAAA,UACA,SAAS;AAAA,UACT;AAAA,UACA,gBAAgB,MAAM,QAAQ,SAAS;AAAA,UACvC;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AACd,YAAQ,KAAK,mBAAmB,QAAQ,KAAM,MAAgB,OAAO;AACrE,WAAO,CAAC;AAAA,EACV;AAEA,SAAO;AACT;AAMA,eAAsB,SACpB,UACA,mBACmE;AACnE,QAAM,UAA6B,CAAC;AACpC,QAAM,SAA2B,CAAC;AAElC,MAAI;AACF,UAAM,aAAa,MAAM,SAAS,UAAU,OAAO;AACnD,UAAM,QAAQ,WAAW,MAAM,IAAI;AACnC,UAAM,MAAM,MAAM,YAAY,oBAAoB;AAGlD,UAAM,mBAAmB,oBAAI,IAAoB;AAEjD,aAAS,KAAK;AAAA,MACZ,kBAAkB,MAAM;AACtB,cAAM,SAAS,KAAK,KAAK,OAAO;AAChC,cAAM,OAAO,KAAK,KAAK,KAAK,MAAM,QAAQ;AAE1C,mBAAW,aAAa,KAAK,KAAK,YAAY;AAC5C,cAAM,oBAAkB,SAAS,GAAG;AAClC,kBAAM,eAAiB,eAAa,UAAU,QAAQ,IAClD,UAAU,SAAS,OACnB,UAAU,SAAS;AACvB,kBAAM,YAAY,UAAU,MAAM;AAElC,gBAAI,aAAa,YAAY,GAAG;AAE9B,kBAAI,CAAC,qBAAqB,kBAAkB,IAAI,YAAY,GAAG;AAC7D,wBAAQ,KAAK;AAAA,kBACX,eAAe;AAAA,kBACf;AAAA,kBACA;AAAA,kBACA,WAAW;AAAA,kBACX;AAAA,kBACA;AAAA,gBACF,CAAC;AACD,iCAAiB,IAAI,WAAW,YAAY;AAAA,cAC9C;AAAA,YACF;AAAA,UACF,WAAa,2BAAyB,SAAS,GAAG;AAChD,kBAAM,YAAY,UAAU,MAAM;AAElC,gBAAI,aAAa,SAAS,GAAG;AAC3B,kBAAI,CAAC,qBAAqB,kBAAkB,IAAI,SAAS,GAAG;AAC1D,wBAAQ,KAAK;AAAA,kBACX,eAAe;AAAA,kBACf;AAAA,kBACA;AAAA,kBACA,WAAW;AAAA,kBACX;AAAA,kBACA;AAAA,gBACF,CAAC;AACD,iCAAiB,IAAI,WAAW,SAAS;AAAA,cAC3C;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MAEA,kBAAkB,MAAM;AACtB,cAAM,cAAc,kBAAkB,KAAK,KAAK,IAAI;AACpD,YAAI,CAAC,YAAa;AAGlB,cAAM,gBAAgB,iBAAiB,IAAI,WAAW;AACtD,YAAI,CAAC,cAAe;AAEpB,cAAM,MAAM,KAAK,KAAK;AACtB,YAAI,CAAC,IAAK;AAEV,cAAM,QAAQ,aAAa,KAAK,KAAK,UAAU;AAC/C,cAAM,eAAe,gBAAgB,OAAO,IAAI,MAAM,OAAO,GAAG,CAAC;AACjE,cAAM,gBAAgB,mBAAmB,IAAI;AAC7C,cAAM,gBAAgB,qBAAqB,IAAI;AAE/C,eAAO,KAAK;AAAA,UACV;AAAA,UACA;AAAA,UACA,MAAM,IAAI,MAAM;AAAA,UAChB,QAAQ,IAAI,MAAM;AAAA,UAClB;AAAA,UACA,SAAS;AAAA,UACT;AAAA,UACA,gBAAgB,MAAM,QAAQ,SAAS;AAAA,UACvC;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AACd,YAAQ,KAAK,mBAAmB,QAAQ,KAAM,MAAgB,OAAO;AACrE,WAAO,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,EAAE;AAAA,EACnC;AAEA,SAAO,EAAE,SAAS,OAAO;AAC3B;AAKA,SAAS,aAAa,KAAsB;AAC1C,SAAO,sBAAsB,KAAK,GAAG;AACvC;AAKA,SAAS,kBACP,MACe;AACf,MAAM,kBAAgB,IAAI,GAAG;AAC3B,WAAO,KAAK;AAAA,EACd;AACA,MAAM,wBAAsB,IAAI,GAAG;AAEjC,UAAM,QAAkB,CAAC;AACzB,QAAI,UAAmD;AACvD,WAAS,wBAAsB,OAAO,GAAG;AACvC,YAAM,QAAQ,QAAQ,SAAS,IAAI;AACnC,gBAAU,QAAQ;AAAA,IACpB;AACA,QAAM,kBAAgB,OAAO,GAAG;AAC9B,YAAM,QAAQ,QAAQ,IAAI;AAAA,IAC5B;AACA,WAAO,MAAM,KAAK,GAAG;AAAA,EACvB;AACA,SAAO;AACT;AAKA,SAAS,aACP,YACY;AACZ,QAAM,SAAqB;AAAA,IACzB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC;AAAA,IACV,SAAS,CAAC;AAAA,EACZ;AAEA,aAAW,QAAQ,YAAY;AAC7B,QAAM,uBAAqB,IAAI,GAAG;AAEhC,UAAM,eAAa,KAAK,QAAQ,GAAG;AACjC,eAAO,QAAQ,KAAK,KAAK,SAAS,IAAI;AAAA,MACxC,OAAO;AACL,eAAO,QAAQ,KAAK,cAAc;AAAA,MACpC;AAAA,IACF,WAAa,iBAAe,IAAI,GAAG;AACjC,YAAM,WAAa,kBAAgB,KAAK,IAAI,IACxC,KAAK,KAAK,OACV,GAAG,KAAK,KAAK,UAAU,IAAI,IAAI,KAAK,KAAK,KAAK,IAAI;AAEtD,YAAM,QAAQ,KAAK;AAEnB,UAAI,UAAU,MAAM;AAElB,eAAO,OAAO,QAAQ,IAAI;AAAA,MAC5B,WAAa,kBAAgB,KAAK,GAAG;AAEnC,eAAO,OAAO,QAAQ,IAAI,MAAM;AAAA,MAClC,WAAa,2BAAyB,KAAK,GAAG;AAC5C,cAAM,OAAO,MAAM;AAEnB,YAAM,kBAAgB,IAAI,GAAG;AAC3B,iBAAO,OAAO,QAAQ,IAAI,KAAK;AAAA,QACjC,WAAa,mBAAiB,IAAI,GAAG;AACnC,iBAAO,OAAO,QAAQ,IAAI,KAAK;AAAA,QACjC,WAAa,mBAAiB,IAAI,GAAG;AACnC,iBAAO,OAAO,QAAQ,IAAI,KAAK;AAAA,QACjC,WAAa,oBAAkB,IAAI,KAAK,KAAK,YAAY,WAAW,GAAG;AAErE,iBAAO,OAAO,QAAQ,IAAI,KAAK,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,EAAE,KAAK,EAAE;AAAA,QACvE,OAAO;AAEL,iBAAO,QAAQ,KAAK,QAAQ;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,gBACP,OACA,YACA,QACQ;AACR,QAAM,QAAQ,KAAK,IAAI,GAAG,aAAa,MAAM;AAC7C,QAAM,MAAM,KAAK,IAAI,MAAM,QAAQ,aAAa,SAAS,CAAC;AAC1D,SAAO,MAAM,MAAM,OAAO,GAAG,EAAE,KAAK,IAAI;AAC1C;AAKA,SAAS,mBAAmB,MAAoD;AAC9E,MAAI,UAAiC,KAAK;AAE1C,SAAO,SAAS;AAEd,QACE,QAAQ,oBAAoB,KAC5B,QAAQ,KAAK,aAAa,MAC1B;AACA,aAAO;AAAA,IACT;AAGA,QAAI,QAAQ,wBAAwB,GAAG;AACrC,aAAO;AAAA,IACT;AAGA,QACE,QAAQ,yBAAyB,KACjC,QAAQ,YAAY,aAAa,GACjC;AACA,YAAM,OAAO,QAAQ,KAAK;AAC1B,UACI,sBAAoB,IAAI,KACxB,0BAAwB,IAAI,GAC9B;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAEA,cAAU,QAAQ;AAAA,EACpB;AAEA,SAAO;AACT;AAKA,SAAS,qBACP,MACoB;AACpB,MAAI,UAAiC,KAAK;AAC1C,QAAM,qBAAqB,kBAAkB,KAAK,KAAK,IAAI;AAE3D,SAAO,SAAS;AACd,QAAI,QAAQ,aAAa,GAAG;AAC1B,YAAM,UAAU,QAAQ,KAAK;AAC7B,YAAM,OAAO,kBAAkB,QAAQ,IAAI;AAC3C,UAAI,QAAQ,SAAS,oBAAoB;AACvC,eAAO;AAAA,MACT;AAAA,IACF;AACA,cAAU,QAAQ;AAAA,EACpB;AAEA,SAAO;AACT;","names":[]}
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
createComponentExtractor
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import {
|
|
6
|
-
generateContextMd,
|
|
7
|
-
generateRegistry,
|
|
8
|
-
loadFragmentFile,
|
|
9
|
-
parseFragmentFile
|
|
10
|
-
} from "./chunk-55KERLWL.js";
|
|
4
|
+
} from "./chunk-MN3TJ3D5.js";
|
|
11
5
|
import {
|
|
12
6
|
discoverBlockFiles,
|
|
13
7
|
discoverComponentFiles,
|
|
14
8
|
discoverFragmentFiles,
|
|
15
9
|
discoverTokenFiles,
|
|
16
|
-
extractComponentName
|
|
17
|
-
|
|
10
|
+
extractComponentName,
|
|
11
|
+
generateContextMd,
|
|
12
|
+
generateRegistry,
|
|
13
|
+
loadFragmentFile,
|
|
14
|
+
parseFragmentFile
|
|
15
|
+
} from "./chunk-65WSVDV5.js";
|
|
18
16
|
import {
|
|
19
17
|
BrowserPool,
|
|
20
18
|
CaptureEngine,
|
|
@@ -24,16 +22,20 @@ import {
|
|
|
24
22
|
formatMs,
|
|
25
23
|
generateHtmlReport,
|
|
26
24
|
getGrade
|
|
27
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-XJQ5BIWI.js";
|
|
28
26
|
import {
|
|
29
27
|
BRAND,
|
|
30
28
|
DEFAULTS,
|
|
31
29
|
classifyComplexity,
|
|
32
30
|
compileBlock,
|
|
33
31
|
fragmentDefinitionSchema,
|
|
32
|
+
isContractFile,
|
|
33
|
+
isDTCGFile,
|
|
34
|
+
parseComponentContract,
|
|
35
|
+
parseDTCGFile,
|
|
34
36
|
parseTokenFile,
|
|
35
37
|
resolvePerformanceConfig
|
|
36
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-32LIWN2P.js";
|
|
37
39
|
|
|
38
40
|
// src/service/snippet-validation.ts
|
|
39
41
|
import ts from "typescript";
|
|
@@ -369,8 +371,10 @@ function sortAndFilterBatch(files, componentStart, componentLimit) {
|
|
|
369
371
|
const getComponentName = (relativePath) => {
|
|
370
372
|
const normalized = relativePath.replace(/\\/g, "/");
|
|
371
373
|
const fileName = normalized.split("/").pop() ?? normalized;
|
|
372
|
-
|
|
373
|
-
|
|
374
|
+
for (const ext of [BRAND.fileExtension, ".fragment.tsx", ".fragment.ts"]) {
|
|
375
|
+
if (fileName.endsWith(ext)) {
|
|
376
|
+
return fileName.slice(0, -ext.length);
|
|
377
|
+
}
|
|
374
378
|
}
|
|
375
379
|
return extractComponentName(relativePath);
|
|
376
380
|
};
|
|
@@ -428,7 +432,9 @@ async function validateSnippetPolicy(config, configDir, options = {}) {
|
|
|
428
432
|
const policy = normalizePolicy(config.snippets, options);
|
|
429
433
|
const issues = [];
|
|
430
434
|
const discovered = await discoverFragmentFiles(config, configDir);
|
|
431
|
-
const fragmentFiles = discovered.filter(
|
|
435
|
+
const fragmentFiles = discovered.filter(
|
|
436
|
+
(file) => file.relativePath.endsWith(".fragment.tsx") || file.relativePath.endsWith(".fragment.ts")
|
|
437
|
+
);
|
|
432
438
|
const batchResult = sortAndFilterBatch(fragmentFiles, policy.componentStart, policy.componentLimit);
|
|
433
439
|
if (batchResult.warning) {
|
|
434
440
|
issues.push({ file: "snippets", message: batchResult.warning });
|
|
@@ -886,6 +892,111 @@ function findVariablesFile(tokensDir) {
|
|
|
886
892
|
return null;
|
|
887
893
|
}
|
|
888
894
|
|
|
895
|
+
// src/core/extractor-adapter.ts
|
|
896
|
+
var ReactExtractorAdapter = class {
|
|
897
|
+
extractor;
|
|
898
|
+
verificationLevel = "full";
|
|
899
|
+
constructor(tsconfigPath) {
|
|
900
|
+
this.extractor = createComponentExtractor(tsconfigPath);
|
|
901
|
+
}
|
|
902
|
+
canHandle(framework) {
|
|
903
|
+
return framework === "react";
|
|
904
|
+
}
|
|
905
|
+
extract(sourcePath, exportName) {
|
|
906
|
+
return this.extractor.extract(sourcePath, exportName);
|
|
907
|
+
}
|
|
908
|
+
dispose() {
|
|
909
|
+
this.extractor.dispose();
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
var NoopExtractorAdapter = class {
|
|
913
|
+
verificationLevel = "none";
|
|
914
|
+
canHandle() {
|
|
915
|
+
return true;
|
|
916
|
+
}
|
|
917
|
+
extract() {
|
|
918
|
+
return null;
|
|
919
|
+
}
|
|
920
|
+
dispose() {
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
function createExtractorAdapter(framework, tsconfigPath) {
|
|
924
|
+
if (framework === "react") {
|
|
925
|
+
return new ReactExtractorAdapter(tsconfigPath);
|
|
926
|
+
}
|
|
927
|
+
return new NoopExtractorAdapter();
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
// src/core/drift-verifier.ts
|
|
931
|
+
function verifyContractDrift(contract, extracted) {
|
|
932
|
+
const contractPropNames = new Set(Object.keys(contract.props));
|
|
933
|
+
const sourcePropNames = new Set(
|
|
934
|
+
Object.entries(extracted.props).filter(([, p]) => p.source === "local").map(([name]) => name)
|
|
935
|
+
);
|
|
936
|
+
const removedProps = [];
|
|
937
|
+
const undocumentedProps = [];
|
|
938
|
+
const typeMismatches = [];
|
|
939
|
+
const defaultMismatches = [];
|
|
940
|
+
for (const name of contractPropNames) {
|
|
941
|
+
if (!sourcePropNames.has(name)) {
|
|
942
|
+
removedProps.push(name);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
for (const name of sourcePropNames) {
|
|
946
|
+
if (!contractPropNames.has(name)) {
|
|
947
|
+
undocumentedProps.push(name);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
for (const name of contractPropNames) {
|
|
951
|
+
const contractProp = contract.props[name];
|
|
952
|
+
const sourceProp = extracted.props[name];
|
|
953
|
+
if (!sourceProp || sourceProp.source !== "local") continue;
|
|
954
|
+
if (contractProp.type !== sourceProp.typeKind) {
|
|
955
|
+
typeMismatches.push({
|
|
956
|
+
prop: name,
|
|
957
|
+
contract: contractProp.type,
|
|
958
|
+
source: sourceProp.typeKind
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
const contractDefault = contractProp.default;
|
|
962
|
+
const sourceDefault = sourceProp.default;
|
|
963
|
+
if (contractDefault !== void 0 && sourceDefault !== void 0) {
|
|
964
|
+
if (String(contractDefault) !== String(sourceDefault)) {
|
|
965
|
+
defaultMismatches.push({
|
|
966
|
+
prop: name,
|
|
967
|
+
contract: contractDefault,
|
|
968
|
+
source: sourceDefault
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
const isClean = removedProps.length === 0 && undocumentedProps.length === 0 && typeMismatches.length === 0 && defaultMismatches.length === 0;
|
|
974
|
+
return {
|
|
975
|
+
componentName: contract.meta.name,
|
|
976
|
+
removedProps,
|
|
977
|
+
undocumentedProps,
|
|
978
|
+
typeMismatches,
|
|
979
|
+
defaultMismatches,
|
|
980
|
+
isClean
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
function formatDriftReport(report2) {
|
|
984
|
+
const lines = [`Drift detected for ${report2.componentName}:`];
|
|
985
|
+
if (report2.removedProps.length > 0) {
|
|
986
|
+
lines.push(` Removed from source: ${report2.removedProps.join(", ")}`);
|
|
987
|
+
}
|
|
988
|
+
if (report2.undocumentedProps.length > 0) {
|
|
989
|
+
lines.push(` Missing from contract: ${report2.undocumentedProps.join(", ")}`);
|
|
990
|
+
}
|
|
991
|
+
for (const m of report2.typeMismatches) {
|
|
992
|
+
lines.push(` Type mismatch: ${m.prop} (contract: ${m.contract}, source: ${m.source})`);
|
|
993
|
+
}
|
|
994
|
+
for (const m of report2.defaultMismatches) {
|
|
995
|
+
lines.push(` Default mismatch: ${m.prop} (contract: ${String(m.contract)}, source: ${String(m.source)})`);
|
|
996
|
+
}
|
|
997
|
+
return lines.join("\n");
|
|
998
|
+
}
|
|
999
|
+
|
|
889
1000
|
// src/core/graph-extractor.ts
|
|
890
1001
|
import ts3 from "typescript";
|
|
891
1002
|
import { readFileSync, existsSync as existsSync4 } from "fs";
|
|
@@ -1573,6 +1684,7 @@ async function buildFragments(config, configDir) {
|
|
|
1573
1684
|
const errors = [];
|
|
1574
1685
|
const warnings = [];
|
|
1575
1686
|
const fragments = {};
|
|
1687
|
+
const contractSourcedNames = /* @__PURE__ */ new Set();
|
|
1576
1688
|
const tsconfigCandidates = [
|
|
1577
1689
|
resolve5(configDir, "tsconfig.json"),
|
|
1578
1690
|
resolve5(configDir, "..", "tsconfig.json")
|
|
@@ -1582,6 +1694,86 @@ async function buildFragments(config, configDir) {
|
|
|
1582
1694
|
for (const file of files) {
|
|
1583
1695
|
try {
|
|
1584
1696
|
const content = await readFile3(file.absolutePath, "utf-8");
|
|
1697
|
+
if (isContractFile(file.absolutePath)) {
|
|
1698
|
+
try {
|
|
1699
|
+
const parsed2 = parseComponentContract(content, file.relativePath);
|
|
1700
|
+
const framework = parsed2.framework ?? config.framework ?? "react";
|
|
1701
|
+
const contractAdapter = createExtractorAdapter(framework, tsconfigPath);
|
|
1702
|
+
let extractedMeta2 = null;
|
|
1703
|
+
if (parsed2.sourcePath && parsed2.exportName && contractAdapter.canHandle(framework)) {
|
|
1704
|
+
try {
|
|
1705
|
+
const absSourcePath = resolve5(configDir, parsed2.sourcePath);
|
|
1706
|
+
extractedMeta2 = contractAdapter.extract(absSourcePath, parsed2.exportName);
|
|
1707
|
+
} catch {
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
let mergedProps2 = parsed2.props;
|
|
1711
|
+
if (extractedMeta2 && Object.keys(extractedMeta2.props).length > 0) {
|
|
1712
|
+
mergedProps2 = mergeDocumentedAndAutoProps(mergedProps2, extractedMeta2.props);
|
|
1713
|
+
}
|
|
1714
|
+
let contractPropsSummary = parsed2.propsSummary;
|
|
1715
|
+
if ((!contractPropsSummary || contractPropsSummary.length === 0) && extractedMeta2) {
|
|
1716
|
+
contractPropsSummary = compilePropsSummary(extractedMeta2.props);
|
|
1717
|
+
}
|
|
1718
|
+
let ai2 = parsed2.ai;
|
|
1719
|
+
if (extractedMeta2?.composition) {
|
|
1720
|
+
const comp = extractedMeta2.composition;
|
|
1721
|
+
ai2 = {
|
|
1722
|
+
compositionPattern: comp.pattern,
|
|
1723
|
+
subComponents: comp.parts.map((p) => p.name),
|
|
1724
|
+
...ai2
|
|
1725
|
+
};
|
|
1726
|
+
}
|
|
1727
|
+
if (parsed2.provenance?.verified && extractedMeta2) {
|
|
1728
|
+
const drift = verifyContractDrift(parsed2, extractedMeta2);
|
|
1729
|
+
if (!drift.isClean) {
|
|
1730
|
+
errors.push({
|
|
1731
|
+
file: file.relativePath,
|
|
1732
|
+
error: formatDriftReport(drift)
|
|
1733
|
+
});
|
|
1734
|
+
contractAdapter.dispose();
|
|
1735
|
+
continue;
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
const compiled2 = {
|
|
1739
|
+
filePath: file.relativePath,
|
|
1740
|
+
meta: {
|
|
1741
|
+
name: parsed2.meta.name,
|
|
1742
|
+
description: parsed2.meta.description,
|
|
1743
|
+
category: parsed2.meta.category,
|
|
1744
|
+
tags: parsed2.meta.tags,
|
|
1745
|
+
status: parsed2.meta.status,
|
|
1746
|
+
figma: parsed2.meta.figma
|
|
1747
|
+
},
|
|
1748
|
+
usage: parsed2.usage,
|
|
1749
|
+
props: mergedProps2,
|
|
1750
|
+
relations: parsed2.relations,
|
|
1751
|
+
variants: parsed2.variants,
|
|
1752
|
+
...parsed2.contract && { contract: parsed2.contract },
|
|
1753
|
+
...ai2 && { ai: ai2 },
|
|
1754
|
+
framework: parsed2.framework,
|
|
1755
|
+
propsSummary: contractPropsSummary,
|
|
1756
|
+
sourcePath: parsed2.sourcePath,
|
|
1757
|
+
exportName: parsed2.exportName,
|
|
1758
|
+
provenance: parsed2.provenance
|
|
1759
|
+
};
|
|
1760
|
+
fragments[compiled2.meta.name] = compiled2;
|
|
1761
|
+
contractSourcedNames.add(compiled2.meta.name);
|
|
1762
|
+
contractAdapter.dispose();
|
|
1763
|
+
} catch (error) {
|
|
1764
|
+
errors.push({
|
|
1765
|
+
file: file.relativePath,
|
|
1766
|
+
error: `Contract parse error: ${error instanceof Error ? error.message : String(error)}`
|
|
1767
|
+
});
|
|
1768
|
+
}
|
|
1769
|
+
continue;
|
|
1770
|
+
}
|
|
1771
|
+
if (file.absolutePath.endsWith(".fragment.tsx") || file.absolutePath.endsWith(".fragment.ts")) {
|
|
1772
|
+
warnings.push({
|
|
1773
|
+
file: file.relativePath,
|
|
1774
|
+
warning: "Deprecated format: .fragment.tsx \u2014 run `fragments migrate-contract` to generate .contract.json"
|
|
1775
|
+
});
|
|
1776
|
+
}
|
|
1585
1777
|
if (!content.includes("defineFragment")) {
|
|
1586
1778
|
warnings.push({
|
|
1587
1779
|
file: file.relativePath,
|
|
@@ -1696,9 +1888,21 @@ async function buildFragments(config, configDir) {
|
|
|
1696
1888
|
// Include AI metadata (auto-enriched or manual)
|
|
1697
1889
|
...ai && { ai },
|
|
1698
1890
|
// Include contract metadata (auto-compiled or manual)
|
|
1699
|
-
...contract && { contract }
|
|
1891
|
+
...contract && { contract },
|
|
1892
|
+
// Provenance from TSX path
|
|
1893
|
+
provenance: {
|
|
1894
|
+
source: extractedMeta ? "extracted" : "manual",
|
|
1895
|
+
verified: !!extractedMeta
|
|
1896
|
+
}
|
|
1700
1897
|
};
|
|
1701
|
-
|
|
1898
|
+
if (contractSourcedNames.has(parsed.meta.name)) {
|
|
1899
|
+
warnings.push({
|
|
1900
|
+
file: file.relativePath,
|
|
1901
|
+
warning: `Duplicate: "${parsed.meta.name}" already loaded from .contract.json \u2014 skipping .fragment.tsx`
|
|
1902
|
+
});
|
|
1903
|
+
} else {
|
|
1904
|
+
fragments[parsed.meta.name] = compiled;
|
|
1905
|
+
}
|
|
1702
1906
|
} catch (error) {
|
|
1703
1907
|
errors.push({
|
|
1704
1908
|
file: file.relativePath,
|
|
@@ -1745,8 +1949,15 @@ async function buildFragments(config, configDir) {
|
|
|
1745
1949
|
}
|
|
1746
1950
|
const allContent = fileContents.map((f) => f.content).join("\n");
|
|
1747
1951
|
for (const { content, path } of fileContents) {
|
|
1748
|
-
|
|
1749
|
-
|
|
1952
|
+
let fileParsed;
|
|
1953
|
+
let parsed;
|
|
1954
|
+
if (isDTCGFile(path)) {
|
|
1955
|
+
fileParsed = parseDTCGFile(content, path);
|
|
1956
|
+
parsed = fileParsed;
|
|
1957
|
+
} else {
|
|
1958
|
+
parsed = parseTokenFile(allContent, path);
|
|
1959
|
+
fileParsed = parseTokenFile(content, path);
|
|
1960
|
+
}
|
|
1750
1961
|
prefix = fileParsed.prefix;
|
|
1751
1962
|
total += fileParsed.total;
|
|
1752
1963
|
for (const [cat, catTokens] of Object.entries(fileParsed.categories)) {
|
|
@@ -2450,4 +2661,4 @@ export {
|
|
|
2450
2661
|
runDiffCommand,
|
|
2451
2662
|
runAnalyzeCommand
|
|
2452
2663
|
};
|
|
2453
|
-
//# sourceMappingURL=chunk-
|
|
2664
|
+
//# sourceMappingURL=chunk-7WHVW72L.js.map
|