mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-24 13:44:54 +00:00
feat: Add JSON definitions for menu, password input, and popover components
- Introduced `menu.json` for menu component structure with bindings for trigger and content. - Created `password-input.json` for password input handling visibility and value changes. - Added `popover.json` for popover component with trigger and content bindings. feat: Implement custom hooks for UI interactions - Added `useAccordion` for managing accordion state with single/multiple item support. - Created `useBindingEditor` for managing bindings in a dynamic editor. - Implemented `useCopyState` for clipboard copy functionality with feedback. - Developed `useFileUpload` for handling file uploads with drag-and-drop support. - Introduced `useFocusState` for managing focus state in components. - Created `useImageState` for handling image loading and error states. - Added `useMenuState` for managing menu interactions and item clicks. - Implemented `usePasswordVisibility` for toggling password visibility. - Developed `usePopoverState` for managing popover visibility and interactions. feat: Add constants and interfaces for JSON UI components - Introduced constants for sizes, placements, styles, and object-fit handling. - Created interfaces for various components including Accordion, Binding Editor, Copy Button, Data Source Editor, File Upload, and more. - Added type definitions for menu items, popover props, and other UI elements to enhance type safety and maintainability.
This commit is contained in:
190
scripts/analyze-duplicates.ts
Normal file
190
scripts/analyze-duplicates.ts
Normal file
@@ -0,0 +1,190 @@
|
||||
#!/usr/bin/env tsx
|
||||
/**
|
||||
* Analyze duplicate TSX files before deletion
|
||||
* Check JSON contents to ensure they're complete
|
||||
*/
|
||||
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { globSync } from 'fs'
|
||||
|
||||
const ROOT_DIR = path.resolve(process.cwd())
|
||||
const CONFIG_PAGES_DIR = path.join(ROOT_DIR, 'src/config/pages')
|
||||
const COMPONENTS_DIR = path.join(ROOT_DIR, 'src/components')
|
||||
const JSON_DEFS_DIR = path.join(ROOT_DIR, 'src/components/json-definitions')
|
||||
|
||||
function toKebabCase(str: string): string {
|
||||
return str.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '')
|
||||
}
|
||||
|
||||
interface AnalysisResult {
|
||||
tsx: string
|
||||
json: string
|
||||
tsxSize: number
|
||||
jsonSize: number
|
||||
tsxHasHooks: boolean
|
||||
tsxHasState: boolean
|
||||
tsxHasEffects: boolean
|
||||
jsonHasBindings: boolean
|
||||
jsonHasChildren: boolean
|
||||
recommendation: 'safe-to-delete' | 'needs-review' | 'keep-tsx'
|
||||
reason: string
|
||||
}
|
||||
|
||||
async function analyzeTsxFile(filePath: string): Promise<{
|
||||
hasHooks: boolean
|
||||
hasState: boolean
|
||||
hasEffects: boolean
|
||||
}> {
|
||||
const content = fs.readFileSync(filePath, 'utf-8')
|
||||
|
||||
return {
|
||||
hasHooks: /use[A-Z]/.test(content),
|
||||
hasState: /useState|useReducer/.test(content),
|
||||
hasEffects: /useEffect|useLayoutEffect/.test(content)
|
||||
}
|
||||
}
|
||||
|
||||
async function analyzeJsonFile(filePath: string): Promise<{
|
||||
hasBindings: boolean
|
||||
hasChildren: boolean
|
||||
size: number
|
||||
}> {
|
||||
const content = fs.readFileSync(filePath, 'utf-8')
|
||||
const json = JSON.parse(content)
|
||||
|
||||
return {
|
||||
hasBindings: !!json.bindings || hasNestedBindings(json),
|
||||
hasChildren: !!json.children,
|
||||
size: content.length
|
||||
}
|
||||
}
|
||||
|
||||
function hasNestedBindings(obj: any): boolean {
|
||||
if (!obj || typeof obj !== 'object') return false
|
||||
if (obj.bindings) return true
|
||||
|
||||
for (const key in obj) {
|
||||
if (hasNestedBindings(obj[key])) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
async function analyzeDuplicates() {
|
||||
console.log('🔍 Analyzing duplicate TSX files...\n')
|
||||
|
||||
const results: AnalysisResult[] = []
|
||||
|
||||
// Find all TSX files in atoms, molecules, organisms
|
||||
const categories = ['atoms', 'molecules', 'organisms']
|
||||
|
||||
for (const category of categories) {
|
||||
const tsxFiles = globSync(path.join(COMPONENTS_DIR, category, '*.tsx'))
|
||||
|
||||
for (const tsxFile of tsxFiles) {
|
||||
const basename = path.basename(tsxFile, '.tsx')
|
||||
const kebab = toKebabCase(basename)
|
||||
|
||||
// Check for JSON equivalent in config/pages
|
||||
const jsonPath = path.join(CONFIG_PAGES_DIR, category, `${kebab}.json`)
|
||||
|
||||
if (!fs.existsSync(jsonPath)) continue
|
||||
|
||||
// Check for JSON definition
|
||||
const jsonDefPath = path.join(JSON_DEFS_DIR, `${kebab}.json`)
|
||||
|
||||
// Analyze both files
|
||||
const tsxAnalysis = await analyzeTsxFile(tsxFile)
|
||||
const tsxSize = fs.statSync(tsxFile).size
|
||||
|
||||
let jsonAnalysis = { hasBindings: false, hasChildren: false, size: 0 }
|
||||
let actualJsonPath = jsonPath
|
||||
|
||||
if (fs.existsSync(jsonDefPath)) {
|
||||
jsonAnalysis = await analyzeJsonFile(jsonDefPath)
|
||||
actualJsonPath = jsonDefPath
|
||||
} else if (fs.existsSync(jsonPath)) {
|
||||
jsonAnalysis = await analyzeJsonFile(jsonPath)
|
||||
}
|
||||
|
||||
// Determine recommendation
|
||||
let recommendation: AnalysisResult['recommendation'] = 'safe-to-delete'
|
||||
let reason = 'JSON definition exists'
|
||||
|
||||
if (tsxAnalysis.hasState || tsxAnalysis.hasEffects) {
|
||||
if (!jsonAnalysis.hasBindings && jsonAnalysis.size < 500) {
|
||||
recommendation = 'needs-review'
|
||||
reason = 'TSX has state/effects but JSON seems incomplete'
|
||||
} else {
|
||||
recommendation = 'safe-to-delete'
|
||||
reason = 'TSX has hooks but JSON should handle via createJsonComponentWithHooks'
|
||||
}
|
||||
}
|
||||
|
||||
if (tsxSize > 5000 && jsonAnalysis.size < 1000) {
|
||||
recommendation = 'needs-review'
|
||||
reason = 'TSX is large but JSON is small - might be missing content'
|
||||
}
|
||||
|
||||
results.push({
|
||||
tsx: path.relative(ROOT_DIR, tsxFile),
|
||||
json: path.relative(ROOT_DIR, actualJsonPath),
|
||||
tsxSize,
|
||||
jsonSize: jsonAnalysis.size,
|
||||
tsxHasHooks: tsxAnalysis.hasHooks,
|
||||
tsxHasState: tsxAnalysis.hasState,
|
||||
tsxHasEffects: tsxAnalysis.hasEffects,
|
||||
jsonHasBindings: jsonAnalysis.hasBindings,
|
||||
jsonHasChildren: jsonAnalysis.hasChildren,
|
||||
recommendation,
|
||||
reason
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Print results
|
||||
console.log(`📊 Found ${results.length} duplicate components\n`)
|
||||
|
||||
const safeToDelete = results.filter(r => r.recommendation === 'safe-to-delete')
|
||||
const needsReview = results.filter(r => r.recommendation === 'needs-review')
|
||||
const keepTsx = results.filter(r => r.recommendation === 'keep-tsx')
|
||||
|
||||
console.log(`✅ Safe to delete: ${safeToDelete.length}`)
|
||||
console.log(`⚠️ Needs review: ${needsReview.length}`)
|
||||
console.log(`🔴 Keep TSX: ${keepTsx.length}\n`)
|
||||
|
||||
if (needsReview.length > 0) {
|
||||
console.log('⚠️ NEEDS REVIEW:')
|
||||
console.log('='.repeat(80))
|
||||
for (const result of needsReview.slice(0, 10)) {
|
||||
console.log(`\n${result.tsx}`)
|
||||
console.log(` → ${result.json}`)
|
||||
console.log(` TSX: ${result.tsxSize} bytes | JSON: ${result.jsonSize} bytes`)
|
||||
console.log(` TSX hooks: ${result.tsxHasHooks} | state: ${result.tsxHasState} | effects: ${result.tsxHasEffects}`)
|
||||
console.log(` JSON bindings: ${result.jsonHasBindings} | children: ${result.jsonHasChildren}`)
|
||||
console.log(` Reason: ${result.reason}`)
|
||||
}
|
||||
if (needsReview.length > 10) {
|
||||
console.log(`\n... and ${needsReview.length - 10} more`)
|
||||
}
|
||||
}
|
||||
|
||||
// Write full report
|
||||
const reportPath = path.join(ROOT_DIR, 'duplicate-analysis.json')
|
||||
fs.writeFileSync(reportPath, JSON.stringify(results, null, 2))
|
||||
console.log(`\n📄 Full report written to: ${reportPath}`)
|
||||
|
||||
// Generate deletion script for safe components
|
||||
if (safeToDelete.length > 0) {
|
||||
const deletionScript = safeToDelete.map(r => `rm "${r.tsx}"`).join('\n')
|
||||
const scriptPath = path.join(ROOT_DIR, 'delete-duplicates.sh')
|
||||
fs.writeFileSync(scriptPath, deletionScript)
|
||||
console.log(`📝 Deletion script written to: ${scriptPath}`)
|
||||
console.log(` Run: bash delete-duplicates.sh`)
|
||||
}
|
||||
}
|
||||
|
||||
analyzeDuplicates().catch(error => {
|
||||
console.error('❌ Analysis failed:', error)
|
||||
process.exit(1)
|
||||
})
|
||||
302
scripts/audit-json-components.ts
Normal file
302
scripts/audit-json-components.ts
Normal file
@@ -0,0 +1,302 @@
|
||||
#!/usr/bin/env tsx
|
||||
/**
|
||||
* Audit script for JSON component definitions
|
||||
*
|
||||
* Goals:
|
||||
* 1. Phase out src/components TSX files
|
||||
* 2. Audit existing JSON definitions for completeness and correctness
|
||||
*/
|
||||
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { globSync } from 'fs'
|
||||
|
||||
interface AuditIssue {
|
||||
severity: 'error' | 'warning' | 'info'
|
||||
category: string
|
||||
file?: string
|
||||
message: string
|
||||
suggestion?: string
|
||||
}
|
||||
|
||||
interface AuditReport {
|
||||
timestamp: string
|
||||
issues: AuditIssue[]
|
||||
stats: {
|
||||
totalJsonFiles: number
|
||||
totalTsxFiles: number
|
||||
registryEntries: number
|
||||
orphanedJson: number
|
||||
duplicates: number
|
||||
obsoleteWrapperRefs: number
|
||||
}
|
||||
}
|
||||
|
||||
const ROOT_DIR = path.resolve(process.cwd())
|
||||
const CONFIG_PAGES_DIR = path.join(ROOT_DIR, 'src/config/pages')
|
||||
const COMPONENTS_DIR = path.join(ROOT_DIR, 'src/components')
|
||||
const JSON_DEFS_DIR = path.join(ROOT_DIR, 'src/components/json-definitions')
|
||||
const REGISTRY_FILE = path.join(ROOT_DIR, 'json-components-registry.json')
|
||||
|
||||
async function loadRegistry(): Promise<any> {
|
||||
const content = fs.readFileSync(REGISTRY_FILE, 'utf-8')
|
||||
return JSON.parse(content)
|
||||
}
|
||||
|
||||
function findAllFiles(pattern: string, cwd: string = ROOT_DIR): string[] {
|
||||
const fullPattern = path.join(cwd, pattern)
|
||||
return globSync(fullPattern, { ignore: '**/node_modules/**' })
|
||||
}
|
||||
|
||||
function toKebabCase(str: string): string {
|
||||
return str.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '')
|
||||
}
|
||||
|
||||
function toPascalCase(str: string): string {
|
||||
return str
|
||||
.split('-')
|
||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join('')
|
||||
}
|
||||
|
||||
async function auditJsonComponents(): Promise<AuditReport> {
|
||||
const issues: AuditIssue[] = []
|
||||
const registry = await loadRegistry()
|
||||
|
||||
// Find all files
|
||||
const jsonFiles = findAllFiles('src/config/pages/**/*.json')
|
||||
const tsxFiles = findAllFiles('src/components/**/*.tsx')
|
||||
const jsonDefFiles = findAllFiles('src/components/json-definitions/*.json')
|
||||
|
||||
console.log(`📊 Found ${jsonFiles.length} JSON files in config/pages`)
|
||||
console.log(`📊 Found ${tsxFiles.length} TSX files in src/components`)
|
||||
console.log(`📊 Found ${jsonDefFiles.length} JSON definitions`)
|
||||
console.log(`📊 Found ${registry.components?.length || 0} registry entries\n`)
|
||||
|
||||
// Build registry lookup maps
|
||||
const registryByType = new Map<string, any>()
|
||||
const registryByName = new Map<string, any>()
|
||||
|
||||
if (registry.components) {
|
||||
for (const component of registry.components) {
|
||||
if (component.type) registryByType.set(component.type, component)
|
||||
if (component.name) registryByName.set(component.name, component)
|
||||
}
|
||||
}
|
||||
|
||||
// Check 1: Find TSX files that have JSON equivalents in config/pages
|
||||
console.log('🔍 Checking for TSX files that could be replaced with JSON...')
|
||||
const tsxBasenames = new Set<string>()
|
||||
for (const tsxFile of tsxFiles) {
|
||||
const basename = path.basename(tsxFile, '.tsx')
|
||||
const dir = path.dirname(tsxFile)
|
||||
const category = path.basename(dir) // atoms, molecules, organisms
|
||||
|
||||
if (!['atoms', 'molecules', 'organisms'].includes(category)) continue
|
||||
|
||||
tsxBasenames.add(basename)
|
||||
const kebab = toKebabCase(basename)
|
||||
|
||||
// Check if there's a corresponding JSON file in config/pages
|
||||
const possibleJsonPath = path.join(CONFIG_PAGES_DIR, category, `${kebab}.json`)
|
||||
|
||||
if (fs.existsSync(possibleJsonPath)) {
|
||||
issues.push({
|
||||
severity: 'warning',
|
||||
category: 'duplicate-implementation',
|
||||
file: tsxFile,
|
||||
message: `TSX file has JSON equivalent at ${path.relative(ROOT_DIR, possibleJsonPath)}`,
|
||||
suggestion: `Consider removing TSX and routing through JSON renderer`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Check 2: Find JSON files without registry entries
|
||||
console.log('🔍 Checking for orphaned JSON files...')
|
||||
for (const jsonFile of jsonFiles) {
|
||||
const content = JSON.parse(fs.readFileSync(jsonFile, 'utf-8'))
|
||||
const componentType = content.type
|
||||
|
||||
if (componentType && !registryByType.has(componentType)) {
|
||||
issues.push({
|
||||
severity: 'error',
|
||||
category: 'orphaned-json',
|
||||
file: jsonFile,
|
||||
message: `JSON file references type "${componentType}" which is not in registry`,
|
||||
suggestion: `Add registry entry for ${componentType} in json-components-registry.json`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Check 3: Find components with obsolete wrapper references
|
||||
console.log('🔍 Checking for obsolete wrapper references...')
|
||||
for (const component of registry.components || []) {
|
||||
if (component.wrapperRequired || component.wrapperComponent) {
|
||||
issues.push({
|
||||
severity: 'warning',
|
||||
category: 'obsolete-wrapper-ref',
|
||||
file: `registry: ${component.type}`,
|
||||
message: `Component "${component.type}" has obsolete wrapperRequired/wrapperComponent fields`,
|
||||
suggestion: `Remove wrapperRequired and wrapperComponent fields - use createJsonComponentWithHooks instead`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Check 4: Find components with load.path that don't exist
|
||||
console.log('🔍 Checking for broken load paths...')
|
||||
for (const component of registry.components || []) {
|
||||
if (component.load?.path) {
|
||||
const loadPath = component.load.path.replace('@/', 'src/')
|
||||
const possibleExtensions = ['.tsx', '.ts', '.jsx', '.js']
|
||||
let found = false
|
||||
|
||||
for (const ext of possibleExtensions) {
|
||||
if (fs.existsSync(path.join(ROOT_DIR, loadPath + ext))) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
issues.push({
|
||||
severity: 'error',
|
||||
category: 'broken-load-path',
|
||||
file: `registry: ${component.type}`,
|
||||
message: `Component "${component.type}" has load.path "${component.load.path}" but file not found`,
|
||||
suggestion: `Fix or remove load.path in registry`
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check 5: Components in src/components/molecules without JSON definitions
|
||||
console.log('🔍 Checking molecules without JSON definitions...')
|
||||
const moleculeTsxFiles = tsxFiles.filter(f => f.includes('/molecules/'))
|
||||
const jsonDefBasenames = new Set(
|
||||
jsonDefFiles.map(f => path.basename(f, '.json'))
|
||||
)
|
||||
|
||||
for (const tsxFile of moleculeTsxFiles) {
|
||||
const basename = path.basename(tsxFile, '.tsx')
|
||||
const kebab = toKebabCase(basename)
|
||||
|
||||
if (!jsonDefBasenames.has(kebab) && registryByType.has(basename)) {
|
||||
const entry = registryByType.get(basename)
|
||||
if (entry.source === 'molecules' && !entry.load?.path) {
|
||||
issues.push({
|
||||
severity: 'info',
|
||||
category: 'potential-conversion',
|
||||
file: tsxFile,
|
||||
message: `Molecule "${basename}" could potentially be converted to JSON`,
|
||||
suggestion: `Evaluate if ${basename} can be expressed as pure JSON`
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stats = {
|
||||
totalJsonFiles: jsonFiles.length,
|
||||
totalTsxFiles: tsxFiles.length,
|
||||
registryEntries: registry.components?.length || 0,
|
||||
orphanedJson: issues.filter(i => i.category === 'orphaned-json').length,
|
||||
duplicates: issues.filter(i => i.category === 'duplicate-implementation').length,
|
||||
obsoleteWrapperRefs: issues.filter(i => i.category === 'obsolete-wrapper-ref').length
|
||||
}
|
||||
|
||||
return {
|
||||
timestamp: new Date().toISOString(),
|
||||
issues,
|
||||
stats
|
||||
}
|
||||
}
|
||||
|
||||
function printReport(report: AuditReport) {
|
||||
console.log('\n' + '='.repeat(80))
|
||||
console.log('📋 AUDIT REPORT')
|
||||
console.log('='.repeat(80))
|
||||
console.log(`\n📅 Generated: ${report.timestamp}\n`)
|
||||
|
||||
console.log('📈 Statistics:')
|
||||
console.log(` • Total JSON files: ${report.stats.totalJsonFiles}`)
|
||||
console.log(` • Total TSX files: ${report.stats.totalTsxFiles}`)
|
||||
console.log(` • Registry entries: ${report.stats.registryEntries}`)
|
||||
console.log(` • Orphaned JSON: ${report.stats.orphanedJson}`)
|
||||
console.log(` • Obsolete wrapper refs: ${report.stats.obsoleteWrapperRefs}`)
|
||||
console.log(` • Duplicate implementations: ${report.stats.duplicates}\n`)
|
||||
|
||||
// Group issues by category
|
||||
const byCategory = new Map<string, AuditIssue[]>()
|
||||
for (const issue of report.issues) {
|
||||
if (!byCategory.has(issue.category)) {
|
||||
byCategory.set(issue.category, [])
|
||||
}
|
||||
byCategory.get(issue.category)!.push(issue)
|
||||
}
|
||||
|
||||
// Print issues by severity
|
||||
const severityOrder = ['error', 'warning', 'info'] as const
|
||||
const severityIcons = { error: '❌', warning: '⚠️', info: 'ℹ️' }
|
||||
|
||||
for (const severity of severityOrder) {
|
||||
const issuesOfSeverity = report.issues.filter(i => i.severity === severity)
|
||||
if (issuesOfSeverity.length === 0) continue
|
||||
|
||||
console.log(`\n${severityIcons[severity]} ${severity.toUpperCase()} (${issuesOfSeverity.length})`)
|
||||
console.log('-'.repeat(80))
|
||||
|
||||
const categories = new Map<string, AuditIssue[]>()
|
||||
for (const issue of issuesOfSeverity) {
|
||||
if (!categories.has(issue.category)) {
|
||||
categories.set(issue.category, [])
|
||||
}
|
||||
categories.get(issue.category)!.push(issue)
|
||||
}
|
||||
|
||||
for (const [category, issues] of categories) {
|
||||
console.log(`\n ${category.replace(/-/g, ' ').toUpperCase()} (${issues.length}):`)
|
||||
|
||||
for (const issue of issues.slice(0, 5)) { // Show first 5 of each category
|
||||
console.log(` • ${issue.file || 'N/A'}`)
|
||||
console.log(` ${issue.message}`)
|
||||
if (issue.suggestion) {
|
||||
console.log(` 💡 ${issue.suggestion}`)
|
||||
}
|
||||
}
|
||||
|
||||
if (issues.length > 5) {
|
||||
console.log(` ... and ${issues.length - 5} more`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n' + '='.repeat(80))
|
||||
console.log(`Total issues found: ${report.issues.length}`)
|
||||
console.log('='.repeat(80) + '\n')
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('🔍 Starting JSON component audit...\n')
|
||||
|
||||
const report = await auditJsonComponents()
|
||||
|
||||
printReport(report)
|
||||
|
||||
// Write report to file
|
||||
const reportPath = path.join(ROOT_DIR, 'audit-report.json')
|
||||
fs.writeFileSync(reportPath, JSON.stringify(report, null, 2))
|
||||
console.log(`📄 Full report written to: ${reportPath}\n`)
|
||||
|
||||
// Exit with error code if there are errors
|
||||
const errorCount = report.issues.filter(i => i.severity === 'error').length
|
||||
if (errorCount > 0) {
|
||||
console.log(`❌ Audit failed with ${errorCount} errors`)
|
||||
process.exit(1)
|
||||
} else {
|
||||
console.log('✅ Audit completed successfully')
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(error => {
|
||||
console.error('❌ Audit failed:', error)
|
||||
process.exit(1)
|
||||
})
|
||||
64
scripts/cleanup-registry.ts
Normal file
64
scripts/cleanup-registry.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env tsx
|
||||
/**
|
||||
* Cleanup script to remove obsolete wrapper references from registry
|
||||
*/
|
||||
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
const REGISTRY_FILE = path.resolve(process.cwd(), 'json-components-registry.json')
|
||||
|
||||
async function cleanupRegistry() {
|
||||
console.log('🧹 Cleaning up registry...\n')
|
||||
|
||||
// Read registry
|
||||
const content = fs.readFileSync(REGISTRY_FILE, 'utf-8')
|
||||
const registry = JSON.parse(content)
|
||||
|
||||
let cleanedCount = 0
|
||||
const cleanedComponents: string[] = []
|
||||
|
||||
// Remove obsolete fields from all components
|
||||
if (registry.components) {
|
||||
for (const component of registry.components) {
|
||||
let modified = false
|
||||
|
||||
if (component.wrapperRequired !== undefined) {
|
||||
delete component.wrapperRequired
|
||||
modified = true
|
||||
}
|
||||
|
||||
if (component.wrapperComponent !== undefined) {
|
||||
delete component.wrapperComponent
|
||||
modified = true
|
||||
}
|
||||
|
||||
if (modified) {
|
||||
cleanedCount++
|
||||
cleanedComponents.push(component.type || component.name || 'Unknown')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write back to file with proper formatting
|
||||
fs.writeFileSync(REGISTRY_FILE, JSON.stringify(registry, null, 2) + '\n')
|
||||
|
||||
console.log(`✅ Cleaned ${cleanedCount} components\n`)
|
||||
|
||||
if (cleanedComponents.length > 0) {
|
||||
console.log('📋 Cleaned components:')
|
||||
cleanedComponents.slice(0, 10).forEach(name => {
|
||||
console.log(` • ${name}`)
|
||||
})
|
||||
if (cleanedComponents.length > 10) {
|
||||
console.log(` ... and ${cleanedComponents.length - 10} more`)
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n✨ Registry cleanup complete!')
|
||||
}
|
||||
|
||||
cleanupRegistry().catch(error => {
|
||||
console.error('❌ Cleanup failed:', error)
|
||||
process.exit(1)
|
||||
})
|
||||
41
scripts/fix-index-files.ts
Normal file
41
scripts/fix-index-files.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env tsx
|
||||
/**
|
||||
* Fix index.ts files to only export existing TSX files
|
||||
*/
|
||||
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { globSync } from 'fs'
|
||||
|
||||
const ROOT_DIR = path.resolve(process.cwd())
|
||||
const COMPONENTS_DIR = path.join(ROOT_DIR, 'src/components')
|
||||
|
||||
const categories = ['atoms', 'molecules', 'organisms']
|
||||
|
||||
for (const category of categories) {
|
||||
const categoryDir = path.join(COMPONENTS_DIR, category)
|
||||
const indexPath = path.join(categoryDir, 'index.ts')
|
||||
|
||||
if (!fs.existsSync(indexPath)) continue
|
||||
|
||||
// Find all TSX files in this category
|
||||
const tsxFiles = globSync(path.join(categoryDir, '*.tsx'))
|
||||
const basenames = tsxFiles.map(f => path.basename(f, '.tsx'))
|
||||
|
||||
console.log(`\n📁 ${category}/`)
|
||||
console.log(` Found ${basenames.length} TSX files`)
|
||||
|
||||
// Generate new exports
|
||||
const exports = basenames
|
||||
.sort()
|
||||
.map(name => `export { ${name} } from './${name}'`)
|
||||
.join('\n')
|
||||
|
||||
// Write new index file
|
||||
const content = `// Auto-generated - only exports existing TSX files\n${exports}\n`
|
||||
fs.writeFileSync(indexPath, content)
|
||||
|
||||
console.log(` ✅ Updated ${category}/index.ts`)
|
||||
}
|
||||
|
||||
console.log('\n✨ All index files updated!')
|
||||
Reference in New Issue
Block a user