@fragments-sdk/cli 0.7.2 → 0.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/bin.js +25 -17
- package/dist/bin.js.map +1 -1
- package/dist/chunk-AWYCDRPG.js +272 -0
- package/dist/chunk-AWYCDRPG.js.map +1 -0
- package/dist/chunk-EKLMXTWU.js +80 -0
- package/dist/chunk-EKLMXTWU.js.map +1 -0
- package/dist/{chunk-DH4ETVSM.js → chunk-NEJ2FBTN.js} +9 -7
- package/dist/{chunk-DH4ETVSM.js.map → chunk-NEJ2FBTN.js.map} +1 -1
- package/dist/{chunk-GHYYFAQN.js → chunk-P33AKQJW.js} +1 -76
- package/dist/chunk-P33AKQJW.js.map +1 -0
- package/dist/{chunk-3T6QL7IY.js → chunk-R6IZZSE7.js} +23 -275
- package/dist/chunk-R6IZZSE7.js.map +1 -0
- package/dist/{chunk-7KUSBMI4.js → chunk-S56I5FST.js} +174 -45
- package/dist/chunk-S56I5FST.js.map +1 -0
- package/dist/{chunk-DQHWLAUV.js → chunk-TOIE7VXF.js} +2 -2
- package/dist/{chunk-OOGTG5FM.js → chunk-UXLGIGSX.js} +56 -2
- package/dist/chunk-UXLGIGSX.js.map +1 -0
- package/dist/{chunk-GKX2HPZ6.js → chunk-YMPGYEWK.js} +9 -3
- package/dist/chunk-YMPGYEWK.js.map +1 -0
- package/dist/chunk-Z7EY4VHE.js +50 -0
- package/dist/{core-UQXZTBFZ.js → core-3NMNCLFW.js} +8 -5
- package/dist/discovery-Z4RDDFVR.js +28 -0
- package/dist/{generate-GP6ZLAQB.js → generate-23VLX7QN.js} +7 -4
- package/dist/{generate-GP6ZLAQB.js.map → generate-23VLX7QN.js.map} +1 -1
- package/dist/index.js +15 -11
- package/dist/index.js.map +1 -1
- package/dist/{init-W72WBSU2.js → init-VYVYMVHH.js} +10 -6
- package/dist/{init-W72WBSU2.js.map → init-VYVYMVHH.js.map} +1 -1
- package/dist/mcp-bin.js +5 -3
- package/dist/mcp-bin.js.map +1 -1
- package/dist/sass.node-4XJK6YBF.js +130708 -0
- package/dist/sass.node-4XJK6YBF.js.map +1 -0
- package/dist/scan-FZR6YVI5.js +15 -0
- package/dist/{service-PVGTYUKX.js → service-CFFBHW4X.js} +6 -4
- package/dist/service-CFFBHW4X.js.map +1 -0
- package/dist/{static-viewer-KILKIVN7.js → static-viewer-VA2JXSCX.js} +6 -4
- package/dist/static-viewer-VA2JXSCX.js.map +1 -0
- package/dist/{test-3YRYQRGV.js → test-VTD7R6G2.js} +8 -4
- package/dist/{test-3YRYQRGV.js.map → test-VTD7R6G2.js.map} +1 -1
- package/dist/{tokens-IXSQHPQK.js → tokens-7JA5CPDL.js} +10 -7
- package/dist/{tokens-IXSQHPQK.js.map → tokens-7JA5CPDL.js.map} +1 -1
- package/dist/{viewer-K42REJU2.js → viewer-WXTDDQGK.js} +403 -26
- package/dist/viewer-WXTDDQGK.js.map +1 -0
- package/package.json +5 -1
- package/src/build.ts +57 -5
- package/src/commands/init.ts +6 -2
- package/src/core/__tests__/token-resolver.test.ts +82 -0
- package/src/core/discovery.ts +7 -1
- package/src/core/token-parser.ts +102 -0
- package/src/core/token-resolver.ts +155 -0
- package/src/migrate/detect.ts +4 -0
- package/src/service/__tests__/patch-generator.test.ts +2 -2
- package/src/service/patch-generator.ts +8 -1
- package/src/viewer/components/App.tsx +63 -2
- package/src/viewer/components/Layout.tsx +1 -1
- package/src/viewer/components/LeftSidebar.tsx +35 -77
- package/src/viewer/preview-frame.html +1 -1
- package/src/viewer/render-utils.ts +141 -0
- package/src/viewer/styles/globals.css +2 -1
- package/src/viewer/vite-plugin.ts +399 -24
- package/dist/chunk-3T6QL7IY.js.map +0 -1
- package/dist/chunk-7KUSBMI4.js.map +0 -1
- package/dist/chunk-GHYYFAQN.js.map +0 -1
- package/dist/chunk-GKX2HPZ6.js.map +0 -1
- package/dist/chunk-OOGTG5FM.js.map +0 -1
- package/dist/scan-V54HWRDY.js +0 -12
- package/dist/viewer-K42REJU2.js.map +0 -1
- /package/dist/{chunk-DQHWLAUV.js.map → chunk-TOIE7VXF.js.map} +0 -0
- /package/dist/{core-UQXZTBFZ.js.map → chunk-Z7EY4VHE.js.map} +0 -0
- /package/dist/{scan-V54HWRDY.js.map → core-3NMNCLFW.js.map} +0 -0
- /package/dist/{service-PVGTYUKX.js.map → discovery-Z4RDDFVR.js.map} +0 -0
- /package/dist/{static-viewer-KILKIVN7.js.map → scan-FZR6YVI5.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/config.ts","../src/core/generators/typescript-extractor.ts","../src/core/generators/registry.ts","../src/core/generators/context.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 } from './constants.js';\nimport type { FragmentsConfig } from './types.js';\nimport { fragmentsConfigSchema } from './schema.js';\n\nconst DEFAULT_CONFIG: FragmentsConfig = {\n include: [\n `src/**/*${BRAND.fileExtension}`, // *.fragment.tsx files\n 'src/**/*.stories.tsx', // Storybook stories (auto-converted)\n ],\n exclude: ['**/node_modules/**'],\n components: ['src/**/index.tsx', 'src/**/*.tsx'],\n framework: 'react',\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 return {\n config: { ...DEFAULT_CONFIG, ...result.data },\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","/**\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 \"../fragment-types.js\";\n\n/**\n * Result of extracting props from a component file\n */\nexport interface ExtractedProps {\n /** Component name */\n componentName: string;\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 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 if (hasExport) {\n componentExports.push(node.name.text);\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\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 type {\n Fragment,\n FragmentRegistry,\n FragmentIndex,\n RegistryComponentEntry,\n} from \"../fragment-types.js\";\nimport { extractPropsFromFile } from \"./typescript-extractor.js\";\nimport { BRAND } from \"../constants.js\";\nimport type { RegistryOptions } from \"../types.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","/**\n * Context.md Generator\n * Generates a consolidated AI-ready context file from the fragment registry\n *\n * Philosophy: Focus on human-authored semantic knowledge that AI can't get from source.\n * - Usage guidelines: When to use, when not to use\n * - Relationships: Similar components, alternatives\n * - Accessibility: Requirements and keyboard patterns\n * - DO NOT: Duplicate prop types (AI can read TypeScript directly)\n */\n\nimport type {\n FragmentRegistry,\n RegistryComponentEntry,\n RegistryPropEntry,\n FragmentDoNotItem,\n FragmentContextOptions,\n} from \"../fragment-types.js\";\n\n/**\n * Result of context generation\n */\nexport interface ContextGeneratorResult {\n /** Generated markdown content */\n content: string;\n /** Estimated token count */\n tokenEstimate: number;\n /** Component count */\n componentCount: number;\n}\n\n/**\n * Generate context.md from a fragment registry\n */\nexport function generateContextMd(\n registry: FragmentRegistry,\n options: FragmentContextOptions = {}\n): ContextGeneratorResult {\n const {\n format = \"markdown\",\n compact = false,\n include = { props: true, relations: true, code: false },\n } = options;\n\n if (format === \"json\") {\n return generateJsonContext(registry, include, compact);\n }\n\n return generateMarkdownContext(registry, include, compact);\n}\n\n/**\n * Generate markdown context\n */\nfunction generateMarkdownContext(\n registry: FragmentRegistry,\n include: { props?: boolean; relations?: boolean; code?: boolean },\n compact: boolean\n): ContextGeneratorResult {\n const lines: string[] = [];\n const componentNames = Object.keys(registry.components).sort();\n const componentCount = componentNames.length;\n\n // Header\n lines.push(\"# Component Library Context\");\n lines.push(`Generated: ${new Date().toISOString().split(\"T\")[0]} | Components: ${componentCount}`);\n lines.push(\"\");\n\n // Quick reference table\n lines.push(\"## Quick Reference\");\n lines.push(\"\");\n lines.push(\"| Component | Path | Category | Status |\");\n lines.push(\"|-----------|------|----------|--------|\");\n\n for (const name of componentNames) {\n const entry = registry.components[name];\n const status = entry.status || \"stable\";\n const category = entry.category || \"-\";\n lines.push(`| ${name} | ${entry.path} | ${category} | ${status} |`);\n }\n\n lines.push(\"\");\n\n // In compact mode, stop here\n if (compact) {\n const content = lines.join(\"\\n\");\n return {\n content,\n tokenEstimate: estimateTokens(content),\n componentCount,\n };\n }\n\n // Full documentation for each component\n lines.push(\"---\");\n lines.push(\"\");\n\n for (const name of componentNames) {\n const entry = registry.components[name];\n const fragment = entry.fragment;\n\n lines.push(`## ${name}`);\n lines.push(`**Path:** \\`${entry.path}\\``);\n\n if (entry.category) {\n lines.push(`**Category:** ${entry.category} | **Status:** ${entry.status || \"stable\"}`);\n }\n lines.push(\"\");\n\n // Description\n if (entry.description || fragment?.description) {\n lines.push(\"### Description\");\n lines.push(entry.description || fragment?.description || \"\");\n lines.push(\"\");\n }\n\n // Usage guidelines\n if (fragment?.usage) {\n if (fragment.usage.when && fragment.usage.when.length > 0) {\n lines.push(\"### When to Use\");\n for (const when of fragment.usage.when) {\n lines.push(`- ${when}`);\n }\n lines.push(\"\");\n }\n\n if (fragment.usage.doNot && fragment.usage.doNot.length > 0) {\n lines.push(\"### Do Not\");\n for (const doNotItem of fragment.usage.doNot) {\n if (typeof doNotItem === \"string\") {\n lines.push(`- ${doNotItem}`);\n } else {\n const item = doNotItem as FragmentDoNotItem;\n if (item.instead) {\n // Resolve component path\n const alternativePath = resolveComponentPath(item.instead, registry);\n if (alternativePath) {\n lines.push(`- ${item.text} → use **${item.instead}** (\\`${alternativePath}\\`)`);\n } else {\n lines.push(`- ${item.text} → use **${item.instead}**`);\n }\n } else {\n lines.push(`- ${item.text}`);\n }\n }\n }\n lines.push(\"\");\n }\n\n if (include.code && fragment.usage.patterns && fragment.usage.patterns.length > 0) {\n lines.push(\"### Patterns\");\n for (const pattern of fragment.usage.patterns) {\n lines.push(`**${pattern.name}**`);\n if (pattern.description) {\n lines.push(pattern.description);\n }\n lines.push(\"```tsx\");\n lines.push(pattern.code);\n lines.push(\"```\");\n lines.push(\"\");\n }\n }\n }\n\n // Props\n if (include.props && entry.props && Object.keys(entry.props).length > 0) {\n lines.push(\"### Props\");\n lines.push(\"| Prop | Type | Default | Description |\");\n lines.push(\"|------|------|---------|-------------|\");\n\n for (const [propName, prop] of Object.entries(entry.props)) {\n const type = formatPropType(prop);\n const defaultVal = prop.default !== undefined ? `\\`${JSON.stringify(prop.default)}\\`` : \"-\";\n const desc = prop.description || \"-\";\n const required = prop.required ? \" (required)\" : \"\";\n lines.push(`| ${propName}${required} | ${type} | ${defaultVal} | ${desc} |`);\n }\n lines.push(\"\");\n }\n\n // Accessibility\n if (fragment?.accessibility) {\n lines.push(\"### Accessibility\");\n if (fragment.accessibility.role) {\n lines.push(`**Role:** ${fragment.accessibility.role}`);\n }\n if (fragment.accessibility.requirements && fragment.accessibility.requirements.length > 0) {\n for (const req of fragment.accessibility.requirements) {\n lines.push(`- ${req}`);\n }\n }\n if (fragment.accessibility.keyboard) {\n lines.push(\"\");\n lines.push(\"**Keyboard:**\");\n for (const [key, action] of Object.entries(fragment.accessibility.keyboard)) {\n lines.push(`- \\`${key}\\`: ${action}`);\n }\n }\n lines.push(\"\");\n }\n\n // Related components\n if (include.relations && fragment?.related) {\n lines.push(\"### Related\");\n if (fragment.related.similar && fragment.related.similar.length > 0) {\n const resolved = fragment.related.similar.map((comp) => {\n const path = resolveComponentPath(comp, registry);\n return path ? `${comp} (\\`${path}\\`)` : comp;\n });\n lines.push(`- **Similar:** ${resolved.join(\", \")}`);\n }\n if (fragment.related.composedWith && fragment.related.composedWith.length > 0) {\n const resolved = fragment.related.composedWith.map((comp) => {\n const path = resolveComponentPath(comp, registry);\n return path ? `${comp} (\\`${path}\\`)` : comp;\n });\n lines.push(`- **Composed with:** ${resolved.join(\", \")}`);\n }\n if (fragment.related.usedIn && fragment.related.usedIn.length > 0) {\n const resolved = fragment.related.usedIn.map((comp) => {\n const path = resolveComponentPath(comp, registry);\n return path ? `${comp} (\\`${path}\\`)` : comp;\n });\n lines.push(`- **Used in:** ${resolved.join(\", \")}`);\n }\n lines.push(\"\");\n }\n\n lines.push(\"---\");\n lines.push(\"\");\n }\n\n const content = lines.join(\"\\n\");\n return {\n content,\n tokenEstimate: estimateTokens(content),\n componentCount,\n };\n}\n\n/**\n * Generate JSON context\n */\nfunction generateJsonContext(\n registry: FragmentRegistry,\n include: { props?: boolean; relations?: boolean; code?: boolean },\n compact: boolean\n): ContextGeneratorResult {\n const componentNames = Object.keys(registry.components).sort();\n const componentCount = componentNames.length;\n\n interface JsonComponent {\n path: string;\n category?: string;\n status?: string;\n description?: string;\n whenToUse?: string[];\n doNot?: Array<{ text: string; instead?: string; insteadPath?: string }>;\n props?: Record<string, {\n type: string;\n required?: boolean;\n default?: unknown;\n description?: string;\n }>;\n related?: {\n similar?: Array<{ name: string; path?: string }>;\n composedWith?: Array<{ name: string; path?: string }>;\n usedIn?: Array<{ name: string; path?: string }>;\n };\n }\n\n const components: Record<string, JsonComponent> = {};\n\n for (const name of componentNames) {\n const entry = registry.components[name];\n const fragment = entry.fragment;\n\n const component: JsonComponent = {\n path: entry.path,\n };\n\n if (entry.category) component.category = entry.category;\n if (entry.status) component.status = entry.status;\n if (entry.description || fragment?.description) {\n component.description = entry.description || fragment?.description;\n }\n\n if (!compact && fragment?.usage) {\n if (fragment.usage.when && fragment.usage.when.length > 0) {\n component.whenToUse = fragment.usage.when;\n }\n\n if (fragment.usage.doNot && fragment.usage.doNot.length > 0) {\n component.doNot = fragment.usage.doNot.map((item) => {\n if (typeof item === \"string\") {\n return { text: item };\n }\n const doNotItem = item as FragmentDoNotItem;\n const result: { text: string; instead?: string; insteadPath?: string } = {\n text: doNotItem.text,\n };\n if (doNotItem.instead) {\n result.instead = doNotItem.instead;\n result.insteadPath = resolveComponentPath(doNotItem.instead, registry);\n }\n return result;\n });\n }\n }\n\n if (!compact && include.props && entry.props) {\n component.props = {};\n for (const [propName, prop] of Object.entries(entry.props)) {\n component.props[propName] = {\n type: formatPropType(prop),\n };\n if (prop.required) component.props[propName].required = true;\n if (prop.default !== undefined) component.props[propName].default = prop.default;\n if (prop.description) component.props[propName].description = prop.description;\n }\n }\n\n if (!compact && include.relations && fragment?.related) {\n component.related = {};\n if (fragment.related.similar) {\n component.related.similar = fragment.related.similar.map((name) => ({\n name,\n path: resolveComponentPath(name, registry),\n }));\n }\n if (fragment.related.composedWith) {\n component.related.composedWith = fragment.related.composedWith.map((name) => ({\n name,\n path: resolveComponentPath(name, registry),\n }));\n }\n if (fragment.related.usedIn) {\n component.related.usedIn = fragment.related.usedIn.map((name) => ({\n name,\n path: resolveComponentPath(name, registry),\n }));\n }\n }\n\n components[name] = component;\n }\n\n const output = {\n version: \"1.0\",\n generatedAt: registry.generatedAt,\n componentCount,\n categories: registry.categories,\n components,\n };\n\n const content = JSON.stringify(output, null, 2);\n return {\n content,\n tokenEstimate: estimateTokens(content),\n componentCount,\n };\n}\n\n/**\n * Resolve component name to path\n */\nfunction resolveComponentPath(\n componentName: string,\n registry: FragmentRegistry\n): string | undefined {\n return registry.components[componentName]?.path;\n}\n\n/**\n * Format prop type for display\n */\nfunction formatPropType(prop: RegistryPropEntry): string {\n if (prop.options && prop.options.length > 0) {\n return prop.options.map((o) => `\"${o}\"`).join(\" \\\\| \");\n }\n return prop.type || \"unknown\";\n}\n\n/**\n * Estimate token count (rough: ~4 chars per token)\n */\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\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 type { FragmentDefinition } from './types.js';\nimport { BRAND } from './constants.js';\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/core imports\n build.onResolve({ filter: /^@fragments\\/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 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 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 .cjs extension to ensure CommonJS evaluation\n const tempFile = join(sourceDir, `.${baseName}.fragments-temp-${Date.now()}.cjs`);\n\n try {\n // Use esbuild to bundle the fragment file\n // We inject a shim for @fragments/core so it doesn't need to be installed\n // Using CommonJS format to avoid ESM/CJS interop issues with node_modules\n await build({\n entryPoints: [absolutePath],\n outfile: tempFile,\n bundle: true,\n format: 'cjs', // Use CommonJS to avoid ESM issues with lodash, etc.\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 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 \"./types.js\";\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 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 \"./storyAdapter.js\";\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":";;;;;;;;;AAAA,SAAS,kBAAkB;AAC3B,SAAS,SAAS,eAAe;AACjC,SAAS,kBAAkB;AAK3B,IAAM,iBAAkC;AAAA,EACtC,SAAS;AAAA,IACP,WAAW,MAAM,aAAa;AAAA;AAAA,IAC9B;AAAA;AAAA,EACF;AAAA,EACA,SAAS,CAAC,oBAAoB;AAAA,EAC9B,YAAY,CAAC,oBAAoB,cAAc;AAAA,EAC/C,WAAW;AACb;AAMO,SAAS,eAAe,WAAmB,QAAQ,IAAI,GAAkB;AAC9E,MAAI,aAAa;AAEjB,SAAO,eAAe,QAAQ,UAAU,GAAG;AAEzC,UAAM,aAAa,QAAQ,YAAY,MAAM,UAAU;AACvD,QAAI,WAAW,UAAU,GAAG;AAC1B,aAAO;AAAA,IACT;AAEA,UAAM,mBAAmB,QAAQ,YAAY,MAAM,gBAAgB;AACnE,QAAI,WAAW,gBAAgB,GAAG;AAChC,aAAO;AAAA,IACT;AACA,iBAAa,QAAQ,UAAU;AAAA,EACjC;AAEA,SAAO;AACT;AAKA,eAAsB,WAAW,YAG9B;AACD,QAAM,eAAe,cAAc,eAAe;AAElD,MAAI,CAAC,cAAc;AACjB,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,WAAW,QAAQ,IAAI;AAAA,IACzB;AAAA,EACF;AAEA,MAAI;AAEF,UAAM,OAAO,WAAW,YAAY,KAAK;AAAA,MACvC,gBAAgB;AAAA,IAClB,CAAC;AACD,UAAM,YAAY,MAAM,KAAK,OAAO,YAAY;AAEhD,UAAM,SAAS,sBAAsB,UAAU,SAAS;AAExD,QAAI,CAAC,OAAO,SAAS;AACnB,YAAM,SAAS,OAAO,MAAM,OACzB,IAAI,CAAC,MAAM,OAAO,EAAE,KAAK,KAAK,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAClD,KAAK,IAAI;AACZ,YAAM,IAAI,MAAM,qBAAqB,YAAY;AAAA,EAAM,MAAM,EAAE;AAAA,IACjE;AAEA,WAAO;AAAA,MACL,QAAQ,EAAE,GAAG,gBAAgB,GAAG,OAAO,KAAK;AAAA,MAC5C,WAAW,QAAQ,YAAY;AAAA,IACjC;AAAA,EACF,SAAS,OAAO;AACd,QAAI,iBAAiB,SAAS,MAAM,QAAQ,SAAS,gBAAgB,GAAG;AACtE,YAAM;AAAA,IACR;AACA,UAAM,IAAI,MAAM,8BAA8B,YAAY,KAAK,KAAK,EAAE;AAAA,EACxE;AACF;;;AC9EA,OAAO,QAAQ;AACf,SAAS,oBAAoB;AAsBtB,SAAS,qBAAqB,UAAyC;AAC5E,QAAM,aAAa,aAAa,UAAU,OAAO;AACjD,SAAO,uBAAuB,YAAY,QAAQ;AACpD;AAKO,SAAS,uBACd,YACA,WAAW,iBACY;AACvB,QAAM,aAAa,GAAG;AAAA,IACpB;AAAA,IACA;AAAA,IACA,GAAG,aAAa;AAAA,IAChB;AAAA,IACA,SAAS,SAAS,MAAM,IAAI,GAAG,WAAW,MAAM,GAAG,WAAW;AAAA,EAChE;AAEA,QAAM,SAAyB;AAAA,IAC7B,eAAe;AAAA,IACf,OAAO,CAAC;AAAA,IACR,SAAS,CAAC;AAAA,IACV,SAAS,CAAC;AAAA,EACZ;AAGA,QAAM,kBAAkB,oBAAI,IAA+D;AAC3F,QAAM,mBAA6B,CAAC;AACpC,QAAM,kBAA4B,CAAC;AAEnC,KAAG,aAAa,YAAY,CAAC,SAAS;AAEpC,QAAI,GAAG,oBAAoB,IAAI,GAAG;AAChC,YAAM,kBAAkB,KAAK;AAC7B,UAAI,GAAG,gBAAgB,eAAe,GAAG;AACvC,wBAAgB,KAAK,gBAAgB,IAAI;AAAA,MAC3C;AAAA,IACF;AAGA,QAAI,GAAG,uBAAuB,IAAI,GAAG;AACnC,YAAM,OAAO,KAAK,KAAK;AACvB,UAAI,KAAK,SAAS,OAAO,GAAG;AAC1B,wBAAgB,IAAI,MAAM,IAAI;AAAA,MAChC;AAAA,IACF;AAGA,QAAI,GAAG,uBAAuB,IAAI,GAAG;AACnC,YAAM,OAAO,KAAK,KAAK;AACvB,UAAI,KAAK,SAAS,OAAO,GAAG;AAC1B,wBAAgB,IAAI,MAAM,IAAI;AAAA,MAChC;AAAA,IACF;AAGA,QAAI,GAAG,sBAAsB,IAAI,KAAK,KAAK,MAAM;AAC/C,YAAM,YAAY,KAAK,WAAW;AAAA,QAChC,CAAC,MAAM,EAAE,SAAS,GAAG,WAAW;AAAA,MAClC;AACA,UAAI,WAAW;AACb,yBAAiB,KAAK,KAAK,KAAK,IAAI;AAAA,MACtC;AAAA,IACF;AAGA,QAAI,GAAG,oBAAoB,IAAI,GAAG;AAChC,YAAM,YAAY,KAAK,WAAW;AAAA,QAChC,CAAC,MAAM,EAAE,SAAS,GAAG,WAAW;AAAA,MAClC;AACA,UAAI,WAAW;AACb,mBAAW,QAAQ,KAAK,gBAAgB,cAAc;AACpD,cAAI,GAAG,aAAa,KAAK,IAAI,GAAG;AAC9B,6BAAiB,KAAK,KAAK,KAAK,IAAI;AAAA,UACtC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAI,GAAG,oBAAoB,IAAI,KAAK,KAAK,cAAc;AACrD,UAAI,GAAG,eAAe,KAAK,YAAY,GAAG;AACxC,mBAAW,WAAW,KAAK,aAAa,UAAU;AAChD,2BAAiB,KAAK,QAAQ,KAAK,IAAI;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO,UAAU;AACjB,SAAO,UAAU;AAGjB,QAAM,gBAAgB,iBAAiB;AAAA,IACrC,CAAC,SAAS,SAAS,KAAK,IAAI,KAAK,CAAC,KAAK,SAAS,OAAO;AAAA,EACzD;AAEA,MAAI,CAAC,eAAe;AAClB,WAAO;AAAA,EACT;AAEA,SAAO,gBAAgB;AAGvB,QAAM,qBAAqB,GAAG,aAAa;AAC3C,QAAM,iBAAiB,gBAAgB,IAAI,kBAAkB;AAE7D,MAAI,gBAAgB;AAClB,WAAO,qBAAqB;AAC5B,WAAO,QAAQ,0BAA0B,gBAAgB,UAAU;AAAA,EACrE;AAEA,SAAO;AACT;AAKA,SAAS,0BACP,MACA,YACmC;AACnC,QAAM,QAA2C,CAAC;AAGlD,MAAI,GAAG,uBAAuB,IAAI,GAAG;AACnC,eAAW,UAAU,KAAK,SAAS;AACjC,UAAI,GAAG,oBAAoB,MAAM,KAAK,OAAO,MAAM;AACjD,cAAM,WAAW,OAAO,KAAK,QAAQ,UAAU;AAC/C,cAAM,OAAO,sBAAsB,QAAQ,UAAU;AACrD,YAAI,MAAM;AACR,gBAAM,QAAQ,IAAI;AAAA,QACpB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,GAAG,uBAAuB,IAAI,GAAG;AACnC,UAAM,WAAW,KAAK;AACtB,QAAI,GAAG,kBAAkB,QAAQ,GAAG;AAClC,iBAAW,UAAU,SAAS,SAAS;AACrC,YAAI,GAAG,oBAAoB,MAAM,KAAK,OAAO,MAAM;AACjD,gBAAM,WAAW,OAAO,KAAK,QAAQ,UAAU;AAC/C,gBAAM,OAAO,sBAAsB,QAAQ,UAAU;AACrD,cAAI,MAAM;AACR,kBAAM,QAAQ,IAAI;AAAA,UACpB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,sBACP,QACA,YAC0B;AAC1B,QAAM,QAA2B,CAAC;AAGlC,QAAM,WAAW,CAAC,OAAO;AAGzB,MAAI,OAAO,MAAM;AACf,UAAM,WAAW,cAAc,OAAO,MAAM,UAAU;AACtD,UAAM,OAAO,SAAS;AACtB,UAAM,WAAW,SAAS;AAC1B,QAAI,SAAS,SAAS;AACpB,YAAM,UAAU,SAAS;AAAA,IAC3B;AAAA,EACF;AAGA,QAAM,eAAe,gBAAgB,MAAM;AAC3C,MAAI,cAAc;AAChB,UAAM,cAAc;AAAA,EACtB;AAGA,QAAM,eAAe,gBAAgB,MAAM;AAC3C,MAAI,iBAAiB,QAAW;AAC9B,UAAM,UAAU;AAAA,EAClB;AAEA,SAAO;AACT;AAKA,SAAS,cACP,UACA,YAC+E;AAE/E,MAAI,SAAS,SAAS,GAAG,WAAW,eAAe;AACjD,WAAO,EAAE,MAAM,UAAU,UAAU,SAAS;AAAA,EAC9C;AAGA,MAAI,SAAS,SAAS,GAAG,WAAW,eAAe;AACjD,WAAO,EAAE,MAAM,UAAU,UAAU,SAAS;AAAA,EAC9C;AAGA,MAAI,SAAS,SAAS,GAAG,WAAW,gBAAgB;AAClD,WAAO,EAAE,MAAM,WAAW,UAAU,UAAU;AAAA,EAChD;AAGA,MAAI,GAAG,gBAAgB,QAAQ,GAAG;AAChC,UAAM,UAAoB,CAAC;AAC3B,QAAI,cAAc;AAElB,eAAW,WAAW,SAAS,OAAO;AACpC,UAAI,GAAG,kBAAkB,OAAO,GAAG;AACjC,YAAI,GAAG,gBAAgB,QAAQ,OAAO,GAAG;AACvC,kBAAQ,KAAK,QAAQ,QAAQ,IAAI;AAAA,QACnC,WAAW,QAAQ,QAAQ,SAAS,GAAG,WAAW,aAAa;AAC7D,kBAAQ,KAAK,MAAM;AAAA,QACrB,WAAW,QAAQ,QAAQ,SAAS,GAAG,WAAW,cAAc;AAC9D,kBAAQ,KAAK,OAAO;AAAA,QACtB,OAAO;AACL,wBAAc;AAAA,QAChB;AAAA,MACF,OAAO;AACL,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,QAAI,eAAe,QAAQ,SAAS,GAAG;AACrC,aAAO;AAAA,QACL,MAAM,QAAQ,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,KAAK;AAAA,QAC7C,UAAU;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,MAAM,SAAS,QAAQ,UAAU;AAAA,MACjC,UAAU;AAAA,IACZ;AAAA,EACF;AAGA,MAAI,GAAG,mBAAmB,QAAQ,GAAG;AACnC,WAAO;AAAA,MACL,MAAM,SAAS,QAAQ,UAAU;AAAA,MACjC,UAAU;AAAA,IACZ;AAAA,EACF;AAGA,MAAI,GAAG,gBAAgB,QAAQ,GAAG;AAChC,WAAO;AAAA,MACL,MAAM,SAAS,QAAQ,UAAU;AAAA,MACjC,UAAU;AAAA,IACZ;AAAA,EACF;AAGA,MAAI,GAAG,oBAAoB,QAAQ,GAAG;AACpC,UAAM,WAAW,SAAS,SAAS,QAAQ,UAAU;AAGrD,QAAI,aAAa,eAAe,aAAa,mBAAmB;AAC9D,aAAO,EAAE,MAAM,aAAa,UAAU,OAAO;AAAA,IAC/C;AACA,QAAI,aAAa,kBAAkB,aAAa,sBAAsB;AACpE,aAAO,EAAE,MAAM,gBAAgB,UAAU,UAAU;AAAA,IACrD;AACA,QAAI,aAAa,eAAe;AAC9B,aAAO,EAAE,MAAM,eAAe,UAAU,UAAU;AAAA,IACpD;AAEA,WAAO;AAAA,MACL,MAAM,SAAS,QAAQ,UAAU;AAAA,MACjC,UAAU;AAAA,IACZ;AAAA,EACF;AAGA,MAAI,GAAG,kBAAkB,QAAQ,GAAG;AAClC,WAAO;AAAA,MACL,MAAM,SAAS,QAAQ,UAAU;AAAA,MACjC,UAAU;AAAA,IACZ;AAAA,EACF;AAGA,SAAO;AAAA,IACL,MAAM,SAAS,QAAQ,UAAU;AAAA,IACjC,UAAU;AAAA,EACZ;AACF;AAKA,SAAS,gBAAgB,MAAmC;AAC1D,QAAM,YAAY,GAAG,aAAa,IAAI;AACtC,QAAM,QAAS,KAA2C;AAE1D,MAAI,SAAS,MAAM,SAAS,GAAG;AAC7B,UAAM,UAAU,MAAM,CAAC,EAAE;AACzB,QAAI,OAAO,YAAY,UAAU;AAC/B,aAAO;AAAA,IACT;AACA,QAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,aAAO,QAAQ,IAAI,CAAC,MAAO,OAAO,MAAM,WAAW,IAAI,EAAE,IAAK,EAAE,KAAK,EAAE;AAAA,IACzE;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,gBAAgB,MAAoC;AAC3D,QAAM,YAAY,GAAG,aAAa,IAAI;AAEtC,aAAW,OAAO,WAAW;AAC3B,QAAI,IAAI,QAAQ,SAAS,WAAW;AAClC,YAAM,UAAU,IAAI;AACpB,UAAI,OAAO,YAAY,UAAU;AAE/B,YAAI;AACF,iBAAO,KAAK,MAAM,OAAO;AAAA,QAC3B,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AC3WA,SAAS,gBAAAA,qBAAgC;AACzC,SAAS,UAAU,WAAAC,UAAS,UAAU,YAAY;AAClD,OAAO,QAAQ;AA4Cf,eAAsB,iBACpB,SACkC;AAClC,QAAM;AAAA,IACJ;AAAA,IACA,oBAAoB,CAAC,gBAAgB,aAAa;AAAA,IAClD,gBAAgB,CAAC,wBAAwB,qBAAqB;AAAA,IAC9D,eAAe,KAAK,aAAa,MAAM,OAAO;AAAA,IAC9C,kBAAkB,CAAC;AAAA,EACrB,IAAI;AAEJ,QAAM;AAAA,IACJ,eAAe;AAAA,IACf,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,iBAAiB;AAAA,EACnB,IAAI;AAEJ,QAAM,SAAiD,CAAC;AACxD,QAAM,WAAqD,CAAC;AAG5D,QAAM,aAAa,MAAM,GAAG,eAAe;AAAA,IACzC,KAAK;AAAA,IACL,QAAQ,CAAC,oBAAoB;AAAA,IAC7B,UAAU;AAAA,EACZ,CAAC;AAGD,QAAM,WAAW,oBAAI,IAAoB;AACzC,aAAW,aAAa,YAAY;AAClC,UAAM,WAAWC,SAAQ,SAAS;AAClC,UAAM,YAAY,SAAS,SAAS,EAAE,QAAQ,2BAA2B,EAAE;AAC3E,aAAS,IAAI,GAAG,QAAQ,IAAI,SAAS,IAAI,SAAS;AAAA,EACpD;AAGA,QAAM,iBAAiB,MAAM,GAAG,mBAAmB;AAAA,IACjD,KAAK;AAAA,IACL,QAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,UAAU;AAAA,EACZ,CAAC;AAGD,QAAM,kBAAkB;AAAA,IACtB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,IAAI,MAAM,aAAa;AAAA,EACzB;AACA,QAAM,gBAAgB,MAAM,GAAG,iBAAiB;AAAA,IAC9C,KAAK;AAAA,IACL,UAAU;AAAA,EACZ,CAAC;AAGD,QAAM,cAAc,oBAAI,IAAkD;AAC1E,aAAW,gBAAgB,eAAe;AACxC,UAAM,eAAe,SAAS,YAAY,EAAE,QAAQ,MAAM,eAAe,EAAE;AAC3E,QAAI;AACF,YAAM,UAAUC,cAAa,cAAc,OAAO;AAClD,YAAM,WAAW,KAAK,MAAM,OAAO;AACnC,kBAAY,IAAI,cAAc;AAAA,QAC5B,MAAM,SAAS,aAAa,YAAY;AAAA,QACxC;AAAA,MACF,CAAC;AAAA,IACH,SAAS,GAAG;AACV,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,OAAO,6BAA6B,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,MAChF,CAAC;AAAA,IACH;AAAA,EACF;AAGA,QAAM,aAAqD,CAAC;AAC5D,QAAM,kBAA0C,CAAC;AACjD,QAAM,aAAuC,CAAC;AAG9C,aAAW,YAAY,gBAAgB;AACrC,QAAI;AACF,YAAM,YAAY,qBAAqB,QAAQ;AAC/C,UAAI,CAAC,aAAa,CAAC,UAAU,eAAe;AAC1C;AAAA,MACF;AAEA,YAAM,gBAAgB,UAAU;AAChC,YAAM,eAAe,SAAS,aAAa,QAAQ;AAGnD,UAAI,cAAc,CAAC,UAAU,QAAQ,SAAS,aAAa,GAAG;AAC5D;AAAA,MACF;AAGA,YAAM,eAAeD,SAAQ,QAAQ;AACrC,YAAM,qBAAqB,SAAS,QAAQ,EAAE,QAAQ,kBAAkB,EAAE;AAC1E,YAAM,YAAY,SAAS,IAAI,GAAG,YAAY,IAAI,kBAAkB,EAAE;AAGtE,UAAI,gBAAgB,CAAC,WAAW;AAC9B;AAAA,MACF;AAGA,YAAM,eAAe,YAAY,IAAI,aAAa;AAGlD,YAAM,WAAW,cAAc,UAAU,MAAM,SAC3C,SACA,oBAAoB,cAAc,aAAa;AAGnD,YAAM,gBAAgB,eAClB,kBAAkB,aAAa,QAAQ,IACvC;AAGJ,YAAM,QAAgC;AAAA,QACpC,MAAM;AAAA,MACR;AAGA,UAAI,WAAW;AACb,cAAM,YAAY,SAAS,aAAa,SAAS;AAAA,MACnD;AAEA,UAAI,cAAc;AAChB,cAAM,eAAe,aAAa;AAClC,YAAI,eAAe;AACjB,gBAAM,gBAAgB;AAAA,QACxB;AACA,YAAI,aAAa,SAAS,aAAa;AACrC,gBAAM,cAAc,aAAa,SAAS;AAAA,QAC5C;AACA,YAAI,aAAa,SAAS,MAAM,QAAQ;AACtC,gBAAM,SAAS,aAAa,SAAS,KAAK;AAAA,QAC5C;AAEA,YAAI,gBAAgB;AAClB,gBAAM,WAAW,aAAa;AAAA,QAChC;AAAA,MACF;AAEA,UAAI,UAAU;AACZ,cAAM,WAAW;AAEjB,YAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,qBAAW,QAAQ,IAAI,CAAC;AAAA,QAC1B;AACA,mBAAW,QAAQ,EAAE,KAAK,aAAa;AAAA,MACzC;AAGA,UAAI,gBAAgB,UAAU,OAAO;AACnC,cAAM,QAAQ,UAAU;AAAA,MAC1B;AAGA,UAAI,UAAU,QAAQ,SAAS,GAAG;AAChC,cAAM,UAAU,UAAU;AAAA,MAC5B;AAEA,iBAAW,aAAa,IAAI;AAC5B,sBAAgB,aAAa,IAAI;AAAA,IACnC,SAAS,GAAG;AACV,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,OAAO,gCAAgC,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,MACnF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,iBAAiB,OAAO,KAAK,UAAU,EAAE;AAG/C,QAAM,WAA6B;AAAA,IACjC,SAAS;AAAA,IACT,SAAS;AAAA,IACT,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAGA,QAAM,QAAuB;AAAA,IAC3B,SAAS;AAAA,IACT,aAAa,SAAS;AAAA,IACtB,YAAY;AAAA,IACZ;AAAA,EACF;AAEA,SAAO,EAAE,UAAU,OAAO,QAAQ,SAAS;AAC7C;AAUA,SAAS,oBAAoB,cAAsB,QAAgB,GAAuB;AACxF,QAAM,QAAQ,aAAa,MAAM,GAAG;AACpC,QAAM,kBAAkB,MAAM,UAAU,CAAC,MAAM,MAAM,YAAY;AAEjE,MAAI,oBAAoB,IAAI;AAC1B,WAAO;AAAA,EACT;AAGA,QAAM,kBAAkB,MAAM,MAAM,kBAAkB,CAAC;AAGvD,MAAI,gBAAgB,UAAU,GAAG;AAC/B,WAAO;AAAA,EACT;AAGA,QAAM,aAAa,gBAAgB,CAAC;AACpC,QAAM,WAAW,gBAAgB,gBAAgB,SAAS,CAAC,EAAE,QAAQ,kBAAkB,EAAE;AACzF,MAAI,gBAAgB,WAAW,KAAK,eAAe,UAAU;AAC3D,WAAO;AAAA,EACT;AAGA,QAAM,gBAAgB,gBAAgB,MAAM,GAAG,KAAK,IAAI,OAAO,gBAAgB,SAAS,CAAC,CAAC;AAG1F,QAAM,mBAAmB,cAAc,cAAc,SAAS,CAAC;AAC/D,MAAI,qBAAqB,UAAU;AACjC,kBAAc,IAAI;AAAA,EACpB;AAEA,MAAI,cAAc,WAAW,GAAG;AAC9B,WAAO;AAAA,EACT;AAEA,SAAO,cAAc,KAAK,GAAG;AAC/B;AAKA,SAAS,kBAAkB,UAA6B;AAEtD,MAAI,SAAS,eAAe,SAAS,YAAY,SAAS,IAAI;AAC5D,WAAO;AAAA,EACT;AAGA,MAAI,SAAS,OAAO,QAAQ,SAAS,MAAM,KAAK,SAAS,GAAG;AAC1D,WAAO;AAAA,EACT;AACA,MAAI,SAAS,OAAO,SAAS,SAAS,MAAM,MAAM,SAAS,GAAG;AAC5D,WAAO;AAAA,EACT;AACA,MAAI,SAAS,OAAO,YAAY,SAAS,MAAM,SAAS,SAAS,GAAG;AAClE,WAAO;AAAA,EACT;AAGA,MAAI,SAAS,eAAe,gBAAgB,SAAS,cAAc,aAAa,SAAS,GAAG;AAC1F,WAAO;AAAA,EACT;AAGA,MAAI,SAAS,OAAO,UAAU,SAAS,OAAO,UAAU;AACtD,WAAO;AAAA,EACT;AAGA,MAAI,SAAS,SAAS,WAAW,SAAS,QAAQ,QAAQ,SAAS,GAAG;AACpE,WAAO;AAAA,EACT;AAEA,SAAO;AACT;;;ACpTO,SAAS,kBACd,UACA,UAAkC,CAAC,GACX;AACxB,QAAM;AAAA,IACJ,SAAS;AAAA,IACT,UAAU;AAAA,IACV,UAAU,EAAE,OAAO,MAAM,WAAW,MAAM,MAAM,MAAM;AAAA,EACxD,IAAI;AAEJ,MAAI,WAAW,QAAQ;AACrB,WAAO,oBAAoB,UAAU,SAAS,OAAO;AAAA,EACvD;AAEA,SAAO,wBAAwB,UAAU,SAAS,OAAO;AAC3D;AAKA,SAAS,wBACP,UACA,SACA,SACwB;AACxB,QAAM,QAAkB,CAAC;AACzB,QAAM,iBAAiB,OAAO,KAAK,SAAS,UAAU,EAAE,KAAK;AAC7D,QAAM,iBAAiB,eAAe;AAGtC,QAAM,KAAK,6BAA6B;AACxC,QAAM,KAAK,eAAc,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC,kBAAkB,cAAc,EAAE;AACjG,QAAM,KAAK,EAAE;AAGb,QAAM,KAAK,oBAAoB;AAC/B,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,0CAA0C;AACrD,QAAM,KAAK,0CAA0C;AAErD,aAAW,QAAQ,gBAAgB;AACjC,UAAM,QAAQ,SAAS,WAAW,IAAI;AACtC,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,WAAW,MAAM,YAAY;AACnC,UAAM,KAAK,KAAK,IAAI,MAAM,MAAM,IAAI,MAAM,QAAQ,MAAM,MAAM,IAAI;AAAA,EACpE;AAEA,QAAM,KAAK,EAAE;AAGb,MAAI,SAAS;AACX,UAAME,WAAU,MAAM,KAAK,IAAI;AAC/B,WAAO;AAAA,MACL,SAAAA;AAAA,MACA,eAAe,eAAeA,QAAO;AAAA,MACrC;AAAA,IACF;AAAA,EACF;AAGA,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,EAAE;AAEb,aAAW,QAAQ,gBAAgB;AACjC,UAAM,QAAQ,SAAS,WAAW,IAAI;AACtC,UAAM,WAAW,MAAM;AAEvB,UAAM,KAAK,MAAM,IAAI,EAAE;AACvB,UAAM,KAAK,eAAe,MAAM,IAAI,IAAI;AAExC,QAAI,MAAM,UAAU;AAClB,YAAM,KAAK,iBAAiB,MAAM,QAAQ,kBAAkB,MAAM,UAAU,QAAQ,EAAE;AAAA,IACxF;AACA,UAAM,KAAK,EAAE;AAGb,QAAI,MAAM,eAAe,UAAU,aAAa;AAC9C,YAAM,KAAK,iBAAiB;AAC5B,YAAM,KAAK,MAAM,eAAe,UAAU,eAAe,EAAE;AAC3D,YAAM,KAAK,EAAE;AAAA,IACf;AAGA,QAAI,UAAU,OAAO;AACnB,UAAI,SAAS,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,GAAG;AACzD,cAAM,KAAK,iBAAiB;AAC5B,mBAAW,QAAQ,SAAS,MAAM,MAAM;AACtC,gBAAM,KAAK,KAAK,IAAI,EAAE;AAAA,QACxB;AACA,cAAM,KAAK,EAAE;AAAA,MACf;AAEA,UAAI,SAAS,MAAM,SAAS,SAAS,MAAM,MAAM,SAAS,GAAG;AAC3D,cAAM,KAAK,YAAY;AACvB,mBAAW,aAAa,SAAS,MAAM,OAAO;AAC5C,cAAI,OAAO,cAAc,UAAU;AACjC,kBAAM,KAAK,KAAK,SAAS,EAAE;AAAA,UAC7B,OAAO;AACL,kBAAM,OAAO;AACb,gBAAI,KAAK,SAAS;AAEhB,oBAAM,kBAAkB,qBAAqB,KAAK,SAAS,QAAQ;AACnE,kBAAI,iBAAiB;AACnB,sBAAM,KAAK,KAAK,KAAK,IAAI,iBAAY,KAAK,OAAO,SAAS,eAAe,KAAK;AAAA,cAChF,OAAO;AACL,sBAAM,KAAK,KAAK,KAAK,IAAI,iBAAY,KAAK,OAAO,IAAI;AAAA,cACvD;AAAA,YACF,OAAO;AACL,oBAAM,KAAK,KAAK,KAAK,IAAI,EAAE;AAAA,YAC7B;AAAA,UACF;AAAA,QACF;AACA,cAAM,KAAK,EAAE;AAAA,MACf;AAEA,UAAI,QAAQ,QAAQ,SAAS,MAAM,YAAY,SAAS,MAAM,SAAS,SAAS,GAAG;AACjF,cAAM,KAAK,cAAc;AACzB,mBAAW,WAAW,SAAS,MAAM,UAAU;AAC7C,gBAAM,KAAK,KAAK,QAAQ,IAAI,IAAI;AAChC,cAAI,QAAQ,aAAa;AACvB,kBAAM,KAAK,QAAQ,WAAW;AAAA,UAChC;AACA,gBAAM,KAAK,QAAQ;AACnB,gBAAM,KAAK,QAAQ,IAAI;AACvB,gBAAM,KAAK,KAAK;AAChB,gBAAM,KAAK,EAAE;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAGA,QAAI,QAAQ,SAAS,MAAM,SAAS,OAAO,KAAK,MAAM,KAAK,EAAE,SAAS,GAAG;AACvE,YAAM,KAAK,WAAW;AACtB,YAAM,KAAK,yCAAyC;AACpD,YAAM,KAAK,yCAAyC;AAEpD,iBAAW,CAAC,UAAU,IAAI,KAAK,OAAO,QAAQ,MAAM,KAAK,GAAG;AAC1D,cAAM,OAAO,eAAe,IAAI;AAChC,cAAM,aAAa,KAAK,YAAY,SAAY,KAAK,KAAK,UAAU,KAAK,OAAO,CAAC,OAAO;AACxF,cAAM,OAAO,KAAK,eAAe;AACjC,cAAM,WAAW,KAAK,WAAW,gBAAgB;AACjD,cAAM,KAAK,KAAK,QAAQ,GAAG,QAAQ,MAAM,IAAI,MAAM,UAAU,MAAM,IAAI,IAAI;AAAA,MAC7E;AACA,YAAM,KAAK,EAAE;AAAA,IACf;AAGA,QAAI,UAAU,eAAe;AAC3B,YAAM,KAAK,mBAAmB;AAC9B,UAAI,SAAS,cAAc,MAAM;AAC/B,cAAM,KAAK,aAAa,SAAS,cAAc,IAAI,EAAE;AAAA,MACvD;AACA,UAAI,SAAS,cAAc,gBAAgB,SAAS,cAAc,aAAa,SAAS,GAAG;AACzF,mBAAW,OAAO,SAAS,cAAc,cAAc;AACrD,gBAAM,KAAK,KAAK,GAAG,EAAE;AAAA,QACvB;AAAA,MACF;AACA,UAAI,SAAS,cAAc,UAAU;AACnC,cAAM,KAAK,EAAE;AACb,cAAM,KAAK,eAAe;AAC1B,mBAAW,CAAC,KAAK,MAAM,KAAK,OAAO,QAAQ,SAAS,cAAc,QAAQ,GAAG;AAC3E,gBAAM,KAAK,OAAO,GAAG,OAAO,MAAM,EAAE;AAAA,QACtC;AAAA,MACF;AACA,YAAM,KAAK,EAAE;AAAA,IACf;AAGA,QAAI,QAAQ,aAAa,UAAU,SAAS;AAC1C,YAAM,KAAK,aAAa;AACxB,UAAI,SAAS,QAAQ,WAAW,SAAS,QAAQ,QAAQ,SAAS,GAAG;AACnE,cAAM,WAAW,SAAS,QAAQ,QAAQ,IAAI,CAAC,SAAS;AACtD,gBAAM,OAAO,qBAAqB,MAAM,QAAQ;AAChD,iBAAO,OAAO,GAAG,IAAI,OAAO,IAAI,QAAQ;AAAA,QAC1C,CAAC;AACD,cAAM,KAAK,kBAAkB,SAAS,KAAK,IAAI,CAAC,EAAE;AAAA,MACpD;AACA,UAAI,SAAS,QAAQ,gBAAgB,SAAS,QAAQ,aAAa,SAAS,GAAG;AAC7E,cAAM,WAAW,SAAS,QAAQ,aAAa,IAAI,CAAC,SAAS;AAC3D,gBAAM,OAAO,qBAAqB,MAAM,QAAQ;AAChD,iBAAO,OAAO,GAAG,IAAI,OAAO,IAAI,QAAQ;AAAA,QAC1C,CAAC;AACD,cAAM,KAAK,wBAAwB,SAAS,KAAK,IAAI,CAAC,EAAE;AAAA,MAC1D;AACA,UAAI,SAAS,QAAQ,UAAU,SAAS,QAAQ,OAAO,SAAS,GAAG;AACjE,cAAM,WAAW,SAAS,QAAQ,OAAO,IAAI,CAAC,SAAS;AACrD,gBAAM,OAAO,qBAAqB,MAAM,QAAQ;AAChD,iBAAO,OAAO,GAAG,IAAI,OAAO,IAAI,QAAQ;AAAA,QAC1C,CAAC;AACD,cAAM,KAAK,kBAAkB,SAAS,KAAK,IAAI,CAAC,EAAE;AAAA,MACpD;AACA,YAAM,KAAK,EAAE;AAAA,IACf;AAEA,UAAM,KAAK,KAAK;AAChB,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,UAAU,MAAM,KAAK,IAAI;AAC/B,SAAO;AAAA,IACL;AAAA,IACA,eAAe,eAAe,OAAO;AAAA,IACrC;AAAA,EACF;AACF;AAKA,SAAS,oBACP,UACA,SACA,SACwB;AACxB,QAAM,iBAAiB,OAAO,KAAK,SAAS,UAAU,EAAE,KAAK;AAC7D,QAAM,iBAAiB,eAAe;AAsBtC,QAAM,aAA4C,CAAC;AAEnD,aAAW,QAAQ,gBAAgB;AACjC,UAAM,QAAQ,SAAS,WAAW,IAAI;AACtC,UAAM,WAAW,MAAM;AAEvB,UAAM,YAA2B;AAAA,MAC/B,MAAM,MAAM;AAAA,IACd;AAEA,QAAI,MAAM,SAAU,WAAU,WAAW,MAAM;AAC/C,QAAI,MAAM,OAAQ,WAAU,SAAS,MAAM;AAC3C,QAAI,MAAM,eAAe,UAAU,aAAa;AAC9C,gBAAU,cAAc,MAAM,eAAe,UAAU;AAAA,IACzD;AAEA,QAAI,CAAC,WAAW,UAAU,OAAO;AAC/B,UAAI,SAAS,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,GAAG;AACzD,kBAAU,YAAY,SAAS,MAAM;AAAA,MACvC;AAEA,UAAI,SAAS,MAAM,SAAS,SAAS,MAAM,MAAM,SAAS,GAAG;AAC3D,kBAAU,QAAQ,SAAS,MAAM,MAAM,IAAI,CAAC,SAAS;AACnD,cAAI,OAAO,SAAS,UAAU;AAC5B,mBAAO,EAAE,MAAM,KAAK;AAAA,UACtB;AACA,gBAAM,YAAY;AAClB,gBAAM,SAAmE;AAAA,YACvE,MAAM,UAAU;AAAA,UAClB;AACA,cAAI,UAAU,SAAS;AACrB,mBAAO,UAAU,UAAU;AAC3B,mBAAO,cAAc,qBAAqB,UAAU,SAAS,QAAQ;AAAA,UACvE;AACA,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF;AAEA,QAAI,CAAC,WAAW,QAAQ,SAAS,MAAM,OAAO;AAC5C,gBAAU,QAAQ,CAAC;AACnB,iBAAW,CAAC,UAAU,IAAI,KAAK,OAAO,QAAQ,MAAM,KAAK,GAAG;AAC1D,kBAAU,MAAM,QAAQ,IAAI;AAAA,UAC1B,MAAM,eAAe,IAAI;AAAA,QAC3B;AACA,YAAI,KAAK,SAAU,WAAU,MAAM,QAAQ,EAAE,WAAW;AACxD,YAAI,KAAK,YAAY,OAAW,WAAU,MAAM,QAAQ,EAAE,UAAU,KAAK;AACzE,YAAI,KAAK,YAAa,WAAU,MAAM,QAAQ,EAAE,cAAc,KAAK;AAAA,MACrE;AAAA,IACF;AAEA,QAAI,CAAC,WAAW,QAAQ,aAAa,UAAU,SAAS;AACtD,gBAAU,UAAU,CAAC;AACrB,UAAI,SAAS,QAAQ,SAAS;AAC5B,kBAAU,QAAQ,UAAU,SAAS,QAAQ,QAAQ,IAAI,CAACC,WAAU;AAAA,UAClE,MAAAA;AAAA,UACA,MAAM,qBAAqBA,OAAM,QAAQ;AAAA,QAC3C,EAAE;AAAA,MACJ;AACA,UAAI,SAAS,QAAQ,cAAc;AACjC,kBAAU,QAAQ,eAAe,SAAS,QAAQ,aAAa,IAAI,CAACA,WAAU;AAAA,UAC5E,MAAAA;AAAA,UACA,MAAM,qBAAqBA,OAAM,QAAQ;AAAA,QAC3C,EAAE;AAAA,MACJ;AACA,UAAI,SAAS,QAAQ,QAAQ;AAC3B,kBAAU,QAAQ,SAAS,SAAS,QAAQ,OAAO,IAAI,CAACA,WAAU;AAAA,UAChE,MAAAA;AAAA,UACA,MAAM,qBAAqBA,OAAM,QAAQ;AAAA,QAC3C,EAAE;AAAA,MACJ;AAAA,IACF;AAEA,eAAW,IAAI,IAAI;AAAA,EACrB;AAEA,QAAM,SAAS;AAAA,IACb,SAAS;AAAA,IACT,aAAa,SAAS;AAAA,IACtB;AAAA,IACA,YAAY,SAAS;AAAA,IACrB;AAAA,EACF;AAEA,QAAM,UAAU,KAAK,UAAU,QAAQ,MAAM,CAAC;AAC9C,SAAO;AAAA,IACL;AAAA,IACA,eAAe,eAAe,OAAO;AAAA,IACrC;AAAA,EACF;AACF;AAKA,SAAS,qBACP,eACA,UACoB;AACpB,SAAO,SAAS,WAAW,aAAa,GAAG;AAC7C;AAKA,SAAS,eAAe,MAAiC;AACvD,MAAI,KAAK,WAAW,KAAK,QAAQ,SAAS,GAAG;AAC3C,WAAO,KAAK,QAAQ,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,OAAO;AAAA,EACvD;AACA,SAAO,KAAK,QAAQ;AACtB;AAKA,SAAS,eAAe,MAAsB;AAC5C,SAAO,KAAK,KAAK,KAAK,SAAS,CAAC;AAClC;;;ACpYA,SAAoB,cAAc;AAClC,SAAS,WAAAC,UAAS,YAAAC,WAAU,QAAAC,aAAY;AACxC,SAAS,qBAAqB;AAC9B,SAAS,aAA0B;AAMnC,IAAM,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgB7B,SAAS,gCAAwC;AAC/C,SAAO;AAAA,IACL,MAAM,MAAM;AAAA,IACZ,MAAMC,QAAO;AAEX,MAAAA,OAAM,UAAU,EAAE,QAAQ,qBAAqB,GAAG,CAAC,SAAS;AAC1D,eAAO;AAAA,UACL,MAAM,KAAK;AAAA,UACX,WAAW,MAAM;AAAA,QACnB;AAAA,MACF,CAAC;AAGD,MAAAA,OAAM,OAAO,EAAE,QAAQ,MAAM,WAAW,MAAM,oBAAoB,GAAG,MAAM;AACzE,eAAO;AAAA,UACL,UAAU;AAAA,UACV,QAAQ;AAAA,QACV;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAMA,eAAsB,iBACpB,cACoC;AACpC,QAAM,MAAM,aAAa,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY;AACvD,QAAM,iBAAiB,QAAQ,SAAS,QAAQ,QAAQ,QAAQ;AAEhE,MAAI,CAAC,gBAAgB;AAEnB,UAAM,UAAU,cAAc,YAAY,EAAE;AAC5C,UAAM,SAAS,MAAM,OAAO;AAC5B,WAAO,OAAO,WAAW;AAAA,EAC3B;AAGA,QAAM,YAAYC,SAAQ,YAAY;AACtC,QAAM,WAAWC,UAAS,cAAc,IAAI,GAAG,EAAE;AAEjD,QAAM,WAAWC,MAAK,WAAW,IAAI,QAAQ,mBAAmB,KAAK,IAAI,CAAC,MAAM;AAEhF,MAAI;AAIF,UAAM,MAAM;AAAA,MACV,aAAa,CAAC,YAAY;AAAA,MAC1B,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,QAAQ;AAAA;AAAA,MACR,QAAQ;AAAA,MACR,KAAK;AAAA,MACL,UAAU;AAAA,MACV,SAAS,CAAC,8BAA8B,CAAC;AAAA;AAAA,MAEzC,UAAU;AAAA;AAAA,MAEV,UAAU;AAAA;AAAA,QAER;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA;AAAA,MAEA,WAAW;AAAA;AAAA,MAEX,UAAU;AAAA;AAAA,MAEV,QAAQ;AAAA,QACN,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV;AAAA,IACF,CAAC;AAED,UAAM,UAAU,cAAc,QAAQ,EAAE;AACxC,UAAM,SAAS,MAAM,OAAO;AAC5B,WAAO,OAAO,WAAW;AAAA,EAC3B,UAAE;AAEA,QAAI;AACF,YAAM,OAAO,QAAQ;AAAA,IACvB,QAAQ;AAAA,IAER;AAAA,EACF;AACF;;;ACpHA,OAAOC,SAAQ;AAmDR,SAAS,kBACd,aACA,UACwB;AACxB,QAAM,WAAqB,CAAC;AAG5B,QAAM,aAAaA,IAAG;AAAA,IACpB,YAAY;AAAA,IACZ;AAAA,IACAA,IAAG,aAAa;AAAA,IAChB;AAAA,IACAA,IAAG,WAAW;AAAA,EAChB;AAGA,QAAM,UAAU,eAAe,UAAU;AAGzC,QAAM,qBAAqB,uBAAuB,UAAU;AAE5D,MAAI,CAAC,oBAAoB;AACvB,aAAS,KAAK,gCAAgC;AAC9C,WAAO;AAAA,MACL,iBAAiB;AAAA,MACjB,eAAe;AAAA,MACf,MAAM,CAAC;AAAA,MACP,OAAO,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,EAAE;AAAA,MAC/B,OAAO,CAAC;AAAA,MACR,UAAU,CAAC;AAAA,MACX,WAAW,CAAC;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAGA,QAAM,MAAM,mBAAmB,UAAU,CAAC;AAC1C,MAAI,CAAC,OAAO,CAACA,IAAG,0BAA0B,GAAG,GAAG;AAC9C,aAAS,KAAK,oDAAoD;AAClE,WAAO;AAAA,MACL,iBAAiB;AAAA,MACjB,eAAe;AAAA,MACf,MAAM,CAAC;AAAA,MACP,OAAO,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,EAAE;AAAA,MAC/B,OAAO,CAAC;AAAA,MACR,UAAU,CAAC;AAAA,MACX,WAAW,CAAC;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAGA,QAAM,gBAAgB,aAAa,KAAK,WAAW;AACnD,MAAI,gBAA+B;AACnC,MAAI,kBAAiC;AAErC,MAAI,iBAAiBA,IAAG,aAAa,aAAa,GAAG;AACnD,oBAAgB,cAAc;AAE9B,sBAAkB,QAAQ,IAAI,aAAa,KAAK;AAAA,EAClD;AAGA,QAAM,OAAO,YAAY,KAAK,QAAQ;AAGtC,QAAM,QAAQ,aAAa,KAAK,QAAQ;AAGxC,QAAM,QAAQ,aAAa,KAAK,QAAQ;AAGxC,QAAM,WAAW,gBAAgB,KAAK,YAAY,QAAQ;AAG1D,QAAM,YAAY,iBAAiB,KAAK,QAAQ;AAGhD,QAAM,KAAK,kBAAkB,KAAK,QAAQ;AAG1C,QAAM,WAAW,wBAAwB,GAAG;AAE5C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAMA,SAAS,eAAe,YAAgD;AACtE,QAAM,UAAU,oBAAI,IAAoB;AAExC,EAAAA,IAAG,aAAa,YAAY,CAAC,SAAS;AACpC,QAAIA,IAAG,oBAAoB,IAAI,GAAG;AAChC,YAAM,kBAAkB,KAAK;AAC7B,UAAIA,IAAG,gBAAgB,eAAe,GAAG;AACvC,cAAM,aAAa,gBAAgB;AAGnC,cAAM,eAAe,KAAK;AAC1B,YAAI,cAAc;AAEhB,cAAI,aAAa,MAAM;AACrB,oBAAQ,IAAI,aAAa,KAAK,MAAM,UAAU;AAAA,UAChD;AAGA,gBAAM,gBAAgB,aAAa;AACnC,cAAI,iBAAiBA,IAAG,eAAe,aAAa,GAAG;AACrD,uBAAW,WAAW,cAAc,UAAU;AAC5C,sBAAQ,IAAI,QAAQ,KAAK,MAAM,UAAU;AAAA,YAC3C;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAKA,SAAS,uBACP,YAC0B;AAC1B,MAAI,SAAmC;AAEvC,WAAS,MAAM,MAAqB;AAClC,QAAIA,IAAG,iBAAiB,IAAI,GAAG;AAC7B,YAAM,aAAa,KAAK;AACxB,UAAIA,IAAG,aAAa,UAAU,KAAK,WAAW,SAAS,kBAAkB;AACvE,iBAAS;AACT;AAAA,MACF;AAAA,IACF;AACA,IAAAA,IAAG,aAAa,MAAM,KAAK;AAAA,EAC7B;AAEA,QAAM,UAAU;AAChB,SAAO;AACT;AAKA,SAAS,aACP,KACA,MACsB;AACtB,aAAW,QAAQ,IAAI,YAAY;AACjC,QAAIA,IAAG,qBAAqB,IAAI,GAAG;AACjC,YAAM,WAAW,KAAK;AACtB,UAAIA,IAAG,aAAa,QAAQ,KAAK,SAAS,SAAS,MAAM;AACvD,eAAO,KAAK;AAAA,MACd;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAKA,SAAS,YACP,KACA,UACuB;AACvB,QAAM,WAAW,aAAa,KAAK,MAAM;AACzC,MAAI,CAAC,YAAY,CAACA,IAAG,0BAA0B,QAAQ,GAAG;AACxD,aAAS,KAAK,sBAAsB;AACpC,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,OAA8B,CAAC;AAGrC,QAAM,OAAO,sBAAsB,UAAU,MAAM;AACnD,MAAI,KAAM,MAAK,OAAO;AAEtB,QAAM,cAAc,sBAAsB,UAAU,aAAa;AACjE,MAAI,YAAa,MAAK,cAAc;AAEpC,QAAM,WAAW,sBAAsB,UAAU,UAAU;AAC3D,MAAI,SAAU,MAAK,WAAW;AAE9B,QAAM,SAAS,sBAAsB,UAAU,QAAQ;AACvD,MAAI,OAAQ,MAAK,SAAS;AAE1B,QAAM,QAAQ,sBAAsB,UAAU,OAAO;AACrD,MAAI,MAAO,MAAK,QAAQ;AAGxB,QAAM,QAAQ,sBAAsB,UAAU,OAAO;AACrD,MAAI,MAAO,MAAK,QAAQ;AAGxB,QAAM,OAAO,mBAAmB,UAAU,MAAM;AAChD,MAAI,KAAK,SAAS,EAAG,MAAK,OAAO;AAEjC,SAAO;AACT;AAKA,SAAS,aACP,KACA,UACwB;AACxB,QAAM,YAAY,aAAa,KAAK,OAAO;AAC3C,MAAI,CAAC,aAAa,CAACA,IAAG,0BAA0B,SAAS,GAAG;AAC1D,WAAO,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,EAAE;AAAA,EACjC;AAEA,SAAO;AAAA,IACL,MAAM,mBAAmB,WAAW,MAAM;AAAA,IAC1C,SAAS,mBAAmB,WAAW,SAAS;AAAA,IAChD,YAAY,mBAAmB,WAAW,YAAY;AAAA,IACtD,eAAe,mBAAmB,WAAW,eAAe;AAAA,EAC9D;AACF;AAKA,SAAS,aACP,KACA,UACyC;AACzC,QAAM,YAAY,aAAa,KAAK,OAAO;AAC3C,MAAI,CAAC,aAAa,CAACA,IAAG,0BAA0B,SAAS,GAAG;AAC1D,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,QAAiD,CAAC;AAExD,aAAW,QAAQ,UAAU,YAAY;AACvC,QAAIA,IAAG,qBAAqB,IAAI,KAAKA,IAAG,aAAa,KAAK,IAAI,GAAG;AAC/D,YAAM,WAAW,KAAK,KAAK;AAC3B,YAAM,YAAY,KAAK;AAEvB,UAAIA,IAAG,0BAA0B,SAAS,GAAG;AAC3C,cAAM,QAAQ,IAAI,sBAAsB,SAAS;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,sBACP,KACyB;AACzB,QAAM,MAA+B,CAAC;AAEtC,QAAM,OAAO,sBAAsB,KAAK,MAAM;AAC9C,MAAI,KAAM,KAAI,OAAO;AAErB,QAAM,cAAc,sBAAsB,KAAK,aAAa;AAC5D,MAAI,YAAa,KAAI,cAAc;AAEnC,QAAM,SAAS,mBAAmB,KAAK,QAAQ;AAC/C,MAAI,OAAO,SAAS,EAAG,KAAI,SAAS;AAEpC,QAAM,WAAW,uBAAuB,KAAK,UAAU;AACvD,MAAI,aAAa,KAAM,KAAI,WAAW;AAGtC,QAAM,cAAc,aAAa,KAAK,SAAS;AAC/C,MAAI,aAAa;AACf,QAAI,UAAU,oBAAoB,WAAW;AAAA,EAC/C;AAEA,QAAM,cAAc,mBAAmB,KAAK,aAAa;AACzD,MAAI,YAAY,SAAS,EAAG,KAAI,cAAc;AAE9C,SAAO;AACT;AAKA,SAAS,gBACP,KACA,YACA,UAC6G;AAC7G,QAAM,eAAe,aAAa,KAAK,UAAU;AACjD,MAAI,CAAC,gBAAgB,CAACA,IAAG,yBAAyB,YAAY,GAAG;AAC/D,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,WAAwH,CAAC;AAE/H,aAAW,WAAW,aAAa,UAAU;AAC3C,QAAIA,IAAG,0BAA0B,OAAO,GAAG;AACzC,YAAM,OAAO,sBAAsB,SAAS,MAAM;AAClD,YAAM,cAAc,sBAAsB,SAAS,aAAa;AAEhE,UAAI,MAAM;AACR,cAAM,UAAgH;AAAA,UACpH;AAAA,UACA,aAAa,eAAe;AAAA,QAC9B;AAGA,cAAM,WAAW,aAAa,SAAS,MAAM;AAC7C,YAAI,aAAaA,IAAG,gBAAgB,QAAQ,KAAKA,IAAG,gCAAgC,QAAQ,IAAI;AAC9F,kBAAQ,OAAO,SAAS;AAAA,QAC1B;AAGA,cAAM,aAAa,aAAa,SAAS,QAAQ;AACjD,YAAI,cAAc,CAAC,QAAQ,MAAM;AAC/B,kBAAQ,OAAO,kBAAkB,YAAY,UAAU;AAAA,QACzD;AAGA,cAAM,QAAQ,sBAAsB,SAAS,OAAO;AACpD,YAAI,OAAO;AACT,kBAAQ,QAAQ;AAAA,QAClB;AAGA,cAAM,WAAW,aAAa,SAAS,MAAM;AAC7C,YAAI,YAAYA,IAAG,0BAA0B,QAAQ,GAAG;AACtD,gBAAM,YAAY,oBAAoB,QAAQ;AAC9C,cAAI,aAAa,OAAO,cAAc,YAAY,CAAC,MAAM,QAAQ,SAAS,GAAG;AAC3E,oBAAQ,OAAO;AAAA,UACjB;AAAA,QACF;AAEA,iBAAS,KAAK,OAAO;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AASA,SAAS,OAAO,KAAqB;AACnC,QAAM,QAAQ,IAAI,MAAM,IAAI;AAE5B,MAAI,MAAM,UAAU,GAAG;AACrB,WAAO;AAAA,EACT;AAGA,QAAM,kBAAkB,MAAM,CAAC,EAAE,MAAM,QAAQ,IAAI,CAAC,EAAE,UAAU;AAChE,QAAM,aAAa,oBAAoB,IAAI,IAAI;AAG/C,MAAI,YAAY;AAChB,WAAS,IAAI,YAAY,IAAI,MAAM,QAAQ,KAAK;AAC9C,UAAM,OAAO,MAAM,CAAC;AACpB,QAAI,KAAK,KAAK,MAAM,GAAI;AACxB,UAAM,QAAQ,KAAK,MAAM,QAAQ;AACjC,QAAI,OAAO;AACT,kBAAY,KAAK,IAAI,WAAW,MAAM,CAAC,EAAE,MAAM;AAAA,IACjD;AAAA,EACF;AAGA,MAAI,cAAc,YAAY,cAAc,GAAG;AAC7C,WAAO;AAAA,EACT;AAGA,SAAO,MACJ,IAAI,CAAC,MAAM,UAAU;AACpB,QAAI,UAAU,KAAK,oBAAoB,GAAG;AACxC,aAAO;AAAA,IACT;AACA,WAAO,KAAK,MAAM,SAAS;AAAA,EAC7B,CAAC,EACA,KAAK,IAAI;AACd;AAKA,SAAS,kBACP,YACA,YACoB;AAEpB,MAAIA,IAAG,gBAAgB,UAAU,GAAG;AAClC,UAAM,OAAO,WAAW;AAExB,UAAM,QAAQ,KAAK,SAAS,UAAU;AACtC,UAAM,MAAM,KAAK,OAAO;AACxB,QAAI,OAAO,WAAW,KAAK,UAAU,OAAO,GAAG,EAAE,KAAK;AAGtD,QAAI,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,GAAG;AAC9C,aAAO,KAAK,MAAM,GAAG,EAAE,EAAE,KAAK;AAAA,IAChC;AAGA,WAAO,OAAO,IAAI;AAElB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAKA,SAAS,iBACP,KACA,UACkE;AAClE,QAAM,gBAAgB,aAAa,KAAK,WAAW;AACnD,MAAI,CAAC,iBAAiB,CAACA,IAAG,yBAAyB,aAAa,GAAG;AACjE,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,YAA8E,CAAC;AAErF,aAAW,WAAW,cAAc,UAAU;AAC5C,QAAIA,IAAG,0BAA0B,OAAO,GAAG;AACzC,YAAM,YAAY,sBAAsB,SAAS,WAAW;AAC5D,YAAM,eAAe,sBAAsB,SAAS,cAAc;AAClE,YAAM,OAAO,sBAAsB,SAAS,MAAM;AAElD,UAAI,aAAa,cAAc;AAC7B,kBAAU,KAAK;AAAA,UACb;AAAA,UACA;AAAA,UACA,MAAM,QAAQ;AAAA,QAChB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,kBACP,KACA,UACwB;AACxB,QAAM,SAAS,aAAa,KAAK,IAAI;AACrC,MAAI,CAAC,UAAU,CAACA,IAAG,0BAA0B,MAAM,GAAG;AACpD,WAAO;AAAA,EACT;AAEA,QAAM,KAAiB,CAAC;AAGxB,QAAM,qBAAqB,sBAAsB,QAAQ,oBAAoB;AAC7E,MAAI,sBAAsB,CAAC,YAAY,UAAU,YAAY,EAAE,SAAS,kBAAkB,GAAG;AAC3F,OAAG,qBAAqB;AAAA,EAC1B;AAGA,QAAM,gBAAgB,mBAAmB,QAAQ,eAAe;AAChE,MAAI,cAAc,SAAS,GAAG;AAC5B,OAAG,gBAAgB;AAAA,EACrB;AAGA,QAAM,mBAAmB,mBAAmB,QAAQ,kBAAkB;AACtE,MAAI,iBAAiB,SAAS,GAAG;AAC/B,OAAG,mBAAmB;AAAA,EACxB;AAGA,QAAM,iBAAiB,mBAAmB,QAAQ,gBAAgB;AAClE,MAAI,eAAe,SAAS,GAAG;AAC7B,OAAG,iBAAiB;AAAA,EACtB;AAGA,MAAI,OAAO,KAAK,EAAE,EAAE,SAAS,GAAG;AAC9B,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAKA,SAAS,wBACP,KAC8B;AAC9B,QAAM,eAAe,aAAa,KAAK,UAAU;AACjD,MAAI,CAAC,gBAAgB,CAACA,IAAG,0BAA0B,YAAY,GAAG;AAChE,WAAO;AAAA,EACT;AAEA,QAAM,WAA6B,CAAC;AAGpC,QAAM,eAAe,mBAAmB,cAAc,cAAc;AACpE,MAAI,aAAa,SAAS,GAAG;AAC3B,aAAS,eAAe;AAAA,EAC1B;AAGA,QAAM,YAAY,mBAAmB,cAAc,WAAW;AAC9D,MAAI,UAAU,SAAS,GAAG;AACxB,aAAS,YAAY;AAAA,EACvB;AAGA,MAAI,OAAO,KAAK,QAAQ,EAAE,SAAS,GAAG;AACpC,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAKA,SAAS,sBACP,KACA,MACe;AACf,QAAM,OAAO,aAAa,KAAK,IAAI;AACnC,MAAI,QAAQA,IAAG,gBAAgB,IAAI,GAAG;AACpC,WAAO,KAAK;AAAA,EACd;AAEA,MAAI,QAAQA,IAAG,gCAAgC,IAAI,GAAG;AACpD,WAAO,KAAK;AAAA,EACd;AACA,SAAO;AACT;AAKA,SAAS,uBACP,KACA,MACgB;AAChB,QAAM,OAAO,aAAa,KAAK,IAAI;AACnC,MAAI,MAAM;AACR,QAAI,KAAK,SAASA,IAAG,WAAW,YAAa,QAAO;AACpD,QAAI,KAAK,SAASA,IAAG,WAAW,aAAc,QAAO;AAAA,EACvD;AACA,SAAO;AACT;AAKA,SAAS,mBACP,KACA,MACU;AACV,QAAM,OAAO,aAAa,KAAK,IAAI;AACnC,MAAI,CAAC,QAAQ,CAACA,IAAG,yBAAyB,IAAI,GAAG;AAC/C,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,SAAmB,CAAC;AAC1B,aAAW,WAAW,KAAK,UAAU;AACnC,QAAIA,IAAG,gBAAgB,OAAO,GAAG;AAC/B,aAAO,KAAK,QAAQ,IAAI;AAAA,IAC1B,WAAWA,IAAG,gCAAgC,OAAO,GAAG;AACtD,aAAO,KAAK,QAAQ,IAAI;AAAA,IAC1B;AAAA,EACF;AACA,SAAO;AACT;AAKA,SAAS,oBAAoB,MAA8B;AACzD,MAAIA,IAAG,gBAAgB,IAAI,GAAG;AAC5B,WAAO,KAAK;AAAA,EACd;AACA,MAAIA,IAAG,iBAAiB,IAAI,GAAG;AAC7B,WAAO,OAAO,KAAK,IAAI;AAAA,EACzB;AACA,MAAI,KAAK,SAASA,IAAG,WAAW,aAAa;AAC3C,WAAO;AAAA,EACT;AACA,MAAI,KAAK,SAASA,IAAG,WAAW,cAAc;AAC5C,WAAO;AAAA,EACT;AACA,MAAI,KAAK,SAASA,IAAG,WAAW,aAAa;AAC3C,WAAO;AAAA,EACT;AACA,MAAIA,IAAG,yBAAyB,IAAI,GAAG;AACrC,WAAO,KAAK,SAAS,IAAI,mBAAmB;AAAA,EAC9C;AACA,MAAIA,IAAG,0BAA0B,IAAI,GAAG;AACtC,UAAM,MAA+B,CAAC;AACtC,eAAW,QAAQ,KAAK,YAAY;AAClC,UAAIA,IAAG,qBAAqB,IAAI,KAAKA,IAAG,aAAa,KAAK,IAAI,GAAG;AAC/D,YAAI,KAAK,KAAK,IAAI,IAAI,oBAAoB,KAAK,WAAW;AAAA,MAC5D;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;ACvqBA,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,QAAAC,OAAM,WAAAC,gBAAe;AAM9B,IAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAQO,SAAS,sBAAsB,cAAqC;AACzE,aAAW,YAAY,eAAe;AACpC,UAAM,WAAWD,MAAK,cAAc,QAAQ;AAC5C,QAAID,YAAW,QAAQ,GAAG;AACxB,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AASO,SAAS,iBAAiB,aAAoC;AACnE,QAAM,gBAAgB;AAAA,IACpBC,MAAK,aAAa,YAAY;AAAA,IAC9BA,MAAK,aAAa,WAAW;AAAA,EAC/B;AAEA,aAAW,OAAO,eAAe;AAC/B,QAAID,YAAW,GAAG,GAAG;AACnB,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAoEO,SAAS,sBAAsB,aAAoC;AACxE,MAAI,CAAC,aAAa;AAEhB,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBT;AAGA,SAAO;AAAA,4BACmB,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBvC;;;AC/JA,OAAOG,SAAQ;AACf,SAAS,gBAAAC,qBAAoB;AAC7B,SAAkB,WAAAC,UAAS,YAAAC,iBAAgB;","names":["readFileSync","dirname","dirname","readFileSync","content","name","dirname","basename","join","build","dirname","basename","join","ts","existsSync","join","resolve","ts","readFileSync","dirname","basename"]}
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
import { createRequire as __banner_createRequire } from 'module'; const require = __banner_createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
generateContextMd,
|
|
4
|
+
generateRegistry,
|
|
5
|
+
loadFragmentFile,
|
|
6
|
+
parseFragmentFile
|
|
7
|
+
} from "./chunk-R6IZZSE7.js";
|
|
8
|
+
import {
|
|
9
|
+
discoverBlockFiles,
|
|
10
|
+
discoverComponentFiles,
|
|
11
|
+
discoverFragmentFiles,
|
|
12
|
+
discoverTokenFiles,
|
|
13
|
+
extractComponentName
|
|
14
|
+
} from "./chunk-AWYCDRPG.js";
|
|
2
15
|
import {
|
|
3
16
|
BrowserPool,
|
|
4
17
|
CaptureEngine,
|
|
@@ -8,27 +21,18 @@ import {
|
|
|
8
21
|
formatMs,
|
|
9
22
|
generateHtmlReport,
|
|
10
23
|
getGrade
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import {
|
|
13
|
-
discoverBlockFiles,
|
|
14
|
-
discoverComponentFiles,
|
|
15
|
-
discoverFragmentFiles,
|
|
16
|
-
discoverTokenFiles,
|
|
17
|
-
extractComponentName,
|
|
18
|
-
generateContextMd,
|
|
19
|
-
generateRegistry,
|
|
20
|
-
loadFragmentFile,
|
|
21
|
-
parseFragmentFile
|
|
22
|
-
} from "./chunk-3T6QL7IY.js";
|
|
24
|
+
} from "./chunk-YMPGYEWK.js";
|
|
23
25
|
import {
|
|
24
26
|
compileBlock,
|
|
25
27
|
parseTokenFile
|
|
26
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-UXLGIGSX.js";
|
|
27
29
|
import {
|
|
28
|
-
BRAND,
|
|
29
|
-
DEFAULTS,
|
|
30
30
|
fragmentDefinitionSchema
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-P33AKQJW.js";
|
|
32
|
+
import {
|
|
33
|
+
BRAND,
|
|
34
|
+
DEFAULTS
|
|
35
|
+
} from "./chunk-EKLMXTWU.js";
|
|
32
36
|
|
|
33
37
|
// src/validators.ts
|
|
34
38
|
async function validateSchema(config, configDir) {
|
|
@@ -120,18 +124,110 @@ async function validateAll(config, configDir) {
|
|
|
120
124
|
|
|
121
125
|
// src/build.ts
|
|
122
126
|
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
123
|
-
import { resolve as
|
|
124
|
-
import { existsSync as
|
|
127
|
+
import { resolve as resolve4, join as join3 } from "path";
|
|
128
|
+
import { existsSync as existsSync4 } from "fs";
|
|
129
|
+
|
|
130
|
+
// src/core/token-resolver.ts
|
|
131
|
+
import { resolve, dirname, basename } from "path";
|
|
132
|
+
import { existsSync, readdirSync } from "fs";
|
|
133
|
+
function roundRgbValues(value) {
|
|
134
|
+
return value.replace(
|
|
135
|
+
/rgb\(([^)]+)\)/g,
|
|
136
|
+
(_full, inner) => {
|
|
137
|
+
const parts = inner.split(",").map((p) => p.trim());
|
|
138
|
+
const rounded = parts.map((p) => {
|
|
139
|
+
const num = parseFloat(p);
|
|
140
|
+
return isNaN(num) ? p : String(Math.round(num));
|
|
141
|
+
});
|
|
142
|
+
return `rgb(${rounded.join(", ")})`;
|
|
143
|
+
}
|
|
144
|
+
).replace(
|
|
145
|
+
/rgba\(([^)]+)\)/g,
|
|
146
|
+
(_full, inner) => {
|
|
147
|
+
const parts = inner.split(",").map((p) => p.trim());
|
|
148
|
+
const rounded = parts.map((p, i) => {
|
|
149
|
+
if (i >= 3) return p;
|
|
150
|
+
const num = parseFloat(p);
|
|
151
|
+
return isNaN(num) ? p : String(Math.round(num));
|
|
152
|
+
});
|
|
153
|
+
return `rgba(${rounded.join(", ")})`;
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
async function resolveTokensWithSass(unresolvedTokens, tokensDir) {
|
|
158
|
+
const resolvedMap = /* @__PURE__ */ new Map();
|
|
159
|
+
const needsResolution = unresolvedTokens.filter(
|
|
160
|
+
(t) => t.value.includes("#{") || t.value.includes("$")
|
|
161
|
+
);
|
|
162
|
+
if (needsResolution.length === 0) {
|
|
163
|
+
return resolvedMap;
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
const sass = await import("./sass.node-4XJK6YBF.js");
|
|
167
|
+
const variablesPath = findVariablesFile(tokensDir);
|
|
168
|
+
if (!variablesPath) {
|
|
169
|
+
return resolvedMap;
|
|
170
|
+
}
|
|
171
|
+
const fileName = basename(variablesPath);
|
|
172
|
+
const moduleName = fileName.replace(/^_/, "").replace(/\.scss$/, "");
|
|
173
|
+
const scssSource = `
|
|
174
|
+
@use '${moduleName}' as vars;
|
|
175
|
+
:root { @include vars.fui-css-variables; }
|
|
176
|
+
`;
|
|
177
|
+
const compiled = sass.compileString(scssSource, {
|
|
178
|
+
loadPaths: [tokensDir, dirname(tokensDir)],
|
|
179
|
+
style: "expanded",
|
|
180
|
+
// Suppress sass deprecation warnings during build
|
|
181
|
+
logger: { warn() {
|
|
182
|
+
}, debug() {
|
|
183
|
+
} }
|
|
184
|
+
});
|
|
185
|
+
const cssVarRegex = /(--[\w-]+)\s*:\s*([^;]+)/g;
|
|
186
|
+
let match;
|
|
187
|
+
const allResolved = /* @__PURE__ */ new Map();
|
|
188
|
+
while ((match = cssVarRegex.exec(compiled.css)) !== null) {
|
|
189
|
+
allResolved.set(match[1], roundRgbValues(match[2].trim()));
|
|
190
|
+
}
|
|
191
|
+
for (const token of needsResolution) {
|
|
192
|
+
const value = allResolved.get(token.name);
|
|
193
|
+
if (value !== void 0) {
|
|
194
|
+
resolvedMap.set(token.name, value);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
} catch {
|
|
198
|
+
}
|
|
199
|
+
return resolvedMap;
|
|
200
|
+
}
|
|
201
|
+
function findVariablesFile(tokensDir) {
|
|
202
|
+
const candidates = ["_variables.scss", "variables.scss"];
|
|
203
|
+
for (const name of candidates) {
|
|
204
|
+
const path = resolve(tokensDir, name);
|
|
205
|
+
if (existsSync(path)) {
|
|
206
|
+
return path;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
try {
|
|
210
|
+
const files = readdirSync(tokensDir).filter((f) => f.endsWith(".scss"));
|
|
211
|
+
for (const file of files) {
|
|
212
|
+
const path = resolve(tokensDir, file);
|
|
213
|
+
if (file.includes("variables") || file.includes("tokens")) {
|
|
214
|
+
return path;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
} catch {
|
|
218
|
+
}
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
125
221
|
|
|
126
222
|
// src/core/auto-props.ts
|
|
127
|
-
import { existsSync, statSync } from "fs";
|
|
128
|
-
import { dirname, extname, join, resolve } from "path";
|
|
223
|
+
import { existsSync as existsSync2, statSync } from "fs";
|
|
224
|
+
import { dirname as dirname2, extname, join, resolve as resolve2 } from "path";
|
|
129
225
|
import ts from "typescript";
|
|
130
226
|
function toPosixPath(filePath) {
|
|
131
227
|
return filePath.replace(/\\/g, "/");
|
|
132
228
|
}
|
|
133
229
|
function isFile(filePath) {
|
|
134
|
-
if (!
|
|
230
|
+
if (!existsSync2(filePath)) return false;
|
|
135
231
|
try {
|
|
136
232
|
return statSync(filePath).isFile();
|
|
137
233
|
} catch {
|
|
@@ -157,7 +253,7 @@ function resolveModulePath(basePath) {
|
|
|
157
253
|
}
|
|
158
254
|
for (const candidate of candidates) {
|
|
159
255
|
if (isFile(candidate)) {
|
|
160
|
-
return
|
|
256
|
+
return resolve2(candidate);
|
|
161
257
|
}
|
|
162
258
|
}
|
|
163
259
|
return null;
|
|
@@ -165,8 +261,8 @@ function resolveModulePath(basePath) {
|
|
|
165
261
|
function resolveComponentSourcePath(fragmentFileAbsolutePath, componentImportPath) {
|
|
166
262
|
if (!componentImportPath) return null;
|
|
167
263
|
if (!componentImportPath.startsWith(".")) return null;
|
|
168
|
-
const fragmentDir =
|
|
169
|
-
const basePath =
|
|
264
|
+
const fragmentDir = dirname2(fragmentFileAbsolutePath);
|
|
265
|
+
const basePath = resolve2(fragmentDir, componentImportPath);
|
|
170
266
|
return resolveModulePath(basePath);
|
|
171
267
|
}
|
|
172
268
|
function collectTopLevelDeclarations(sourceFile) {
|
|
@@ -354,8 +450,8 @@ function resolveComponentSignature(exportName, declarations, sourceFile) {
|
|
|
354
450
|
}
|
|
355
451
|
function extractCustomPropsFromComponentFile(componentFilePath, exportName) {
|
|
356
452
|
const warnings = [];
|
|
357
|
-
const resolvedPath =
|
|
358
|
-
if (!
|
|
453
|
+
const resolvedPath = resolve2(componentFilePath);
|
|
454
|
+
if (!existsSync2(resolvedPath)) {
|
|
359
455
|
return {
|
|
360
456
|
props: {},
|
|
361
457
|
warnings: [`Component file not found: ${resolvedPath}`],
|
|
@@ -431,9 +527,9 @@ function extractCustomPropsFromComponentFile(componentFilePath, exportName) {
|
|
|
431
527
|
|
|
432
528
|
// src/core/graph-extractor.ts
|
|
433
529
|
import ts2 from "typescript";
|
|
434
|
-
import { readFileSync, existsSync as
|
|
530
|
+
import { readFileSync, existsSync as existsSync3 } from "fs";
|
|
435
531
|
import { join as join2 } from "path";
|
|
436
|
-
import { readdirSync } from "fs";
|
|
532
|
+
import { readdirSync as readdirSync2 } from "fs";
|
|
437
533
|
import { EDGE_TYPE_WEIGHTS, computeHealthFromData } from "@fragments-sdk/context/graph";
|
|
438
534
|
async function buildComponentGraph(fragments, blocks, componentDir, options) {
|
|
439
535
|
const knownComponents = new Set(Object.keys(fragments));
|
|
@@ -790,12 +886,12 @@ function findComponentIndex(componentDir, componentName) {
|
|
|
790
886
|
join2(componentDir, componentName, `${componentName}.ts`)
|
|
791
887
|
];
|
|
792
888
|
for (const candidate of candidates) {
|
|
793
|
-
if (
|
|
889
|
+
if (existsSync3(candidate)) {
|
|
794
890
|
return candidate;
|
|
795
891
|
}
|
|
796
892
|
}
|
|
797
893
|
try {
|
|
798
|
-
const entries =
|
|
894
|
+
const entries = readdirSync2(componentDir, { withFileTypes: true });
|
|
799
895
|
for (const entry of entries) {
|
|
800
896
|
if (entry.isDirectory() && entry.name === componentName) {
|
|
801
897
|
const subCandidates = [
|
|
@@ -803,7 +899,7 @@ function findComponentIndex(componentDir, componentName) {
|
|
|
803
899
|
join2(componentDir, entry.name, "index.ts")
|
|
804
900
|
];
|
|
805
901
|
for (const sc of subCandidates) {
|
|
806
|
-
if (
|
|
902
|
+
if (existsSync3(sc)) return sc;
|
|
807
903
|
}
|
|
808
904
|
}
|
|
809
905
|
}
|
|
@@ -988,38 +1084,71 @@ async function buildFragments(config, configDir) {
|
|
|
988
1084
|
const mergedCategories = {};
|
|
989
1085
|
let prefix = "--";
|
|
990
1086
|
let total = 0;
|
|
1087
|
+
const fileContents = [];
|
|
991
1088
|
for (const file of tokenFiles) {
|
|
992
1089
|
const content = await readFile(file.absolutePath, "utf-8");
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1090
|
+
fileContents.push({ content, path: file.relativePath });
|
|
1091
|
+
}
|
|
1092
|
+
const allContent = fileContents.map((f) => f.content).join("\n");
|
|
1093
|
+
for (const { content, path } of fileContents) {
|
|
1094
|
+
const parsed = parseTokenFile(allContent, path);
|
|
1095
|
+
const fileParsed = parseTokenFile(content, path);
|
|
1096
|
+
prefix = fileParsed.prefix;
|
|
1097
|
+
total += fileParsed.total;
|
|
1098
|
+
for (const [cat, catTokens] of Object.entries(fileParsed.categories)) {
|
|
997
1099
|
if (!mergedCategories[cat]) {
|
|
998
1100
|
mergedCategories[cat] = [];
|
|
999
1101
|
}
|
|
1000
1102
|
for (const t of catTokens) {
|
|
1001
1103
|
if (!mergedCategories[cat].some((e) => e.name === t.name)) {
|
|
1002
|
-
|
|
1104
|
+
const combinedToken = Object.values(parsed.categories).flat().find((ct) => ct.name === t.name);
|
|
1105
|
+
const resolvedValue = combinedToken?.resolvedValue ?? t.resolvedValue;
|
|
1106
|
+
mergedCategories[cat].push({
|
|
1107
|
+
name: t.name,
|
|
1108
|
+
...resolvedValue ? { value: resolvedValue } : t.value ? { value: t.value } : {},
|
|
1109
|
+
description: t.description
|
|
1110
|
+
});
|
|
1003
1111
|
}
|
|
1004
1112
|
}
|
|
1005
1113
|
}
|
|
1006
1114
|
}
|
|
1007
1115
|
if (total > 0) {
|
|
1116
|
+
const allTokens = Object.values(mergedCategories).flat();
|
|
1117
|
+
const unresolved = allTokens.filter(
|
|
1118
|
+
(t) => t.value && (t.value.includes("#{") || t.value.includes("$"))
|
|
1119
|
+
);
|
|
1120
|
+
if (unresolved.length > 0 && tokenFiles.length > 0) {
|
|
1121
|
+
const tokensDir = resolve4(configDir, tokenFiles[0].relativePath, "..");
|
|
1122
|
+
const sassResolved = await resolveTokensWithSass(
|
|
1123
|
+
unresolved,
|
|
1124
|
+
tokensDir
|
|
1125
|
+
);
|
|
1126
|
+
if (sassResolved.size > 0) {
|
|
1127
|
+
for (const catTokens of Object.values(mergedCategories)) {
|
|
1128
|
+
for (const token of catTokens) {
|
|
1129
|
+
const resolved = sassResolved.get(token.name);
|
|
1130
|
+
if (resolved && token.value && (token.value.includes("#{") || token.value.includes("$"))) {
|
|
1131
|
+
token.value = resolved;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1008
1137
|
tokens = { prefix, total, categories: mergedCategories };
|
|
1009
1138
|
}
|
|
1010
1139
|
}
|
|
1011
1140
|
} catch {
|
|
1012
1141
|
}
|
|
1013
1142
|
let packageName;
|
|
1014
|
-
const pkgJsonPath =
|
|
1015
|
-
if (
|
|
1143
|
+
const pkgJsonPath = resolve4(configDir, "package.json");
|
|
1144
|
+
if (existsSync4(pkgJsonPath)) {
|
|
1016
1145
|
try {
|
|
1017
1146
|
const pkg = JSON.parse(await readFile(pkgJsonPath, "utf-8"));
|
|
1018
1147
|
if (pkg.name) packageName = pkg.name;
|
|
1019
1148
|
} catch {
|
|
1020
1149
|
}
|
|
1021
1150
|
}
|
|
1022
|
-
const componentDir =
|
|
1151
|
+
const componentDir = resolve4(configDir, "src", "components");
|
|
1023
1152
|
let graphData;
|
|
1024
1153
|
try {
|
|
1025
1154
|
const graphResult = await buildComponentGraph(fragments, blocks, componentDir);
|
|
@@ -1059,7 +1188,7 @@ async function buildFragments(config, configDir) {
|
|
|
1059
1188
|
...tokens && { tokens },
|
|
1060
1189
|
...graphData && { graph: graphData }
|
|
1061
1190
|
};
|
|
1062
|
-
const outputPath =
|
|
1191
|
+
const outputPath = resolve4(configDir, config.outFile ?? BRAND.outFile);
|
|
1063
1192
|
await writeFile(outputPath, JSON.stringify(output));
|
|
1064
1193
|
return {
|
|
1065
1194
|
success: errors.length === 0,
|
|
@@ -1450,9 +1579,9 @@ ${BRAND.name} Diff
|
|
|
1450
1579
|
}
|
|
1451
1580
|
|
|
1452
1581
|
// src/analyze.ts
|
|
1453
|
-
import { existsSync as
|
|
1582
|
+
import { existsSync as existsSync5 } from "fs";
|
|
1454
1583
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
1455
|
-
import { join as join4, dirname as
|
|
1584
|
+
import { join as join4, dirname as dirname3 } from "path";
|
|
1456
1585
|
import pc3 from "picocolors";
|
|
1457
1586
|
async function runAnalyzeCommand(config, configDir, options = {}) {
|
|
1458
1587
|
const format = options.format ?? "html";
|
|
@@ -1461,7 +1590,7 @@ async function runAnalyzeCommand(config, configDir, options = {}) {
|
|
|
1461
1590
|
${BRAND.name} Analyzer
|
|
1462
1591
|
`));
|
|
1463
1592
|
const fragmentsPath = join4(configDir, config.outFile ?? "fragments.json");
|
|
1464
|
-
if (!
|
|
1593
|
+
if (!existsSync5(fragmentsPath)) {
|
|
1465
1594
|
console.log(pc3.red(`\u2717 No fragments.json found. Run \`${BRAND.cliCommand} build\` first.
|
|
1466
1595
|
`));
|
|
1467
1596
|
return {
|
|
@@ -1477,7 +1606,7 @@ ${BRAND.name} Analyzer
|
|
|
1477
1606
|
let outputPath;
|
|
1478
1607
|
if (format === "html" || format === "json") {
|
|
1479
1608
|
outputPath = options.output ?? getDefaultOutputPath(format, configDir);
|
|
1480
|
-
await mkdir2(
|
|
1609
|
+
await mkdir2(dirname3(outputPath), { recursive: true });
|
|
1481
1610
|
if (format === "html") {
|
|
1482
1611
|
const html = generateHtmlReport(analytics);
|
|
1483
1612
|
await writeFile2(outputPath, html);
|
|
@@ -1624,4 +1753,4 @@ export {
|
|
|
1624
1753
|
runDiffCommand,
|
|
1625
1754
|
runAnalyzeCommand
|
|
1626
1755
|
};
|
|
1627
|
-
//# sourceMappingURL=chunk-
|
|
1756
|
+
//# sourceMappingURL=chunk-S56I5FST.js.map
|