@fragments-sdk/cli 0.7.3 → 0.7.5

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 (70) hide show
  1. package/LICENSE +1 -4
  2. package/README.md +2 -0
  3. package/dist/bin.js +39 -16
  4. package/dist/bin.js.map +1 -1
  5. package/dist/{chunk-D34Q6A7S.js → chunk-AWYCDRPG.js} +8 -2
  6. package/dist/chunk-AWYCDRPG.js.map +1 -0
  7. package/dist/{chunk-R2YH7NLN.js → chunk-CR3XHBGM.js} +3 -3
  8. package/dist/{chunk-QPY4DUFB.js → chunk-EFQ7SIBX.js} +583 -108
  9. package/dist/chunk-EFQ7SIBX.js.map +1 -0
  10. package/dist/{chunk-UXLGIGSX.js → chunk-GIC3I2KZ.js} +2 -2
  11. package/dist/{chunk-R6IZZSE7.js → chunk-JZNATKQA.js} +9 -3
  12. package/dist/chunk-JZNATKQA.js.map +1 -0
  13. package/dist/{chunk-P33AKQJW.js → chunk-SFWZ4K7C.js} +8 -2
  14. package/dist/{chunk-P33AKQJW.js.map → chunk-SFWZ4K7C.js.map} +1 -1
  15. package/dist/{core-3NMNCLFW.js → core-T7BDYEGO.js} +3 -3
  16. package/dist/{discovery-AKGA6CJD.js → discovery-Z4RDDFVR.js} +2 -2
  17. package/dist/{generate-JAUEHKK7.js → generate-C2DKFCFJ.js} +5 -5
  18. package/dist/index.d.ts +28 -2
  19. package/dist/index.js +9 -7
  20. package/dist/index.js.map +1 -1
  21. package/dist/{init-DZQOT54X.js → init-O3FCHEPN.js} +26 -8
  22. package/dist/init-O3FCHEPN.js.map +1 -0
  23. package/dist/mcp-bin.js +3 -3
  24. package/dist/{scan-OJRCVKK2.js → scan-IYTZDUKG.js} +6 -6
  25. package/dist/{service-CFFBHW4X.js → service-VA6XKADO.js} +3 -3
  26. package/dist/{static-viewer-VA2JXSCX.js → static-viewer-5N42MBDR.js} +3 -3
  27. package/dist/{test-O7DZNKDC.js → test-OMMDWL2W.js} +4 -4
  28. package/dist/{tokens-N7THFD6J.js → tokens-6VJAHFIG.js} +5 -5
  29. package/dist/{viewer-QTR7QJMM.js → viewer-IVP5XC7U.js} +37 -17
  30. package/dist/viewer-IVP5XC7U.js.map +1 -0
  31. package/package.json +8 -2
  32. package/src/bin.ts +4 -0
  33. package/src/commands/add.ts +6 -0
  34. package/src/commands/init.ts +24 -4
  35. package/src/commands/validate.ts +24 -2
  36. package/src/core/config.ts +6 -0
  37. package/src/core/discovery.ts +7 -1
  38. package/src/core/index.ts +1 -0
  39. package/src/core/schema.ts +6 -0
  40. package/src/core/types.ts +21 -0
  41. package/src/index.ts +2 -1
  42. package/src/migrate/detect.ts +4 -0
  43. package/src/service/snippet-validation.test.ts +209 -0
  44. package/src/service/snippet-validation.ts +635 -0
  45. package/src/validators.ts +53 -5
  46. package/src/viewer/__tests__/viewer-integration.test.ts +8 -0
  47. package/src/viewer/components/App.tsx +63 -2
  48. package/src/viewer/components/CodePanel.naming.test.tsx +60 -0
  49. package/src/viewer/components/CodePanel.tsx +76 -468
  50. package/src/viewer/components/Layout.tsx +2 -2
  51. package/src/viewer/components/LeftSidebar.tsx +35 -77
  52. package/src/viewer/preview-frame.html +1 -1
  53. package/src/viewer/styles/globals.css +2 -1
  54. package/src/viewer/utils/a11y-fixes.ts +24 -9
  55. package/src/viewer/vite-plugin.ts +27 -2
  56. package/dist/chunk-D34Q6A7S.js.map +0 -1
  57. package/dist/chunk-QPY4DUFB.js.map +0 -1
  58. package/dist/chunk-R6IZZSE7.js.map +0 -1
  59. package/dist/init-DZQOT54X.js.map +0 -1
  60. package/dist/viewer-QTR7QJMM.js.map +0 -1
  61. /package/dist/{chunk-R2YH7NLN.js.map → chunk-CR3XHBGM.js.map} +0 -0
  62. /package/dist/{chunk-UXLGIGSX.js.map → chunk-GIC3I2KZ.js.map} +0 -0
  63. /package/dist/{core-3NMNCLFW.js.map → core-T7BDYEGO.js.map} +0 -0
  64. /package/dist/{discovery-AKGA6CJD.js.map → discovery-Z4RDDFVR.js.map} +0 -0
  65. /package/dist/{generate-JAUEHKK7.js.map → generate-C2DKFCFJ.js.map} +0 -0
  66. /package/dist/{scan-OJRCVKK2.js.map → scan-IYTZDUKG.js.map} +0 -0
  67. /package/dist/{service-CFFBHW4X.js.map → service-VA6XKADO.js.map} +0 -0
  68. /package/dist/{static-viewer-VA2JXSCX.js.map → static-viewer-5N42MBDR.js.map} +0 -0
  69. /package/dist/{test-O7DZNKDC.js.map → test-OMMDWL2W.js.map} +0 -0
  70. /package/dist/{tokens-N7THFD6J.js.map → tokens-6VJAHFIG.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/init.ts"],"sourcesContent":["/**\n * fragments init - Smart interactive initialization\n *\n * Handles three scenarios:\n * 1. Stories found → Configure and load existing stories\n * 2. Components found (no stories) → Auto-generate documentation\n * 3. Fresh project → Guided setup with example component\n */\n\nimport { readFile, writeFile, mkdir, access } from \"node:fs/promises\";\nimport { resolve, join, relative } from \"node:path\";\nimport { spawn } from \"node:child_process\";\nimport pc from \"picocolors\";\nimport { BRAND } from \"../core/index.js\";\nimport fg from \"fast-glob\";\nimport { input, confirm, select } from \"@inquirer/prompts\";\n\nexport interface InitOptions {\n /** Project root directory */\n projectRoot?: string;\n /** Force overwrite existing config */\n force?: boolean;\n /** Non-interactive mode - auto-detect and use defaults */\n yes?: boolean;\n}\n\nexport interface InitResult {\n success: boolean;\n configPath?: string;\n scenario: \"stories\" | \"components\" | \"fresh\";\n storiesFound: number;\n componentsFound: number;\n errors: string[];\n}\n\ninterface DetectionResult {\n storyFiles: string[];\n componentFiles: string[];\n hasConfig: boolean;\n configPath: string | null;\n suggestedComponentPath: string;\n}\n\n/**\n * Detect what exists in the project\n */\nasync function detectProject(projectRoot: string): Promise<DetectionResult> {\n console.log(pc.dim(\"\\nScanning project...\\n\"));\n\n // Check for existing config\n const configPath = join(projectRoot, BRAND.configFile);\n const legacyConfigPath = join(projectRoot, BRAND.legacyConfigFile);\n let hasConfig = false;\n let foundConfigPath: string | null = null;\n\n try {\n await access(configPath);\n hasConfig = true;\n foundConfigPath = configPath;\n } catch {\n try {\n await access(legacyConfigPath);\n hasConfig = true;\n foundConfigPath = legacyConfigPath;\n } catch {\n // No config\n }\n }\n\n // Scan for story files\n const storyFiles = await fg(\n [\"**/*.stories.tsx\", \"**/*.stories.ts\", \"**/*.stories.jsx\", \"**/*.stories.js\"],\n {\n cwd: projectRoot,\n ignore: [\"**/node_modules/**\", \"**/dist/**\", \"**/build/**\", \"**/.storybook/**\"],\n }\n );\n\n // Scan for component files (React components)\n const componentFiles = await fg(\n [\"**/components/**/*.tsx\", \"**/Components/**/*.tsx\", \"src/**/*.tsx\"],\n {\n cwd: projectRoot,\n ignore: [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/build/**\",\n \"**/*.stories.*\",\n \"**/*.test.*\",\n \"**/*.spec.*\",\n \"**/*.d.ts\",\n \"**/index.tsx\", // Skip barrel files\n ],\n }\n );\n\n // Filter to likely component files (capitalized names, not utility files)\n const likelyComponents = componentFiles.filter((f) => {\n const fileName = f.split(\"/\").pop() || \"\";\n return /^[A-Z]/.test(fileName) && !fileName.includes(\".styles\");\n });\n\n // Suggest component path based on what we found\n let suggestedComponentPath = \"src/components\";\n if (likelyComponents.length > 0) {\n const firstComponent = likelyComponents[0];\n const parts = firstComponent.split(\"/\");\n const componentsIndex = parts.findIndex(\n (p) => p.toLowerCase() === \"components\"\n );\n if (componentsIndex !== -1) {\n suggestedComponentPath = parts.slice(0, componentsIndex + 1).join(\"/\");\n }\n }\n\n return {\n storyFiles,\n componentFiles: likelyComponents,\n hasConfig,\n configPath: foundConfigPath,\n suggestedComponentPath,\n };\n}\n\n/**\n * Generate config file content\n */\nfunction generateConfig(options: {\n includePaths: string[];\n componentPaths: string[];\n framework: string;\n}): string {\n const includeStr = options.includePaths.map((p) => ` '${p}'`).join(\",\\n\");\n const componentStr = options.componentPaths.map((p) => ` '${p}'`).join(\",\\n\");\n\n return `import type { FragmentsConfig } from '@fragments-sdk/cli';\n\nconst config: FragmentsConfig = {\n // Glob patterns for finding fragment/story files\n include: [\n${includeStr}\n ],\n\n // Glob patterns to exclude\n exclude: ['**/node_modules/**'],\n\n // Glob patterns for finding component files (for auto-documentation)\n components: [\n${componentStr}\n ],\n\n // Framework (react, vue, svelte)\n framework: '${options.framework}',\n};\n\nexport default config;\n`;\n}\n\n/**\n * Generate example Button component\n */\nfunction generateExampleComponent(): string {\n return `import React from 'react';\n\nexport interface ButtonProps {\n /** Button label */\n children: React.ReactNode;\n /** Visual style variant */\n variant?: 'primary' | 'secondary' | 'ghost';\n /** Button size */\n size?: 'sm' | 'md' | 'lg';\n /** Disabled state */\n disabled?: boolean;\n /** Click handler */\n onClick?: () => void;\n}\n\nexport function Button({\n children,\n variant = 'primary',\n size = 'md',\n disabled = false,\n onClick,\n}: ButtonProps) {\n const baseStyles = 'inline-flex items-center justify-center font-medium rounded-md transition-colors';\n\n const variantStyles = {\n primary: 'bg-blue-600 text-white hover:bg-blue-700',\n secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',\n ghost: 'bg-transparent text-gray-700 hover:bg-gray-100',\n };\n\n const sizeStyles = {\n sm: 'px-3 py-1.5 text-sm',\n md: 'px-4 py-2 text-base',\n lg: 'px-6 py-3 text-lg',\n };\n\n return (\n <button\n className={\\`\\${baseStyles} \\${variantStyles[variant]} \\${sizeStyles[size]}\\`}\n disabled={disabled}\n onClick={onClick}\n >\n {children}\n </button>\n );\n}\n`;\n}\n\n/**\n * Generate example Button fragment file\n */\nfunction generateExampleFragment(): string {\n return `import React from 'react';\nimport { defineFragment } from '@fragments-sdk/cli';\nimport { Button } from './Button';\n\nexport default defineFragment({\n component: Button,\n\n meta: {\n name: 'Button',\n description: 'Interactive button for triggering actions',\n category: 'Actions',\n status: 'stable',\n },\n\n usage: {\n when: [\n 'Triggering an action (save, submit, delete)',\n 'Form submission',\n 'Opening dialogs or menus',\n ],\n whenNot: [\n 'Simple navigation (use Link)',\n 'Toggling state (use Switch)',\n ],\n guidelines: [\n 'Use Primary for the main action in a context',\n 'Only one Primary button per section',\n ],\n },\n\n props: {\n children: {\n type: 'node',\n required: true,\n description: 'Button label content',\n },\n variant: {\n type: 'enum',\n values: ['primary', 'secondary', 'ghost'],\n default: 'primary',\n description: 'Visual style variant',\n },\n size: {\n type: 'enum',\n values: ['sm', 'md', 'lg'],\n default: 'md',\n description: 'Button size',\n },\n },\n\n variants: [\n {\n name: 'Primary',\n description: 'Default action button',\n code: \\`import { Button } from './Button';\n\n<Button variant=\"primary\">Save Changes</Button>\\`,\n render: () => <Button variant=\"primary\">Save Changes</Button>,\n },\n {\n name: 'Secondary',\n description: 'Less prominent action',\n code: \\`import { Button } from './Button';\n\n<Button variant=\"secondary\">Cancel</Button>\\`,\n render: () => <Button variant=\"secondary\">Cancel</Button>,\n },\n {\n name: 'Ghost',\n description: 'Minimal visual weight',\n code: \\`import { Button } from './Button';\n\n<Button variant=\"ghost\">Learn More</Button>\\`,\n render: () => <Button variant=\"ghost\">Learn More</Button>,\n },\n {\n name: 'Sizes',\n description: 'Available size options',\n code: \\`import { Button } from './Button';\n\n<>\n <Button size=\"sm\">Small</Button>\n <Button size=\"md\">Medium</Button>\n <Button size=\"lg\">Large</Button>\n</>\\`,\n render: () => (\n <>\n <Button size=\"sm\">Small</Button>\n <Button size=\"md\">Medium</Button>\n <Button size=\"lg\">Large</Button>\n </>\n ),\n },\n ],\n});\n`;\n}\n\n/**\n * Start the dev server\n */\nfunction startDevServer(projectRoot: string): void {\n console.log(pc.dim(\"\\nStarting development server...\\n\"));\n\n // Use process.platform to determine the correct command\n const isWindows = process.platform === \"win32\";\n const cmd = isWindows ? \"npx.cmd\" : \"npx\";\n\n const child = spawn(cmd, [BRAND.cliCommand, \"dev\"], {\n cwd: projectRoot,\n stdio: \"inherit\",\n });\n\n child.on(\"error\", (err) => {\n console.error(pc.red(\"Failed to start dev server:\"), err.message);\n });\n}\n\n/**\n * Main init function - smart and interactive by default\n */\nexport async function init(options: InitOptions = {}): Promise<InitResult> {\n const projectRoot = resolve(options.projectRoot || process.cwd());\n const errors: string[] = [];\n\n console.log(pc.cyan(`\\n✨ Welcome to ${BRAND.name}!\\n`));\n\n // Step 1: Detect what exists\n const detection = await detectProject(projectRoot);\n\n // Check for existing config\n if (detection.hasConfig && !options.force) {\n console.log(pc.yellow(`⚠ Config already exists: ${BRAND.configFile}`));\n\n if (!options.yes) {\n const overwrite = await confirm({\n message: \"Do you want to reinitialize? (This will overwrite your config)\",\n default: false,\n });\n\n if (!overwrite) {\n console.log(pc.dim(`\\nKeeping existing configuration. Run \\`${BRAND.cliCommand} dev\\` to start.\\n`));\n return {\n success: true,\n scenario: \"stories\",\n storiesFound: detection.storyFiles.length,\n componentsFound: detection.componentFiles.length,\n errors: [],\n };\n }\n }\n }\n\n // Step 2: Determine scenario and show what we found\n let scenario: \"stories\" | \"components\" | \"fresh\";\n\n if (detection.storyFiles.length > 0) {\n scenario = \"stories\";\n console.log(pc.green(`✓ Found ${detection.storyFiles.length} Storybook story file(s)`));\n console.log(pc.dim(` ${detection.storyFiles.slice(0, 3).join(\"\\n \")}`));\n if (detection.storyFiles.length > 3) {\n console.log(pc.dim(` ... and ${detection.storyFiles.length - 3} more`));\n }\n console.log();\n console.log(\n pc.cyan(\"Great news! \") +\n \"Fragments can load your existing stories automatically.\"\n );\n } else if (detection.componentFiles.length > 0) {\n scenario = \"components\";\n console.log(pc.green(`✓ Found ${detection.componentFiles.length} component file(s)`));\n console.log(pc.dim(` ${detection.componentFiles.slice(0, 3).join(\"\\n \")}`));\n if (detection.componentFiles.length > 3) {\n console.log(pc.dim(` ... and ${detection.componentFiles.length - 3} more`));\n }\n console.log();\n console.log(\n pc.cyan(\"No stories found, but that's fine! \") +\n \"Fragments can auto-generate documentation from your TypeScript.\"\n );\n } else {\n scenario = \"fresh\";\n console.log(pc.yellow(\"No components or stories found.\"));\n console.log();\n console.log(pc.cyan(\"Let's create your first fragment!\"));\n }\n\n console.log();\n\n // Step 3: Gather configuration (interactive unless --yes)\n let componentPath = detection.suggestedComponentPath;\n let runScan = scenario === \"components\";\n let createExample = scenario === \"fresh\";\n let startServer = true;\n\n if (!options.yes) {\n // Ask about component location\n componentPath = await input({\n message: \"Where are your components located?\",\n default: detection.suggestedComponentPath,\n });\n\n if (scenario === \"components\") {\n // For component-only projects, ask about scanning\n runScan = await confirm({\n message: \"Auto-generate documentation from TypeScript?\",\n default: true,\n });\n } else {\n // Fresh project - ask about example\n createExample = await confirm({\n message: \"Create an example Button component to get started?\",\n default: true,\n });\n }\n\n // Ask about starting the server\n startServer = await confirm({\n message: \"Start the viewer now?\",\n default: true,\n });\n }\n\n // Step 4: Create configuration\n console.log(pc.dim(\"\\nCreating configuration...\\n\"));\n\n // Build include patterns\n const includePaths: string[] = [\n `${componentPath}/**/*.fragment.tsx`,\n ];\n\n // Include story files when Storybook is detected\n if (scenario === 'stories') {\n includePaths.push(`${componentPath}/**/*.stories.tsx`);\n includePaths.push(`${componentPath}/**/*.stories.ts`);\n }\n\n // Create config file\n const configPath = join(projectRoot, BRAND.configFile);\n const configContent = generateConfig({\n includePaths,\n componentPaths: [`${componentPath}/**/*.tsx`],\n framework: \"react\",\n });\n\n try {\n await writeFile(configPath, configContent, \"utf-8\");\n console.log(pc.green(`✓ Created ${BRAND.configFile}`));\n } catch (e) {\n errors.push(`Failed to create config: ${e}`);\n }\n\n // Step 5: Handle scenario-specific setup\n if (scenario === \"fresh\" && createExample) {\n // Create example component\n const exampleDir = join(projectRoot, componentPath, \"Button\");\n\n try {\n await mkdir(exampleDir, { recursive: true });\n\n // Write Button.tsx\n await writeFile(\n join(exampleDir, \"Button.tsx\"),\n generateExampleComponent(),\n \"utf-8\"\n );\n console.log(\n pc.green(`✓ Created ${relative(projectRoot, join(exampleDir, \"Button.tsx\"))}`)\n );\n\n // Write Button.fragment.tsx\n await writeFile(\n join(exampleDir, \"Button.fragment.tsx\"),\n generateExampleFragment(),\n \"utf-8\"\n );\n console.log(\n pc.green(\n `✓ Created ${relative(projectRoot, join(exampleDir, \"Button.fragment.tsx\"))}`\n )\n );\n } catch (e) {\n errors.push(`Failed to create example component: ${e}`);\n }\n }\n\n if (scenario === \"components\" && runScan) {\n // Run scan to generate fragments.json\n console.log(pc.dim(\"\\nGenerating documentation from source code...\\n\"));\n try {\n const { scan } = await import(\"./scan.js\");\n await scan({\n config: configPath,\n verbose: false,\n });\n } catch (e) {\n console.log(\n pc.yellow(`Note: Auto-documentation will run when you start the dev server.`)\n );\n }\n }\n\n // Step 6: Show next steps or start server\n if (errors.length === 0) {\n console.log(pc.green(\"\\n✓ Setup complete!\\n\"));\n\n if (startServer) {\n const serverMessage =\n scenario === \"stories\"\n ? `Your ${detection.storyFiles.length} stories are loading...`\n : scenario === \"components\"\n ? `Your ${detection.componentFiles.length} components are being documented...`\n : `Your first component is ready!`;\n\n console.log(pc.cyan(serverMessage));\n startDevServer(projectRoot);\n } else {\n console.log(pc.cyan(\"Next steps:\"));\n console.log(` 1. Run ${pc.bold(`${BRAND.cliCommand} dev`)} to start the viewer`);\n if (scenario === \"fresh\") {\n console.log(` 2. Edit ${pc.bold(`${componentPath}/Button/Button.fragment.tsx`)}`);\n }\n console.log();\n }\n }\n\n return {\n success: errors.length === 0,\n configPath: errors.length === 0 ? configPath : undefined,\n scenario,\n storiesFound: detection.storyFiles.length,\n componentsFound: detection.componentFiles.length,\n errors,\n };\n}\n"],"mappings":";;;;;;;;;AASA,SAAmB,WAAW,OAAO,cAAc;AACnD,SAAS,SAAS,MAAM,gBAAgB;AACxC,SAAS,aAAa;AACtB,OAAO,QAAQ;AAEf,OAAO,QAAQ;AACf,SAAS,OAAO,eAAuB;AA+BvC,eAAe,cAAc,aAA+C;AAC1E,UAAQ,IAAI,GAAG,IAAI,yBAAyB,CAAC;AAG7C,QAAM,aAAa,KAAK,aAAa,MAAM,UAAU;AACrD,QAAM,mBAAmB,KAAK,aAAa,MAAM,gBAAgB;AACjE,MAAI,YAAY;AAChB,MAAI,kBAAiC;AAErC,MAAI;AACF,UAAM,OAAO,UAAU;AACvB,gBAAY;AACZ,sBAAkB;AAAA,EACpB,QAAQ;AACN,QAAI;AACF,YAAM,OAAO,gBAAgB;AAC7B,kBAAY;AACZ,wBAAkB;AAAA,IACpB,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,QAAM,aAAa,MAAM;AAAA,IACvB,CAAC,oBAAoB,mBAAmB,oBAAoB,iBAAiB;AAAA,IAC7E;AAAA,MACE,KAAK;AAAA,MACL,QAAQ,CAAC,sBAAsB,cAAc,eAAe,kBAAkB;AAAA,IAChF;AAAA,EACF;AAGA,QAAM,iBAAiB,MAAM;AAAA,IAC3B,CAAC,0BAA0B,0BAA0B,cAAc;AAAA,IACnE;AAAA,MACE,KAAK;AAAA,MACL,QAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,mBAAmB,eAAe,OAAO,CAAC,MAAM;AACpD,UAAM,WAAW,EAAE,MAAM,GAAG,EAAE,IAAI,KAAK;AACvC,WAAO,SAAS,KAAK,QAAQ,KAAK,CAAC,SAAS,SAAS,SAAS;AAAA,EAChE,CAAC;AAGD,MAAI,yBAAyB;AAC7B,MAAI,iBAAiB,SAAS,GAAG;AAC/B,UAAM,iBAAiB,iBAAiB,CAAC;AACzC,UAAM,QAAQ,eAAe,MAAM,GAAG;AACtC,UAAM,kBAAkB,MAAM;AAAA,MAC5B,CAAC,MAAM,EAAE,YAAY,MAAM;AAAA,IAC7B;AACA,QAAI,oBAAoB,IAAI;AAC1B,+BAAyB,MAAM,MAAM,GAAG,kBAAkB,CAAC,EAAE,KAAK,GAAG;AAAA,IACvE;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,gBAAgB;AAAA,IAChB;AAAA,IACA,YAAY;AAAA,IACZ;AAAA,EACF;AACF;AAKA,SAAS,eAAe,SAIb;AACT,QAAM,aAAa,QAAQ,aAAa,IAAI,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,KAAK,KAAK;AAC3E,QAAM,eAAe,QAAQ,eAAe,IAAI,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,KAAK,KAAK;AAE/E,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAKP,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQV,YAAY;AAAA;AAAA;AAAA;AAAA,gBAIE,QAAQ,SAAS;AAAA;AAAA;AAAA;AAAA;AAKjC;AAKA,SAAS,2BAAmC;AAC1C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+CT;AAKA,SAAS,0BAAkC;AACzC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgGT;AAKA,SAAS,eAAe,aAA2B;AACjD,UAAQ,IAAI,GAAG,IAAI,oCAAoC,CAAC;AAGxD,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,MAAM,YAAY,YAAY;AAEpC,QAAM,QAAQ,MAAM,KAAK,CAAC,MAAM,YAAY,KAAK,GAAG;AAAA,IAClD,KAAK;AAAA,IACL,OAAO;AAAA,EACT,CAAC;AAED,QAAM,GAAG,SAAS,CAAC,QAAQ;AACzB,YAAQ,MAAM,GAAG,IAAI,6BAA6B,GAAG,IAAI,OAAO;AAAA,EAClE,CAAC;AACH;AAKA,eAAsB,KAAK,UAAuB,CAAC,GAAwB;AACzE,QAAM,cAAc,QAAQ,QAAQ,eAAe,QAAQ,IAAI,CAAC;AAChE,QAAM,SAAmB,CAAC;AAE1B,UAAQ,IAAI,GAAG,KAAK;AAAA,oBAAkB,MAAM,IAAI;AAAA,CAAK,CAAC;AAGtD,QAAM,YAAY,MAAM,cAAc,WAAW;AAGjD,MAAI,UAAU,aAAa,CAAC,QAAQ,OAAO;AACzC,YAAQ,IAAI,GAAG,OAAO,iCAA4B,MAAM,UAAU,EAAE,CAAC;AAErE,QAAI,CAAC,QAAQ,KAAK;AAChB,YAAM,YAAY,MAAM,QAAQ;AAAA,QAC9B,SAAS;AAAA,QACT,SAAS;AAAA,MACX,CAAC;AAED,UAAI,CAAC,WAAW;AACd,gBAAQ,IAAI,GAAG,IAAI;AAAA,wCAA2C,MAAM,UAAU;AAAA,CAAoB,CAAC;AACnG,eAAO;AAAA,UACL,SAAS;AAAA,UACT,UAAU;AAAA,UACV,cAAc,UAAU,WAAW;AAAA,UACnC,iBAAiB,UAAU,eAAe;AAAA,UAC1C,QAAQ,CAAC;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI;AAEJ,MAAI,UAAU,WAAW,SAAS,GAAG;AACnC,eAAW;AACX,YAAQ,IAAI,GAAG,MAAM,gBAAW,UAAU,WAAW,MAAM,0BAA0B,CAAC;AACtF,YAAQ,IAAI,GAAG,IAAI,KAAK,UAAU,WAAW,MAAM,GAAG,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC;AACxE,QAAI,UAAU,WAAW,SAAS,GAAG;AACnC,cAAQ,IAAI,GAAG,IAAI,aAAa,UAAU,WAAW,SAAS,CAAC,OAAO,CAAC;AAAA,IACzE;AACA,YAAQ,IAAI;AACZ,YAAQ;AAAA,MACN,GAAG,KAAK,cAAc,IACpB;AAAA,IACJ;AAAA,EACF,WAAW,UAAU,eAAe,SAAS,GAAG;AAC9C,eAAW;AACX,YAAQ,IAAI,GAAG,MAAM,gBAAW,UAAU,eAAe,MAAM,oBAAoB,CAAC;AACpF,YAAQ,IAAI,GAAG,IAAI,KAAK,UAAU,eAAe,MAAM,GAAG,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC;AAC5E,QAAI,UAAU,eAAe,SAAS,GAAG;AACvC,cAAQ,IAAI,GAAG,IAAI,aAAa,UAAU,eAAe,SAAS,CAAC,OAAO,CAAC;AAAA,IAC7E;AACA,YAAQ,IAAI;AACZ,YAAQ;AAAA,MACN,GAAG,KAAK,qCAAqC,IAC3C;AAAA,IACJ;AAAA,EACF,OAAO;AACL,eAAW;AACX,YAAQ,IAAI,GAAG,OAAO,iCAAiC,CAAC;AACxD,YAAQ,IAAI;AACZ,YAAQ,IAAI,GAAG,KAAK,mCAAmC,CAAC;AAAA,EAC1D;AAEA,UAAQ,IAAI;AAGZ,MAAI,gBAAgB,UAAU;AAC9B,MAAI,UAAU,aAAa;AAC3B,MAAI,gBAAgB,aAAa;AACjC,MAAI,cAAc;AAElB,MAAI,CAAC,QAAQ,KAAK;AAEhB,oBAAgB,MAAM,MAAM;AAAA,MAC1B,SAAS;AAAA,MACT,SAAS,UAAU;AAAA,IACrB,CAAC;AAED,QAAI,aAAa,cAAc;AAE7B,gBAAU,MAAM,QAAQ;AAAA,QACtB,SAAS;AAAA,QACT,SAAS;AAAA,MACX,CAAC;AAAA,IACH,OAAO;AAEL,sBAAgB,MAAM,QAAQ;AAAA,QAC5B,SAAS;AAAA,QACT,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAGA,kBAAc,MAAM,QAAQ;AAAA,MAC1B,SAAS;AAAA,MACT,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAGA,UAAQ,IAAI,GAAG,IAAI,+BAA+B,CAAC;AAGnD,QAAM,eAAyB;AAAA,IAC7B,GAAG,aAAa;AAAA,EAClB;AAGA,MAAI,aAAa,WAAW;AAC1B,iBAAa,KAAK,GAAG,aAAa,mBAAmB;AACrD,iBAAa,KAAK,GAAG,aAAa,kBAAkB;AAAA,EACtD;AAGA,QAAM,aAAa,KAAK,aAAa,MAAM,UAAU;AACrD,QAAM,gBAAgB,eAAe;AAAA,IACnC;AAAA,IACA,gBAAgB,CAAC,GAAG,aAAa,WAAW;AAAA,IAC5C,WAAW;AAAA,EACb,CAAC;AAED,MAAI;AACF,UAAM,UAAU,YAAY,eAAe,OAAO;AAClD,YAAQ,IAAI,GAAG,MAAM,kBAAa,MAAM,UAAU,EAAE,CAAC;AAAA,EACvD,SAAS,GAAG;AACV,WAAO,KAAK,4BAA4B,CAAC,EAAE;AAAA,EAC7C;AAGA,MAAI,aAAa,WAAW,eAAe;AAEzC,UAAM,aAAa,KAAK,aAAa,eAAe,QAAQ;AAE5D,QAAI;AACF,YAAM,MAAM,YAAY,EAAE,WAAW,KAAK,CAAC;AAG3C,YAAM;AAAA,QACJ,KAAK,YAAY,YAAY;AAAA,QAC7B,yBAAyB;AAAA,QACzB;AAAA,MACF;AACA,cAAQ;AAAA,QACN,GAAG,MAAM,kBAAa,SAAS,aAAa,KAAK,YAAY,YAAY,CAAC,CAAC,EAAE;AAAA,MAC/E;AAGA,YAAM;AAAA,QACJ,KAAK,YAAY,qBAAqB;AAAA,QACtC,wBAAwB;AAAA,QACxB;AAAA,MACF;AACA,cAAQ;AAAA,QACN,GAAG;AAAA,UACD,kBAAa,SAAS,aAAa,KAAK,YAAY,qBAAqB,CAAC,CAAC;AAAA,QAC7E;AAAA,MACF;AAAA,IACF,SAAS,GAAG;AACV,aAAO,KAAK,uCAAuC,CAAC,EAAE;AAAA,IACxD;AAAA,EACF;AAEA,MAAI,aAAa,gBAAgB,SAAS;AAExC,YAAQ,IAAI,GAAG,IAAI,kDAAkD,CAAC;AACtE,QAAI;AACF,YAAM,EAAE,KAAK,IAAI,MAAM,OAAO,oBAAW;AACzC,YAAM,KAAK;AAAA,QACT,QAAQ;AAAA,QACR,SAAS;AAAA,MACX,CAAC;AAAA,IACH,SAAS,GAAG;AACV,cAAQ;AAAA,QACN,GAAG,OAAO,kEAAkE;AAAA,MAC9E;AAAA,IACF;AAAA,EACF;AAGA,MAAI,OAAO,WAAW,GAAG;AACvB,YAAQ,IAAI,GAAG,MAAM,4BAAuB,CAAC;AAE7C,QAAI,aAAa;AACf,YAAM,gBACJ,aAAa,YACT,QAAQ,UAAU,WAAW,MAAM,4BACnC,aAAa,eACb,QAAQ,UAAU,eAAe,MAAM,wCACvC;AAEN,cAAQ,IAAI,GAAG,KAAK,aAAa,CAAC;AAClC,qBAAe,WAAW;AAAA,IAC5B,OAAO;AACL,cAAQ,IAAI,GAAG,KAAK,aAAa,CAAC;AAClC,cAAQ,IAAI,YAAY,GAAG,KAAK,GAAG,MAAM,UAAU,MAAM,CAAC,sBAAsB;AAChF,UAAI,aAAa,SAAS;AACxB,gBAAQ,IAAI,aAAa,GAAG,KAAK,GAAG,aAAa,6BAA6B,CAAC,EAAE;AAAA,MACnF;AACA,cAAQ,IAAI;AAAA,IACd;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS,OAAO,WAAW;AAAA,IAC3B,YAAY,OAAO,WAAW,IAAI,aAAa;AAAA,IAC/C;AAAA,IACA,cAAc,UAAU,WAAW;AAAA,IACnC,iBAAiB,UAAU,eAAe;AAAA,IAC1C;AAAA,EACF;AACF;","names":[]}
