@fragments-sdk/cli 0.5.2 → 0.6.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 (118) hide show
  1. package/dist/bin.js +712 -39
  2. package/dist/bin.js.map +1 -1
  3. package/dist/{chunk-ICAIQ57V.js → chunk-6JBGU74P.js} +5 -3
  4. package/dist/chunk-6JBGU74P.js.map +1 -0
  5. package/dist/{chunk-U4GQ2JTD.js → chunk-D35RGPAG.js} +412 -35
  6. package/dist/chunk-D35RGPAG.js.map +1 -0
  7. package/dist/{chunk-XNWDI6UT.js → chunk-F7ITZPDJ.js} +5 -5
  8. package/dist/{chunk-IOJE35DZ.js → chunk-NWQ4CJOQ.js} +3 -3
  9. package/dist/{chunk-V7YLRR4C.js → chunk-Q7GOHVOK.js} +3 -3
  10. package/dist/{chunk-2DJH4F4P.js → chunk-RVRTRESS.js} +3 -3
  11. package/dist/{chunk-2H2JAA3U.js → chunk-SSLQXHNX.js} +3 -3
  12. package/dist/{core-DKHB7FYV.js → core-SKRPJQZG.js} +4 -4
  13. package/dist/{generate-KL24VZVD.js → generate-7AF7WRVK.js} +5 -5
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.js +15 -7
  16. package/dist/index.js.map +1 -1
  17. package/dist/{init-NION5S3M.js → init-WKGDPYI4.js} +5 -5
  18. package/dist/mcp-bin.js +8 -220
  19. package/dist/mcp-bin.js.map +1 -1
  20. package/dist/scan-K6JNMCGM.js +12 -0
  21. package/dist/{service-RWUMZ3EW.js → service-F3E4JJM7.js} +5 -5
  22. package/dist/static-viewer-4LQZ5AGA.js +12 -0
  23. package/dist/{test-ECPEXFDN.js → test-CJDNJTPZ.js} +4 -4
  24. package/dist/{tokens-ITADYVPF.js → tokens-JAJABYXP.js} +6 -6
  25. package/dist/viewer-R3Q6WAMJ.js +1822 -0
  26. package/dist/viewer-R3Q6WAMJ.js.map +1 -0
  27. package/package.json +5 -4
  28. package/src/bin.ts +8 -0
  29. package/src/build.ts +104 -13
  30. package/src/cli-commands.ts +18 -0
  31. package/src/commands/__tests__/a11y-scoring.test.ts +278 -0
  32. package/src/commands/a11y-report.ts +625 -0
  33. package/src/commands/a11y.ts +168 -14
  34. package/src/commands/build.ts +16 -0
  35. package/src/core/auto-props.ts +464 -0
  36. package/src/core/schema.ts +2 -0
  37. package/src/core/types.ts +3 -1
  38. package/src/index.ts +4 -0
  39. package/src/mcp/server.ts +13 -220
  40. package/src/theme/__tests__/component-contrast.test.ts +338 -0
  41. package/src/theme/__tests__/contrast-validation.test.ts +326 -0
  42. package/src/theme/contrast.test.ts +331 -0
  43. package/src/theme/contrast.ts +246 -0
  44. package/src/theme/generator.ts +213 -1
  45. package/src/theme/index.ts +16 -0
  46. package/src/theme/types.ts +51 -0
  47. package/src/viewer/__tests__/a11y-fixes.test.ts +358 -0
  48. package/src/viewer/__tests__/viewer-integration.test.ts +2 -7
  49. package/src/viewer/components/AccessibilityPanel.tsx +493 -433
  50. package/src/viewer/components/ActionCapture.tsx +1 -1
  51. package/src/viewer/components/ActionsPanel.tsx +142 -183
  52. package/src/viewer/components/App.tsx +159 -164
  53. package/src/viewer/components/BottomPanel.tsx +40 -80
  54. package/src/viewer/components/CodePanel.tsx +9 -87
  55. package/src/viewer/components/CommandPalette.tsx +117 -74
  56. package/src/viewer/components/ComponentGraph.tsx +143 -126
  57. package/src/viewer/components/ComponentHeader.tsx +46 -43
  58. package/src/viewer/components/ContractPanel.tsx +124 -117
  59. package/src/viewer/components/ErrorBoundary.tsx +47 -35
  60. package/src/viewer/components/FigmaEmbed.tsx +18 -13
  61. package/src/viewer/components/FragmentEditor.tsx +126 -63
  62. package/src/viewer/components/HealthDashboard.tsx +146 -171
  63. package/src/viewer/components/HmrStatusIndicator.tsx +31 -41
  64. package/src/viewer/components/Icons.tsx +99 -98
  65. package/src/viewer/components/InteractionsPanel.tsx +317 -264
  66. package/src/viewer/components/IsolatedPreviewFrame.tsx +52 -27
  67. package/src/viewer/components/IsolatedRender.tsx +12 -6
  68. package/src/viewer/components/KeyboardShortcutsHelp.tsx +34 -70
  69. package/src/viewer/components/LandingPage.tsx +285 -305
  70. package/src/viewer/components/Layout.tsx +7 -9
  71. package/src/viewer/components/LeftSidebar.tsx +78 -108
  72. package/src/viewer/components/MultiViewportPreview.tsx +254 -63
  73. package/src/viewer/components/PreviewArea.tsx +113 -44
  74. package/src/viewer/components/PreviewFrameHost.tsx +6 -5
  75. package/src/viewer/components/PreviewPane.tsx +2 -3
  76. package/src/viewer/components/PreviewToolbar.tsx +61 -104
  77. package/src/viewer/components/PropsEditor.tsx +154 -74
  78. package/src/viewer/components/PropsTable.tsx +95 -82
  79. package/src/viewer/components/RelationsSection.tsx +71 -40
  80. package/src/viewer/components/ResizablePanel.tsx +158 -55
  81. package/src/viewer/components/RightSidebar.tsx +46 -56
  82. package/src/viewer/components/ScreenshotButton.tsx +12 -12
  83. package/src/viewer/components/SkeletonLoader.tsx +99 -83
  84. package/src/viewer/components/StoryRenderer.tsx +4 -11
  85. package/src/viewer/components/Toast.tsx +3 -67
  86. package/src/viewer/components/TokenStylePanel.tsx +136 -118
  87. package/src/viewer/components/UsageSection.tsx +26 -26
  88. package/src/viewer/components/VariantMatrix.tsx +140 -47
  89. package/src/viewer/components/VariantTabs.tsx +24 -68
  90. package/src/viewer/components/ViewportSelector.tsx +106 -110
  91. package/src/viewer/constants/ui.ts +19 -18
  92. package/src/viewer/entry.tsx +8 -3
  93. package/src/viewer/index.ts +3 -6
  94. package/src/viewer/preview-frame.html +21 -5
  95. package/src/viewer/server.ts +7 -16
  96. package/src/viewer/styles/globals.css +4 -4
  97. package/src/viewer/utils/a11y-fixes.ts +53 -30
  98. package/dist/chunk-ICAIQ57V.js.map +0 -1
  99. package/dist/chunk-U4GQ2JTD.js.map +0 -1
  100. package/dist/scan-ESEXV7LF.js +0 -12
  101. package/dist/static-viewer-O37MJ5B6.js +0 -12
  102. package/dist/viewer-YDGFDTK5.js +0 -11104
  103. package/dist/viewer-YDGFDTK5.js.map +0 -1
  104. package/src/viewer/postcss.config.js +0 -6
  105. package/src/viewer/tailwind.config.js +0 -37
  106. /package/dist/{chunk-XNWDI6UT.js.map → chunk-F7ITZPDJ.js.map} +0 -0
  107. /package/dist/{chunk-IOJE35DZ.js.map → chunk-NWQ4CJOQ.js.map} +0 -0
  108. /package/dist/{chunk-V7YLRR4C.js.map → chunk-Q7GOHVOK.js.map} +0 -0
  109. /package/dist/{chunk-2DJH4F4P.js.map → chunk-RVRTRESS.js.map} +0 -0
  110. /package/dist/{chunk-2H2JAA3U.js.map → chunk-SSLQXHNX.js.map} +0 -0
  111. /package/dist/{core-DKHB7FYV.js.map → core-SKRPJQZG.js.map} +0 -0
  112. /package/dist/{generate-KL24VZVD.js.map → generate-7AF7WRVK.js.map} +0 -0
  113. /package/dist/{init-NION5S3M.js.map → init-WKGDPYI4.js.map} +0 -0
  114. /package/dist/{scan-ESEXV7LF.js.map → scan-K6JNMCGM.js.map} +0 -0
  115. /package/dist/{service-RWUMZ3EW.js.map → service-F3E4JJM7.js.map} +0 -0
  116. /package/dist/{static-viewer-O37MJ5B6.js.map → static-viewer-4LQZ5AGA.js.map} +0 -0
  117. /package/dist/{test-ECPEXFDN.js.map → test-CJDNJTPZ.js.map} +0 -0
  118. /package/dist/{tokens-ITADYVPF.js.map → tokens-JAJABYXP.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- import { createRequire } from 'module'; const require = createRequire(import.meta.url);
1
+ import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
2
2
 
3
3
  // src/core/constants.ts
4
4
  var BRAND = {
@@ -152,7 +152,9 @@ var relationshipTypeSchema = z.enum([
152
152
  "sibling",
153
153
  "parent",
154
154
  "child",
155
- "composition"
155
+ "composition",
156
+ "complementary",
157
+ "used-by"
156
158
  ]);
157
159
  var componentRelationSchema = z.object({
158
160
  component: z.string().min(1),
@@ -244,4 +246,4 @@ export {
244
246
  segmentsConfigSchema,
245
247
  recipeDefinitionSchema
246
248
  };
247
- //# sourceMappingURL=chunk-ICAIQ57V.js.map
249
+ //# sourceMappingURL=chunk-6JBGU74P.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/constants.ts","../src/core/schema.ts"],"sourcesContent":["/**\n * Brand constants for easy rebranding if domain availability requires it.\n * All naming throughout the codebase should reference these constants.\n */\nexport const BRAND = {\n /** Display name (e.g., \"Fragments\") */\n name: \"Fragments\",\n\n /** Lowercase name for file paths and CLI (e.g., \"fragments\") */\n nameLower: \"fragments\",\n\n /** File extension for fragment definition files (e.g., \".fragment.tsx\") */\n fileExtension: \".fragment.tsx\",\n\n /** Legacy file extension for segments (still supported for migration) */\n legacyFileExtension: \".segment.tsx\",\n\n /** JSON file extension for compiled output */\n jsonExtension: \".fragment.json\",\n\n /** Default output file name (e.g., \"fragments.json\") */\n outFile: \"fragments.json\",\n\n /** Config file name (e.g., \"fragments.config.ts\") */\n configFile: \"fragments.config.ts\",\n\n /** Legacy config file name (still supported for migration) */\n legacyConfigFile: \"segments.config.ts\",\n\n /** CLI command name (e.g., \"fragments\") */\n cliCommand: \"fragments\",\n\n /** Package scope (e.g., \"@fragments\") */\n packageScope: \"@fragments\",\n\n /** Directory for storing fragments, registry, and cache */\n dataDir: \".fragments\",\n\n /** Components subdirectory within .fragments/ */\n componentsDir: \"components\",\n\n /** Registry file name */\n registryFile: \"registry.json\",\n\n /** Context file name (AI-ready markdown) */\n contextFile: \"context.md\",\n\n /** Screenshots subdirectory */\n screenshotsDir: \"screenshots\",\n\n /** Cache subdirectory (gitignored) */\n cacheDir: \"cache\",\n\n /** Diff output subdirectory (gitignored) */\n diffDir: \"diff\",\n\n /** Manifest filename */\n manifestFile: \"manifest.json\",\n\n /** Prefix for localStorage keys (e.g., \"fragments-\") */\n storagePrefix: \"fragments-\",\n\n /** Static viewer HTML file name */\n viewerHtmlFile: \"fragments-viewer.html\",\n\n /** MCP tool name prefix (e.g., \"fragments_\") */\n mcpToolPrefix: \"fragments_\",\n\n /** File extension for block definition files */\n blockFileExtension: \".block.ts\",\n\n /** @deprecated Use blockFileExtension instead */\n recipeFileExtension: \".recipe.ts\",\n\n /** Vite plugin namespace */\n vitePluginNamespace: \"fragments-core-shim\",\n} as const;\n\nexport type Brand = typeof BRAND;\n\n/**\n * Default configuration values for the service.\n * These can be overridden in fragments.config.ts\n */\nexport const DEFAULTS = {\n /** Default viewport dimensions */\n viewport: {\n width: 1280,\n height: 800,\n },\n\n /** Default diff threshold (percentage) */\n diffThreshold: 5,\n\n /** Browser pool size */\n poolSize: 3,\n\n /** Idle timeout before browser shutdown (ms) - 5 minutes */\n idleTimeoutMs: 5 * 60 * 1000,\n\n /** Delay after render before capture (ms) */\n captureDelayMs: 100,\n\n /** Font loading timeout (ms) */\n fontTimeoutMs: 3000,\n\n /** Default theme */\n theme: \"light\" as const,\n\n /** Dev server port */\n port: 6006,\n} as const;\n\nexport type Defaults = typeof DEFAULTS;\n","import { z } from 'zod';\n\n/**\n * Zod schemas for runtime validation of segment definitions\n */\n\n// Figma property mapping schemas\nconst figmaStringMappingSchema = z.object({\n __type: z.literal('figma-string'),\n figmaProperty: z.string().min(1),\n});\n\nconst figmaBooleanMappingSchema = z.object({\n __type: z.literal('figma-boolean'),\n figmaProperty: z.string().min(1),\n valueMapping: z.object({ true: z.unknown(), false: z.unknown() }).optional(),\n});\n\nconst figmaEnumMappingSchema = z.object({\n __type: z.literal('figma-enum'),\n figmaProperty: z.string().min(1),\n valueMapping: z.record(z.unknown()),\n});\n\nconst figmaInstanceMappingSchema = z.object({\n __type: z.literal('figma-instance'),\n figmaProperty: z.string().min(1),\n});\n\nconst figmaChildrenMappingSchema = z.object({\n __type: z.literal('figma-children'),\n layers: z.array(z.string().min(1)),\n});\n\nconst figmaTextContentMappingSchema = z.object({\n __type: z.literal('figma-text-content'),\n layer: z.string().min(1),\n});\n\nexport const figmaPropMappingSchema = z.discriminatedUnion('__type', [\n figmaStringMappingSchema,\n figmaBooleanMappingSchema,\n figmaEnumMappingSchema,\n figmaInstanceMappingSchema,\n figmaChildrenMappingSchema,\n figmaTextContentMappingSchema,\n]);\n\nexport const segmentMetaSchema = z.object({\n name: z.string().min(1),\n description: z.string().min(1),\n category: z.string().min(1),\n tags: z.array(z.string()).optional(),\n status: z.enum(['stable', 'beta', 'deprecated', 'experimental']).optional(),\n since: z.string().optional(),\n figma: z.string().url().optional(),\n figmaProps: z.record(figmaPropMappingSchema).optional(),\n});\n\nexport const segmentUsageSchema = z.object({\n when: z.array(z.string()).min(1),\n whenNot: z.array(z.string()).min(1),\n guidelines: z.array(z.string()).optional(),\n accessibility: z.array(z.string()).optional(),\n});\n\nexport const propTypeSchema: z.ZodType<string> = z.enum([\n 'string',\n 'number',\n 'boolean',\n 'enum',\n 'function',\n 'node',\n 'element',\n 'object',\n 'array',\n 'union',\n 'custom',\n]);\n\nexport const propDefinitionSchema = z.object({\n type: propTypeSchema,\n values: z.array(z.string()).readonly().optional(),\n default: z.unknown().optional(),\n description: z.string().optional(),\n required: z.boolean().optional(),\n constraints: z.array(z.string()).optional(),\n typeDetails: z.record(z.unknown()).optional(),\n});\n\nexport const relationshipTypeSchema = z.enum([\n 'alternative',\n 'sibling',\n 'parent',\n 'child',\n 'composition',\n 'complementary',\n 'used-by',\n]);\n\nexport const componentRelationSchema = z.object({\n component: z.string().min(1),\n relationship: relationshipTypeSchema,\n note: z.string().min(1),\n});\n\nexport const segmentVariantSchema = z.object({\n name: z.string().min(1),\n description: z.string().min(1),\n render: z.function().returns(z.unknown()),\n code: z.string().optional(),\n figma: z.string().url().optional(),\n});\n\n/**\n * Schema for banned patterns in codebase\n */\nexport const segmentBanSchema = z.object({\n pattern: z.string().min(1),\n message: z.string().min(1),\n});\n\n/**\n * Schema for agent-optimized contract metadata\n */\nexport const segmentContractSchema = z.object({\n propsSummary: z.array(z.string()).optional(),\n a11yRules: z.array(z.string()).optional(),\n bans: z.array(segmentBanSchema).optional(),\n scenarioTags: z.array(z.string()).optional(),\n});\n\n/**\n * Schema for provenance tracking of generated segments\n */\nexport const segmentGeneratedSchema = z.object({\n source: z.enum(['storybook', 'manual', 'ai']),\n sourceFile: z.string().optional(),\n confidence: z.number().min(0).max(1).optional(),\n timestamp: z.string().datetime().optional(),\n});\n\n/**\n * Schema for AI-specific metadata for playground context generation\n */\nexport const aiMetadataSchema = z.object({\n compositionPattern: z.enum(['compound', 'simple', 'controlled']).optional(),\n subComponents: z.array(z.string()).optional(),\n requiredChildren: z.array(z.string()).optional(),\n commonPatterns: z.array(z.string()).optional(),\n});\n\n/**\n * Schema for block definitions\n */\nexport const blockDefinitionSchema = z.object({\n name: z.string().min(1),\n description: z.string().min(1),\n category: z.string().min(1),\n components: z.array(z.string().min(1)).min(1),\n code: z.string().min(1),\n tags: z.array(z.string()).optional(),\n});\n\nexport const segmentDefinitionSchema = z.object({\n component: z.any(), // Allow any component type (function, class, forwardRef, etc.)\n meta: segmentMetaSchema,\n usage: segmentUsageSchema,\n props: z.record(propDefinitionSchema),\n relations: z.array(componentRelationSchema).optional(),\n variants: z.array(segmentVariantSchema), // Allow empty variants array\n contract: segmentContractSchema.optional(),\n ai: aiMetadataSchema.optional(),\n _generated: segmentGeneratedSchema.optional(),\n});\n\n/**\n * Config schema - validates required fields, passes through optional config objects.\n * Type definitions are in types.ts - schema just ensures basic structure.\n */\nexport const segmentsConfigSchema = z.object({\n include: z.array(z.string()).min(1),\n exclude: z.array(z.string()).optional(),\n components: z.array(z.string()).optional(),\n outFile: z.string().optional(),\n framework: z.enum(['react', 'vue', 'svelte']).optional(),\n figmaFile: z.string().url().optional(),\n figmaToken: z.string().optional(),\n screenshots: z.object({}).passthrough().optional(),\n service: z.object({}).passthrough().optional(),\n registry: z.object({}).passthrough().optional(),\n tokens: z.object({\n include: z.array(z.string()).min(1),\n }).passthrough().optional(),\n});\n\n/**\n * @deprecated Use blockDefinitionSchema instead\n */\nexport const recipeDefinitionSchema = blockDefinitionSchema;\n"],"mappings":"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","names":[]}
@@ -1,4 +1,4 @@
1
- import { createRequire } from 'module'; const require = createRequire(import.meta.url);
1
+ import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
2
2
  import {
3
3
  BrowserPool,
4
4
  CaptureEngine,
@@ -8,7 +8,7 @@ import {
8
8
  formatMs,
9
9
  generateHtmlReport,
10
10
  getGrade
11
- } from "./chunk-IOJE35DZ.js";
11
+ } from "./chunk-NWQ4CJOQ.js";
12
12
  import {
13
13
  discoverBlockFiles,
14
14
  discoverComponentFiles,
@@ -19,16 +19,16 @@ import {
19
19
  generateRegistry,
20
20
  loadSegmentFile,
21
21
  parseSegmentFile
22
- } from "./chunk-2H2JAA3U.js";
22
+ } from "./chunk-SSLQXHNX.js";
23
23
  import {
24
24
  compileBlock,
25
25
  parseTokenFile
26
- } from "./chunk-V7YLRR4C.js";
26
+ } from "./chunk-Q7GOHVOK.js";
27
27
  import {
28
28
  BRAND,
29
29
  DEFAULTS,
30
30
  segmentDefinitionSchema
31
- } from "./chunk-ICAIQ57V.js";
31
+ } from "./chunk-6JBGU74P.js";
32
32
 
33
33
  // src/validators.ts
34
34
  async function validateSchema(config, configDir) {
@@ -120,8 +120,350 @@ async function validateAll(config, configDir) {
120
120
 
121
121
  // src/build.ts
122
122
  import { readFile, writeFile, mkdir } from "fs/promises";
123
- import { resolve, join } from "path";
124
- import { existsSync } from "fs";
123
+ import { resolve as resolve2, join as join2 } from "path";
124
+ import { existsSync as existsSync2 } from "fs";
125
+
126
+ // src/core/auto-props.ts
127
+ import { existsSync, statSync } from "fs";
128
+ import { dirname, extname, join, resolve } from "path";
129
+ import ts from "typescript";
130
+ function toPosixPath(filePath) {
131
+ return filePath.replace(/\\/g, "/");
132
+ }
133
+ function isFile(filePath) {
134
+ if (!existsSync(filePath)) return false;
135
+ try {
136
+ return statSync(filePath).isFile();
137
+ } catch {
138
+ return false;
139
+ }
140
+ }
141
+ function resolveModulePath(basePath) {
142
+ const candidates = [];
143
+ const extension = extname(basePath);
144
+ if (extension) {
145
+ candidates.push(basePath);
146
+ } else {
147
+ candidates.push(
148
+ `${basePath}.tsx`,
149
+ `${basePath}.ts`,
150
+ `${basePath}.jsx`,
151
+ `${basePath}.js`,
152
+ join(basePath, "index.tsx"),
153
+ join(basePath, "index.ts"),
154
+ join(basePath, "index.jsx"),
155
+ join(basePath, "index.js")
156
+ );
157
+ }
158
+ for (const candidate of candidates) {
159
+ if (isFile(candidate)) {
160
+ return resolve(candidate);
161
+ }
162
+ }
163
+ return null;
164
+ }
165
+ function resolveComponentSourcePath(segmentFileAbsolutePath, componentImportPath) {
166
+ if (!componentImportPath) return null;
167
+ if (!componentImportPath.startsWith(".")) return null;
168
+ const segmentDir = dirname(segmentFileAbsolutePath);
169
+ const basePath = resolve(segmentDir, componentImportPath);
170
+ return resolveModulePath(basePath);
171
+ }
172
+ function collectTopLevelDeclarations(sourceFile) {
173
+ const typeDeclarations = /* @__PURE__ */ new Map();
174
+ const functionDeclarations = /* @__PURE__ */ new Map();
175
+ const variableDeclarations = /* @__PURE__ */ new Map();
176
+ for (const node of sourceFile.statements) {
177
+ if (ts.isInterfaceDeclaration(node)) {
178
+ typeDeclarations.set(node.name.text, node);
179
+ continue;
180
+ }
181
+ if (ts.isTypeAliasDeclaration(node)) {
182
+ typeDeclarations.set(node.name.text, node);
183
+ continue;
184
+ }
185
+ if (ts.isFunctionDeclaration(node) && node.name) {
186
+ functionDeclarations.set(node.name.text, node);
187
+ continue;
188
+ }
189
+ if (ts.isVariableStatement(node)) {
190
+ for (const declaration of node.declarationList.declarations) {
191
+ if (ts.isIdentifier(declaration.name)) {
192
+ variableDeclarations.set(declaration.name.text, declaration);
193
+ }
194
+ }
195
+ }
196
+ }
197
+ return { typeDeclarations, functionDeclarations, variableDeclarations };
198
+ }
199
+ function readDefaultValue(expression) {
200
+ if (ts.isStringLiteral(expression) || ts.isNoSubstitutionTemplateLiteral(expression)) {
201
+ return expression.text;
202
+ }
203
+ if (ts.isNumericLiteral(expression)) {
204
+ return Number(expression.text);
205
+ }
206
+ if (expression.kind === ts.SyntaxKind.TrueKeyword) return true;
207
+ if (expression.kind === ts.SyntaxKind.FalseKeyword) return false;
208
+ if (expression.kind === ts.SyntaxKind.NullKeyword) return null;
209
+ if (ts.isPrefixUnaryExpression(expression) && expression.operator === ts.SyntaxKind.MinusToken && ts.isNumericLiteral(expression.operand)) {
210
+ return -Number(expression.operand.text);
211
+ }
212
+ return void 0;
213
+ }
214
+ function extractDefaultValues(componentNode) {
215
+ const defaults = {};
216
+ if (!componentNode?.parameters?.length) return defaults;
217
+ const firstParam = componentNode.parameters[0];
218
+ if (!ts.isObjectBindingPattern(firstParam.name)) return defaults;
219
+ for (const element of firstParam.name.elements) {
220
+ let propName = null;
221
+ if (element.propertyName) {
222
+ if (ts.isIdentifier(element.propertyName) || ts.isStringLiteral(element.propertyName)) {
223
+ propName = element.propertyName.text;
224
+ }
225
+ } else if (ts.isIdentifier(element.name)) {
226
+ propName = element.name.text;
227
+ }
228
+ if (!propName || !element.initializer) continue;
229
+ const value = readDefaultValue(element.initializer);
230
+ if (value !== void 0) {
231
+ defaults[propName] = value;
232
+ }
233
+ }
234
+ return defaults;
235
+ }
236
+ function isNullishType(type) {
237
+ return (type.flags & ts.TypeFlags.Null) !== 0 || (type.flags & ts.TypeFlags.Undefined) !== 0 || (type.flags & ts.TypeFlags.Void) !== 0;
238
+ }
239
+ function isBooleanLikeType(type) {
240
+ return (type.flags & ts.TypeFlags.BooleanLike) !== 0 || type.flags === ts.TypeFlags.BooleanLiteral;
241
+ }
242
+ function inferPropType(type, checker) {
243
+ const typeText = checker.typeToString(type, void 0, ts.TypeFormatFlags.NoTruncation);
244
+ if (typeText.includes("ReactNode")) {
245
+ return { type: "node" };
246
+ }
247
+ if (typeText.includes("ReactElement") || typeText.includes("JSX.Element")) {
248
+ return { type: "element" };
249
+ }
250
+ if (type.getCallSignatures().length > 0) {
251
+ return { type: "function" };
252
+ }
253
+ if (checker.isArrayType(type) || checker.isTupleType(type)) {
254
+ return { type: "array" };
255
+ }
256
+ if (type.isUnion()) {
257
+ const nonNullableTypes = type.types.filter((unionType) => !isNullishType(unionType));
258
+ if (nonNullableTypes.length === 1) {
259
+ return inferPropType(nonNullableTypes[0], checker);
260
+ }
261
+ const stringLiteralValues = nonNullableTypes.filter((unionType) => (unionType.flags & ts.TypeFlags.StringLiteral) !== 0).map((unionType) => unionType.value);
262
+ if (stringLiteralValues.length > 0 && stringLiteralValues.length === nonNullableTypes.length) {
263
+ return { type: "enum", values: stringLiteralValues };
264
+ }
265
+ if (nonNullableTypes.every((unionType) => isBooleanLikeType(unionType))) {
266
+ return { type: "boolean" };
267
+ }
268
+ return { type: "union" };
269
+ }
270
+ if ((type.flags & ts.TypeFlags.StringLike) !== 0) {
271
+ return { type: "string" };
272
+ }
273
+ if ((type.flags & ts.TypeFlags.NumberLike) !== 0) {
274
+ return { type: "number" };
275
+ }
276
+ if ((type.flags & ts.TypeFlags.BooleanLike) !== 0) {
277
+ return { type: "boolean" };
278
+ }
279
+ if ((type.flags & ts.TypeFlags.Object) !== 0) {
280
+ return { type: "object" };
281
+ }
282
+ return { type: "custom" };
283
+ }
284
+ function resolveComponentSignature(exportName, declarations, sourceFile) {
285
+ const visitedNames = /* @__PURE__ */ new Set();
286
+ const typeNodeFromFunction = (node) => ({
287
+ propsTypeNode: node.parameters[0]?.type ?? null,
288
+ componentNode: node
289
+ });
290
+ const resolveFromExpression = (expression) => {
291
+ if (ts.isParenthesizedExpression(expression)) {
292
+ return resolveFromExpression(expression.expression);
293
+ }
294
+ if (ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression)) {
295
+ return resolveFromExpression(expression.expression);
296
+ }
297
+ if (ts.isArrowFunction(expression) || ts.isFunctionExpression(expression)) {
298
+ return typeNodeFromFunction(expression);
299
+ }
300
+ if (ts.isIdentifier(expression)) {
301
+ return resolveFromIdentifier(expression.text);
302
+ }
303
+ if (ts.isCallExpression(expression)) {
304
+ if (ts.isPropertyAccessExpression(expression.expression) && expression.expression.name.text === "forwardRef") {
305
+ const forwardRefPropsType = expression.typeArguments?.[1] ?? null;
306
+ const innerArg = expression.arguments[0];
307
+ const inner = innerArg && (ts.isArrowFunction(innerArg) || ts.isFunctionExpression(innerArg)) ? typeNodeFromFunction(innerArg) : innerArg && ts.isIdentifier(innerArg) ? resolveFromIdentifier(innerArg.text) : { propsTypeNode: null, componentNode: null };
308
+ return {
309
+ propsTypeNode: forwardRefPropsType ?? inner.propsTypeNode,
310
+ componentNode: inner.componentNode
311
+ };
312
+ }
313
+ if (ts.isPropertyAccessExpression(expression.expression) && expression.expression.name.text === "memo" && expression.arguments[0]) {
314
+ return resolveFromExpression(expression.arguments[0]);
315
+ }
316
+ if (ts.isPropertyAccessExpression(expression.expression) && expression.expression.expression.getText(sourceFile) === "Object" && expression.expression.name.text === "assign" && expression.arguments[0]) {
317
+ return resolveFromExpression(expression.arguments[0]);
318
+ }
319
+ }
320
+ return { propsTypeNode: null, componentNode: null };
321
+ };
322
+ const resolveFromVariable = (declaration) => {
323
+ if (declaration.type && ts.isTypeReferenceNode(declaration.type) && declaration.type.typeArguments?.length) {
324
+ const typeName = declaration.type.typeName.getText(sourceFile);
325
+ if (typeName.includes("FC") || typeName.includes("FunctionComponent")) {
326
+ const componentNode = declaration.initializer && (ts.isArrowFunction(declaration.initializer) || ts.isFunctionExpression(declaration.initializer)) ? declaration.initializer : null;
327
+ return {
328
+ propsTypeNode: declaration.type.typeArguments[0] ?? null,
329
+ componentNode
330
+ };
331
+ }
332
+ }
333
+ if (declaration.initializer) {
334
+ return resolveFromExpression(declaration.initializer);
335
+ }
336
+ return { propsTypeNode: null, componentNode: null };
337
+ };
338
+ const resolveFromIdentifier = (name) => {
339
+ if (!name || visitedNames.has(name)) {
340
+ return { propsTypeNode: null, componentNode: null };
341
+ }
342
+ visitedNames.add(name);
343
+ const functionDeclaration = declarations.functionDeclarations.get(name);
344
+ if (functionDeclaration) {
345
+ return typeNodeFromFunction(functionDeclaration);
346
+ }
347
+ const variableDeclaration = declarations.variableDeclarations.get(name);
348
+ if (variableDeclaration) {
349
+ return resolveFromVariable(variableDeclaration);
350
+ }
351
+ return { propsTypeNode: null, componentNode: null };
352
+ };
353
+ return resolveFromIdentifier(exportName);
354
+ }
355
+ function extractCustomPropsFromComponentFile(componentFilePath, exportName) {
356
+ const warnings = [];
357
+ const resolvedPath = resolve(componentFilePath);
358
+ if (!existsSync(resolvedPath)) {
359
+ return {
360
+ props: {},
361
+ warnings: [`Component file not found: ${resolvedPath}`],
362
+ resolved: false
363
+ };
364
+ }
365
+ const compilerOptions = {
366
+ target: ts.ScriptTarget.ESNext,
367
+ module: ts.ModuleKind.ESNext,
368
+ moduleResolution: ts.ModuleResolutionKind.Bundler,
369
+ jsx: ts.JsxEmit.ReactJSX,
370
+ allowSyntheticDefaultImports: true,
371
+ esModuleInterop: true,
372
+ skipLibCheck: true,
373
+ strict: false,
374
+ noEmit: true
375
+ };
376
+ const program = ts.createProgram([resolvedPath], compilerOptions);
377
+ const sourceFile = program.getSourceFile(resolvedPath);
378
+ if (!sourceFile) {
379
+ return {
380
+ props: {},
381
+ warnings: [`Unable to parse component source: ${resolvedPath}`],
382
+ resolved: false
383
+ };
384
+ }
385
+ const checker = program.getTypeChecker();
386
+ const declarations = collectTopLevelDeclarations(sourceFile);
387
+ const signature = resolveComponentSignature(exportName, declarations, sourceFile);
388
+ if (!signature.propsTypeNode) {
389
+ return {
390
+ props: {},
391
+ warnings: [`Unable to resolve props type for export: ${exportName}`],
392
+ resolved: false
393
+ };
394
+ }
395
+ const propsType = checker.getTypeFromTypeNode(signature.propsTypeNode);
396
+ const defaultValues = extractDefaultValues(signature.componentNode);
397
+ const sourceFilePath = toPosixPath(sourceFile.fileName);
398
+ const extractedProps = {};
399
+ for (const symbol of checker.getPropertiesOfType(propsType)) {
400
+ const propName = symbol.getName();
401
+ if (propName.startsWith("_") || propName.startsWith("$")) {
402
+ continue;
403
+ }
404
+ const declarationsForSymbol = symbol.getDeclarations() ?? [];
405
+ const localDeclarations = declarationsForSymbol.filter(
406
+ (declaration) => toPosixPath(declaration.getSourceFile().fileName) === sourceFilePath
407
+ );
408
+ if (localDeclarations.length === 0) {
409
+ continue;
410
+ }
411
+ const referenceNode = localDeclarations[0];
412
+ const inferredType = inferPropType(checker.getTypeOfSymbolAtLocation(symbol, referenceNode), checker);
413
+ const description = ts.displayPartsToString(symbol.getDocumentationComment(checker)).trim();
414
+ extractedProps[propName] = {
415
+ type: inferredType.type,
416
+ description,
417
+ required: (symbol.getFlags() & ts.SymbolFlags.Optional) === 0,
418
+ ...inferredType.values && { values: inferredType.values },
419
+ ...defaultValues[propName] !== void 0 && { default: defaultValues[propName] }
420
+ };
421
+ }
422
+ if (Object.keys(extractedProps).length === 0) {
423
+ warnings.push(`Resolved props type for ${exportName}, but no local custom props were found`);
424
+ }
425
+ return {
426
+ props: extractedProps,
427
+ warnings,
428
+ resolved: true
429
+ };
430
+ }
431
+
432
+ // src/build.ts
433
+ function normalizeParsedProps(parsedProps) {
434
+ return Object.fromEntries(
435
+ Object.entries(parsedProps).map(([name, prop]) => [
436
+ name,
437
+ {
438
+ type: prop.type ?? "custom",
439
+ description: prop.description ?? "",
440
+ default: prop.default,
441
+ required: prop.required,
442
+ values: prop.values,
443
+ constraints: prop.constraints
444
+ }
445
+ ])
446
+ );
447
+ }
448
+ function mergeDocumentedAndAutoProps(documentedProps, autoProps) {
449
+ return Object.fromEntries(
450
+ Object.keys(autoProps).map((name) => {
451
+ const documented = documentedProps[name];
452
+ const auto = autoProps[name];
453
+ return [
454
+ name,
455
+ {
456
+ type: auto.type,
457
+ description: documented?.description ?? auto.description ?? "",
458
+ default: auto.default !== void 0 ? auto.default : documented?.default,
459
+ required: auto.required,
460
+ values: auto.values ?? documented?.values,
461
+ constraints: documented?.constraints
462
+ }
463
+ ];
464
+ })
465
+ );
466
+ }
125
467
  async function buildSegments(config, configDir) {
126
468
  const files = await discoverSegmentFiles(config, configDir);
127
469
  const errors = [];
@@ -141,6 +483,53 @@ async function buildSegments(config, configDir) {
141
483
  });
142
484
  continue;
143
485
  }
486
+ const documentedProps = normalizeParsedProps(parsed.props);
487
+ let mergedProps = documentedProps;
488
+ const componentExportName = parsed.componentName ?? parsed.meta.name;
489
+ const componentSourcePath = resolveComponentSourcePath(
490
+ file.absolutePath,
491
+ parsed.componentImport
492
+ );
493
+ if (componentExportName && componentSourcePath) {
494
+ const autoPropsResult = extractCustomPropsFromComponentFile(
495
+ componentSourcePath,
496
+ componentExportName
497
+ );
498
+ for (const warning of autoPropsResult.warnings) {
499
+ warnings.push({ file: file.relativePath, warning });
500
+ }
501
+ const hasAutoProps = Object.keys(autoPropsResult.props).length > 0;
502
+ if (autoPropsResult.resolved && hasAutoProps) {
503
+ const removedDocumentedProps = Object.keys(documentedProps).filter(
504
+ (propName) => !(propName in autoPropsResult.props)
505
+ );
506
+ if (removedDocumentedProps.length > 0) {
507
+ warnings.push({
508
+ file: file.relativePath,
509
+ warning: `Removed ${removedDocumentedProps.length} documented props not present in source API: ${removedDocumentedProps.join(", ")}`
510
+ });
511
+ }
512
+ mergedProps = mergeDocumentedAndAutoProps(
513
+ documentedProps,
514
+ autoPropsResult.props
515
+ );
516
+ } else if (autoPropsResult.resolved && !hasAutoProps && Object.keys(documentedProps).length > 0) {
517
+ warnings.push({
518
+ file: file.relativePath,
519
+ warning: "Auto-props extraction returned no custom props; falling back to documented props"
520
+ });
521
+ }
522
+ } else if (!componentExportName) {
523
+ warnings.push({
524
+ file: file.relativePath,
525
+ warning: "Unable to resolve component export name for auto-props extraction"
526
+ });
527
+ } else if (!componentSourcePath) {
528
+ warnings.push({
529
+ file: file.relativePath,
530
+ warning: `Unable to resolve component source path from import: ${parsed.componentImport ?? "unknown"}`
531
+ });
532
+ }
144
533
  const compiled = {
145
534
  filePath: file.relativePath,
146
535
  meta: {
@@ -158,19 +547,7 @@ async function buildSegments(config, configDir) {
158
547
  guidelines: parsed.usage.guidelines,
159
548
  accessibility: parsed.usage.accessibility
160
549
  },
161
- props: Object.fromEntries(
162
- Object.entries(parsed.props).map(([name, prop]) => [
163
- name,
164
- {
165
- type: prop.type ?? "custom",
166
- description: prop.description ?? "",
167
- default: prop.default,
168
- required: prop.required,
169
- values: prop.values,
170
- constraints: prop.constraints
171
- }
172
- ])
173
- ),
550
+ props: mergedProps,
174
551
  relations: parsed.relations.map((rel) => ({
175
552
  component: rel.component,
176
553
  relationship: rel.relationship,
@@ -248,8 +625,8 @@ async function buildSegments(config, configDir) {
248
625
  } catch {
249
626
  }
250
627
  let packageName;
251
- const pkgJsonPath = resolve(configDir, "package.json");
252
- if (existsSync(pkgJsonPath)) {
628
+ const pkgJsonPath = resolve2(configDir, "package.json");
629
+ if (existsSync2(pkgJsonPath)) {
253
630
  try {
254
631
  const pkg = JSON.parse(await readFile(pkgJsonPath, "utf-8"));
255
632
  if (pkg.name) packageName = pkg.name;
@@ -264,7 +641,7 @@ async function buildSegments(config, configDir) {
264
641
  ...Object.keys(blocks).length > 0 && { blocks },
265
642
  ...tokens && { tokens }
266
643
  };
267
- const outputPath = resolve(configDir, config.outFile ?? BRAND.outFile);
644
+ const outputPath = resolve2(configDir, config.outFile ?? BRAND.outFile);
268
645
  await writeFile(outputPath, JSON.stringify(output));
269
646
  return {
270
647
  success: errors.length === 0,
@@ -275,8 +652,8 @@ async function buildSegments(config, configDir) {
275
652
  };
276
653
  }
277
654
  async function buildFragmentsDir(config, configDir) {
278
- const fragmentsDir = join(configDir, BRAND.dataDir);
279
- const componentsDir = join(fragmentsDir, BRAND.componentsDir);
655
+ const fragmentsDir = join2(configDir, BRAND.dataDir);
656
+ const componentsDir = join2(fragmentsDir, BRAND.componentsDir);
280
657
  await mkdir(fragmentsDir, { recursive: true });
281
658
  await mkdir(componentsDir, { recursive: true });
282
659
  const registryResult = await generateRegistry({
@@ -288,9 +665,9 @@ async function buildFragmentsDir(config, configDir) {
288
665
  });
289
666
  const errors = [...registryResult.errors];
290
667
  const warnings = [...registryResult.warnings];
291
- const indexPath = join(fragmentsDir, "index.json");
668
+ const indexPath = join2(fragmentsDir, "index.json");
292
669
  await writeFile(indexPath, JSON.stringify(registryResult.index, null, 2));
293
- const registryPath = join(fragmentsDir, BRAND.registryFile);
670
+ const registryPath = join2(fragmentsDir, BRAND.registryFile);
294
671
  await writeFile(registryPath, JSON.stringify(registryResult.registry, null, 2));
295
672
  const contextResult = generateContextMd(registryResult.registry, {
296
673
  format: "markdown",
@@ -302,7 +679,7 @@ async function buildFragmentsDir(config, configDir) {
302
679
  code: false
303
680
  }
304
681
  });
305
- const contextPath = join(fragmentsDir, BRAND.contextFile);
682
+ const contextPath = join2(fragmentsDir, BRAND.contextFile);
306
683
  await writeFile(contextPath, contextResult.content);
307
684
  return {
308
685
  success: errors.length === 0,
@@ -655,9 +1032,9 @@ ${BRAND.name} Diff
655
1032
  }
656
1033
 
657
1034
  // src/analyze.ts
658
- import { existsSync as existsSync2 } from "fs";
1035
+ import { existsSync as existsSync3 } from "fs";
659
1036
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
660
- import { join as join2, dirname } from "path";
1037
+ import { join as join3, dirname as dirname2 } from "path";
661
1038
  import pc3 from "picocolors";
662
1039
  async function runAnalyzeCommand(config, configDir, options = {}) {
663
1040
  const format = options.format ?? "html";
@@ -665,8 +1042,8 @@ async function runAnalyzeCommand(config, configDir, options = {}) {
665
1042
  console.log(pc3.cyan(`
666
1043
  ${BRAND.name} Analyzer
667
1044
  `));
668
- const segmentsPath = join2(configDir, config.outFile ?? "segments.json");
669
- if (!existsSync2(segmentsPath)) {
1045
+ const segmentsPath = join3(configDir, config.outFile ?? "segments.json");
1046
+ if (!existsSync3(segmentsPath)) {
670
1047
  console.log(pc3.red(`\u2717 No segments.json found. Run \`${BRAND.cliCommand} build\` first.
671
1048
  `));
672
1049
  return {
@@ -682,7 +1059,7 @@ ${BRAND.name} Analyzer
682
1059
  let outputPath;
683
1060
  if (format === "html" || format === "json") {
684
1061
  outputPath = options.output ?? getDefaultOutputPath(format, configDir);
685
- await mkdir2(dirname(outputPath), { recursive: true });
1062
+ await mkdir2(dirname2(outputPath), { recursive: true });
686
1063
  if (format === "html") {
687
1064
  const html = generateHtmlReport(analytics);
688
1065
  await writeFile2(outputPath, html);
@@ -761,7 +1138,7 @@ function colorizeScore(score) {
761
1138
  }
762
1139
  function getDefaultOutputPath(format, configDir) {
763
1140
  const filename = format === "html" ? "segments-report.html" : "segments-report.json";
764
- return join2(configDir, filename);
1141
+ return join3(configDir, filename);
765
1142
  }
766
1143
  async function openInBrowser(path) {
767
1144
  const { platform } = await import("os");
@@ -829,4 +1206,4 @@ export {
829
1206
  runDiffCommand,
830
1207
  runAnalyzeCommand
831
1208
  };
832
- //# sourceMappingURL=chunk-U4GQ2JTD.js.map
1209
+ //# sourceMappingURL=chunk-D35RGPAG.js.map