@fragments-sdk/cli 0.15.10 → 0.17.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/dist/bin.js +901 -789
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-6SQPP47U.js → chunk-ANTWP3UG.js} +532 -31
- package/dist/chunk-ANTWP3UG.js.map +1 -0
- package/dist/{chunk-ONUP6Z4W.js → chunk-B4A4ZEGS.js} +9 -9
- package/dist/{chunk-32LIWN2P.js → chunk-FFCI6OVZ.js} +584 -261
- package/dist/chunk-FFCI6OVZ.js.map +1 -0
- package/dist/{chunk-HQ6A6DTV.js → chunk-HNHE64CR.js} +315 -1089
- package/dist/chunk-HNHE64CR.js.map +1 -0
- package/dist/{chunk-BJE3425I.js → chunk-MN3B2EE6.js} +2 -2
- package/dist/{chunk-QCN35LJU.js → chunk-SAQW37L5.js} +3 -2
- package/dist/chunk-SAQW37L5.js.map +1 -0
- package/dist/{chunk-2WXKALIG.js → chunk-SNZXGHL2.js} +2 -2
- package/dist/{chunk-5JF26E55.js → chunk-VT2J62ND.js} +11 -11
- package/dist/{codebase-scanner-MQHUZC2G.js → codebase-scanner-2T5QIDBA.js} +2 -2
- package/dist/core/index.js +53 -1
- package/dist/{create-EXURTBKK.js → create-D44QD7MV.js} +2 -2
- package/dist/{doctor-BDPMYYE6.js → doctor-7B5N4JYU.js} +2 -2
- package/dist/{generate-PVOLUAAC.js → generate-T47JZRVU.js} +4 -4
- package/dist/govern-scan-X6UEIOSV.js +632 -0
- package/dist/govern-scan-X6UEIOSV.js.map +1 -0
- package/dist/index.js +7 -8
- package/dist/index.js.map +1 -1
- package/dist/{init-SSGUSP7Z.js → init-2RGAY4W6.js} +5 -5
- package/dist/mcp-bin.js +2 -2
- package/dist/scan-A2WJM54L.js +14 -0
- package/dist/{scan-generate-VY27PIOX.js → scan-generate-LUSOHT36.js} +4 -4
- package/dist/{service-QJGWUIVL.js → service-ROCP7TKG.js} +13 -15
- package/dist/{snapshot-WIJMEIFT.js → snapshot-B3SAW74Y.js} +2 -2
- package/dist/{static-viewer-7QIBQZRC.js → static-viewer-7L6UEYTJ.js} +3 -3
- package/dist/{test-64Z5BKBA.js → test-PQDVDURE.js} +3 -3
- package/dist/{token-normalizer-TEPOVBPV.js → token-normalizer-7TFCVDZL.js} +2 -2
- package/dist/{tokens-NZWFQIAB.js → tokens-64FG5FDP.js} +8 -9
- package/dist/{tokens-NZWFQIAB.js.map → tokens-64FG5FDP.js.map} +1 -1
- package/dist/{tokens-generate-5JQSJ27E.js → tokens-generate-CL4LBBQA.js} +2 -2
- package/package.json +9 -8
- package/src/bin.ts +55 -88
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/label.contract.json +1 -1
- package/src/commands/__fixtures__/shadcn-label-wrapper/src/components/ui/primitive.contract.json +1 -1
- package/src/commands/__tests__/context-cloud.test.ts +291 -0
- package/src/commands/__tests__/govern-scan.test.ts +185 -0
- package/src/commands/__tests__/govern.test.ts +1 -0
- package/src/commands/context-cloud.ts +355 -0
- package/src/commands/govern-scan-report.ts +170 -0
- package/src/commands/govern-scan.ts +282 -135
- package/src/commands/govern.ts +0 -157
- package/src/mcp/__tests__/server.integration.test.ts +9 -20
- package/src/service/enhance/codebase-scanner.ts +3 -2
- package/src/service/enhance/types.ts +3 -0
- package/dist/chunk-32LIWN2P.js.map +0 -1
- package/dist/chunk-6SQPP47U.js.map +0 -1
- package/dist/chunk-HQ6A6DTV.js.map +0 -1
- package/dist/chunk-MHIBEEW4.js +0 -511
- package/dist/chunk-MHIBEEW4.js.map +0 -1
- package/dist/chunk-QCN35LJU.js.map +0 -1
- package/dist/govern-scan-DW4QUAYD.js +0 -414
- package/dist/govern-scan-DW4QUAYD.js.map +0 -1
- package/dist/init-cloud-3DNKPWFB.js +0 -304
- package/dist/init-cloud-3DNKPWFB.js.map +0 -1
- package/dist/node-37AUE74M.js +0 -65
- package/dist/push-contracts-WY32TFP6.js +0 -84
- package/dist/push-contracts-WY32TFP6.js.map +0 -1
- package/dist/scan-PKSYSTRR.js +0 -15
- package/dist/static-viewer-7QIBQZRC.js.map +0 -1
- package/dist/token-parser-32KOIOFN.js +0 -22
- package/dist/token-parser-32KOIOFN.js.map +0 -1
- package/dist/tokens-push-HY3KO36V.js +0 -148
- package/dist/tokens-push-HY3KO36V.js.map +0 -1
- package/src/commands/init-cloud.ts +0 -382
- package/src/commands/push-contracts.ts +0 -112
- package/src/commands/tokens-push.ts +0 -199
- /package/dist/{chunk-ONUP6Z4W.js.map → chunk-B4A4ZEGS.js.map} +0 -0
- /package/dist/{chunk-BJE3425I.js.map → chunk-MN3B2EE6.js.map} +0 -0
- /package/dist/{chunk-2WXKALIG.js.map → chunk-SNZXGHL2.js.map} +0 -0
- /package/dist/{chunk-5JF26E55.js.map → chunk-VT2J62ND.js.map} +0 -0
- /package/dist/{codebase-scanner-MQHUZC2G.js.map → codebase-scanner-2T5QIDBA.js.map} +0 -0
- /package/dist/{create-EXURTBKK.js.map → create-D44QD7MV.js.map} +0 -0
- /package/dist/{doctor-BDPMYYE6.js.map → doctor-7B5N4JYU.js.map} +0 -0
- /package/dist/{generate-PVOLUAAC.js.map → generate-T47JZRVU.js.map} +0 -0
- /package/dist/{init-SSGUSP7Z.js.map → init-2RGAY4W6.js.map} +0 -0
- /package/dist/{node-37AUE74M.js.map → scan-A2WJM54L.js.map} +0 -0
- /package/dist/{scan-generate-VY27PIOX.js.map → scan-generate-LUSOHT36.js.map} +0 -0
- /package/dist/{scan-PKSYSTRR.js.map → service-ROCP7TKG.js.map} +0 -0
- /package/dist/{snapshot-WIJMEIFT.js.map → snapshot-B3SAW74Y.js.map} +0 -0
- /package/dist/{service-QJGWUIVL.js.map → static-viewer-7L6UEYTJ.js.map} +0 -0
- /package/dist/{test-64Z5BKBA.js.map → test-PQDVDURE.js.map} +0 -0
- /package/dist/{token-normalizer-TEPOVBPV.js.map → token-normalizer-7TFCVDZL.js.map} +0 -0
- /package/dist/{tokens-generate-5JQSJ27E.js.map → tokens-generate-CL4LBBQA.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/config.ts","../src/core/discovery.ts","../src/core/generators/typescript-extractor.ts","../src/core/generators/registry.ts","../src/core/loader.ts","../src/core/parser.ts","../src/core/previewLoader.ts","../src/core/importAnalyzer.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { resolve, dirname } from 'node:path';\nimport { createJiti } from 'jiti';\nimport { BRAND, fragmentsConfigSchema } from '@fragments-sdk/core';\nimport type { FragmentsConfig, StorybookFilterConfig } from '@fragments-sdk/core';\n\nconst STORYBOOK_FILTER_DEFAULTS: StorybookFilterConfig = {\n excludeDeprecated: true,\n excludeTests: true,\n excludeSvgIcons: true,\n excludeSubComponents: true,\n};\n\nconst DEFAULT_CONFIG: FragmentsConfig = {\n include: [\n `src/**/*${BRAND.fileExtension}`, // *.contract.json files (V2 canonical)\n 'src/**/*.fragment.tsx', // Legacy fragment files (still supported)\n 'src/**/*.stories.tsx', // Storybook stories (auto-converted)\n ],\n exclude: ['**/node_modules/**'],\n components: ['src/**/index.tsx', 'src/**/*.tsx'],\n framework: 'react',\n storybook: STORYBOOK_FILTER_DEFAULTS,\n snippets: {\n mode: 'warn',\n scope: 'snippet+render',\n requireFullSnippet: true,\n allowedExternalModules: ['@phosphor-icons/react', 'recharts', 'react-day-picker'],\n },\n};\n\n/**\n * Find the config file in the current directory or parent directories.\n * Checks for both the current config file name and the legacy name.\n */\nexport function findConfigFile(startDir: string = process.cwd()): string | null {\n let currentDir = startDir;\n\n while (currentDir !== dirname(currentDir)) {\n // Check for current config file name first\n const configPath = resolve(currentDir, BRAND.configFile);\n if (existsSync(configPath)) {\n return configPath;\n }\n // Also check for legacy config file name\n const legacyConfigPath = resolve(currentDir, BRAND.legacyConfigFile);\n if (existsSync(legacyConfigPath)) {\n return legacyConfigPath;\n }\n currentDir = dirname(currentDir);\n }\n\n return null;\n}\n\n/**\n * Load and validate the config file\n */\nexport async function loadConfig(configPath?: string): Promise<{\n config: FragmentsConfig;\n configDir: string;\n}> {\n const resolvedPath = configPath ?? findConfigFile();\n\n if (!resolvedPath) {\n return {\n config: DEFAULT_CONFIG,\n configDir: process.cwd(),\n };\n }\n\n try {\n // Use jiti to load TypeScript config files\n const jiti = createJiti(import.meta.url, {\n interopDefault: true,\n });\n const rawConfig = await jiti.import(resolvedPath);\n\n const result = fragmentsConfigSchema.safeParse(rawConfig);\n\n if (!result.success) {\n const errors = result.error.errors\n .map((e) => ` - ${e.path.join('.')}: ${e.message}`)\n .join('\\n');\n throw new Error(`Invalid config in ${resolvedPath}:\\n${errors}`);\n }\n\n const merged: FragmentsConfig = { ...DEFAULT_CONFIG, ...result.data };\n\n // Deep-merge storybook filter defaults so consumers only override what they need\n merged.storybook = { ...STORYBOOK_FILTER_DEFAULTS, ...result.data?.storybook };\n\n return {\n config: merged,\n configDir: dirname(resolvedPath),\n };\n } catch (error) {\n if (error instanceof Error && error.message.includes('Invalid config')) {\n throw error;\n }\n throw new Error(`Failed to load config from ${resolvedPath}: ${error}`);\n }\n}\n","import { resolve, dirname, basename } from 'node:path';\nimport { readFile } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport fg from 'fast-glob';\nimport { BRAND } from '@fragments-sdk/core';\nimport type { FragmentsConfig } from '@fragments-sdk/core';\n\n/**\n * Convert a lowercase file name to PascalCase component name.\n * e.g., \"button\" → \"Button\", \"date-picker\" → \"DatePicker\"\n */\nfunction toPascalCase(name: string): string {\n return name\n .split(/[-_]/)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('');\n}\n\n/**\n * Extract PascalCase named exports from a source file using regex.\n * Finds patterns like:\n * - `export function Button`\n * - `export const Button`\n * - `export { Button, CardHeader }` (from export blocks)\n * - `function Button` + later `export { Button }` (shadcn pattern)\n */\nasync function extractPascalCaseExports(filePath: string): Promise<string[]> {\n try {\n const content = await readFile(filePath, 'utf-8');\n const exports = new Set<string>();\n\n // Pattern 1: export function ComponentName\n const exportFuncRegex = /export\\s+function\\s+([A-Z][a-zA-Z0-9]*)/g;\n let match;\n while ((match = exportFuncRegex.exec(content)) !== null) {\n exports.add(match[1]);\n }\n\n // Pattern 2: export const ComponentName\n const exportConstRegex = /export\\s+const\\s+([A-Z][a-zA-Z0-9]*)/g;\n while ((match = exportConstRegex.exec(content)) !== null) {\n exports.add(match[1]);\n }\n\n // Pattern 3: export { Name1, Name2, ... }\n const exportBlockRegex = /export\\s*\\{([^}]+)\\}/g;\n while ((match = exportBlockRegex.exec(content)) !== null) {\n const names = match[1].split(',').map((n) => n.trim().split(/\\s+as\\s+/)[0].trim());\n for (const name of names) {\n if (/^[A-Z]/.test(name)) {\n exports.add(name);\n }\n }\n }\n\n return Array.from(exports);\n } catch {\n return [];\n }\n}\n\nexport interface DiscoveredFile {\n /** Absolute path to the file */\n absolutePath: string;\n /** Path relative to config directory */\n relativePath: string;\n}\n\n/**\n * Discovered component with source file information\n */\nexport interface DiscoveredComponent {\n /** Component name (e.g., \"Button\") */\n name: string;\n /** Absolute path to the component source file */\n sourcePath: string;\n /** Path relative to config directory */\n relativePath: string;\n /** Path to storybook file if found */\n storyPath?: string;\n}\n\n/**\n * Discover block files (*.block.ts) under the config directory.\n * Also discovers legacy *.recipe.ts files for backward compatibility.\n */\nexport async function discoverBlockFiles(\n configDir: string,\n exclude?: string[]\n): Promise<DiscoveredFile[]> {\n const patterns = [\n `**/*${BRAND.blockFileExtension}`,\n `**/*${BRAND.recipeFileExtension}`,\n ];\n const files = await fg(patterns, {\n cwd: configDir,\n ignore: exclude ?? ['**/node_modules/**', '**/dist/**'],\n absolute: false,\n });\n\n return files.map((relativePath) => ({\n relativePath,\n absolutePath: resolve(configDir, relativePath),\n }));\n}\n\n/**\n * @deprecated Use discoverBlockFiles instead\n */\nexport const discoverRecipeFiles = discoverBlockFiles;\n\n/**\n * Discover fragment files matching the config patterns.\n * Also discovers .contract.json files for framework-agnostic component contracts.\n */\nexport async function discoverFragmentFiles(\n config: FragmentsConfig,\n configDir: string\n): Promise<DiscoveredFile[]> {\n const defaultExcludes = [\n '**/*.test.stories.*',\n '**/*.stories.test.*',\n '**/*.test.story.*',\n '**/*.story.test.*',\n ];\n\n // Include .contract.json files alongside configured patterns\n const patterns = [\n ...config.include,\n '**/*.contract.json',\n ];\n\n const files = await fg(patterns, {\n cwd: configDir,\n ignore: [...defaultExcludes, ...(config.exclude ?? [])],\n absolute: false,\n });\n\n return files.map((relativePath) => ({\n relativePath,\n absolutePath: resolve(configDir, relativePath),\n }));\n}\n\n/**\n * Discover component files for coverage validation\n */\nexport async function discoverComponentFiles(\n config: FragmentsConfig,\n configDir: string\n): Promise<DiscoveredFile[]> {\n if (!config.components || config.components.length === 0) {\n return [];\n }\n\n const files = await fg(config.components, {\n cwd: configDir,\n ignore: [\n ...(config.exclude ?? []),\n // Exclude fragment files themselves\n ...config.include,\n // Exclude test files\n '**/*.test.*',\n '**/*.spec.*',\n '**/__tests__/**',\n ],\n absolute: false,\n });\n\n return files.map((relativePath) => ({\n relativePath,\n absolutePath: resolve(configDir, relativePath),\n }));\n}\n\n/**\n * Extract component name from file path\n */\nexport function extractComponentName(filePath: string): string {\n // Handle index.tsx files - use parent directory name\n const parts = filePath.replace(/\\\\/g, '/').split('/');\n const fileName = parts[parts.length - 1];\n\n if (fileName === 'index.tsx' || fileName === 'index.ts') {\n return parts[parts.length - 2] ?? 'Unknown';\n }\n\n // Remove extension\n return fileName.replace(/\\.(tsx?|jsx?)$/, '');\n}\n\n/**\n * Default patterns for component discovery\n */\nconst DEFAULT_COMPONENT_PATTERNS = [\n 'src/components/**/*.tsx',\n 'src/components/**/index.tsx',\n 'components/**/*.tsx',\n 'lib/components/**/*.tsx',\n 'packages/*/src/components/**/*.tsx',\n];\n\n/**\n * Patterns to exclude from component discovery\n */\nconst DEFAULT_EXCLUDE_PATTERNS = [\n '**/*.test.*',\n '**/*.spec.*',\n '**/*.stories.*',\n '**/*.story.*',\n '**/__tests__/**',\n '**/__mocks__/**',\n '**/node_modules/**',\n '**/dist/**',\n];\n\n/**\n * Discover components from source files\n *\n * This function finds React components by:\n * 1. Looking for TypeScript/TSX files in common component directories\n * 2. Filtering out test files, stories, and internal files\n * 3. Extracting component names from file names or directories\n */\nexport async function discoverComponentsFromSource(\n configDir: string,\n patterns?: string[],\n exclude?: string[]\n): Promise<DiscoveredComponent[]> {\n const searchPatterns = patterns && patterns.length > 0\n ? patterns\n : DEFAULT_COMPONENT_PATTERNS;\n\n const excludePatterns = [\n ...DEFAULT_EXCLUDE_PATTERNS,\n ...(exclude ?? []),\n ];\n\n const files = await fg(searchPatterns, {\n cwd: configDir,\n ignore: excludePatterns,\n absolute: false,\n });\n\n // Separate files into PascalCase (existing behavior) and lowercase (new: parse exports)\n const pascalCaseFiles: string[] = [];\n const lowercaseFiles: string[] = [];\n\n for (const file of files) {\n const name = extractComponentName(file);\n if (/^[A-Z]/.test(name)) {\n pascalCaseFiles.push(file);\n } else if (/^[a-z]/.test(name)) {\n lowercaseFiles.push(file);\n }\n }\n\n // Find associated story files\n const storyPatterns = [\n '**/*.stories.tsx',\n '**/*.stories.ts',\n '**/*.story.tsx',\n '**/*.story.ts',\n ];\n\n const storyFiles = await fg(storyPatterns, {\n cwd: configDir,\n ignore: ['**/node_modules/**', '**/dist/**'],\n absolute: false,\n });\n\n const storyMap = new Map<string, string>();\n for (const storyFile of storyFiles) {\n const name = extractComponentName(storyFile.replace(/\\.stories?\\.(tsx?|jsx?)$/, '.tsx'));\n storyMap.set(name, storyFile);\n }\n\n // Build discovered components\n const components: DiscoveredComponent[] = [];\n\n // Add PascalCase-named files directly (existing behavior)\n for (const file of pascalCaseFiles) {\n const name = extractComponentName(file);\n const absolutePath = resolve(configDir, file);\n const storyFile = storyMap.get(name);\n\n components.push({\n name,\n sourcePath: absolutePath,\n relativePath: file,\n storyPath: storyFile ? resolve(configDir, storyFile) : undefined,\n });\n }\n\n // For lowercase files (e.g., shadcn's button.tsx, card.tsx), extract the\n // primary PascalCase export as the component name. This discovers components\n // from libraries that use lowercase file names.\n for (const file of lowercaseFiles) {\n const absolutePath = resolve(configDir, file);\n const fileName = extractComponentName(file);\n const pascalName = toPascalCase(fileName);\n\n // Parse exports from the file to find PascalCase component names\n const exports = await extractPascalCaseExports(absolutePath);\n\n // Use the primary component: prefer the PascalCase version of the file name,\n // otherwise take the first PascalCase export\n const primaryExport = exports.find((e) => e === pascalName) || exports[0];\n if (primaryExport) {\n const storyFile = storyMap.get(primaryExport) || storyMap.get(fileName);\n\n components.push({\n name: primaryExport,\n sourcePath: absolutePath,\n relativePath: file,\n storyPath: storyFile ? resolve(configDir, storyFile) : undefined,\n });\n }\n }\n\n // Sort by name\n components.sort((a, b) => a.name.localeCompare(b.name));\n\n return components;\n}\n\n/**\n * Discover components from a barrel export file (index.ts)\n *\n * Parses the barrel file to find exported components.\n * This is useful for libraries that expose components through a single entry point.\n */\nexport async function discoverComponentsFromBarrel(\n barrelPath: string,\n configDir: string\n): Promise<DiscoveredComponent[]> {\n const absoluteBarrelPath = resolve(configDir, barrelPath);\n\n if (!existsSync(absoluteBarrelPath)) {\n return [];\n }\n\n const content = await readFile(absoluteBarrelPath, 'utf-8');\n const components: DiscoveredComponent[] = [];\n\n // Match export statements like:\n // export { Button } from './Button'\n // export { Card, CardHeader } from './Card'\n // export * from './Modal'\n const exportRegex = /export\\s+(?:\\*|{([^}]+)})\\s+from\\s+['\"]([^'\"]+)['\"]/g;\n\n let match;\n while ((match = exportRegex.exec(content)) !== null) {\n const exportedNames = match[1];\n const importPath = match[2];\n\n // Resolve the import path\n const barrelDir = dirname(absoluteBarrelPath);\n let resolvedPath = resolve(barrelDir, importPath);\n\n // Add extension if needed\n if (!resolvedPath.endsWith('.tsx') && !resolvedPath.endsWith('.ts')) {\n if (existsSync(`${resolvedPath}.tsx`)) {\n resolvedPath = `${resolvedPath}.tsx`;\n } else if (existsSync(`${resolvedPath}.ts`)) {\n resolvedPath = `${resolvedPath}.ts`;\n } else if (existsSync(`${resolvedPath}/index.tsx`)) {\n resolvedPath = `${resolvedPath}/index.tsx`;\n } else if (existsSync(`${resolvedPath}/index.ts`)) {\n resolvedPath = `${resolvedPath}/index.ts`;\n }\n }\n\n if (!existsSync(resolvedPath)) {\n continue;\n }\n\n if (exportedNames) {\n // Named exports: { Button, Card }\n const names = exportedNames.split(',').map((n) => n.trim().split(/\\s+as\\s+/)[0].trim());\n for (const name of names) {\n if (/^[A-Z]/.test(name)) {\n const relativePath = resolvedPath.replace(configDir + '/', '');\n components.push({\n name,\n sourcePath: resolvedPath,\n relativePath,\n });\n }\n }\n } else {\n // Star export: export * from './Component'\n const name = extractComponentName(importPath);\n if (/^[A-Z]/.test(name)) {\n const relativePath = resolvedPath.replace(configDir + '/', '');\n components.push({\n name,\n sourcePath: resolvedPath,\n relativePath,\n });\n }\n }\n }\n\n return components;\n}\n\n/**\n * Default glob patterns for discovering token files (SCSS/CSS with custom properties)\n */\nconst DEFAULT_TOKEN_PATTERNS = [\n 'src/**/tokens/**/_variables.scss',\n 'src/**/tokens/**/variables.scss',\n 'src/**/styles/**/variables.scss',\n 'src/**/styles/**/tokens.scss',\n 'src/**/styles/**/variables.css',\n 'src/**/theme/**/_variables.scss',\n 'src/**/theme/**/tokens.css',\n // DTCG token files\n '**/*.tokens.json',\n '**/*.tokens',\n];\n\n/**\n * Discover token files (SCSS/CSS files containing CSS custom properties).\n * Uses config.tokens.include patterns if provided, otherwise falls back\n * to default patterns that match common project structures.\n */\nexport async function discoverTokenFiles(\n configDir: string,\n patterns?: string[],\n exclude?: string[]\n): Promise<DiscoveredFile[]> {\n const searchPatterns = patterns && patterns.length > 0\n ? patterns\n : DEFAULT_TOKEN_PATTERNS;\n\n const files = await fg(searchPatterns, {\n cwd: configDir,\n ignore: exclude ?? ['**/node_modules/**', '**/dist/**'],\n absolute: false,\n });\n\n return files.map((relativePath) => ({\n relativePath,\n absolutePath: resolve(configDir, relativePath),\n }));\n}\n\n/**\n * Discover fragment files from installed packages that declare a \"fragments\" field\n * in their package.json. This allows consumer projects to see components from\n * installed packages (e.g. @fragments-sdk/ui) in the dev viewer.\n */\nexport async function discoverInstalledFragments(\n projectRoot: string\n): Promise<DiscoveredFile[]> {\n const pkgJsonPath = resolve(projectRoot, 'package.json');\n if (!existsSync(pkgJsonPath)) return [];\n\n const pkgJson = JSON.parse(await readFile(pkgJsonPath, 'utf-8'));\n const allDeps = { ...pkgJson.dependencies, ...pkgJson.devDependencies };\n const results: DiscoveredFile[] = [];\n\n for (const depName of Object.keys(allDeps)) {\n const depDir = resolve(projectRoot, 'node_modules', depName);\n const depPkgPath = resolve(depDir, 'package.json');\n if (!existsSync(depPkgPath)) continue;\n\n const depPkg = JSON.parse(await readFile(depPkgPath, 'utf-8'));\n if (!depPkg.fragments) continue;\n\n // Package declares fragments — scan for source fragment files\n const files = await fg(\n [`src/**/*${BRAND.fileExtension}`, 'src/**/*.stories.tsx'],\n { cwd: depDir, ignore: ['**/node_modules/**'], absolute: false }\n );\n\n for (const rel of files) {\n results.push({\n relativePath: `${depName}/${rel}`,\n absolutePath: resolve(depDir, rel),\n });\n }\n }\n\n return results;\n}\n\n/**\n * Discover all components using multiple strategies\n */\nexport async function discoverAllComponents(\n configDir: string,\n options: {\n patterns?: string[];\n exclude?: string[];\n barrelFiles?: string[];\n } = {}\n): Promise<DiscoveredComponent[]> {\n const componentsMap = new Map<string, DiscoveredComponent>();\n\n // Discover from source files\n const sourceComponents = await discoverComponentsFromSource(\n configDir,\n options.patterns,\n options.exclude\n );\n\n for (const comp of sourceComponents) {\n componentsMap.set(comp.name, comp);\n }\n\n // Discover from barrel files if specified\n if (options.barrelFiles && options.barrelFiles.length > 0) {\n for (const barrelFile of options.barrelFiles) {\n const barrelComponents = await discoverComponentsFromBarrel(barrelFile, configDir);\n for (const comp of barrelComponents) {\n // Only add if not already found\n if (!componentsMap.has(comp.name)) {\n componentsMap.set(comp.name, comp);\n }\n }\n }\n }\n\n return Array.from(componentsMap.values()).sort((a, b) => a.name.localeCompare(b.name));\n}\n","/**\n * TypeScript Props Extractor\n * Extracts prop types, default values, and JSDoc comments from React component files\n */\n\nimport ts from \"typescript\";\nimport { readFileSync } from \"node:fs\";\nimport type { RegistryPropEntry } from '@fragments-sdk/core';\n\n/**\n * Result of extracting props from a component file\n */\nexport interface ExtractedProps {\n /** Component name */\n componentName: string;\n /** Whether the component uses export default */\n isDefaultExport?: boolean;\n /** Props interface name (e.g., \"ButtonProps\") */\n propsInterfaceName?: string;\n /** Extracted props */\n props: Record<string, RegistryPropEntry>;\n /** Named exports from the file */\n exports: string[];\n /** Import statements (for dependency tracking) */\n imports: string[];\n}\n\n/**\n * Extract props from a TypeScript/TSX component file\n */\nexport function extractPropsFromFile(filePath: string): ExtractedProps | null {\n const sourceText = readFileSync(filePath, \"utf-8\");\n return extractPropsFromSource(sourceText, filePath);\n}\n\n/**\n * Extract props from TypeScript source code\n */\nexport function extractPropsFromSource(\n sourceText: string,\n fileName = \"component.tsx\"\n): ExtractedProps | null {\n const sourceFile = ts.createSourceFile(\n fileName,\n sourceText,\n ts.ScriptTarget.Latest,\n true,\n fileName.endsWith(\".tsx\") ? ts.ScriptKind.TSX : ts.ScriptKind.TS\n );\n\n const result: ExtractedProps = {\n componentName: \"\",\n props: {},\n exports: [],\n imports: [],\n };\n\n // Find all exports and props interfaces\n const propsInterfaces = new Map<string, ts.InterfaceDeclaration | ts.TypeAliasDeclaration>();\n const componentExports: string[] = [];\n const defaultExports = new Set<string>();\n const importedModules: string[] = [];\n\n ts.forEachChild(sourceFile, (node) => {\n // Track imports\n if (ts.isImportDeclaration(node)) {\n const moduleSpecifier = node.moduleSpecifier;\n if (ts.isStringLiteral(moduleSpecifier)) {\n importedModules.push(moduleSpecifier.text);\n }\n }\n\n // Find interface declarations (e.g., interface ButtonProps { ... })\n if (ts.isInterfaceDeclaration(node)) {\n const name = node.name.text;\n if (name.endsWith(\"Props\")) {\n propsInterfaces.set(name, node);\n }\n }\n\n // Find type alias declarations (e.g., type ButtonProps = { ... })\n if (ts.isTypeAliasDeclaration(node)) {\n const name = node.name.text;\n if (name.endsWith(\"Props\")) {\n propsInterfaces.set(name, node);\n }\n }\n\n // Find exported functions/components\n if (ts.isFunctionDeclaration(node) && node.name) {\n const hasExport = node.modifiers?.some(\n (m) => m.kind === ts.SyntaxKind.ExportKeyword\n );\n const hasDefault = node.modifiers?.some(\n (m) => m.kind === ts.SyntaxKind.DefaultKeyword\n );\n if (hasExport) {\n componentExports.push(node.name.text);\n if (hasDefault) {\n defaultExports.add(node.name.text);\n }\n }\n }\n\n // Find exported variable declarations (e.g., export const Button = ...)\n if (ts.isVariableStatement(node)) {\n const hasExport = node.modifiers?.some(\n (m) => m.kind === ts.SyntaxKind.ExportKeyword\n );\n if (hasExport) {\n for (const decl of node.declarationList.declarations) {\n if (ts.isIdentifier(decl.name)) {\n componentExports.push(decl.name.text);\n }\n }\n }\n }\n\n // Find export declarations (e.g., export { Button })\n if (ts.isExportDeclaration(node) && node.exportClause) {\n if (ts.isNamedExports(node.exportClause)) {\n for (const element of node.exportClause.elements) {\n componentExports.push(element.name.text);\n }\n }\n }\n });\n\n result.exports = componentExports;\n result.imports = importedModules;\n\n // Find the main component (first PascalCase export)\n const mainComponent = componentExports.find(\n (name) => /^[A-Z]/.test(name) && !name.endsWith(\"Props\")\n );\n\n if (!mainComponent) {\n return null;\n }\n\n result.componentName = mainComponent;\n result.isDefaultExport = defaultExports.has(mainComponent);\n\n // Find matching props interface\n const propsInterfaceName = `${mainComponent}Props`;\n const propsInterface = propsInterfaces.get(propsInterfaceName);\n\n if (propsInterface) {\n result.propsInterfaceName = propsInterfaceName;\n result.props = extractPropsFromInterface(propsInterface, sourceFile);\n }\n\n return result;\n}\n\n/**\n * Extract props from an interface or type alias declaration\n */\nfunction extractPropsFromInterface(\n node: ts.InterfaceDeclaration | ts.TypeAliasDeclaration,\n sourceFile: ts.SourceFile\n): Record<string, RegistryPropEntry> {\n const props: Record<string, RegistryPropEntry> = {};\n\n // Handle interface declaration\n if (ts.isInterfaceDeclaration(node)) {\n for (const member of node.members) {\n if (ts.isPropertySignature(member) && member.name) {\n const propName = member.name.getText(sourceFile);\n const prop = extractPropFromMember(member, sourceFile);\n if (prop) {\n props[propName] = prop;\n }\n }\n }\n }\n\n // Handle type alias declaration\n if (ts.isTypeAliasDeclaration(node)) {\n const typeNode = node.type;\n if (ts.isTypeLiteralNode(typeNode)) {\n for (const member of typeNode.members) {\n if (ts.isPropertySignature(member) && member.name) {\n const propName = member.name.getText(sourceFile);\n const prop = extractPropFromMember(member, sourceFile);\n if (prop) {\n props[propName] = prop;\n }\n }\n }\n }\n }\n\n return props;\n}\n\n/**\n * Extract prop info from a property signature\n */\nfunction extractPropFromMember(\n member: ts.PropertySignature,\n sourceFile: ts.SourceFile\n): RegistryPropEntry | null {\n const entry: RegistryPropEntry = {};\n\n // Check if required\n entry.required = !member.questionToken;\n\n // Get type\n if (member.type) {\n const typeInfo = parseTypeNode(member.type, sourceFile);\n entry.type = typeInfo.type;\n entry.typeKind = typeInfo.typeKind;\n if (typeInfo.options) {\n entry.options = typeInfo.options;\n }\n }\n\n // Get JSDoc comment\n const jsDocComment = getJSDocComment(member);\n if (jsDocComment) {\n entry.description = jsDocComment;\n }\n\n // Get default value from JSDoc @default tag\n const defaultValue = getJSDocDefault(member);\n if (defaultValue !== undefined) {\n entry.default = defaultValue;\n }\n\n return entry;\n}\n\n/**\n * Parse a TypeScript type node into a simplified representation\n */\nfunction parseTypeNode(\n typeNode: ts.TypeNode,\n sourceFile: ts.SourceFile\n): { type: string; typeKind: RegistryPropEntry[\"typeKind\"]; options?: string[] } {\n // String\n if (typeNode.kind === ts.SyntaxKind.StringKeyword) {\n return { type: \"string\", typeKind: \"string\" };\n }\n\n // Number\n if (typeNode.kind === ts.SyntaxKind.NumberKeyword) {\n return { type: \"number\", typeKind: \"number\" };\n }\n\n // Boolean\n if (typeNode.kind === ts.SyntaxKind.BooleanKeyword) {\n return { type: \"boolean\", typeKind: \"boolean\" };\n }\n\n // Union type (string literal union for enums)\n if (ts.isUnionTypeNode(typeNode)) {\n const options: string[] = [];\n let allLiterals = true;\n\n for (const subType of typeNode.types) {\n if (ts.isLiteralTypeNode(subType)) {\n if (ts.isStringLiteral(subType.literal)) {\n options.push(subType.literal.text);\n } else if (subType.literal.kind === ts.SyntaxKind.TrueKeyword) {\n options.push(\"true\");\n } else if (subType.literal.kind === ts.SyntaxKind.FalseKeyword) {\n options.push(\"false\");\n } else {\n allLiterals = false;\n }\n } else {\n allLiterals = false;\n }\n }\n\n if (allLiterals && options.length > 0) {\n return {\n type: options.map((o) => `\"${o}\"`).join(\" | \"),\n typeKind: \"enum\",\n options,\n };\n }\n\n return {\n type: typeNode.getText(sourceFile),\n typeKind: \"union\",\n };\n }\n\n // Function type\n if (ts.isFunctionTypeNode(typeNode)) {\n return {\n type: typeNode.getText(sourceFile),\n typeKind: \"function\",\n };\n }\n\n // Array type\n if (ts.isArrayTypeNode(typeNode)) {\n return {\n type: typeNode.getText(sourceFile),\n typeKind: \"array\",\n };\n }\n\n // Type reference (e.g., ReactNode, React.ReactElement)\n if (ts.isTypeReferenceNode(typeNode)) {\n const typeName = typeNode.typeName.getText(sourceFile);\n\n // React types\n if (typeName === \"ReactNode\" || typeName === \"React.ReactNode\") {\n return { type: \"ReactNode\", typeKind: \"node\" };\n }\n if (typeName === \"ReactElement\" || typeName === \"React.ReactElement\") {\n return { type: \"ReactElement\", typeKind: \"element\" };\n }\n if (typeName === \"JSX.Element\") {\n return { type: \"JSX.Element\", typeKind: \"element\" };\n }\n\n return {\n type: typeNode.getText(sourceFile),\n typeKind: \"object\",\n };\n }\n\n // Object type literal\n if (ts.isTypeLiteralNode(typeNode)) {\n return {\n type: typeNode.getText(sourceFile),\n typeKind: \"object\",\n };\n }\n\n // Default: unknown\n return {\n type: typeNode.getText(sourceFile),\n typeKind: \"unknown\",\n };\n}\n\n/**\n * Get JSDoc comment from a node\n */\nfunction getJSDocComment(node: ts.Node): string | undefined {\n const jsDocTags = ts.getJSDocTags(node);\n const jsDoc = (node as unknown as { jsDoc?: ts.JSDoc[] }).jsDoc;\n\n if (jsDoc && jsDoc.length > 0) {\n const comment = jsDoc[0].comment;\n if (typeof comment === \"string\") {\n return comment;\n }\n if (Array.isArray(comment)) {\n return comment.map((c) => (typeof c === \"string\" ? c : c.text)).join(\"\");\n }\n }\n\n return undefined;\n}\n\n/**\n * Get @default value from JSDoc\n */\nfunction getJSDocDefault(node: ts.Node): unknown | undefined {\n const jsDocTags = ts.getJSDocTags(node);\n\n for (const tag of jsDocTags) {\n if (tag.tagName.text === \"default\") {\n const comment = tag.comment;\n if (typeof comment === \"string\") {\n // Try to parse as JSON\n try {\n return JSON.parse(comment);\n } catch {\n return comment;\n }\n }\n }\n }\n\n return undefined;\n}\n","/**\n * Registry Generator\n * Generates .fragments/registry.json and .fragments/index.json\n *\n * Philosophy: Generate only what AI agents and humans can't easily get from source.\n * - Props: AI can read TypeScript directly (skip by default)\n * - Paths: Essential for file navigation (always include)\n * - Enrichment: Human knowledge that doesn't exist elsewhere (include references)\n */\n\nimport { readFileSync, existsSync } from \"node:fs\";\nimport { relative, dirname, basename, join } from \"node:path\";\nimport fg from \"fast-glob\";\nimport { BRAND } from '@fragments-sdk/core';\nimport type {\n Fragment,\n FragmentRegistry,\n FragmentIndex,\n RegistryComponentEntry,\n RegistryOptions,\n} from '@fragments-sdk/core';\nimport { extractPropsFromFile } from \"./typescript-extractor.js\";\n\n/**\n * Options for registry generation\n */\nexport interface RegistryGeneratorOptions {\n /** Project root directory */\n projectRoot: string;\n /** Glob patterns for component files */\n componentPatterns?: string[];\n /** Glob patterns for story files */\n storyPatterns?: string[];\n /** Path to .fragments directory */\n fragmentsDir?: string;\n /** Registry options from config */\n registryOptions?: RegistryOptions;\n}\n\n/**\n * Result of registry generation\n */\nexport interface RegistryGeneratorResult {\n /** Generated registry (full metadata) */\n registry: FragmentRegistry;\n /** Generated index (minimal name -> path) */\n index: FragmentIndex;\n /** Errors encountered during generation */\n errors: Array<{ file: string; error: string }>;\n /** Warnings */\n warnings: Array<{ file: string; warning: string }>;\n}\n\n/**\n * Generate a fragment registry and index by scanning the project\n */\nexport async function generateRegistry(\n options: RegistryGeneratorOptions\n): Promise<RegistryGeneratorResult> {\n const {\n projectRoot,\n componentPatterns = [\"src/**/*.tsx\", \"src/**/*.ts\"],\n storyPatterns = [\"src/**/*.stories.tsx\", \"src/**/*.stories.ts\"],\n fragmentsDir = join(projectRoot, BRAND.dataDir),\n registryOptions = {},\n } = options;\n\n const {\n requireStory = false,\n publicOnly = false,\n categoryDepth = 1,\n includeProps = false,\n embedFragments = false,\n } = registryOptions;\n\n const errors: Array<{ file: string; error: string }> = [];\n const warnings: Array<{ file: string; warning: string }> = [];\n\n // Find all story files first (for requireStory filtering)\n const storyFiles = await fg(storyPatterns, {\n cwd: projectRoot,\n ignore: [\"**/node_modules/**\"],\n absolute: true,\n });\n\n // Build a map of story files by component directory and base name\n const storyMap = new Map<string, string>();\n for (const storyPath of storyFiles) {\n const storyDir = dirname(storyPath);\n const storyBase = basename(storyPath).replace(/\\.stories\\.(tsx?|jsx?)$/, \"\");\n storyMap.set(`${storyDir}/${storyBase}`, storyPath);\n }\n\n // Find all component files\n const componentFiles = await fg(componentPatterns, {\n cwd: projectRoot,\n ignore: [\n \"**/node_modules/**\",\n \"**/*.stories.*\",\n \"**/*.test.*\",\n \"**/*.spec.*\",\n \"**/*.d.ts\",\n ],\n absolute: true,\n });\n\n // Find all fragment files\n const fragmentPattern = join(\n BRAND.dataDir,\n BRAND.componentsDir,\n `*${BRAND.fileExtension}`\n );\n const fragmentFiles = await fg(fragmentPattern, {\n cwd: projectRoot,\n absolute: true,\n });\n\n // Build fragment lookup map\n const fragmentMap = new Map<string, { path: string; fragment: Fragment }>();\n for (const fragmentPath of fragmentFiles) {\n const fragmentName = basename(fragmentPath).replace(BRAND.fileExtension, \"\");\n try {\n const content = readFileSync(fragmentPath, \"utf-8\");\n const fragment = JSON.parse(content) as Fragment;\n fragmentMap.set(fragmentName, {\n path: relative(projectRoot, fragmentPath),\n fragment,\n });\n } catch (e) {\n errors.push({\n file: fragmentPath,\n error: `Failed to parse fragment: ${e instanceof Error ? e.message : String(e)}`,\n });\n }\n }\n\n // Build component index\n const components: Record<string, RegistryComponentEntry> = {};\n const indexComponents: Record<string, string> = {};\n const categories: Record<string, string[]> = {};\n\n // Process component files\n for (const filePath of componentFiles) {\n try {\n const extracted = extractPropsFromFile(filePath);\n if (!extracted || !extracted.componentName) {\n continue;\n }\n\n const componentName = extracted.componentName;\n const relativePath = relative(projectRoot, filePath);\n\n // Check if component is exported (for publicOnly filter)\n if (publicOnly && !extracted.exports.includes(componentName)) {\n continue;\n }\n\n // Find matching story file\n const componentDir = dirname(filePath);\n const baseNameWithoutExt = basename(filePath).replace(/\\.(tsx?|jsx?)$/, \"\");\n const storyPath = storyMap.get(`${componentDir}/${baseNameWithoutExt}`);\n\n // Apply requireStory filter\n if (requireStory && !storyPath) {\n continue;\n }\n\n // Get fragment data if exists\n const fragmentData = fragmentMap.get(componentName);\n\n // Determine category from directory structure\n const category = fragmentData?.fragment?.meta?.status\n ? undefined // Don't use status as category\n : getCategoryFromPath(relativePath, categoryDepth);\n\n // Check if fragment has meaningful enrichment (not just a skeleton)\n const hasEnrichment = fragmentData\n ? hasRealEnrichment(fragmentData.fragment)\n : false;\n\n // Build minimal component entry\n const entry: RegistryComponentEntry = {\n path: relativePath,\n };\n\n // Add optional fields only if present\n if (storyPath) {\n entry.storyPath = relative(projectRoot, storyPath);\n }\n\n if (fragmentData) {\n entry.fragmentPath = fragmentData.path;\n if (hasEnrichment) {\n entry.hasEnrichment = true;\n }\n if (fragmentData.fragment.description) {\n entry.description = fragmentData.fragment.description;\n }\n if (fragmentData.fragment.meta?.status) {\n entry.status = fragmentData.fragment.meta.status;\n }\n // Only embed full fragment if explicitly requested\n if (embedFragments) {\n entry.fragment = fragmentData.fragment;\n }\n }\n\n if (category) {\n entry.category = category;\n // Add to categories index\n if (!categories[category]) {\n categories[category] = [];\n }\n categories[category].push(componentName);\n }\n\n // Only include props if explicitly requested\n if (includeProps && extracted.props) {\n entry.props = extracted.props;\n }\n\n // Only include exports if multiple exports\n if (extracted.exports.length > 1) {\n entry.exports = extracted.exports;\n }\n\n components[componentName] = entry;\n indexComponents[componentName] = relativePath;\n } catch (e) {\n errors.push({\n file: filePath,\n error: `Failed to extract component: ${e instanceof Error ? e.message : String(e)}`,\n });\n }\n }\n\n const componentCount = Object.keys(components).length;\n\n // Build registry\n const registry: FragmentRegistry = {\n $schema: \"https://fragments.dev/schema/registry-v1.json\",\n version: \"1.0\",\n generatedAt: new Date().toISOString(),\n componentCount,\n components,\n categories,\n };\n\n // Build minimal index\n const index: FragmentIndex = {\n version: \"1.0\",\n generatedAt: registry.generatedAt,\n components: indexComponents,\n categories,\n };\n\n return { registry, index, errors, warnings };\n}\n\n/**\n * Get category from file path based on directory structure\n *\n * Examples:\n * - src/components/buttons/Button.tsx -> \"buttons\"\n * - src/components/forms/inputs/TextInput.tsx -> \"forms\" (depth 1) or \"forms/inputs\" (depth 2)\n * - src/components/Button/Button.tsx -> \"Button\" (component folder)\n */\nfunction getCategoryFromPath(relativePath: string, depth: number = 1): string | undefined {\n const parts = relativePath.split(\"/\");\n const componentsIndex = parts.findIndex((p) => p === \"components\");\n\n if (componentsIndex === -1) {\n return undefined;\n }\n\n // Get the parts after \"components/\"\n const afterComponents = parts.slice(componentsIndex + 1);\n\n // If it's just components/Button.tsx, no category\n if (afterComponents.length <= 1) {\n return undefined;\n }\n\n // If it's components/Button/Button.tsx (component folder pattern), no category\n const folderName = afterComponents[0];\n const fileName = afterComponents[afterComponents.length - 1].replace(/\\.(tsx?|jsx?)$/, \"\");\n if (afterComponents.length === 2 && folderName === fileName) {\n return undefined;\n }\n\n // Get category parts based on depth\n const categoryParts = afterComponents.slice(0, Math.min(depth, afterComponents.length - 1));\n\n // Filter out component folders (where folder name matches file name)\n const lastCategoryPart = categoryParts[categoryParts.length - 1];\n if (lastCategoryPart === fileName) {\n categoryParts.pop();\n }\n\n if (categoryParts.length === 0) {\n return undefined;\n }\n\n return categoryParts.join(\"/\");\n}\n\n/**\n * Check if a fragment has meaningful enrichment beyond a skeleton\n */\nfunction hasRealEnrichment(fragment: Fragment): boolean {\n // Has description beyond just the name\n if (fragment.description && fragment.description.length > 20) {\n return true;\n }\n\n // Has usage guidelines\n if (fragment.usage?.when && fragment.usage.when.length > 0) {\n return true;\n }\n if (fragment.usage?.doNot && fragment.usage.doNot.length > 0) {\n return true;\n }\n if (fragment.usage?.patterns && fragment.usage.patterns.length > 0) {\n return true;\n }\n\n // Has accessibility info\n if (fragment.accessibility?.requirements && fragment.accessibility.requirements.length > 0) {\n return true;\n }\n\n // Has figma links\n if (fragment.figma?.nodeId || fragment.figma?.variants) {\n return true;\n }\n\n // Has related components\n if (fragment.related?.similar && fragment.related.similar.length > 0) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Resolve component name to path using registry\n */\nexport function resolveComponentPath(\n componentName: string,\n registry: FragmentRegistry\n): string | undefined {\n const entry = registry.components[componentName];\n return entry?.path;\n}\n\n/**\n * Get all components by category\n */\nexport function getComponentsByCategory(\n category: string,\n registry: FragmentRegistry\n): string[] {\n return registry.categories?.[category] || [];\n}\n","import { writeFile, unlink } from 'node:fs/promises';\nimport { dirname, basename, join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { build, type Plugin } from 'esbuild';\nimport { BRAND } from '@fragments-sdk/core';\nimport type { FragmentDefinition } from '@fragments-sdk/core';\n\n// Inline implementation of defineFragment that will be injected into bundled files\n// This allows fragment files to work without @fragments/core being installed\nconst DEFINE_FRAGMENT_SHIM = `\nexport function defineFragment(def) {\n return def;\n}\nexport function defineBlock(def) {\n return def;\n}\nexport function defineRecipe(def) {\n return def;\n}\n`;\n\n/**\n * Creates an esbuild plugin that replaces @fragments/core imports with an inline shim.\n * This allows fragment files to be loaded without @fragments/core being installed in the target project.\n */\nfunction createFragmentsCoreShimPlugin(): Plugin {\n return {\n name: BRAND.vitePluginNamespace,\n setup(build) {\n // Intercept @fragments-sdk/cli/core imports\n build.onResolve({ filter: /^@fragments-sdk\\/cli\\/core$/ }, (args) => {\n return {\n path: args.path,\n namespace: BRAND.vitePluginNamespace,\n };\n });\n\n // Return the shim content\n build.onLoad({ filter: /.*/, namespace: BRAND.vitePluginNamespace }, () => {\n return {\n contents: DEFINE_FRAGMENT_SHIM,\n loader: 'js',\n };\n });\n },\n };\n}\n\n/**\n * Load a fragment file, handling TSX/TS transformation automatically.\n * Uses esbuild to bundle and transform TypeScript/JSX before importing.\n */\nexport async function loadFragmentFile(\n absolutePath: string\n): Promise<FragmentDefinition | null> {\n const unwrapFragmentExport = (\n value: unknown\n ): FragmentDefinition | null => {\n if (!value) return null;\n\n // Some CJS/ESM interop paths produce { default: fragment } wrappers.\n // Prefer a shape that actually looks like a fragment definition.\n const asObject = (v: unknown): Record<string, unknown> | null =>\n v && typeof v === 'object' ? (v as Record<string, unknown>) : null;\n const isFragmentLike = (v: unknown): boolean => {\n const obj = asObject(v);\n return !!obj && ('component' in obj || 'meta' in obj || 'variants' in obj);\n };\n\n if (isFragmentLike(value)) {\n return value as FragmentDefinition;\n }\n\n const first = asObject(value)?.default;\n if (isFragmentLike(first)) {\n return first as FragmentDefinition;\n }\n\n const second = asObject(first)?.default;\n if (isFragmentLike(second)) {\n return second as FragmentDefinition;\n }\n\n return (value as FragmentDefinition) ?? null;\n };\n\n const ext = absolutePath.split('.').pop()?.toLowerCase();\n const needsTransform = ext === 'tsx' || ext === 'ts' || ext === 'jsx';\n\n if (!needsTransform) {\n // Plain JS file, import directly\n const fileUrl = pathToFileURL(absolutePath).href;\n const module = await import(fileUrl);\n return unwrapFragmentExport(module.default ?? null);\n }\n\n // Bundle the file with all its local dependencies\n const sourceDir = dirname(absolutePath);\n const baseName = basename(absolutePath, `.${ext}`);\n // Use .mjs and ESM output for compatibility with ESM-only dependencies.\n const tempFile = join(sourceDir, `.${baseName}.fragments-temp-${Date.now()}.mjs`);\n\n try {\n // Use esbuild to bundle the fragment file.\n // We inject a shim for @fragments-sdk/cli/core so it doesn't need to be installed.\n await build({\n entryPoints: [absolutePath],\n outfile: tempFile,\n bundle: true,\n format: 'esm',\n target: 'es2022',\n jsx: 'automatic',\n platform: 'node',\n plugins: [createFragmentsCoreShimPlugin()],\n // Externalize all node_modules - we only need fragment metadata, not component code\n packages: 'external',\n // Also explicitly list patterns for nested imports\n external: [\n // React and its subpaths\n 'react',\n 'react-dom',\n 'react/*',\n 'react-dom/*',\n ],\n // Don't emit sourcemaps for temp files\n sourcemap: false,\n // Suppress warnings\n logLevel: 'silent',\n // Use loader to ignore style imports\n loader: {\n '.scss': 'empty',\n '.css': 'empty',\n '.svg': 'empty',\n '.png': 'empty',\n '.jpg': 'empty',\n '.jpeg': 'empty',\n '.gif': 'empty',\n '.woff': 'empty',\n '.woff2': 'empty',\n '.ttf': 'empty',\n '.eot': 'empty',\n },\n });\n\n const fileUrl = pathToFileURL(tempFile).href;\n const module = await import(fileUrl);\n return unwrapFragmentExport(module.default ?? null);\n } finally {\n // Clean up temp file\n try {\n await unlink(tempFile);\n } catch {\n // Ignore cleanup errors\n }\n }\n}\n\n/**\n * Load multiple fragment files in parallel with error handling.\n */\nexport async function loadFragmentFiles(\n absolutePaths: string[]\n): Promise<Map<string, FragmentDefinition | Error>> {\n const results = new Map<string, FragmentDefinition | Error>();\n\n await Promise.all(\n absolutePaths.map(async (path) => {\n try {\n const fragment = await loadFragmentFile(path);\n if (fragment) {\n results.set(path, fragment);\n } else {\n results.set(path, new Error('No default export found'));\n }\n } catch (error) {\n results.set(\n path,\n error instanceof Error ? error : new Error(String(error))\n );\n }\n })\n );\n\n return results;\n}\n","/**\n * AST-Based Fragment Parser\n *\n * Extracts fragment metadata from .fragment.tsx files WITHOUT executing them.\n * This allows `fragments build` to work without any project dependencies.\n *\n * Uses TypeScript's compiler API to parse and analyze the AST.\n */\n\nimport ts from \"typescript\";\nimport type { FragmentMeta, FragmentUsage, PropDefinition, AIMetadata, FragmentContract } from '@fragments-sdk/core';\n\n/**\n * Parsed fragment metadata (extracted statically from AST)\n */\nexport interface ParsedFragmentMetadata {\n /** Component import path (e.g., \"./Button\" or \"@/components/Button\") */\n componentImport: string | null;\n\n /** Component name as used in the file */\n componentName: string | null;\n\n /** Component metadata */\n meta: Partial<FragmentMeta>;\n\n /** Usage guidelines */\n usage: Partial<FragmentUsage>;\n\n /** Props documentation */\n props: Record<string, Partial<PropDefinition>>;\n\n /** Variant definitions */\n variants: Array<{\n name: string;\n description: string;\n code?: string;\n figma?: string;\n args?: Record<string, unknown>;\n }>;\n\n /** Related components */\n relations: Array<{\n component: string;\n relationship: string;\n note: string;\n }>;\n\n /** AI-specific metadata for playground context generation */\n ai?: AIMetadata;\n\n /** Agent-optimized contract metadata */\n contract?: FragmentContract;\n\n /** Parse warnings */\n warnings: string[];\n}\n\n/**\n * Parse a fragment file and extract metadata without executing it.\n */\nexport function parseFragmentFile(\n fileContent: string,\n filePath?: string\n): ParsedFragmentMetadata {\n const warnings: string[] = [];\n\n // Parse the file\n const sourceFile = ts.createSourceFile(\n filePath ?? \"fragment.tsx\",\n fileContent,\n ts.ScriptTarget.Latest,\n true,\n ts.ScriptKind.TSX\n );\n\n // Find imports\n const imports = extractImports(sourceFile);\n\n // Find the defineFragment call\n const defineFragmentCall = findDefineFragmentCall(sourceFile);\n\n if (!defineFragmentCall) {\n warnings.push(\"No defineFragment() call found\");\n return {\n componentImport: null,\n componentName: null,\n meta: {},\n usage: { when: [], whenNot: [] },\n props: {},\n variants: [],\n relations: [],\n warnings,\n };\n }\n\n // Extract the argument (object literal)\n const arg = defineFragmentCall.arguments[0];\n if (!arg || !ts.isObjectLiteralExpression(arg)) {\n warnings.push(\"defineFragment() argument is not an object literal\");\n return {\n componentImport: null,\n componentName: null,\n meta: {},\n usage: { when: [], whenNot: [] },\n props: {},\n variants: [],\n relations: [],\n warnings,\n };\n }\n\n // Extract component reference\n const componentProp = findProperty(arg, \"component\");\n let componentName: string | null = null;\n let componentImport: string | null = null;\n\n if (componentProp && ts.isIdentifier(componentProp)) {\n componentName = componentProp.text;\n // Find the import for this component\n componentImport = imports.get(componentName) ?? null;\n }\n\n // Extract meta\n const meta = extractMeta(arg, warnings);\n\n // Extract usage\n const usage = extractUsage(arg, warnings);\n\n // Extract props\n const props = extractProps(arg, warnings);\n\n // Extract variants\n const variants = extractVariants(arg, sourceFile, warnings);\n\n // Extract relations\n const relations = extractRelations(arg, warnings);\n\n // Extract AI metadata\n const ai = extractAIMetadata(arg, warnings);\n\n // Extract contract metadata\n const contract = extractContractMetadata(arg);\n\n return {\n componentImport,\n componentName,\n meta,\n usage,\n props,\n variants,\n relations,\n ai,\n contract,\n warnings,\n };\n}\n\n/**\n * Extract all imports from the source file.\n * Returns a map of imported name -> module path\n */\nfunction extractImports(sourceFile: ts.SourceFile): Map<string, string> {\n const imports = new Map<string, string>();\n\n ts.forEachChild(sourceFile, (node) => {\n if (ts.isImportDeclaration(node)) {\n const moduleSpecifier = node.moduleSpecifier;\n if (ts.isStringLiteral(moduleSpecifier)) {\n const modulePath = moduleSpecifier.text;\n\n // Handle named imports\n const importClause = node.importClause;\n if (importClause) {\n // Default import\n if (importClause.name) {\n imports.set(importClause.name.text, modulePath);\n }\n\n // Named imports\n const namedBindings = importClause.namedBindings;\n if (namedBindings && ts.isNamedImports(namedBindings)) {\n for (const element of namedBindings.elements) {\n imports.set(element.name.text, modulePath);\n }\n }\n }\n }\n }\n });\n\n return imports;\n}\n\n/**\n * Find the defineFragment() call in the source file.\n */\nfunction findDefineFragmentCall(\n sourceFile: ts.SourceFile\n): ts.CallExpression | null {\n let result: ts.CallExpression | null = null;\n\n function visit(node: ts.Node): void {\n if (ts.isCallExpression(node)) {\n const expression = node.expression;\n if (ts.isIdentifier(expression) && expression.text === \"defineFragment\") {\n result = node;\n return;\n }\n }\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return result;\n}\n\n/**\n * Find a property in an object literal by name.\n */\nfunction findProperty(\n obj: ts.ObjectLiteralExpression,\n name: string\n): ts.Expression | null {\n for (const prop of obj.properties) {\n if (ts.isPropertyAssignment(prop)) {\n const propName = prop.name;\n if (ts.isIdentifier(propName) && propName.text === name) {\n return prop.initializer;\n }\n }\n }\n return null;\n}\n\n/**\n * Extract meta object from defineFragment call.\n */\nfunction extractMeta(\n arg: ts.ObjectLiteralExpression,\n warnings: string[]\n): Partial<FragmentMeta> {\n const metaProp = findProperty(arg, \"meta\");\n if (!metaProp || !ts.isObjectLiteralExpression(metaProp)) {\n warnings.push(\"No meta object found\");\n return {};\n }\n\n const meta: Partial<FragmentMeta> = {};\n\n // Extract string properties\n const name = extractStringProperty(metaProp, \"name\");\n if (name) meta.name = name;\n\n const description = extractStringProperty(metaProp, \"description\");\n if (description) meta.description = description;\n\n const category = extractStringProperty(metaProp, \"category\");\n if (category) meta.category = category;\n\n const status = extractStringProperty(metaProp, \"status\") as FragmentMeta[\"status\"];\n if (status) meta.status = status;\n\n const since = extractStringProperty(metaProp, \"since\");\n if (since) meta.since = since;\n\n // Extract figma URL\n const figma = extractStringProperty(metaProp, \"figma\");\n if (figma) meta.figma = figma;\n\n // Extract tags array\n const tags = extractStringArray(metaProp, \"tags\");\n if (tags.length > 0) meta.tags = tags;\n\n // Extract dependencies array\n const depsProp = findProperty(metaProp, \"dependencies\");\n if (depsProp && ts.isArrayLiteralExpression(depsProp)) {\n const deps = extractLiteralValue(depsProp) as Array<{ name: string; version: string; reason?: string }>;\n if (Array.isArray(deps) && deps.length > 0) {\n meta.dependencies = deps;\n }\n }\n\n return meta;\n}\n\n/**\n * Extract usage object from defineFragment call.\n */\nfunction extractUsage(\n arg: ts.ObjectLiteralExpression,\n warnings: string[]\n): Partial<FragmentUsage> {\n const usageProp = findProperty(arg, \"usage\");\n if (!usageProp || !ts.isObjectLiteralExpression(usageProp)) {\n return { when: [], whenNot: [] };\n }\n\n return {\n when: extractStringArray(usageProp, \"when\"),\n whenNot: extractStringArray(usageProp, \"whenNot\"),\n guidelines: extractStringArray(usageProp, \"guidelines\"),\n accessibility: extractStringArray(usageProp, \"accessibility\"),\n };\n}\n\n/**\n * Extract props object from defineFragment call.\n */\nfunction extractProps(\n arg: ts.ObjectLiteralExpression,\n warnings: string[]\n): Record<string, Partial<PropDefinition>> {\n const propsProp = findProperty(arg, \"props\");\n if (!propsProp || !ts.isObjectLiteralExpression(propsProp)) {\n return {};\n }\n\n const props: Record<string, Partial<PropDefinition>> = {};\n\n for (const prop of propsProp.properties) {\n if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {\n const propName = prop.name.text;\n const propValue = prop.initializer;\n\n if (ts.isObjectLiteralExpression(propValue)) {\n props[propName] = extractPropDefinition(propValue);\n }\n }\n }\n\n return props;\n}\n\n/**\n * Extract a single prop definition.\n */\nfunction extractPropDefinition(\n obj: ts.ObjectLiteralExpression\n): Partial<PropDefinition> {\n const def: Partial<PropDefinition> = {};\n\n const type = extractStringProperty(obj, \"type\");\n if (type) def.type = type as PropDefinition[\"type\"];\n\n const description = extractStringProperty(obj, \"description\");\n if (description) def.description = description;\n\n const values = extractStringArray(obj, \"values\");\n if (values.length > 0) def.values = values;\n\n const required = extractBooleanProperty(obj, \"required\");\n if (required !== null) def.required = required;\n\n // Default value - try to extract as literal\n const defaultProp = findProperty(obj, \"default\");\n if (defaultProp) {\n def.default = extractLiteralValue(defaultProp);\n }\n\n const constraints = extractStringArray(obj, \"constraints\");\n if (constraints.length > 0) def.constraints = constraints;\n\n return def;\n}\n\n/**\n * Extract variants array from defineFragment call.\n */\nfunction extractVariants(\n arg: ts.ObjectLiteralExpression,\n sourceFile: ts.SourceFile,\n warnings: string[]\n): Array<{ name: string; description: string; code?: string; figma?: string; args?: Record<string, unknown> }> {\n const variantsProp = findProperty(arg, \"variants\");\n if (!variantsProp || !ts.isArrayLiteralExpression(variantsProp)) {\n return [];\n }\n\n const variants: Array<{ name: string; description: string; code?: string; figma?: string; args?: Record<string, unknown> }> = [];\n\n for (const element of variantsProp.elements) {\n if (ts.isObjectLiteralExpression(element)) {\n const name = extractStringProperty(element, \"name\");\n const description = extractStringProperty(element, \"description\");\n\n if (name) {\n const variant: { name: string; description: string; code?: string; figma?: string; args?: Record<string, unknown> } = {\n name,\n description: description ?? \"\",\n };\n\n // Try to extract code property if present\n const codeProp = findProperty(element, \"code\");\n if (codeProp && (ts.isStringLiteral(codeProp) || ts.isNoSubstitutionTemplateLiteral(codeProp))) {\n variant.code = codeProp.text;\n }\n\n // Try to extract render function and convert to code string\n const renderProp = findProperty(element, \"render\");\n if (renderProp && !variant.code) {\n variant.code = extractRenderCode(renderProp, sourceFile);\n }\n\n // Extract figma URL for variant\n const figma = extractStringProperty(element, \"figma\");\n if (figma) {\n variant.figma = figma;\n }\n\n // Extract args object for code generation\n const argsProp = findProperty(element, \"args\");\n if (argsProp && ts.isObjectLiteralExpression(argsProp)) {\n const argsValue = extractLiteralValue(argsProp);\n if (argsValue && typeof argsValue === 'object' && !Array.isArray(argsValue)) {\n variant.args = argsValue as Record<string, unknown>;\n }\n }\n\n variants.push(variant);\n }\n }\n }\n\n return variants;\n}\n\n/**\n * Remove common leading whitespace from all lines (dedent).\n * This handles template literals and JSX that have extra indentation from code formatting.\n *\n * Special handling: If the first line has no indentation (common after .trim()),\n * we calculate minimum indent from subsequent lines only.\n */\nfunction dedent(str: string): string {\n const lines = str.split('\\n');\n\n if (lines.length <= 1) {\n return str;\n }\n\n // Check if first line has no indentation\n const firstLineIndent = lines[0].match(/^(\\s*)/)?.[1].length ?? 0;\n const startIndex = firstLineIndent === 0 ? 1 : 0;\n\n // Find the minimum indentation (ignoring empty lines)\n let minIndent = Infinity;\n for (let i = startIndex; i < lines.length; i++) {\n const line = lines[i];\n if (line.trim() === '') continue;\n const match = line.match(/^(\\s*)/);\n if (match) {\n minIndent = Math.min(minIndent, match[1].length);\n }\n }\n\n // If no indentation found, return as-is\n if (minIndent === Infinity || minIndent === 0) {\n return str;\n }\n\n // Remove the common indentation from all lines (except first if it had no indent)\n return lines\n .map((line, index) => {\n if (index === 0 && firstLineIndent === 0) {\n return line; // Keep first line as-is\n }\n return line.slice(minIndent);\n })\n .join('\\n');\n}\n\n/**\n * Extract the code from a render function.\n */\nfunction extractRenderCode(\n renderProp: ts.Expression,\n sourceFile: ts.SourceFile\n): string | undefined {\n // Handle arrow function: () => <Component />\n if (ts.isArrowFunction(renderProp)) {\n const body = renderProp.body;\n // Get the source text of the body\n const start = body.getStart(sourceFile);\n const end = body.getEnd();\n let code = sourceFile.text.substring(start, end).trim();\n\n // Remove parentheses if present\n if (code.startsWith(\"(\") && code.endsWith(\")\")) {\n code = code.slice(1, -1).trim();\n }\n\n // Dedent the code to remove common leading whitespace\n code = dedent(code);\n\n return code;\n }\n\n return undefined;\n}\n\n/**\n * Extract relations array from defineFragment call.\n */\nfunction extractRelations(\n arg: ts.ObjectLiteralExpression,\n warnings: string[]\n): Array<{ component: string; relationship: string; note: string }> {\n const relationsProp = findProperty(arg, \"relations\");\n if (!relationsProp || !ts.isArrayLiteralExpression(relationsProp)) {\n return [];\n }\n\n const relations: Array<{ component: string; relationship: string; note: string }> = [];\n\n for (const element of relationsProp.elements) {\n if (ts.isObjectLiteralExpression(element)) {\n const component = extractStringProperty(element, \"component\");\n const relationship = extractStringProperty(element, \"relationship\");\n const note = extractStringProperty(element, \"note\");\n\n if (component && relationship) {\n relations.push({\n component,\n relationship,\n note: note ?? \"\",\n });\n }\n }\n }\n\n return relations;\n}\n\n/**\n * Extract AI metadata from defineFragment call.\n */\nfunction extractAIMetadata(\n arg: ts.ObjectLiteralExpression,\n warnings: string[]\n): AIMetadata | undefined {\n const aiProp = findProperty(arg, \"ai\");\n if (!aiProp || !ts.isObjectLiteralExpression(aiProp)) {\n return undefined;\n }\n\n const ai: AIMetadata = {};\n\n // Extract compositionPattern\n const compositionPattern = extractStringProperty(aiProp, \"compositionPattern\");\n if (compositionPattern && ['compound', 'simple', 'controlled'].includes(compositionPattern)) {\n ai.compositionPattern = compositionPattern as AIMetadata['compositionPattern'];\n }\n\n // Extract subComponents array\n const subComponents = extractStringArray(aiProp, \"subComponents\");\n if (subComponents.length > 0) {\n ai.subComponents = subComponents;\n }\n\n // Extract requiredChildren array\n const requiredChildren = extractStringArray(aiProp, \"requiredChildren\");\n if (requiredChildren.length > 0) {\n ai.requiredChildren = requiredChildren;\n }\n\n // Extract commonPatterns array\n const commonPatterns = extractStringArray(aiProp, \"commonPatterns\");\n if (commonPatterns.length > 0) {\n ai.commonPatterns = commonPatterns;\n }\n\n // Only return if we have any fields\n if (Object.keys(ai).length > 0) {\n return ai;\n }\n\n return undefined;\n}\n\n/**\n * Extract contract metadata from defineFragment call.\n */\nfunction extractContractMetadata(\n arg: ts.ObjectLiteralExpression,\n): FragmentContract | undefined {\n const contractProp = findProperty(arg, \"contract\");\n if (!contractProp || !ts.isObjectLiteralExpression(contractProp)) {\n return undefined;\n }\n\n const contract: FragmentContract = {};\n\n // Extract propsSummary array\n const propsSummary = extractStringArray(contractProp, \"propsSummary\");\n if (propsSummary.length > 0) {\n contract.propsSummary = propsSummary;\n }\n\n // Extract a11yRules array\n const a11yRules = extractStringArray(contractProp, \"a11yRules\");\n if (a11yRules.length > 0) {\n contract.a11yRules = a11yRules;\n }\n\n // Only return if we have any fields\n if (Object.keys(contract).length > 0) {\n return contract;\n }\n\n return undefined;\n}\n\n/**\n * Extract a string property from an object literal.\n */\nfunction extractStringProperty(\n obj: ts.ObjectLiteralExpression,\n name: string\n): string | null {\n const prop = findProperty(obj, name);\n if (prop && ts.isStringLiteral(prop)) {\n return prop.text;\n }\n // Handle template literals without expressions\n if (prop && ts.isNoSubstitutionTemplateLiteral(prop)) {\n return prop.text;\n }\n return null;\n}\n\n/**\n * Extract a boolean property from an object literal.\n */\nfunction extractBooleanProperty(\n obj: ts.ObjectLiteralExpression,\n name: string\n): boolean | null {\n const prop = findProperty(obj, name);\n if (prop) {\n if (prop.kind === ts.SyntaxKind.TrueKeyword) return true;\n if (prop.kind === ts.SyntaxKind.FalseKeyword) return false;\n }\n return null;\n}\n\n/**\n * Extract a string array from an object literal.\n */\nfunction extractStringArray(\n obj: ts.ObjectLiteralExpression,\n name: string\n): string[] {\n const prop = findProperty(obj, name);\n if (!prop || !ts.isArrayLiteralExpression(prop)) {\n return [];\n }\n\n const result: string[] = [];\n for (const element of prop.elements) {\n if (ts.isStringLiteral(element)) {\n result.push(element.text);\n } else if (ts.isNoSubstitutionTemplateLiteral(element)) {\n result.push(element.text);\n }\n }\n return result;\n}\n\n/**\n * Extract a literal value from an expression.\n */\nfunction extractLiteralValue(expr: ts.Expression): unknown {\n if (ts.isStringLiteral(expr)) {\n return expr.text;\n }\n if (ts.isNumericLiteral(expr)) {\n return Number(expr.text);\n }\n if (expr.kind === ts.SyntaxKind.TrueKeyword) {\n return true;\n }\n if (expr.kind === ts.SyntaxKind.FalseKeyword) {\n return false;\n }\n if (expr.kind === ts.SyntaxKind.NullKeyword) {\n return null;\n }\n if (ts.isArrayLiteralExpression(expr)) {\n return expr.elements.map(extractLiteralValue);\n }\n if (ts.isObjectLiteralExpression(expr)) {\n const obj: Record<string, unknown> = {};\n for (const prop of expr.properties) {\n if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {\n obj[prop.name.text] = extractLiteralValue(prop.initializer);\n }\n }\n return obj;\n }\n return undefined;\n}\n","/**\n * Loader for Storybook .storybook/preview.{tsx,ts,jsx,js} configuration.\n *\n * This module detects and loads Storybook preview configuration to extract:\n * - decorators: Global decorators applied to all stories\n * - parameters: Global parameters for all stories\n * - globalTypes: Global type definitions (e.g., for toolbar controls)\n * - args: Default args for all stories\n * - argTypes: Default argTypes for all stories\n * - loaders: Global loaders for all stories\n */\n\nimport { existsSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport type { PreviewConfig } from '@fragments-sdk/core';\n\n/**\n * Possible file extensions and names for preview config\n */\nconst PREVIEW_FILES = [\n \"preview.tsx\",\n \"preview.ts\",\n \"preview.jsx\",\n \"preview.js\",\n];\n\n/**\n * Find the preview config file in a .storybook directory\n *\n * @param storybookDir - Path to the .storybook directory\n * @returns The full path to the preview file, or null if not found\n */\nexport function findPreviewConfigPath(storybookDir: string): string | null {\n for (const fileName of PREVIEW_FILES) {\n const filePath = join(storybookDir, fileName);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n return null;\n}\n\n/**\n * Find the .storybook directory starting from a project root.\n * Checks common locations.\n *\n * @param projectRoot - The project root directory\n * @returns The path to the .storybook directory, or null if not found\n */\nexport function findStorybookDir(projectRoot: string): string | null {\n const possiblePaths = [\n join(projectRoot, \".storybook\"),\n join(projectRoot, \"storybook\"),\n ];\n\n for (const dir of possiblePaths) {\n if (existsSync(dir)) {\n return dir;\n }\n }\n return null;\n}\n\n/**\n * Load and parse the Storybook preview configuration.\n *\n * This function dynamically imports the preview file and extracts\n * the relevant configuration exports.\n *\n * @param previewPath - Full path to the preview config file\n * @returns The parsed preview configuration\n */\nexport async function loadPreviewConfig(\n previewPath: string\n): Promise<PreviewConfig> {\n try {\n // Dynamic import with file:// URL for ESM compatibility\n const fileUrl = new URL(`file://${resolve(previewPath)}`);\n const module = await import(fileUrl.href);\n\n // Extract configuration from the module\n const config: PreviewConfig = {\n decorators: module.decorators ?? module.default?.decorators ?? [],\n parameters: module.parameters ?? module.default?.parameters ?? {},\n globalTypes: module.globalTypes ?? module.default?.globalTypes ?? {},\n args: module.args ?? module.default?.args ?? {},\n argTypes: module.argTypes ?? module.default?.argTypes ?? {},\n loaders: module.loaders ?? module.default?.loaders ?? [],\n };\n\n return config;\n } catch (error) {\n console.warn(\n `[Fragments] Failed to load preview config from ${previewPath}:`,\n error instanceof Error ? error.message : error\n );\n return {};\n }\n}\n\n/**\n * Auto-detect and load preview configuration from a project.\n *\n * @param projectRoot - The project root directory\n * @returns The preview configuration, or empty config if not found\n */\nexport async function autoLoadPreviewConfig(\n projectRoot: string\n): Promise<PreviewConfig> {\n const storybookDir = findStorybookDir(projectRoot);\n if (!storybookDir) {\n return {};\n }\n\n const previewPath = findPreviewConfigPath(storybookDir);\n if (!previewPath) {\n return {};\n }\n\n return loadPreviewConfig(previewPath);\n}\n\n/**\n * Generate a virtual module that imports and re-exports preview config.\n * This is used in the Vite plugin to make preview config available at runtime.\n *\n * @param previewPath - Full path to the preview config file, or null\n * @returns JavaScript code for the virtual module\n */\nexport function generatePreviewModule(previewPath: string | null): string {\n if (!previewPath) {\n // No preview config found - export empty defaults\n return `\nexport const decorators = [];\nexport const parameters = {};\nexport const globalTypes = {};\nexport const args = {};\nexport const argTypes = {};\nexport const loaders = [];\n\nexport default {\n decorators,\n parameters,\n globalTypes,\n args,\n argTypes,\n loaders,\n};\n`;\n }\n\n // Import from the actual preview file and re-export\n return `\nimport * as preview from \"${previewPath}\";\n\nexport const decorators = preview.decorators ?? preview.default?.decorators ?? [];\nexport const parameters = preview.parameters ?? preview.default?.parameters ?? {};\nexport const globalTypes = preview.globalTypes ?? preview.default?.globalTypes ?? {};\nexport const args = preview.args ?? preview.default?.args ?? {};\nexport const argTypes = preview.argTypes ?? preview.default?.argTypes ?? {};\nexport const loaders = preview.loaders ?? preview.default?.loaders ?? [];\n\nexport default {\n decorators,\n parameters,\n globalTypes,\n args,\n argTypes,\n loaders,\n};\n`;\n}\n","/**\n * AST-based import analysis for detecting component relationships\n *\n * Analyzes TypeScript/JavaScript files to find which components import others,\n * providing accurate \"used by\" relationships for the component graph.\n *\n * @deprecated Import analysis is now handled by graph-extractor.ts which provides\n * richer edge-typed relationships via the ComponentGraph. These functions are\n * maintained for backward compatibility. For new code, use\n * `buildComponentGraph()` from `./graph-extractor.js` instead.\n */\n\nimport ts from 'typescript';\nimport { readFileSync } from 'node:fs';\nimport { resolve, dirname, basename } from 'node:path';\n\nexport interface ComponentImport {\n /** Name of the imported component */\n name: string;\n /** Import path (relative or package) */\n path: string;\n /** Whether this is a default import */\n isDefault: boolean;\n /** Whether this is a namespace import */\n isNamespace: boolean;\n}\n\nexport interface ImportAnalysisResult {\n /** Source file path */\n filePath: string;\n /** Component name extracted from file */\n componentName: string;\n /** List of component imports found */\n imports: ComponentImport[];\n}\n\n/**\n * Extract component name from a file path\n */\nfunction extractComponentNameFromPath(filePath: string): string {\n const fileName = basename(filePath);\n\n // Handle index.tsx files - use parent directory name\n if (fileName === 'index.tsx' || fileName === 'index.ts' || fileName === 'index.jsx' || fileName === 'index.js') {\n const parentDir = basename(dirname(filePath));\n return parentDir;\n }\n\n // Remove extension and common suffixes\n return fileName\n .replace(/\\.(tsx?|jsx?)$/, '')\n .replace(/\\.stories$/, '')\n .replace(/\\.fragment$/, '')\n .replace(/\\.fragment$/, '');\n}\n\n/**\n * Check if an import path looks like a component import (not a utility/library)\n */\nfunction isComponentImportPath(importPath: string): boolean {\n // Skip node_modules packages\n if (!importPath.startsWith('.') && !importPath.startsWith('/')) {\n return false;\n }\n\n // Skip common utility/hook patterns\n const skipPatterns = [\n /\\/hooks\\//,\n /\\/utils\\//,\n /\\/helpers\\//,\n /\\/lib\\//,\n /\\/types\\//,\n /\\/constants\\//,\n /\\/styles\\//,\n /\\/context\\//,\n /\\.css$/,\n /\\.scss$/,\n /\\.less$/,\n /\\.json$/,\n ];\n\n for (const pattern of skipPatterns) {\n if (pattern.test(importPath)) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Check if an imported name looks like a React component (PascalCase)\n */\nfunction isPascalCase(name: string): boolean {\n return /^[A-Z][a-zA-Z0-9]*$/.test(name);\n}\n\n/**\n * Analyze a single file for component imports\n */\nexport function analyzeFileImports(filePath: string): ImportAnalysisResult {\n const componentName = extractComponentNameFromPath(filePath);\n const imports: ComponentImport[] = [];\n\n let sourceText: string;\n try {\n sourceText = readFileSync(filePath, 'utf-8');\n } catch {\n return { filePath, componentName, imports };\n }\n\n const sourceFile = ts.createSourceFile(\n filePath,\n sourceText,\n ts.ScriptTarget.Latest,\n true,\n filePath.endsWith('.tsx') || filePath.endsWith('.jsx')\n ? ts.ScriptKind.TSX\n : ts.ScriptKind.TS\n );\n\n ts.forEachChild(sourceFile, (node) => {\n if (ts.isImportDeclaration(node)) {\n const moduleSpecifier = node.moduleSpecifier;\n if (!ts.isStringLiteral(moduleSpecifier)) return;\n\n const importPath = moduleSpecifier.text;\n\n // Skip non-component imports\n if (!isComponentImportPath(importPath)) return;\n\n const importClause = node.importClause;\n if (!importClause) return;\n\n // Default import: import Button from './Button'\n if (importClause.name) {\n const name = importClause.name.text;\n if (isPascalCase(name)) {\n imports.push({\n name,\n path: importPath,\n isDefault: true,\n isNamespace: false,\n });\n }\n }\n\n // Named imports: import { Button, Icon } from './components'\n const namedBindings = importClause.namedBindings;\n if (namedBindings) {\n if (ts.isNamedImports(namedBindings)) {\n for (const element of namedBindings.elements) {\n const name = element.name.text;\n if (isPascalCase(name)) {\n imports.push({\n name,\n path: importPath,\n isDefault: false,\n isNamespace: false,\n });\n }\n }\n } else if (ts.isNamespaceImport(namedBindings)) {\n // Namespace import: import * as Components from './components'\n // We can't reliably know what components are used without more analysis\n const name = namedBindings.name.text;\n imports.push({\n name,\n path: importPath,\n isDefault: false,\n isNamespace: true,\n });\n }\n }\n }\n });\n\n return { filePath, componentName, imports };\n}\n\n/**\n * Build a map of which components are imported by which files\n */\nexport function buildImportGraph(\n filePaths: string[]\n): Map<string, string[]> {\n // Map from component name -> list of component names that import it\n const importedBy = new Map<string, string[]>();\n\n for (const filePath of filePaths) {\n const result = analyzeFileImports(filePath);\n\n for (const imp of result.imports) {\n // Skip namespace imports for now\n if (imp.isNamespace) continue;\n\n const importedComponent = imp.name;\n const importingComponent = result.componentName;\n\n // Don't add self-references\n if (importedComponent === importingComponent) continue;\n\n const existing = importedBy.get(importedComponent) || [];\n if (!existing.includes(importingComponent)) {\n existing.push(importingComponent);\n importedBy.set(importedComponent, existing);\n }\n }\n }\n\n return importedBy;\n}\n\n/**\n * Get components that import a specific component\n */\nexport function getImportedBy(\n componentName: string,\n importGraph: Map<string, string[]>\n): string[] {\n return importGraph.get(componentName) || [];\n}\n"],"mappings":"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","names":["resolve","dirname","existsSync","resolve","resolve","existsSync","dirname","readFileSync","dirname","basename","fg","dirname","basename","join","build","dirname","basename","join","ts","existsSync","join","resolve","ts","readFileSync","dirname","basename"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
BRAND
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-FFCI6OVZ.js";
|
|
5
5
|
|
|
6
6
|
// src/commands/setup.ts
|
|
7
7
|
import { readFile, writeFile, access, mkdir } from "fs/promises";
|
|
@@ -407,4 +407,4 @@ export {
|
|
|
407
407
|
addTranspilePackages,
|
|
408
408
|
setup
|
|
409
409
|
};
|
|
410
|
-
//# sourceMappingURL=chunk-
|
|
410
|
+
//# sourceMappingURL=chunk-MN3B2EE6.js.map
|
|
@@ -422,6 +422,7 @@ async function scanCodebase(options) {
|
|
|
422
422
|
rootDir,
|
|
423
423
|
include = DEFAULT_INCLUDE,
|
|
424
424
|
exclude = DEFAULT_EXCLUDE,
|
|
425
|
+
files: explicitFiles,
|
|
425
426
|
componentNames,
|
|
426
427
|
useCache = true,
|
|
427
428
|
onProgress
|
|
@@ -440,7 +441,7 @@ async function scanCodebase(options) {
|
|
|
440
441
|
currentFile: "",
|
|
441
442
|
phase: "discovering"
|
|
442
443
|
});
|
|
443
|
-
const files = await fg(include, {
|
|
444
|
+
const files = explicitFiles ?? await fg(include, {
|
|
444
445
|
cwd: absoluteRoot,
|
|
445
446
|
ignore: exclude,
|
|
446
447
|
absolute: true,
|
|
@@ -627,4 +628,4 @@ export {
|
|
|
627
628
|
getScanStats,
|
|
628
629
|
hasCachedAnalysis
|
|
629
630
|
};
|
|
630
|
-
//# sourceMappingURL=chunk-
|
|
631
|
+
//# sourceMappingURL=chunk-SAQW37L5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/service/enhance/codebase-scanner.ts","../src/service/enhance/aggregator.ts","../src/service/enhance/cache.ts"],"sourcesContent":["/**\n * Full Codebase Scanner\n *\n * Scans entire codebase for component usage patterns with caching and progress.\n */\n\nimport fg from \"fast-glob\";\nimport { readFile } from \"node:fs/promises\";\nimport { relative, resolve, dirname, basename } from \"node:path\";\nimport type {\n ScanOptions,\n ScanProgress,\n UsageAnalysis,\n ComponentImport,\n ComponentUsage,\n FileChanges,\n AnalysisCache,\n} from \"./types.js\";\nimport { scanFile } from \"./scanner.js\";\nimport { aggregateAllUsages } from \"./aggregator.js\";\nimport {\n loadCache,\n saveCache,\n createEmptyCache,\n computeFileHash,\n isFileCached,\n updateCacheFile,\n removeCacheFile,\n getCachedFile,\n detectFileChanges,\n getCacheStats,\n} from \"./cache.js\";\n\n/**\n * Default patterns for files to scan\n */\nconst DEFAULT_INCLUDE = [\n \"**/*.tsx\",\n \"**/*.ts\",\n \"**/*.jsx\",\n \"**/*.js\",\n];\n\n/**\n * Default patterns for files to exclude\n */\nconst DEFAULT_EXCLUDE = [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/build/**\",\n \"**/.next/**\",\n \"**/coverage/**\",\n \"**/__tests__/**\",\n \"**/*.test.*\",\n \"**/*.spec.*\",\n \"**/*.stories.*\",\n \"**/*.fragment.*\",\n \"**/storybook-static/**\",\n];\n\n/**\n * Scan entire codebase for component usages\n */\nexport async function scanCodebase(\n options: ScanOptions\n): Promise<UsageAnalysis> {\n const {\n rootDir,\n include = DEFAULT_INCLUDE,\n exclude = DEFAULT_EXCLUDE,\n files: explicitFiles,\n componentNames,\n useCache = true,\n onProgress,\n } = options;\n\n const absoluteRoot = resolve(rootDir);\n\n // Load or create cache\n let cache: AnalysisCache | null = null;\n if (useCache) {\n cache = await loadCache(absoluteRoot);\n }\n if (!cache) {\n cache = createEmptyCache(absoluteRoot);\n }\n\n // Discover files — use explicit list when provided, otherwise glob\n onProgress?.({\n current: 0,\n total: 0,\n currentFile: \"\",\n phase: \"discovering\",\n });\n\n const files = explicitFiles ?? await fg(include, {\n cwd: absoluteRoot,\n ignore: exclude,\n absolute: true,\n onlyFiles: true,\n });\n\n const totalFiles = files.length;\n\n // Track components to find (if specific ones provided)\n const trackedComponents = componentNames\n ? new Set(componentNames)\n : undefined;\n\n // Collect all imports and usages\n const allImports: ComponentImport[] = [];\n const allUsages: ComponentUsage[] = [];\n const errorFiles: string[] = [];\n const componentSources = new Map<string, string>();\n\n // Process files\n for (let i = 0; i < files.length; i++) {\n const filePath = files[i];\n const relativePath = relative(absoluteRoot, filePath);\n\n onProgress?.({\n current: i + 1,\n total: totalFiles,\n currentFile: relativePath,\n phase: \"scanning\",\n });\n\n try {\n // Read file content for hash\n const content = await readFile(filePath, \"utf-8\");\n const fileHash = computeFileHash(content);\n\n // Check cache\n const cachedEntry = getCachedFile(cache, filePath);\n if (cachedEntry && cachedEntry.hash === fileHash) {\n // Use cached results\n allImports.push(...cachedEntry.imports);\n allUsages.push(...cachedEntry.usages);\n\n // Track component sources from imports\n for (const imp of cachedEntry.imports) {\n if (!componentSources.has(imp.componentName)) {\n const sourceFile = resolveImportSource(filePath, imp.source);\n if (sourceFile) {\n componentSources.set(imp.componentName, sourceFile);\n }\n }\n }\n continue;\n }\n\n // Scan file\n const { imports, usages } = await scanFile(filePath, trackedComponents);\n\n // Update cache\n updateCacheFile(cache, filePath, fileHash, imports, usages);\n\n allImports.push(...imports);\n allUsages.push(...usages);\n\n // Track component sources\n for (const imp of imports) {\n if (!componentSources.has(imp.componentName)) {\n const sourceFile = resolveImportSource(filePath, imp.source);\n if (sourceFile) {\n componentSources.set(imp.componentName, sourceFile);\n }\n }\n }\n } catch (error) {\n errorFiles.push(relativePath);\n console.warn(`Error scanning ${relativePath}:`, (error as Error).message);\n }\n }\n\n // Save cache\n if (useCache) {\n await saveCache(absoluteRoot, cache);\n }\n\n // Aggregate results\n onProgress?.({\n current: totalFiles,\n total: totalFiles,\n currentFile: \"\",\n phase: \"aggregating\",\n });\n\n const analysis = aggregateAllUsages(allUsages, allImports, componentSources);\n analysis.rootDir = absoluteRoot;\n analysis.totalFiles = totalFiles;\n analysis.errorFiles = errorFiles;\n\n return analysis;\n}\n\n/**\n * Perform incremental scan for changed files only\n */\nexport async function incrementalScan(\n rootDir: string,\n changes: FileChanges,\n existingCache: AnalysisCache,\n onProgress?: (progress: ScanProgress) => void\n): Promise<{ analysis: UsageAnalysis; cache: AnalysisCache }> {\n const absoluteRoot = resolve(rootDir);\n const cache = { ...existingCache, files: { ...existingCache.files } };\n\n // Remove deleted files from cache\n for (const filePath of changes.deleted) {\n removeCacheFile(cache, filePath);\n }\n\n // Files to scan (added + modified)\n const filesToScan = [...changes.added, ...changes.modified];\n const totalFiles = filesToScan.length;\n\n const allImports: ComponentImport[] = [];\n const allUsages: ComponentUsage[] = [];\n const errorFiles: string[] = [];\n const componentSources = new Map<string, string>();\n\n // First, collect unchanged file data from cache\n for (const filePath of changes.unchanged) {\n const cachedEntry = getCachedFile(cache, filePath);\n if (cachedEntry) {\n allImports.push(...cachedEntry.imports);\n allUsages.push(...cachedEntry.usages);\n\n for (const imp of cachedEntry.imports) {\n if (!componentSources.has(imp.componentName)) {\n const sourceFile = resolveImportSource(filePath, imp.source);\n if (sourceFile) {\n componentSources.set(imp.componentName, sourceFile);\n }\n }\n }\n }\n }\n\n // Scan changed files\n for (let i = 0; i < filesToScan.length; i++) {\n const filePath = filesToScan[i];\n const relativePath = relative(absoluteRoot, filePath);\n\n onProgress?.({\n current: i + 1,\n total: totalFiles,\n currentFile: relativePath,\n phase: \"scanning\",\n });\n\n try {\n const content = await readFile(filePath, \"utf-8\");\n const fileHash = computeFileHash(content);\n\n const { imports, usages } = await scanFile(filePath);\n\n updateCacheFile(cache, filePath, fileHash, imports, usages);\n\n allImports.push(...imports);\n allUsages.push(...usages);\n\n for (const imp of imports) {\n if (!componentSources.has(imp.componentName)) {\n const sourceFile = resolveImportSource(filePath, imp.source);\n if (sourceFile) {\n componentSources.set(imp.componentName, sourceFile);\n }\n }\n }\n } catch (error) {\n errorFiles.push(relativePath);\n }\n }\n\n // Save updated cache\n await saveCache(absoluteRoot, cache);\n\n // Aggregate\n const analysis = aggregateAllUsages(allUsages, allImports, componentSources);\n analysis.rootDir = absoluteRoot;\n analysis.totalFiles = changes.unchanged.length + filesToScan.length;\n analysis.errorFiles = errorFiles;\n\n return { analysis, cache };\n}\n\n/**\n * Resolve import source to absolute file path\n */\nfunction resolveImportSource(\n importingFile: string,\n source: string\n): string | null {\n // Skip node_modules imports\n if (!source.startsWith(\".\") && !source.startsWith(\"/\")) {\n return null;\n }\n\n const importDir = dirname(importingFile);\n\n // Try common extensions\n const extensions = [\"\", \".tsx\", \".ts\", \".jsx\", \".js\", \"/index.tsx\", \"/index.ts\"];\n for (const ext of extensions) {\n const fullPath = resolve(importDir, source + ext);\n // We don't check if file exists here for performance\n // The source path is mainly for reference\n if (ext === \"\" && source.endsWith(\".tsx\")) {\n return fullPath;\n }\n if (ext) {\n return resolve(importDir, source) + ext;\n }\n }\n\n return resolve(importDir, source);\n}\n\n/**\n * Get scan statistics for display\n */\nexport function getScanStats(analysis: UsageAnalysis): {\n totalFiles: number;\n totalComponents: number;\n totalUsages: number;\n topComponents: { name: string; usages: number }[];\n} {\n const totalUsages = Object.values(analysis.components).reduce(\n (sum, c) => sum + c.totalUsages,\n 0\n );\n\n const topComponents = Object.values(analysis.components)\n .map((c) => ({ name: c.name, usages: c.totalUsages }))\n .sort((a, b) => b.usages - a.usages)\n .slice(0, 10);\n\n return {\n totalFiles: analysis.totalFiles,\n totalComponents: analysis.totalComponents,\n totalUsages,\n topComponents,\n };\n}\n\n/**\n * Export for quick check if cache exists and is valid\n */\nexport async function hasCachedAnalysis(rootDir: string): Promise<boolean> {\n const cache = await loadCache(resolve(rootDir));\n if (!cache) return false;\n const stats = getCacheStats(cache);\n return stats.totalFiles > 0;\n}\n\n// Re-export types and utilities\nexport { loadCache, getCacheStats, detectFileChanges } from \"./cache.js\";\n","/**\n * Usage Pattern Aggregator\n *\n * Aggregates component usages into patterns for AI analysis.\n */\n\nimport type {\n ComponentUsage,\n ComponentImport,\n ComponentAnalysis,\n UsagePattern,\n FileContext,\n UsageAnalysis,\n} from \"./types.js\";\n\n/**\n * Aggregate usages for a single component into patterns\n */\nexport function aggregateComponentUsages(\n componentName: string,\n sourceFile: string,\n usages: ComponentUsage[],\n imports: ComponentImport[]\n): ComponentAnalysis {\n // Count unique files\n const uniqueFiles = new Set(usages.map((u) => u.filePath));\n\n // Group usages by prop pattern\n const patternMap = new Map<string, UsagePattern>();\n\n for (const usage of usages) {\n // Create a key from static props (sorted for consistency)\n const propKey = createPropKey(usage.props.static);\n\n const existing = patternMap.get(propKey);\n if (existing) {\n existing.count++;\n if (!existing.files.includes(usage.filePath)) {\n existing.files.push(usage.filePath);\n }\n if (existing.sampleContexts.length < 3) {\n existing.sampleContexts.push(usage.context);\n }\n } else {\n patternMap.set(propKey, {\n props: { ...usage.props.static },\n count: 1,\n files: [usage.filePath],\n sampleContexts: [usage.context],\n });\n }\n }\n\n // Sort patterns by frequency\n const patterns = Array.from(patternMap.values()).sort(\n (a, b) => b.count - a.count\n );\n\n // Classify file contexts\n const contextMap = new Map<FileContext, { count: number; files: string[] }>();\n\n for (const usage of usages) {\n const context = classifyFileContext(usage.filePath, usage.context);\n const existing = contextMap.get(context);\n if (existing) {\n existing.count++;\n if (!existing.files.includes(usage.filePath)) {\n existing.files.push(usage.filePath);\n }\n } else {\n contextMap.set(context, { count: 1, files: [usage.filePath] });\n }\n }\n\n // Convert to sorted array\n const contexts = Array.from(contextMap.entries())\n .map(([type, data]) => ({ type, ...data }))\n .sort((a, b) => b.count - a.count);\n\n return {\n name: componentName,\n sourceFile,\n totalUsages: usages.length,\n uniqueFiles: uniqueFiles.size,\n patterns,\n contexts,\n usages,\n imports,\n };\n}\n\n/**\n * Aggregate all usages across the codebase\n */\nexport function aggregateAllUsages(\n usages: ComponentUsage[],\n imports: ComponentImport[],\n componentSources: Map<string, string>\n): UsageAnalysis {\n // Group usages by component\n const usagesByComponent = new Map<string, ComponentUsage[]>();\n for (const usage of usages) {\n const existing = usagesByComponent.get(usage.componentName) ?? [];\n existing.push(usage);\n usagesByComponent.set(usage.componentName, existing);\n }\n\n // Group imports by component\n const importsByComponent = new Map<string, ComponentImport[]>();\n for (const imp of imports) {\n const existing = importsByComponent.get(imp.componentName) ?? [];\n existing.push(imp);\n importsByComponent.set(imp.componentName, existing);\n }\n\n // Build component analyses\n const components: Record<string, ComponentAnalysis> = {};\n const allComponentNames = new Set([\n ...usagesByComponent.keys(),\n ...importsByComponent.keys(),\n ]);\n\n for (const componentName of allComponentNames) {\n const componentUsages = usagesByComponent.get(componentName) ?? [];\n const componentImports = importsByComponent.get(componentName) ?? [];\n const sourceFile = componentSources.get(componentName) ?? \"unknown\";\n\n components[componentName] = aggregateComponentUsages(\n componentName,\n sourceFile,\n componentUsages,\n componentImports\n );\n }\n\n // Collect unique files\n const allFiles = new Set<string>();\n for (const usage of usages) {\n allFiles.add(usage.filePath);\n }\n for (const imp of imports) {\n allFiles.add(imp.filePath);\n }\n\n return {\n timestamp: new Date().toISOString(),\n rootDir: \"\", // Will be set by caller\n totalFiles: allFiles.size,\n totalComponents: Object.keys(components).length,\n components,\n errorFiles: [], // Will be populated by scanner\n };\n}\n\n/**\n * Create a stable key from props for pattern grouping\n */\nfunction createPropKey(props: Record<string, string | boolean | number>): string {\n const entries = Object.entries(props).sort(([a], [b]) => a.localeCompare(b));\n return entries.map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(\"|\");\n}\n\n/**\n * Classify file context based on path and content\n */\nfunction classifyFileContext(filePath: string, context: string): FileContext {\n const lowerPath = filePath.toLowerCase();\n const lowerContext = context.toLowerCase();\n\n // Check path patterns first\n if (\n lowerPath.includes(\"/modal\") ||\n lowerPath.includes(\"modal.\") ||\n lowerContext.includes(\"<modal\")\n ) {\n return \"modal\";\n }\n\n if (\n lowerPath.includes(\"/dialog\") ||\n lowerPath.includes(\"dialog.\") ||\n lowerContext.includes(\"<dialog\")\n ) {\n return \"dialog\";\n }\n\n if (\n lowerPath.includes(\"/form\") ||\n lowerPath.includes(\"form.\") ||\n lowerContext.includes(\"<form\") ||\n lowerContext.includes(\"onsubmit\")\n ) {\n return \"form\";\n }\n\n if (\n lowerPath.includes(\"/page\") ||\n lowerPath.includes(\"pages/\") ||\n lowerPath.includes(\"/routes/\")\n ) {\n return \"page\";\n }\n\n if (\n lowerPath.includes(\"/layout\") ||\n lowerPath.includes(\"layout.\") ||\n lowerPath.includes(\"/layouts/\")\n ) {\n return \"layout\";\n }\n\n if (\n lowerPath.includes(\"/card\") ||\n lowerPath.includes(\"card.\") ||\n lowerContext.includes(\"<card\")\n ) {\n return \"card\";\n }\n\n if (\n lowerPath.includes(\"/table\") ||\n lowerPath.includes(\"table.\") ||\n lowerContext.includes(\"<table\") ||\n lowerContext.includes(\"<tr\")\n ) {\n return \"table\";\n }\n\n if (\n lowerPath.includes(\"/list\") ||\n lowerPath.includes(\"list.\") ||\n lowerContext.includes(\"<ul\") ||\n lowerContext.includes(\"<ol\") ||\n lowerContext.includes(\"<li\")\n ) {\n return \"list\";\n }\n\n if (\n lowerPath.includes(\"/nav\") ||\n lowerPath.includes(\"navigation\") ||\n lowerContext.includes(\"<nav\")\n ) {\n return \"navigation\";\n }\n\n if (\n lowerPath.includes(\"/header\") ||\n lowerPath.includes(\"header.\") ||\n lowerContext.includes(\"<header\")\n ) {\n return \"header\";\n }\n\n if (\n lowerPath.includes(\"/footer\") ||\n lowerPath.includes(\"footer.\") ||\n lowerContext.includes(\"<footer\")\n ) {\n return \"footer\";\n }\n\n if (\n lowerPath.includes(\"/sidebar\") ||\n lowerPath.includes(\"sidebar.\") ||\n lowerContext.includes(\"<aside\")\n ) {\n return \"sidebar\";\n }\n\n return \"unknown\";\n}\n\n/**\n * Find common prop combinations across usages\n */\nexport function findCommonPropCombinations(\n usages: ComponentUsage[],\n minOccurrences: number = 3\n): { props: string[]; count: number }[] {\n const combinations = new Map<string, number>();\n\n for (const usage of usages) {\n // Get all prop names (static and dynamic)\n const allProps = [\n ...Object.keys(usage.props.static),\n ...usage.props.dynamic,\n ].sort();\n\n // Generate all combinations of 2+ props\n for (let size = 2; size <= Math.min(allProps.length, 4); size++) {\n for (const combo of combinations_k(allProps, size)) {\n const key = combo.join(\",\");\n combinations.set(key, (combinations.get(key) ?? 0) + 1);\n }\n }\n }\n\n // Filter and sort by frequency\n return Array.from(combinations.entries())\n .filter(([, count]) => count >= minOccurrences)\n .map(([key, count]) => ({ props: key.split(\",\"), count }))\n .sort((a, b) => b.count - a.count);\n}\n\n/**\n * Generate k-combinations of an array\n */\nfunction* combinations_k<T>(arr: T[], k: number): Generator<T[]> {\n if (k === 0) {\n yield [];\n return;\n }\n if (arr.length < k) return;\n\n for (let i = 0; i <= arr.length - k; i++) {\n for (const combo of combinations_k(arr.slice(i + 1), k - 1)) {\n yield [arr[i], ...combo];\n }\n }\n}\n\n/**\n * Component relationship with frequency data\n */\nexport interface ComponentRelation {\n /** Related component name */\n component: string;\n /** Type of relationship */\n relationship: \"parent\" | \"sibling\" | \"child\";\n /** How often this relationship occurs */\n frequency: number;\n /** Sample files where this relationship occurs */\n sampleFiles: string[];\n}\n\n/**\n * Infer component relationships from usage patterns\n *\n * Analyzes parent/sibling relationships from actual usage data:\n * - parent: Components that contain this component (from parentElement)\n * - sibling: Components that appear alongside this component in the same parent\n */\nexport function inferRelations(\n componentName: string,\n analysis: ComponentAnalysis,\n allAnalyses: Record<string, ComponentAnalysis>\n): ComponentRelation[] {\n const relations: ComponentRelation[] = [];\n const parentCounts = new Map<string, { count: number; files: string[] }>();\n const siblingCounts = new Map<string, { count: number; files: string[] }>();\n\n // Count parent relationships\n for (const usage of analysis.usages) {\n if (usage.parentElement && usage.parentElement !== \"div\" && usage.parentElement !== \"span\") {\n const parent = usage.parentElement;\n const existing = parentCounts.get(parent);\n if (existing) {\n existing.count++;\n if (!existing.files.includes(usage.filePath)) {\n existing.files.push(usage.filePath);\n }\n } else {\n parentCounts.set(parent, { count: 1, files: [usage.filePath] });\n }\n }\n }\n\n // Infer sibling relationships: other components used in the same files\n const filesWithThisComponent = new Set(analysis.usages.map((u) => u.filePath));\n\n for (const [otherName, otherAnalysis] of Object.entries(allAnalyses)) {\n if (otherName === componentName) continue;\n\n // Count how many files have both components\n let sharedFiles = 0;\n const sharedFileList: string[] = [];\n\n for (const usage of otherAnalysis.usages) {\n if (filesWithThisComponent.has(usage.filePath)) {\n if (!sharedFileList.includes(usage.filePath)) {\n sharedFiles++;\n sharedFileList.push(usage.filePath);\n }\n }\n }\n\n // Only include if they appear together frequently\n if (sharedFiles >= 3) {\n siblingCounts.set(otherName, {\n count: sharedFiles,\n files: sharedFileList.slice(0, 5),\n });\n }\n }\n\n // Convert to relations array (parents)\n for (const [parent, data] of parentCounts) {\n // Only include meaningful parent relationships (count >= 2)\n if (data.count >= 2) {\n relations.push({\n component: parent,\n relationship: \"parent\",\n frequency: data.count,\n sampleFiles: data.files.slice(0, 3),\n });\n }\n }\n\n // Convert to relations array (siblings)\n for (const [sibling, data] of siblingCounts) {\n relations.push({\n component: sibling,\n relationship: \"sibling\",\n frequency: data.count,\n sampleFiles: data.files.slice(0, 3),\n });\n }\n\n // Sort by frequency\n relations.sort((a, b) => b.frequency - a.frequency);\n\n return relations;\n}\n\n/**\n * Infer relations for all components in the analysis\n */\nexport function inferAllRelations(\n analysis: UsageAnalysis\n): Map<string, ComponentRelation[]> {\n const allRelations = new Map<string, ComponentRelation[]>();\n\n for (const [componentName, componentAnalysis] of Object.entries(analysis.components)) {\n const relations = inferRelations(componentName, componentAnalysis, analysis.components);\n if (relations.length > 0) {\n allRelations.set(componentName, relations);\n }\n }\n\n return allRelations;\n}\n\n/**\n * Summarize patterns for AI prompt\n */\nexport function summarizePatternsForPrompt(\n analysis: ComponentAnalysis,\n maxPatterns: number = 10,\n maxContexts: number = 5\n): string {\n const lines: string[] = [];\n\n lines.push(`## ${analysis.name}`);\n lines.push(`Total usages: ${analysis.totalUsages} across ${analysis.uniqueFiles} files`);\n lines.push(\"\");\n\n // Top patterns\n lines.push(\"### Usage Patterns (by frequency)\");\n const topPatterns = analysis.patterns.slice(0, maxPatterns);\n for (const pattern of topPatterns) {\n const propsStr = Object.entries(pattern.props)\n .map(([k, v]) => `${k}=${JSON.stringify(v)}`)\n .join(\", \");\n lines.push(`- ${propsStr || \"(no props)\"}: ${pattern.count} usages in ${pattern.files.length} files`);\n }\n lines.push(\"\");\n\n // File contexts\n lines.push(\"### File Contexts\");\n const topContexts = analysis.contexts.slice(0, maxContexts);\n for (const ctx of topContexts) {\n lines.push(`- ${ctx.type}: ${ctx.count} usages`);\n }\n lines.push(\"\");\n\n // Sample code contexts (one per pattern)\n lines.push(\"### Sample Usages\");\n for (const pattern of topPatterns.slice(0, 3)) {\n if (pattern.sampleContexts[0]) {\n lines.push(\"```tsx\");\n lines.push(pattern.sampleContexts[0].trim());\n lines.push(\"```\");\n lines.push(\"\");\n }\n }\n\n return lines.join(\"\\n\");\n}\n","/**\n * Analysis Cache Layer\n *\n * Caches file analysis results to enable fast incremental updates.\n */\n\nimport { readFile, writeFile, stat } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { createHash } from \"node:crypto\";\nimport { join, dirname } from \"node:path\";\nimport { mkdir } from \"node:fs/promises\";\nimport type {\n AnalysisCache,\n FileCacheEntry,\n FileChanges,\n ComponentImport,\n ComponentUsage,\n CACHE_VERSION,\n} from \"./types.js\";\n\nconst CURRENT_CACHE_VERSION = 1;\nconst CACHE_FILENAME = \"analysis-cache.json\";\n\n/**\n * Get the cache file path for a project\n */\nexport function getCachePath(rootDir: string): string {\n return join(rootDir, \".fragments\", CACHE_FILENAME);\n}\n\n/**\n * Load cache from disk\n * Returns null if cache doesn't exist or is invalid\n */\nexport async function loadCache(rootDir: string): Promise<AnalysisCache | null> {\n const cachePath = getCachePath(rootDir);\n\n if (!existsSync(cachePath)) {\n return null;\n }\n\n try {\n const content = await readFile(cachePath, \"utf-8\");\n const cache = JSON.parse(content) as AnalysisCache;\n\n // Validate version\n if (cache.version !== CURRENT_CACHE_VERSION) {\n console.warn(\n `Cache version mismatch: expected ${CURRENT_CACHE_VERSION}, got ${cache.version}. Invalidating cache.`\n );\n return null;\n }\n\n // Validate root dir matches\n if (cache.rootDir !== rootDir) {\n console.warn(`Cache root mismatch. Invalidating cache.`);\n return null;\n }\n\n return cache;\n } catch (error) {\n console.warn(`Failed to load cache: ${(error as Error).message}`);\n return null;\n }\n}\n\n/**\n * Save cache to disk\n */\nexport async function saveCache(\n rootDir: string,\n cache: AnalysisCache\n): Promise<void> {\n const cachePath = getCachePath(rootDir);\n const cacheDir = dirname(cachePath);\n\n // Ensure .fragments directory exists\n if (!existsSync(cacheDir)) {\n await mkdir(cacheDir, { recursive: true });\n }\n\n cache.updatedAt = new Date().toISOString();\n await writeFile(cachePath, JSON.stringify(cache, null, 2));\n}\n\n/**\n * Create a new empty cache\n */\nexport function createEmptyCache(rootDir: string): AnalysisCache {\n const now = new Date().toISOString();\n return {\n version: CURRENT_CACHE_VERSION,\n createdAt: now,\n updatedAt: now,\n rootDir,\n files: {},\n };\n}\n\n/**\n * Compute content hash for a file\n */\nexport function computeFileHash(content: string): string {\n return createHash(\"md5\").update(content).digest(\"hex\");\n}\n\n/**\n * Compute file hash from disk\n */\nexport async function computeFileHashFromDisk(\n filePath: string\n): Promise<string> {\n const content = await readFile(filePath, \"utf-8\");\n return computeFileHash(content);\n}\n\n/**\n * Check if a file is cached and unchanged\n */\nexport function isFileCached(\n cache: AnalysisCache,\n filePath: string,\n currentHash: string\n): boolean {\n const entry = cache.files[filePath];\n if (!entry) return false;\n return entry.hash === currentHash;\n}\n\n/**\n * Get cached data for a file\n */\nexport function getCachedFile(\n cache: AnalysisCache,\n filePath: string\n): FileCacheEntry | null {\n return cache.files[filePath] ?? null;\n}\n\n/**\n * Update cache with results for a file\n */\nexport function updateCacheFile(\n cache: AnalysisCache,\n filePath: string,\n hash: string,\n imports: ComponentImport[],\n usages: ComponentUsage[]\n): void {\n cache.files[filePath] = {\n hash,\n timestamp: new Date().toISOString(),\n imports,\n usages,\n };\n}\n\n/**\n * Remove a file from cache\n */\nexport function removeCacheFile(cache: AnalysisCache, filePath: string): void {\n delete cache.files[filePath];\n}\n\n/**\n * Invalidate cache entries for specific files\n */\nexport function invalidateCache(\n cache: AnalysisCache,\n filePaths: string[]\n): void {\n for (const filePath of filePaths) {\n delete cache.files[filePath];\n }\n}\n\n/**\n * Detect file changes by comparing current files to cache\n */\nexport async function detectFileChanges(\n cache: AnalysisCache,\n currentFiles: string[],\n getFileHash: (filePath: string) => Promise<string>\n): Promise<FileChanges> {\n const changes: FileChanges = {\n added: [],\n modified: [],\n deleted: [],\n unchanged: [],\n };\n\n const currentFileSet = new Set(currentFiles);\n const cachedFileSet = new Set(Object.keys(cache.files));\n\n // Check for added and modified files\n for (const filePath of currentFiles) {\n const entry = cache.files[filePath];\n\n if (!entry) {\n changes.added.push(filePath);\n } else {\n const currentHash = await getFileHash(filePath);\n if (currentHash !== entry.hash) {\n changes.modified.push(filePath);\n } else {\n changes.unchanged.push(filePath);\n }\n }\n }\n\n // Check for deleted files\n for (const cachedFile of cachedFileSet) {\n if (!currentFileSet.has(cachedFile)) {\n changes.deleted.push(cachedFile);\n }\n }\n\n return changes;\n}\n\n/**\n * Get all cached imports\n */\nexport function getAllCachedImports(cache: AnalysisCache): ComponentImport[] {\n const imports: ComponentImport[] = [];\n for (const entry of Object.values(cache.files)) {\n imports.push(...entry.imports);\n }\n return imports;\n}\n\n/**\n * Get all cached usages\n */\nexport function getAllCachedUsages(cache: AnalysisCache): ComponentUsage[] {\n const usages: ComponentUsage[] = [];\n for (const entry of Object.values(cache.files)) {\n usages.push(...entry.usages);\n }\n return usages;\n}\n\n/**\n * Get cache statistics\n */\nexport function getCacheStats(cache: AnalysisCache): {\n totalFiles: number;\n totalImports: number;\n totalUsages: number;\n cacheAge: string;\n} {\n let totalImports = 0;\n let totalUsages = 0;\n\n for (const entry of Object.values(cache.files)) {\n totalImports += entry.imports.length;\n totalUsages += entry.usages.length;\n }\n\n const ageMs = Date.now() - new Date(cache.updatedAt).getTime();\n const ageMinutes = Math.round(ageMs / 60000);\n const cacheAge =\n ageMinutes < 60\n ? `${ageMinutes} minutes ago`\n : ageMinutes < 1440\n ? `${Math.round(ageMinutes / 60)} hours ago`\n : `${Math.round(ageMinutes / 1440)} days ago`;\n\n return {\n totalFiles: Object.keys(cache.files).length,\n totalImports,\n totalUsages,\n cacheAge,\n };\n}\n"],"mappings":"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","names":["readFile","dirname","readFile","dirname"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
BRAND
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-FFCI6OVZ.js";
|
|
5
5
|
|
|
6
6
|
// src/static-viewer.ts
|
|
7
7
|
import { readFile } from "fs/promises";
|
|
@@ -616,4 +616,4 @@ export {
|
|
|
616
616
|
generateStaticViewer,
|
|
617
617
|
generateViewerFromJson
|
|
618
618
|
};
|
|
619
|
-
//# sourceMappingURL=chunk-
|
|
619
|
+
//# sourceMappingURL=chunk-SNZXGHL2.js.map
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
discoverBlockFiles,
|
|
4
|
+
discoverComponentFiles,
|
|
5
|
+
discoverFragmentFiles,
|
|
6
|
+
extractComponentName,
|
|
7
|
+
loadFragmentFile,
|
|
8
|
+
parseFragmentFile
|
|
9
|
+
} from "./chunk-HNHE64CR.js";
|
|
2
10
|
import {
|
|
3
11
|
BrowserPool,
|
|
4
12
|
CaptureEngine,
|
|
@@ -8,20 +16,12 @@ import {
|
|
|
8
16
|
formatMs,
|
|
9
17
|
generateHtmlReport,
|
|
10
18
|
getGrade
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import {
|
|
13
|
-
discoverBlockFiles,
|
|
14
|
-
discoverComponentFiles,
|
|
15
|
-
discoverFragmentFiles,
|
|
16
|
-
extractComponentName,
|
|
17
|
-
loadFragmentFile,
|
|
18
|
-
parseFragmentFile
|
|
19
|
-
} from "./chunk-HQ6A6DTV.js";
|
|
19
|
+
} from "./chunk-ANTWP3UG.js";
|
|
20
20
|
import {
|
|
21
21
|
BRAND,
|
|
22
22
|
DEFAULTS,
|
|
23
23
|
fragmentDefinitionSchema
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-FFCI6OVZ.js";
|
|
25
25
|
|
|
26
26
|
// src/service/snippet-validation.ts
|
|
27
27
|
import ts from "typescript";
|
|
@@ -1252,4 +1252,4 @@ export {
|
|
|
1252
1252
|
runDiffCommand,
|
|
1253
1253
|
runAnalyzeCommand
|
|
1254
1254
|
};
|
|
1255
|
-
//# sourceMappingURL=chunk-
|
|
1255
|
+
//# sourceMappingURL=chunk-VT2J62ND.js.map
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
incrementalScan,
|
|
8
8
|
loadCache,
|
|
9
9
|
scanCodebase
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-SAQW37L5.js";
|
|
11
11
|
import "./chunk-7DZC4YEV.js";
|
|
12
12
|
export {
|
|
13
13
|
detectFileChanges,
|
|
@@ -18,4 +18,4 @@ export {
|
|
|
18
18
|
loadCache,
|
|
19
19
|
scanCodebase
|
|
20
20
|
};
|
|
21
|
-
//# sourceMappingURL=codebase-scanner-
|
|
21
|
+
//# sourceMappingURL=codebase-scanner-2T5QIDBA.js.map
|
package/dist/core/index.js
CHANGED
|
@@ -11,6 +11,13 @@ import {
|
|
|
11
11
|
analyzeComposition,
|
|
12
12
|
blockDefinitionSchema,
|
|
13
13
|
budgetBar,
|
|
14
|
+
bundleArtifactMetadataSchema,
|
|
15
|
+
bundleComponentShardSchema,
|
|
16
|
+
bundleManifestComponentEntrySchema,
|
|
17
|
+
bundleManifestSchema,
|
|
18
|
+
bundleSchemaVersionSchema,
|
|
19
|
+
bundleTargetSchema,
|
|
20
|
+
bundleTokenFileSchema,
|
|
14
21
|
checkStoryExclusion,
|
|
15
22
|
classifyComplexity,
|
|
16
23
|
compareColors,
|
|
@@ -59,6 +66,25 @@ import {
|
|
|
59
66
|
isFigmaPropMapping,
|
|
60
67
|
isForceIncluded,
|
|
61
68
|
isReactComponent,
|
|
69
|
+
mcpBlockSchema,
|
|
70
|
+
mcpCapabilitySchema,
|
|
71
|
+
mcpComponentExampleSchema,
|
|
72
|
+
mcpComponentGuidanceSchema,
|
|
73
|
+
mcpComponentMetadataSchema,
|
|
74
|
+
mcpComponentPropSchema,
|
|
75
|
+
mcpComponentRelationSchema,
|
|
76
|
+
mcpComponentSchema,
|
|
77
|
+
mcpCompoundChildSchema,
|
|
78
|
+
mcpGuidancePatternSchema,
|
|
79
|
+
mcpPerformanceDataSchema,
|
|
80
|
+
mcpPerformanceImportSchema,
|
|
81
|
+
mcpPerformanceSummarySchema,
|
|
82
|
+
mcpSnapshotMetadataSchema,
|
|
83
|
+
mcpSnapshotSchema,
|
|
84
|
+
mcpSnapshotSchemaVersionSchema,
|
|
85
|
+
mcpSourceTypeSchema,
|
|
86
|
+
mcpTokenDataSchema,
|
|
87
|
+
mcpTokenSchema,
|
|
62
88
|
normalizeStyleValue,
|
|
63
89
|
normalizeToV1,
|
|
64
90
|
parseColor,
|
|
@@ -75,7 +101,7 @@ import {
|
|
|
75
101
|
storyNameFromExport,
|
|
76
102
|
toId,
|
|
77
103
|
usePreviewVariantRuntime
|
|
78
|
-
} from "../chunk-
|
|
104
|
+
} from "../chunk-FFCI6OVZ.js";
|
|
79
105
|
export {
|
|
80
106
|
BRAND,
|
|
81
107
|
DEFAULTS,
|
|
@@ -87,6 +113,13 @@ export {
|
|
|
87
113
|
analyzeComposition,
|
|
88
114
|
blockDefinitionSchema,
|
|
89
115
|
budgetBar,
|
|
116
|
+
bundleArtifactMetadataSchema,
|
|
117
|
+
bundleComponentShardSchema,
|
|
118
|
+
bundleManifestComponentEntrySchema,
|
|
119
|
+
bundleManifestSchema,
|
|
120
|
+
bundleSchemaVersionSchema,
|
|
121
|
+
bundleTargetSchema,
|
|
122
|
+
bundleTokenFileSchema,
|
|
90
123
|
checkStoryExclusion,
|
|
91
124
|
classifyComplexity,
|
|
92
125
|
compareColors,
|
|
@@ -135,6 +168,25 @@ export {
|
|
|
135
168
|
isFigmaPropMapping,
|
|
136
169
|
isForceIncluded,
|
|
137
170
|
isReactComponent,
|
|
171
|
+
mcpBlockSchema,
|
|
172
|
+
mcpCapabilitySchema,
|
|
173
|
+
mcpComponentExampleSchema,
|
|
174
|
+
mcpComponentGuidanceSchema,
|
|
175
|
+
mcpComponentMetadataSchema,
|
|
176
|
+
mcpComponentPropSchema,
|
|
177
|
+
mcpComponentRelationSchema,
|
|
178
|
+
mcpComponentSchema,
|
|
179
|
+
mcpCompoundChildSchema,
|
|
180
|
+
mcpGuidancePatternSchema,
|
|
181
|
+
mcpPerformanceDataSchema,
|
|
182
|
+
mcpPerformanceImportSchema,
|
|
183
|
+
mcpPerformanceSummarySchema,
|
|
184
|
+
mcpSnapshotMetadataSchema,
|
|
185
|
+
mcpSnapshotSchema,
|
|
186
|
+
mcpSnapshotSchemaVersionSchema,
|
|
187
|
+
mcpSourceTypeSchema,
|
|
188
|
+
mcpTokenDataSchema,
|
|
189
|
+
mcpTokenSchema,
|
|
138
190
|
normalizeStyleValue,
|
|
139
191
|
normalizeToV1,
|
|
140
192
|
parseColor,
|
|
@@ -2,7 +2,7 @@ import { createRequire as __banner_createRequire } from 'module'; const require
|
|
|
2
2
|
import "./chunk-D2CDBRNU.js";
|
|
3
3
|
import {
|
|
4
4
|
BRAND
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-FFCI6OVZ.js";
|
|
6
6
|
|
|
7
7
|
// src/commands/create.ts
|
|
8
8
|
import { execSync } from "child_process";
|
|
@@ -1096,4 +1096,4 @@ export {
|
|
|
1096
1096
|
generateNextjsProviders,
|
|
1097
1097
|
generatePageCssModule
|
|
1098
1098
|
};
|
|
1099
|
-
//# sourceMappingURL=create-
|
|
1099
|
+
//# sourceMappingURL=create-D44QD7MV.js.map
|
|
@@ -2,7 +2,7 @@ import { createRequire as __banner_createRequire } from 'module'; const require
|
|
|
2
2
|
import "./chunk-D2CDBRNU.js";
|
|
3
3
|
import {
|
|
4
4
|
BRAND
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-FFCI6OVZ.js";
|
|
6
6
|
|
|
7
7
|
// src/commands/doctor.ts
|
|
8
8
|
import { readFile, access } from "fs/promises";
|
|
@@ -382,4 +382,4 @@ ${BRAND.name} Doctor
|
|
|
382
382
|
export {
|
|
383
383
|
doctor
|
|
384
384
|
};
|
|
385
|
-
//# sourceMappingURL=doctor-
|
|
385
|
+
//# sourceMappingURL=doctor-7B5N4JYU.js.map
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
|
|
2
|
-
import "./chunk-D2CDBRNU.js";
|
|
3
2
|
import {
|
|
4
3
|
extractPropsFromFile
|
|
5
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-HNHE64CR.js";
|
|
5
|
+
import "./chunk-D2CDBRNU.js";
|
|
6
6
|
import {
|
|
7
7
|
BRAND
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-FFCI6OVZ.js";
|
|
9
9
|
|
|
10
10
|
// src/commands/generate.ts
|
|
11
11
|
import { readFile, writeFile, access } from "fs/promises";
|
|
@@ -454,4 +454,4 @@ function inferStatus(filePath) {
|
|
|
454
454
|
export {
|
|
455
455
|
generate
|
|
456
456
|
};
|
|
457
|
-
//# sourceMappingURL=generate-
|
|
457
|
+
//# sourceMappingURL=generate-T47JZRVU.js.map
|