import fs from 'node:fs/promises' import path from 'node:path' import { fileURLToPath } from 'node:url' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const rootDir = path.resolve(__dirname, '..') interface JSONComponent { type: string jsonCompatible?: boolean wrapperRequired?: boolean load?: { path: string export: string lazy?: boolean } props?: Record metadata?: { notes?: string } } interface RegistryEntry { type: string name: string category: string canHaveChildren: boolean description: string status: 'supported' | 'deprecated' source: 'atoms' | 'molecules' | 'organisms' | 'ui' | 'wrappers' | 'custom' jsonCompatible: boolean wrapperRequired?: boolean load?: { path: string export: string lazy?: boolean } metadata?: { conversionDate?: string autoGenerated?: boolean notes?: string } } interface Registry { version: string categories: Record sourceRoots: Record components: RegistryEntry[] statistics: { total: number supported: number jsonCompatible: number byCategory: Record bySource: Record } } /** * Determine component category based on name and source */ function determineCategory(componentName: string, source: string): string { const name = componentName.toLowerCase() // Layout components if (/container|section|stack|flex|grid|layout|panel|sidebar|header|footer/.test(name)) { return 'layout' } // Input components if (/input|select|checkbox|radio|slider|switch|form|textarea|date|file|number|password|search/.test(name)) { return 'input' } // Navigation components if (/nav|menu|breadcrumb|tab|link|pagination/.test(name)) { return 'navigation' } // Feedback components if (/alert|toast|notification|spinner|loading|progress|skeleton|badge|indicator/.test(name)) { return 'feedback' } // Data display components if (/table|list|card|chart|graph|tree|timeline|avatar|image/.test(name)) { return 'data' } // Display components if (/text|heading|label|code|icon|divider|separator|spacer/.test(name)) { return 'display' } // Default to custom for organisms and complex components if (source === 'organisms' || source === 'molecules') { return 'custom' } return 'display' } /** * Determine if component can have children */ function canHaveChildren(componentName: string): boolean { const name = componentName.toLowerCase() // These typically don't have children const noChildren = /input|select|checkbox|radio|slider|switch|image|icon|divider|separator|spacer|spinner|progress|badge|dot/ return !noChildren.test(name) } /** * Generate description for component */ function generateDescription(componentName: string, category: string): string { const descriptions: Record = { layout: 'Layout container component', input: 'Form input component', navigation: 'Navigation component', feedback: 'Feedback and status component', data: 'Data display component', display: 'Display component', custom: 'Custom component', } return descriptions[category] || 'Component' } /** * Read all JSON files from a directory and create registry entries */ async function processDirectory( dir: string, source: 'atoms' | 'molecules' | 'organisms' | 'ui' | 'custom' ): Promise { const entries: RegistryEntry[] = [] try { const files = await fs.readdir(dir) const jsonFiles = files.filter(f => f.endsWith('.json')) for (const file of jsonFiles) { const filePath = path.join(dir, file) const content = await fs.readFile(filePath, 'utf-8') const jsonComponent: JSONComponent = JSON.parse(content) const componentName = jsonComponent.type if (!componentName) continue const category = determineCategory(componentName, source) const entry: RegistryEntry = { type: componentName, name: componentName, category, canHaveChildren: canHaveChildren(componentName), description: generateDescription(componentName, category), status: 'supported', source, jsonCompatible: jsonComponent.jsonCompatible !== false, wrapperRequired: jsonComponent.wrapperRequired || false, metadata: { conversionDate: new Date().toISOString().split('T')[0], autoGenerated: true, notes: jsonComponent.metadata?.notes, }, } if (jsonComponent.load) { entry.load = jsonComponent.load } entries.push(entry) } } catch (error) { console.error(`Error processing ${dir}:`, error) } return entries } /** * Update the registry with new components */ async function updateRegistry() { console.log('šŸ“ Updating json-components-registry.json...\n') const registryPath = path.join(rootDir, 'json-components-registry.json') // Read existing registry const registryContent = await fs.readFile(registryPath, 'utf-8') const registry: Registry = JSON.parse(registryContent) console.log(` Current components: ${registry.components.length}`) // Process each directory const newEntries: RegistryEntry[] = [] const directories = [ { dir: path.join(rootDir, 'src/config/pages/atoms'), source: 'atoms' as const }, { dir: path.join(rootDir, 'src/config/pages/molecules'), source: 'molecules' as const }, { dir: path.join(rootDir, 'src/config/pages/organisms'), source: 'organisms' as const }, { dir: path.join(rootDir, 'src/config/pages/ui'), source: 'ui' as const }, { dir: path.join(rootDir, 'src/config/pages/components'), source: 'custom' as const }, ] for (const { dir, source } of directories) { const entries = await processDirectory(dir, source) newEntries.push(...entries) console.log(` Processed ${source}: ${entries.length} components`) } // Merge with existing components (remove duplicates) const existingTypes = new Set(registry.components.map(c => c.type)) const uniqueNewEntries = newEntries.filter(e => !existingTypes.has(e.type)) console.log(`\n New unique components: ${uniqueNewEntries.length}`) console.log(` Skipped duplicates: ${newEntries.length - uniqueNewEntries.length}`) // Add new components registry.components.push(...uniqueNewEntries) // Update statistics const byCategory: Record = {} const bySource: Record = {} for (const component of registry.components) { byCategory[component.category] = (byCategory[component.category] || 0) + 1 bySource[component.source] = (bySource[component.source] || 0) + 1 } registry.statistics = { total: registry.components.length, supported: registry.components.filter(c => c.status === 'supported').length, jsonCompatible: registry.components.filter(c => c.jsonCompatible).length, byCategory, bySource, } // Sort components by type registry.components.sort((a, b) => a.type.localeCompare(b.type)) // Write updated registry await fs.writeFile(registryPath, JSON.stringify(registry, null, 2) + '\n') console.log(`\nāœ… Registry updated successfully!`) console.log(` Total components: ${registry.statistics.total}`) console.log(` JSON compatible: ${registry.statistics.jsonCompatible}`) console.log(`\nšŸ“Š By source:`) for (const [source, count] of Object.entries(bySource)) { console.log(` ${source.padEnd(12)}: ${count}`) } console.log(`\nšŸ“Š By category:`) for (const [category, count] of Object.entries(byCategory)) { console.log(` ${category.padEnd(12)}: ${count}`) } } updateRegistry().catch(console.error)