package/dist/mcp-bin.js CHANGED
@@ -2,8 +2,8 @@
2
2
  import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
3
3
  import {
4
4
  generateContext
5
- } from "./chunk-UXLGIGSX.js";
6
- import "./chunk-P33AKQJW.js";
5
+ } from "./chunk-GIC3I2KZ.js";
6
+ import "./chunk-SFWZ4K7C.js";
7
7
  import {
8
8
  BRAND,
9
9
  DEFAULTS
@@ -60,7 +60,7 @@ var _service = null;
60
60
  async function getService() {
61
61
  if (!_service) {
62
62
  try {
63
- _service = await import("./service-CFFBHW4X.js");
63
+ _service = await import("./service-VA6XKADO.js");
64
64
  } catch {
65
65
  throw new Error(
66
66
  "Visual tools require playwright. Install it with: npm install playwright"
@@ -1,15 +1,15 @@
1
1
  import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
2
2
  import {
3
3
  scan
4
- } from "./chunk-R2YH7NLN.js";
5
- import "./chunk-R6IZZSE7.js";
6
- import "./chunk-D34Q6A7S.js";
4
+ } from "./chunk-CR3XHBGM.js";
5
+ import "./chunk-JZNATKQA.js";
6
+ import "./chunk-AWYCDRPG.js";
7
7
  import "./chunk-YMPGYEWK.js";
8
- import "./chunk-UXLGIGSX.js";
9
- import "./chunk-P33AKQJW.js";
8
+ import "./chunk-GIC3I2KZ.js";
9
+ import "./chunk-SFWZ4K7C.js";
10
10
  import "./chunk-EKLMXTWU.js";
11
11
  import "./chunk-Z7EY4VHE.js";
12
12
  export {
13
13
  scan
14
14
  };
15
- //# sourceMappingURL=scan-OJRCVKK2.js.map
15
+ //# sourceMappingURL=scan-IYTZDUKG.js.map
@@ -98,8 +98,8 @@ import {
98
98
  sleep,
99
99
  summarizePatternsForPrompt
100
100
  } from "./chunk-YMPGYEWK.js";
101
- import "./chunk-UXLGIGSX.js";
102
- import "./chunk-P33AKQJW.js";
101
+ import "./chunk-GIC3I2KZ.js";
102
+ import "./chunk-SFWZ4K7C.js";
103
103
  import {
104
104
  BRAND,
105
105
  DEFAULTS
@@ -207,4 +207,4 @@ export {
207
207
  sleep,
208
208
  summarizePatternsForPrompt
209
209
  };
210
- //# sourceMappingURL=service-CFFBHW4X.js.map
210
+ //# sourceMappingURL=service-VA6XKADO.js.map
@@ -3,12 +3,12 @@ import {
3
3
  generateStaticViewer,
4
4
  generateViewerFromJson
5
5
  } from "./chunk-TOIE7VXF.js";
6
- import "./chunk-UXLGIGSX.js";
7
- import "./chunk-P33AKQJW.js";
6
+ import "./chunk-GIC3I2KZ.js";
7
+ import "./chunk-SFWZ4K7C.js";
8
8
  import "./chunk-EKLMXTWU.js";
9
9
  import "./chunk-Z7EY4VHE.js";
10
10
  export {
11
11
  generateStaticViewer,
12
12
  generateViewerFromJson
13
13
  };
14
- //# sourceMappingURL=static-viewer-VA2JXSCX.js.map
14
+ //# sourceMappingURL=static-viewer-5N42MBDR.js.map
@@ -1,11 +1,11 @@
1
1
  import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
2
2
  import {
3
3
  parseFragmentFile
4
- } from "./chunk-R6IZZSE7.js";
4
+ } from "./chunk-JZNATKQA.js";
5
5
  import {
6
6
  discoverFragmentFiles
7
- } from "./chunk-D34Q6A7S.js";
8
- import "./chunk-P33AKQJW.js";
7
+ } from "./chunk-AWYCDRPG.js";
8
+ import "./chunk-SFWZ4K7C.js";
9
9
  import "./chunk-EKLMXTWU.js";
10
10
  import "./chunk-Z7EY4VHE.js";
11
11
 
@@ -1072,4 +1072,4 @@ export {
1072
1072
  listTests,
1073
1073
  runTestCommand
1074
1074
  };
1075
- //# sourceMappingURL=test-O7DZNKDC.js.map
1075
+ //# sourceMappingURL=test-OMMDWL2W.js.map
@@ -1,13 +1,13 @@
1
1
  import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
2
2
  import {
3
3
  loadConfig
4
- } from "./chunk-R6IZZSE7.js";
5
- import "./chunk-D34Q6A7S.js";
4
+ } from "./chunk-JZNATKQA.js";
5
+ import "./chunk-AWYCDRPG.js";
6
6
  import {
7
7
  parseTokenFiles
8
8
  } from "./chunk-YMPGYEWK.js";
9
- import "./chunk-UXLGIGSX.js";
10
- import "./chunk-P33AKQJW.js";
9
+ import "./chunk-GIC3I2KZ.js";
10
+ import "./chunk-SFWZ4K7C.js";
11
11
  import {
12
12
  BRAND
13
13
  } from "./chunk-EKLMXTWU.js";
@@ -173,4 +173,4 @@ export {
173
173
  tokens_default as default,
174
174
  tokens
175
175
  };
176
- //# sourceMappingURL=tokens-N7THFD6J.js.map
176
+ //# sourceMappingURL=tokens-6VJAHFIG.js.map
@@ -4,15 +4,15 @@ import {
4
4
  findStorybookDir,
5
5
  generatePreviewModule,
6
6
  loadConfig
7
- } from "./chunk-R6IZZSE7.js";
7
+ } from "./chunk-JZNATKQA.js";
8
8
  import {
9
9
  discoverFragmentFiles,
10
10
  discoverInstalledFragments
11
- } from "./chunk-D34Q6A7S.js";
11
+ } from "./chunk-AWYCDRPG.js";
12
12
  import {
13
13
  generateContext
14
- } from "./chunk-UXLGIGSX.js";
15
- import "./chunk-P33AKQJW.js";
14
+ } from "./chunk-GIC3I2KZ.js";
15
+ import "./chunk-SFWZ4K7C.js";
16
16
  import {
17
17
  BRAND
18
18
  } from "./chunk-EKLMXTWU.js";
