From 7feb4491c0df7412fecc0d0210c0c578a6a3e549 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 27 Dec 2025 15:35:53 +0000 Subject: [PATCH] Add refactoring tracker tool and progress report for 106 large files Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com> --- docs/todo/LAMBDA_REFACTOR_PROGRESS.md | 141 ++++++++++++++ tools/refactoring/refactor-to-lambda.ts | 243 ++++++++++++++++++++++++ 2 files changed, 384 insertions(+) create mode 100644 docs/todo/LAMBDA_REFACTOR_PROGRESS.md create mode 100644 tools/refactoring/refactor-to-lambda.ts diff --git a/docs/todo/LAMBDA_REFACTOR_PROGRESS.md b/docs/todo/LAMBDA_REFACTOR_PROGRESS.md new file mode 100644 index 000000000..681e4487a --- /dev/null +++ b/docs/todo/LAMBDA_REFACTOR_PROGRESS.md @@ -0,0 +1,141 @@ +# Lambda-per-File Refactoring Progress + +**Generated:** 2025-12-27T15:35:24.150Z + +## Summary + +- **Total files > 150 lines:** 106 +- **Pending:** 94 +- **In Progress:** 0 +- **Completed:** 0 +- **Skipped:** 12 + +## By Category + +- **component:** 60 +- **dbal:** 12 +- **library:** 11 +- **tool:** 10 +- **test:** 10 +- **type:** 2 +- **other:** 1 + +## Refactoring Queue + +Files are prioritized by ease of refactoring and impact. + +### High Priority (20 files) + +Library and tool files - easiest to refactor + +- [ ] `frontends/nextjs/src/lib/nerd-mode-ide/templates/template-configs.ts` (267 lines) +- [ ] `frontends/nextjs/src/lib/db/core/index.ts` (216 lines) +- [ ] `frontends/nextjs/src/lib/security/functions/patterns/javascript-patterns.ts` (184 lines) +- [ ] `frontends/nextjs/src/lib/rendering/page/page-renderer.ts` (178 lines) +- [ ] `frontends/nextjs/src/lib/github/workflows/analysis/runs/analyze-workflow-runs.ts` (164 lines) +- [ ] `frontends/nextjs/src/lib/rendering/page/page-definition-builder.ts` (483 lines) +- [ ] `frontends/nextjs/src/lib/db/database-admin/seed-default-data.ts` (471 lines) +- [ ] `frontends/nextjs/src/lib/components/component-catalog.ts` (337 lines) +- [ ] `frontends/nextjs/src/lib/schema/default-schema.ts` (308 lines) +- [ ] `frontends/nextjs/src/lib/lua/snippets/lua-snippets-data.ts` (983 lines) +- [ ] `tools/analysis/code/analyze-render-performance.ts` (294 lines) +- [ ] `tools/misc/metrics/enforce-size-limits.ts` (249 lines) +- [ ] `tools/refactoring/refactor-to-lambda.ts` (243 lines) +- [ ] `tools/analysis/test/analyze-implementation-completeness.ts` (230 lines) +- [ ] `tools/detection/detect-stub-implementations.ts` (215 lines) +- [ ] `tools/generation/generate-stub-report.ts` (204 lines) +- [ ] `tools/quality/code/check-code-complexity.ts` (175 lines) +- [ ] `tools/generation/generate-quality-summary.ts` (159 lines) +- [ ] `dbal/shared/tools/cpp-build-assistant.ts` (342 lines) +- [ ] `tools/analysis/test/analyze-test-coverage.ts` (332 lines) + +### Medium Priority (68 files) + +DBAL and component files - moderate complexity + +- [ ] `frontends/nextjs/src/lib/packages/core/package-catalog.ts` (1169 lines) +- [ ] `dbal/development/src/blob/providers/tenant-aware-storage.ts` (260 lines) +- [ ] `dbal/development/src/adapters/acl-adapter.ts` (258 lines) +- [ ] `dbal/development/src/blob/providers/memory-storage.ts` (230 lines) +- [ ] `dbal/development/src/core/foundation/types.ts` (216 lines) +- [ ] `dbal/development/src/core/entities/operations/core/user-operations.ts` (185 lines) +- [ ] `dbal/development/src/core/entities/operations/system/package-operations.ts` (185 lines) +- [ ] `dbal/development/src/bridges/websocket-bridge.ts` (168 lines) +- [ ] `dbal/development/src/blob/providers/filesystem-storage.ts` (410 lines) +- [ ] `dbal/development/src/blob/providers/s3-storage.ts` (361 lines) +- [ ] `dbal/development/src/adapters/prisma-adapter.ts` (350 lines) +- [ ] `frontends/nextjs/src/lib/dbal/core/client/dbal-integration.ts` (313 lines) +- [ ] `dbal/development/src/core/foundation/kv-store.ts` (307 lines) +- [ ] `frontends/nextjs/src/components/misc/data/QuickGuide.tsx` (297 lines) +- [ ] `frontends/nextjs/src/components/editors/ThemeEditor.tsx` (294 lines) +- [ ] `frontends/nextjs/src/components/managers/PageRoutesManager.tsx` (290 lines) +- [ ] `frontends/nextjs/src/components/managers/component/ComponentConfigDialog.tsx` (290 lines) +- [ ] `frontends/nextjs/src/components/level/levels/Level5.tsx` (289 lines) +- [ ] `frontends/nextjs/src/components/editors/lua/LuaSnippetLibrary.tsx` (285 lines) +- [ ] `frontends/nextjs/src/components/misc/data/GenericPage.tsx` (274 lines) +- ... and 48 more + +### Low Priority (6 files) + +- [ ] `frontends/nextjs/src/components/editors/lua/LuaEditor.tsx` (681 lines) +- [ ] `frontends/nextjs/src/components/managers/package/PackageImportExport.tsx` (594 lines) +- [ ] `frontends/nextjs/src/components/workflow/WorkflowEditor.tsx` (508 lines) +- [ ] `frontends/nextjs/src/components/ui/index.ts` (263 lines) +- [ ] `frontends/nextjs/src/components/misc/github/GitHubActionsFetcher.tsx` (1069 lines) +- [ ] `frontends/nextjs/src/components/editors/lua/LuaBlocksEditor.tsx` (1048 lines) + +### Skipped Files (12) + +These files do not need refactoring: + +- `frontends/nextjs/src/hooks/ui/state/useAutoRefresh.test.ts` (268 lines) - Test files can remain large for comprehensive coverage +- `frontends/nextjs/src/lib/rendering/tests/page-renderer.test.ts` (265 lines) - Test files can remain large for comprehensive coverage +- `frontends/nextjs/src/lib/security/scanner/security-scanner.test.ts` (257 lines) - Test files can remain large for comprehensive coverage +- `frontends/nextjs/src/theme/types/theme.d.ts` (200 lines) - Type definition files are typically large +- `frontends/nextjs/src/hooks/data/useKV.test.ts` (196 lines) - Test files can remain large for comprehensive coverage +- `frontends/nextjs/src/hooks/useAuth.test.ts` (181 lines) - Test files can remain large for comprehensive coverage +- `frontends/nextjs/src/types/dbal.d.ts` (154 lines) - Type definition files are typically large +- `frontends/nextjs/src/lib/schema/schema-utils.test.ts` (440 lines) - Test files can remain large for comprehensive coverage +- `frontends/nextjs/src/lib/workflow/engine/workflow-engine.test.ts` (388 lines) - Test files can remain large for comprehensive coverage +- `frontends/nextjs/src/lib/lua/engine/core/lua-engine.test.ts` (357 lines) - Test files can remain large for comprehensive coverage +- ... and 2 more + +## Refactoring Patterns + +### For Library Files +1. Create a `functions/` subdirectory +2. Extract each function to its own file +3. Create a class wrapper (like SchemaUtils) +4. Update main file to re-export +5. Verify tests still pass + +### For Components +1. Extract hooks into separate files +2. Extract sub-components +3. Extract utility functions +4. Keep main component < 150 lines + +### For DBAL Files +1. Split adapters by operation type +2. Extract provider implementations +3. Keep interfaces separate from implementations + +## Example: SchemaUtils Pattern + +The `frontends/nextjs/src/lib/schema/` directory demonstrates the lambda-per-file pattern: + +``` +schema/ +├── functions/ +│ ├── field/ +│ │ ├── get-field-label.ts +│ │ ├── validate-field.ts +│ │ └── ... +│ ├── model/ +│ │ ├── find-model.ts +│ │ └── ... +│ └── index.ts (re-exports all) +├── SchemaUtils.ts (class wrapper) +└── schema-utils.ts (backward compat re-exports) +``` + diff --git a/tools/refactoring/refactor-to-lambda.ts b/tools/refactoring/refactor-to-lambda.ts new file mode 100644 index 000000000..ab25b2430 --- /dev/null +++ b/tools/refactoring/refactor-to-lambda.ts @@ -0,0 +1,243 @@ +#!/usr/bin/env ts-node +/** + * Refactor large TypeScript files into lambda-per-file structure + * + * This tool helps identify files exceeding 150 lines and tracks refactoring progress. + */ + +import { exec } from 'child_process' +import { promisify } from 'util' +import * as fs from 'fs/promises' +import * as path from 'path' + +const execAsync = promisify(exec) + +interface FileInfo { + path: string + lines: number + category: 'component' | 'library' | 'test' | 'tool' | 'dbal' | 'type' | 'other' + priority: number + status: 'pending' | 'in-progress' | 'completed' | 'skipped' + reason?: string +} + +async function countLines(filePath: string): Promise { + try { + const content = await fs.readFile(filePath, 'utf-8') + return content.split('\n').length + } catch { + return 0 + } +} + +function categorizeFile(filePath: string): FileInfo['category'] { + if (filePath.includes('.test.')) return 'test' + if (filePath.endsWith('.tsx')) return 'component' + if (filePath.includes('/tools/')) return 'tool' + if (filePath.includes('/dbal/')) return 'dbal' + if (filePath.includes('/types/') || filePath.endsWith('.d.ts')) return 'type' + if (filePath.includes('/lib/') && filePath.endsWith('.ts')) return 'library' + return 'other' +} + +function calculatePriority(file: FileInfo): number { + // Higher priority for library files (easiest to refactor) + // Lower priority for components (need more complex refactoring) + // Skip tests and types + const categoryPriority = { + library: 10, + tool: 8, + dbal: 6, + component: 4, + test: 0, // Skip + type: 0, // Skip + other: 2, + } + + const base = categoryPriority[file.category] + + // Prioritize moderately large files over extremely large ones + // (easier to refactor step-by-step) + if (file.lines > 1000) return base - 3 + if (file.lines > 500) return base - 1 + if (file.lines > 300) return base + return base + 1 +} + +async function findLargeFiles(rootDir: string, minLines: number = 150): Promise { + const { stdout } = await execAsync( + `find ${rootDir} \\( -name "*.ts" -o -name "*.tsx" \\) ` + + `-not -path "*/node_modules/*" ` + + `-not -path "*/.next/*" ` + + `-not -path "*/dist/*" ` + + `-not -path "*/build/*" ` + + `-exec sh -c 'lines=$(wc -l < "$1"); if [ "$lines" -gt ${minLines} ]; then echo "$lines $1"; fi' _ {} \\;` + ) + + const files: FileInfo[] = [] + for (const line of stdout.trim().split('\n').filter(Boolean)) { + const [linesStr, filePath] = line.trim().split(' ', 2) + const lines = parseInt(linesStr, 10) + const category = categorizeFile(filePath) + const fileInfo: FileInfo = { + path: filePath.replace(rootDir + '/', ''), + lines, + category, + priority: 0, + status: category === 'test' || category === 'type' ? 'skipped' : 'pending', + reason: category === 'test' ? 'Test files can remain large for comprehensive coverage' : + category === 'type' ? 'Type definition files are typically large' : undefined + } + fileInfo.priority = calculatePriority(fileInfo) + files.push(fileInfo) + } + + return files.sort((a, b) => b.priority - a.priority || b.lines - a.lines) +} + +async function generateReport(files: FileInfo[]): Promise { + const total = files.length + const byCategory = files.reduce((acc, f) => { + acc[f.category] = (acc[f.category] || 0) + 1 + return acc + }, {} as Record) + + const byStatus = files.reduce((acc, f) => { + acc[f.status] = (acc[f.status] || 0) + 1 + return acc + }, {} as Record) + + let report = '# Lambda-per-File Refactoring Progress\n\n' + report += `**Generated:** ${new Date().toISOString()}\n\n` + report += `## Summary\n\n` + report += `- **Total files > 150 lines:** ${total}\n` + report += `- **Pending:** ${byStatus.pending || 0}\n` + report += `- **In Progress:** ${byStatus['in-progress'] || 0}\n` + report += `- **Completed:** ${byStatus.completed || 0}\n` + report += `- **Skipped:** ${byStatus.skipped || 0}\n\n` + + report += `## By Category\n\n` + for (const [category, count] of Object.entries(byCategory).sort((a, b) => b[1] - a[1])) { + report += `- **${category}:** ${count}\n` + } + + report += `\n## Refactoring Queue\n\n` + report += `Files are prioritized by ease of refactoring and impact.\n\n` + + // Group by priority + const highPriority = files.filter(f => f.priority >= 8 && f.status === 'pending') + const medPriority = files.filter(f => f.priority >= 4 && f.priority < 8 && f.status === 'pending') + const lowPriority = files.filter(f => f.priority < 4 && f.status === 'pending') + + if (highPriority.length > 0) { + report += `### High Priority (${highPriority.length} files)\n\n` + report += `Library and tool files - easiest to refactor\n\n` + for (const file of highPriority.slice(0, 20)) { + report += `- [ ] \`${file.path}\` (${file.lines} lines)\n` + } + if (highPriority.length > 20) { + report += `- ... and ${highPriority.length - 20} more\n` + } + report += `\n` + } + + if (medPriority.length > 0) { + report += `### Medium Priority (${medPriority.length} files)\n\n` + report += `DBAL and component files - moderate complexity\n\n` + for (const file of medPriority.slice(0, 20)) { + report += `- [ ] \`${file.path}\` (${file.lines} lines)\n` + } + if (medPriority.length > 20) { + report += `- ... and ${medPriority.length - 20} more\n` + } + report += `\n` + } + + if (lowPriority.length > 0) { + report += `### Low Priority (${lowPriority.length} files)\n\n` + for (const file of lowPriority.slice(0, 20)) { + report += `- [ ] \`${file.path}\` (${file.lines} lines)\n` + } + if (lowPriority.length > 20) { + report += `- ... and ${lowPriority.length - 20} more\n` + } + report += `\n` + } + + // Skipped files + const skipped = files.filter(f => f.status === 'skipped') + if (skipped.length > 0) { + report += `### Skipped Files (${skipped.length})\n\n` + report += `These files do not need refactoring:\n\n` + for (const file of skipped.slice(0, 10)) { + report += `- \`${file.path}\` (${file.lines} lines) - ${file.reason}\n` + } + if (skipped.length > 10) { + report += `- ... and ${skipped.length - 10} more\n` + } + report += `\n` + } + + report += `## Refactoring Patterns\n\n` + report += `### For Library Files\n` + report += `1. Create a \`functions/\` subdirectory\n` + report += `2. Extract each function to its own file\n` + report += `3. Create a class wrapper (like SchemaUtils)\n` + report += `4. Update main file to re-export\n` + report += `5. Verify tests still pass\n\n` + + report += `### For Components\n` + report += `1. Extract hooks into separate files\n` + report += `2. Extract sub-components\n` + report += `3. Extract utility functions\n` + report += `4. Keep main component < 150 lines\n\n` + + report += `### For DBAL Files\n` + report += `1. Split adapters by operation type\n` + report += `2. Extract provider implementations\n` + report += `3. Keep interfaces separate from implementations\n\n` + + report += `## Example: SchemaUtils Pattern\n\n` + report += `The \`frontends/nextjs/src/lib/schema/\` directory demonstrates the lambda-per-file pattern:\n\n` + report += `\`\`\`\n` + report += `schema/\n` + report += `├── functions/\n` + report += `│ ├── field/\n` + report += `│ │ ├── get-field-label.ts\n` + report += `│ │ ├── validate-field.ts\n` + report += `│ │ └── ...\n` + report += `│ ├── model/\n` + report += `│ │ ├── find-model.ts\n` + report += `│ │ └── ...\n` + report += `│ └── index.ts (re-exports all)\n` + report += `├── SchemaUtils.ts (class wrapper)\n` + report += `└── schema-utils.ts (backward compat re-exports)\n` + report += `\`\`\`\n\n` + + return report +} + +async function main() { + const rootDir = process.cwd() + console.log('Scanning for TypeScript files exceeding 150 lines...') + + const files = await findLargeFiles(rootDir, 150) + console.log(`Found ${files.length} files`) + + const report = await generateReport(files) + + const outputPath = path.join(rootDir, 'docs', 'todo', 'LAMBDA_REFACTOR_PROGRESS.md') + await fs.writeFile(outputPath, report, 'utf-8') + + console.log(`Report generated: ${outputPath}`) + console.log(`\nSummary:`) + console.log(`- Total files: ${files.length}`) + console.log(`- Pending refactor: ${files.filter(f => f.status === 'pending').length}`) + console.log(`- Skipped: ${files.filter(f => f.status === 'skipped').length}`) +} + +if (require.main === module) { + main().catch(console.error) +} + +export { findLargeFiles, generateReport }