@@ -360,7 +360,7 @@ var sharedRenderPool = null;
360
360
  var browserPoolModule = null;
361
361
  async function getSharedRenderPool() {
362
362
  if (!browserPoolModule) {
363
- browserPoolModule = await import("./service-CFFBHW4X.js");
363
+ browserPoolModule = await import("./service-VA6XKADO.js");
364
364
  }
365
365
  if (!sharedRenderPool) {
366
366
  sharedRenderPool = new browserPoolModule.BrowserPool({
@@ -392,6 +392,16 @@ function fragmentsPlugin(options) {
392
392
  // Add process.env shim and esbuild config for Storybook compatibility
393
393
  config() {
394
394
  return {
395
+ build: {
396
+ rollupOptions: {
397
+ onwarn(warning, defaultHandler) {
398
+ if (warning.code === "MODULE_LEVEL_DIRECTIVE" || warning.message && warning.message.includes("has been externalized")) {
399
+ return;
400
+ }
401
+ defaultHandler(warning);
402
+ }
403
+ }
404
+ },
395
405
  define: {
396
406
  // Shim process.env for story files that use it (e.g., process.env.STORYBOOK_*)
397
407
  "process.env": "{}"
@@ -593,7 +603,7 @@ function fragmentsPlugin(options) {
593
603
  const address = _server.httpServer?.address();
594
604
  const port = typeof address === "object" && address ? address.port : 6006;
595
605
  const renderViewport = viewport || { width: 800, height: 600 };
596
- const { FigmaClient, bufferToBase64Url } = await import("./service-CFFBHW4X.js");
606
+ const { FigmaClient, bufferToBase64Url } = await import("./service-VA6XKADO.js");
597
607
  const figmaClient = new FigmaClient({
598
608
  accessToken: figmaToken
599
609
  });
@@ -684,7 +694,7 @@ function fragmentsPlugin(options) {
684
694
  );
685
695
  return;
686
696
  }
687
- const { FigmaClient } = await import("./service-CFFBHW4X.js");
697
+ const { FigmaClient } = await import("./service-VA6XKADO.js");
688
698
  const figmaClient = new FigmaClient({ accessToken: figmaToken });
689
699
  const { fileKey, nodeId } = figmaClient.parseUrl(figmaUrl);
690
700
  const figmaDesignProps = await figmaClient.getNodeProperties(
@@ -725,7 +735,7 @@ function fragmentsPlugin(options) {
725
735
  }));
726
736
  return;
727
737
  }
728
- const { getSharedTokenRegistry } = await import("./service-CFFBHW4X.js");
738
+ const { getSharedTokenRegistry } = await import("./service-VA6XKADO.js");
729
739
  const registry = getSharedTokenRegistry();
730
740
  if (!registry.isInitialized()) {
731
741
  await registry.initialize(config.tokens, projectRoot);
@@ -785,7 +795,7 @@ function fragmentsPlugin(options) {
785
795
  }));
786
796
  return;
787
797
  }
788
- const { getSharedTokenRegistry } = await import("./service-CFFBHW4X.js");
798
+ const { getSharedTokenRegistry } = await import("./service-VA6XKADO.js");
789
799
  const registry = getSharedTokenRegistry();
790
800
  if (!registry.isInitialized()) {
791
801
  await registry.initialize(config.tokens, projectRoot);
@@ -847,7 +857,7 @@ function fragmentsPlugin(options) {
847
857
  res.end(JSON.stringify({ error: "Could not resolve fragment file path" }));
848
858
  return;
849
859
  }
850
- const { getSharedTokenRegistry } = await import("./service-CFFBHW4X.js");
860
+ const { getSharedTokenRegistry } = await import("./service-VA6XKADO.js");
851
861
  const registry = getSharedTokenRegistry();
852
862
  if (!registry.isInitialized()) {
853
863
  await registry.initialize(config.tokens, projectRoot);
@@ -973,7 +983,7 @@ function fragmentsPlugin(options) {
973
983
  }
974
984
  const { writeFile, mkdir } = await import("fs/promises");
975
985
  const { join: join2 } = await import("path");
976
- const { BRAND: BRAND2 } = await import("./core-3NMNCLFW.js");
986
+ const { BRAND: BRAND2 } = await import("./core-T7BDYEGO.js");
977
987
  const fragmentsDir = join2(projectRoot, BRAND2.dataDir, BRAND2.componentsDir);
978
988
  await mkdir(fragmentsDir, { recursive: true });
979
989
  const fragmentPath = join2(
@@ -1009,7 +1019,7 @@ function fragmentsPlugin(options) {
1009
1019
  }
1010
1020
  if (!config.tokens || !config.tokens.include || config.tokens.include.length === 0) {
1011
1021
  try {
1012
- const { discoverTokenFiles } = await import("./discovery-AKGA6CJD.js");
1022
+ const { discoverTokenFiles } = await import("./discovery-Z4RDDFVR.js");
1013
1023
  const discovered = await discoverTokenFiles(projectRoot);
1014
1024
  if (discovered.length > 0) {
1015
1025
  config.tokens = {
@@ -1046,7 +1056,7 @@ function fragmentsPlugin(options) {
1046
1056
  const {
1047
1057
  getSharedTokenRegistry,
1048
1058
  generateTokenPatches
1049
- } = await import("./service-CFFBHW4X.js");
1059
+ } = await import("./service-VA6XKADO.js");
1050
1060
  const registry = getSharedTokenRegistry();
1051
1061
  if (!registry.isInitialized()) {
1052
1062
  await registry.initialize(config.tokens, projectRoot);
@@ -1465,7 +1475,15 @@ function mergeMetadata(fragment, metadataModule) {
1465
1475
  if (metadata.variants && fragment.variants) {
1466
1476
  for (const metaVariant of metadata.variants) {
1467
1477
  const fragmentVariant = fragment.variants.find(v => v.name === metaVariant.name);
1468
- if (fragmentVariant && metaVariant.figma && !fragmentVariant.figma) {
1478
+ if (!fragmentVariant) continue;
1479
+
1480
+ // Use authored code snippets from fragment metadata when story variants
1481
+ // don't define their own code.
1482
+ if (metaVariant.code && !fragmentVariant.code) {
1483
+ fragmentVariant.code = metaVariant.code;
1484
+ }
1485
+
1486
+ if (metaVariant.figma && !fragmentVariant.figma) {
1469
1487
  fragmentVariant.figma = metaVariant.figma;
1470
1488
  }
1471
1489
  }
@@ -1552,7 +1570,9 @@ export async function loadFragment(path) {
1552
1570
  }
1553
1571
  }
1554
1572
 
1555
- loadedFragments.set(path, fragment);
1573
+ if (fragment) {
1574
+ loadedFragments.set(path, fragment);
1575
+ }
1556
1576
  return fragment;
1557
1577
  }
1558
1578
 
@@ -1931,7 +1951,7 @@ async function loadFullFragmentForCompare(_server, _fragmentFiles, componentName
1931
1951
  }
1932
1952
  }
1933
1953
  async function compareImages(image1Base64, image2Base64, threshold) {
1934
- const { DiffEngine, base64UrlToBuffer, bufferToBase64Url } = await import("./service-CFFBHW4X.js");
1954
+ const { DiffEngine, base64UrlToBuffer, bufferToBase64Url } = await import("./service-VA6XKADO.js");
1935
1955
  const { PNG } = await import("pngjs");
1936
1956
  const buffer1 = base64UrlToBuffer(image1Base64);
1937
1957
  const buffer2 = base64UrlToBuffer(image2Base64);
@@ -2184,4 +2204,4 @@ export {
2184
2204
  createDevServer,
2185
2205
  fragmentsPlugin
2186
2206
  };
2187
- //# sourceMappingURL=viewer-QTR7QJMM.js.map
2207
+ //# sourceMappingURL=viewer-IVP5XC7U.js.map