diff --git a/docs/todo/AUTO_EXTRACT_RESULTS.json b/docs/todo/AUTO_EXTRACT_RESULTS.json index 182090eb5..a2d2705f4 100644 --- a/docs/todo/AUTO_EXTRACT_RESULTS.json +++ b/docs/todo/AUTO_EXTRACT_RESULTS.json @@ -1,21 +1,21 @@ { - "timestamp": "2025-12-29T18:39:04.533Z", - "duration": "4.22s", + "timestamp": "2025-12-29T18:54:34.117Z", + "duration": "7.75s", "options": { - "dryRun": true, - "priority": "all", - "limit": 100, + "dryRun": false, + "priority": "high", + "limit": 5, "batchSize": 5, "skipLint": false, "skipTest": false, - "autoConfirm": false, - "verbose": false + "autoConfirm": true, + "verbose": true }, "summary": { - "total": 52, - "completed": 52, + "total": 5, + "completed": 1, "failed": 0, - "skipped": 0 + "skipped": 4 }, "files": [ { @@ -23,364 +23,50 @@ "lines": 278, "priority": "high", "category": "library", - "status": "completed" + "status": "skipped", + "error": "No functions found in file" }, { "path": "frontends/nextjs/src/lib/nerd-mode-ide/templates/configs/base.ts", "lines": 267, "priority": "high", "category": "library", - "status": "completed" + "status": "skipped", + "error": "No functions found in file" }, { "path": "frontends/nextjs/src/lib/schema/default/forms.ts", "lines": 244, "priority": "high", "category": "library", - "status": "completed" + "status": "skipped", + "error": "No functions found in file" }, { "path": "frontends/nextjs/src/lib/db/core/operations.ts", "lines": 190, "priority": "high", "category": "library", - "status": "completed" + "status": "skipped", + "error": "No functions found in file" }, { "path": "frontends/nextjs/src/lib/rendering/page/page-renderer.ts", "lines": 178, "priority": "high", "category": "library", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/lib/github/workflows/analysis/runs/stats.ts", - "lines": 153, - "priority": "high", - "category": "library", - "status": "completed" - }, - { - "path": "tools/refactoring/orchestrate-refactor.ts", - "lines": 249, - "priority": "high", - "category": "tool", - "status": "completed" - }, - { - "path": "tools/refactoring/bulk-lambda-refactor.ts", - "lines": 249, - "priority": "high", - "category": "tool", - "status": "completed" - }, - { - "path": "tools/refactoring/languages/typescript-refactor.ts", - "lines": 219, - "priority": "high", - "category": "tool", - "status": "completed" - }, - { - "path": "tools/refactoring/cli/orchestrate-refactor.ts", - "lines": 213, - "priority": "high", - "category": "tool", - "status": "completed" - }, - { - "path": "tools/refactoring/languages/cpp-refactor.ts", - "lines": 209, - "priority": "high", - "category": "tool", - "status": "completed" - }, - { - "path": "tools/refactoring/ast-lambda-refactor.ts", - "lines": 192, - "priority": "high", - "category": "tool", - "status": "completed" - }, - { - "path": "tools/refactoring/error-as-todo-refactor/index.ts", - "lines": 163, - "priority": "high", - "category": "tool", - "status": "completed" - }, - { - "path": "dbal/shared/tools/cpp-build-assistant/workflow.ts", - "lines": 153, - "priority": "high", - "category": "tool", - "status": "completed" - }, - { - "path": "tools/refactoring/auto-code-extractor-3000.ts", - "lines": 508, - "priority": "medium", - "category": "tool", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/lib/dbal/core/client/dbal-integration.ts", - "lines": 313, - "priority": "medium", - "category": "dbal", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/misc/data/QuickGuide.tsx", - "lines": 297, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/misc/data/GenericPage.tsx", - "lines": 274, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/molecules/overlay/DropdownMenu.tsx", - "lines": 268, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/managers/database/DatabaseManager.tsx", - "lines": 261, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/examples/ContactForm.example.tsx", - "lines": 258, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/managers/component/ComponentHierarchyEditor.tsx", - "lines": 242, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/managers/component/ComponentConfigDialog/Fields.tsx", - "lines": 238, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/editors/lua/blocks/BlockItem.tsx", - "lines": 218, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/rendering/FieldRenderer.tsx", - "lines": 210, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/ui/organisms/data/Form.tsx", - "lines": 210, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/level5/tabs/PowerTransferTab.tsx", - "lines": 207, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/misc/auth/UnifiedLogin.tsx", - "lines": 207, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/ui/molecules/overlay/DropdownMenu.tsx", - "lines": 207, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/ui/organisms/navigation/NavigationMenuItems.tsx", - "lines": 203, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/editors/lua/LuaBlocksEditor.tsx", - "lines": 193, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/molecules/overlay/Dialog.tsx", - "lines": 191, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/editors/JsonEditor.tsx", - "lines": 191, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/misc/demos/IRCWebchatDeclarative.tsx", - "lines": 190, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/rendering/components/RenderNode.tsx", - "lines": 188, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/misc/viewers/AuditLogViewer.tsx", - "lines": 188, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/misc/viewers/audit-log/Filters.tsx", - "lines": 188, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/schema/level4/Tabs.tsx", - "lines": 186, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/managers/package/PackageDetailsDialog.tsx", - "lines": 185, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/misc/data/SMTPConfigEditor.tsx", - "lines": 184, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/managers/dropdown/DropdownConfigForm.tsx", - "lines": 182, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/ui/organisms/data/Table.tsx", - "lines": 174, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/misc/github/views/run-list/RunListAlerts.tsx", - "lines": 171, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/organisms/security/SecurityMessage.tsx", - "lines": 171, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/rendering/Builder.tsx", - "lines": 163, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/level4/tabs/TabContent.tsx", - "lines": 153, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/misc/demos/IRCWebchat.tsx", - "lines": 153, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/managers/UserManagement.tsx", - "lines": 334, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/managers/css/CssClassManager.tsx", - "lines": 327, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/misc/viewers/ModelListView.tsx", - "lines": 318, - "priority": "medium", - "category": "component", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/nerd-mode-ide/core/NerdModeIDE/useNerdIdeState.ts", - "lines": 274, - "priority": "low", - "category": "other", - "status": "completed" - }, - { - "path": "frontends/nextjs/src/components/editors/lua/hooks/useLuaBlocksState/actions.ts", - "lines": 208, - "priority": "low", - "category": "other", - "status": "completed" + "status": "completed", + "extractedFunctions": [ + "registerPage", + "loadPages", + "getPage", + "getPagesByLevel", + "executeLuaScript", + "checkPermissions", + "onPageLoad", + "onPageUnload", + "getPageRenderer" + ] } ] } \ No newline at end of file diff --git a/docs/todo/EXTRACTION_REGISTRY.json b/docs/todo/EXTRACTION_REGISTRY.json new file mode 100644 index 000000000..39bb740ab --- /dev/null +++ b/docs/todo/EXTRACTION_REGISTRY.json @@ -0,0 +1,60 @@ +{ + "version": "1.0.0", + "lastUpdated": "2025-12-29T18:54:30.245Z", + "functions": [ + { + "functionName": "registerPage", + "originalFile": "frontends/nextjs/src/lib/rendering/page/page-renderer.ts", + "extractedPath": "frontends/nextjs/src/lib/rendering/page/page-renderer/functions/register-page.ts", + "timestamp": "2025-12-29T18:54:30.244Z" + }, + { + "functionName": "loadPages", + "originalFile": "frontends/nextjs/src/lib/rendering/page/page-renderer.ts", + "extractedPath": "frontends/nextjs/src/lib/rendering/page/page-renderer/functions/load-pages.ts", + "timestamp": "2025-12-29T18:54:30.244Z" + }, + { + "functionName": "getPage", + "originalFile": "frontends/nextjs/src/lib/rendering/page/page-renderer.ts", + "extractedPath": "frontends/nextjs/src/lib/rendering/page/page-renderer/functions/get-page.ts", + "timestamp": "2025-12-29T18:54:30.244Z" + }, + { + "functionName": "getPagesByLevel", + "originalFile": "frontends/nextjs/src/lib/rendering/page/page-renderer.ts", + "extractedPath": "frontends/nextjs/src/lib/rendering/page/page-renderer/functions/get-pages-by-level.ts", + "timestamp": "2025-12-29T18:54:30.244Z" + }, + { + "functionName": "executeLuaScript", + "originalFile": "frontends/nextjs/src/lib/rendering/page/page-renderer.ts", + "extractedPath": "frontends/nextjs/src/lib/rendering/page/page-renderer/functions/execute-lua-script.ts", + "timestamp": "2025-12-29T18:54:30.244Z" + }, + { + "functionName": "checkPermissions", + "originalFile": "frontends/nextjs/src/lib/rendering/page/page-renderer.ts", + "extractedPath": "frontends/nextjs/src/lib/rendering/page/page-renderer/functions/check-permissions.ts", + "timestamp": "2025-12-29T18:54:30.244Z" + }, + { + "functionName": "onPageLoad", + "originalFile": "frontends/nextjs/src/lib/rendering/page/page-renderer.ts", + "extractedPath": "frontends/nextjs/src/lib/rendering/page/page-renderer/functions/on-page-load.ts", + "timestamp": "2025-12-29T18:54:30.244Z" + }, + { + "functionName": "onPageUnload", + "originalFile": "frontends/nextjs/src/lib/rendering/page/page-renderer.ts", + "extractedPath": "frontends/nextjs/src/lib/rendering/page/page-renderer/functions/on-page-unload.ts", + "timestamp": "2025-12-29T18:54:30.244Z" + }, + { + "functionName": "getPageRenderer", + "originalFile": "frontends/nextjs/src/lib/rendering/page/page-renderer.ts", + "extractedPath": "frontends/nextjs/src/lib/rendering/page/page-renderer/functions/get-page-renderer.ts", + "timestamp": "2025-12-29T18:54:30.244Z" + } + ] +} \ No newline at end of file diff --git a/docs/todo/LAMBDA_REFACTOR_PROGRESS.md b/docs/todo/LAMBDA_REFACTOR_PROGRESS.md index 2e0a06626..6febed3f7 100644 --- a/docs/todo/LAMBDA_REFACTOR_PROGRESS.md +++ b/docs/todo/LAMBDA_REFACTOR_PROGRESS.md @@ -1,11 +1,11 @@ # Lambda-per-File Refactoring Progress -**Generated:** 2025-12-29T18:28:41.724Z +**Generated:** 2025-12-29T18:54:34.116Z ## Summary -- **Total files > 150 lines:** 62 -- **Pending:** 52 +- **Total files > 150 lines:** 61 +- **Pending:** 51 - **In Progress:** 0 - **Completed:** 0 - **Skipped:** 10 @@ -15,7 +15,7 @@ - **component:** 34 - **test:** 10 - **tool:** 9 -- **library:** 6 +- **library:** 5 - **other:** 2 - **dbal:** 1 @@ -23,7 +23,7 @@ Files are prioritized by ease of refactoring and impact. -### High Priority (15 files) +### High Priority (13 files) Library and tool files - easiest to refactor @@ -31,7 +31,6 @@ Library and tool files - easiest to refactor - [ ] `frontends/nextjs/src/lib/nerd-mode-ide/templates/configs/base.ts` (267 lines) - [ ] `frontends/nextjs/src/lib/schema/default/forms.ts` (244 lines) - [ ] `frontends/nextjs/src/lib/db/core/operations.ts` (190 lines) -- [ ] `frontends/nextjs/src/lib/rendering/page/page-renderer.ts` (178 lines) - [ ] `frontends/nextjs/src/lib/github/workflows/analysis/runs/stats.ts` (153 lines) - [ ] `tools/refactoring/orchestrate-refactor.ts` (249 lines) - [ ] `tools/refactoring/bulk-lambda-refactor.ts` (249 lines) @@ -41,12 +40,12 @@ Library and tool files - easiest to refactor - [ ] `tools/refactoring/ast-lambda-refactor.ts` (192 lines) - [ ] `tools/refactoring/error-as-todo-refactor/index.ts` (163 lines) - [ ] `dbal/shared/tools/cpp-build-assistant/workflow.ts` (153 lines) -- [ ] `tools/refactoring/auto-code-extractor-3000.ts` (487 lines) -### Medium Priority (35 files) +### Medium Priority (36 files) DBAL and component files - moderate complexity +- [ ] `tools/refactoring/auto-code-extractor-3000.ts` (655 lines) - [ ] `frontends/nextjs/src/lib/dbal/core/client/dbal-integration.ts` (313 lines) - [ ] `frontends/nextjs/src/components/misc/data/QuickGuide.tsx` (297 lines) - [ ] `frontends/nextjs/src/components/misc/data/GenericPage.tsx` (274 lines) @@ -66,8 +65,7 @@ DBAL and component files - moderate complexity - [ ] `frontends/nextjs/src/components/molecules/overlay/Dialog.tsx` (191 lines) - [ ] `frontends/nextjs/src/components/editors/JsonEditor.tsx` (191 lines) - [ ] `frontends/nextjs/src/components/misc/demos/IRCWebchatDeclarative.tsx` (190 lines) -- [ ] `frontends/nextjs/src/components/rendering/components/RenderNode.tsx` (188 lines) -- ... and 15 more +- ... and 16 more ### Low Priority (2 files) diff --git a/frontends/nextjs/src/lib/rendering/page/page-renderer.ts b/frontends/nextjs/src/lib/rendering/page/page-renderer.ts index 04e953bdd..9eee6edcd 100644 --- a/frontends/nextjs/src/lib/rendering/page/page-renderer.ts +++ b/frontends/nextjs/src/lib/rendering/page/page-renderer.ts @@ -1,178 +1,13 @@ -import { Database } from '@/lib/database' -import type { LuaEngine } from '@/lib/lua-engine' -import { executeLuaScriptWithProfile } from '@/lib/lua/execute-lua-script-with-profile' -import type { ComponentInstance } from '@/lib/types/builder-types' -import type { User } from '@/lib/types/level-types' +/** + * This file has been refactored into modular lambda-per-file structure. + * + * Import individual functions or use the class wrapper: + * @example + * import { registerPage } from './page-renderer' + * + * @example + * import { PageRendererUtils } from './page-renderer' + * PageRendererUtils.registerPage(...) + */ -export interface PageDefinition { - id: string - level: 1 | 2 | 3 | 4 | 5 | 6 - title: string - description?: string - layout: 'default' | 'sidebar' | 'dashboard' | 'blank' - components: ComponentInstance[] - luaScripts?: { - onLoad?: string - onUnload?: string - handlers?: Record - } - permissions?: { - requiresAuth: boolean - requiredRole?: string - customCheck?: string - } - metadata?: { - showHeader?: boolean - showFooter?: boolean - headerTitle?: string - headerActions?: ComponentInstance[] - sidebarItems?: Array<{ - id: string - label: string - icon: string - action: 'navigate' | 'lua' | 'external' - target: string - }> - } -} - -export interface PageContext { - user: User | null - level: number - isPreviewMode: boolean - navigationHandlers: { - onNavigate: (level: number) => void - onLogout: () => void - } - luaEngine: LuaEngine -} - -export class PageRenderer { - private pages: Map = new Map() - - async registerPage(page: PageDefinition): Promise { - this.pages.set(page.id, page) - const pageConfig = { - id: page.id, - path: `/_page_${page.id}`, - title: page.title, - level: page.level, - componentTree: page.components, - requiresAuth: page.permissions?.requiresAuth || false, - requiredRole: page.permissions?.requiredRole as any - } - await Database.addPage(pageConfig) - } - - async loadPages(): Promise { - const savedPages = await Database.getPages() - savedPages.forEach(page => { - const pageDef: PageDefinition = { - id: page.id, - level: page.level as 1 | 2 | 3 | 4 | 5 | 6, - title: page.title, - layout: 'default', - components: page.componentTree, - permissions: { - requiresAuth: page.requiresAuth, - requiredRole: page.requiredRole - } - } - this.pages.set(page.id, pageDef) - }) - } - - getPage(id: string): PageDefinition | undefined { - return this.pages.get(id) - } - - getPagesByLevel(level: number): PageDefinition[] { - return Array.from(this.pages.values()).filter(p => p.level === level) - } - - async executeLuaScript(scriptId: string, context: any): Promise { - const scripts = await Database.getLuaScripts() - const script = scripts.find(s => s.id === scriptId) - if (!script) { - throw new Error(`Lua script not found: ${scriptId}`) - } - - const result = await executeLuaScriptWithProfile(script.code, context, script) - if (!result.success) { - throw new Error(result.error || 'Lua execution failed') - } - - return result.result - } - - async checkPermissions( - page: PageDefinition, - user: User | null - ): Promise<{ allowed: boolean; reason?: string }> { - if (!page.permissions) { - return { allowed: true } - } - - if (page.permissions.requiresAuth && !user) { - return { allowed: false, reason: 'Authentication required' } - } - - if (page.permissions.requiredRole) { - const roleHierarchy = ['public', 'user', 'moderator', 'admin', 'god', 'supergod'] - const userRole = user?.role ?? 'public' - const userRoleIndex = roleHierarchy.indexOf(userRole) - const requiredRoleIndex = roleHierarchy.indexOf(page.permissions.requiredRole) - - if (requiredRoleIndex >= 0 && userRoleIndex >= 0 && userRoleIndex < requiredRoleIndex) { - return { allowed: false, reason: 'Insufficient permissions' } - } - } - - if (page.permissions.customCheck) { - try { - const result = await this.executeLuaScript(page.permissions.customCheck, { - data: { user } - }) - if (!result) { - return { allowed: false, reason: 'Custom permission check failed' } - } - } catch (error) { - return { allowed: false, reason: 'Permission check error' } - } - } - - return { allowed: true } - } - - async onPageLoad(page: PageDefinition, context: PageContext): Promise { - if (page.luaScripts?.onLoad) { - await this.executeLuaScript(page.luaScripts.onLoad, { - data: { - user: context.user, - level: context.level, - isPreviewMode: context.isPreviewMode - } - }) - } - } - - async onPageUnload(page: PageDefinition, context: PageContext): Promise { - if (page.luaScripts?.onUnload) { - await this.executeLuaScript(page.luaScripts.onUnload, { - data: { - user: context.user, - level: context.level - } - }) - } - } -} - -let pageRendererInstance: PageRenderer | null = null - -export function getPageRenderer(): PageRenderer { - if (!pageRendererInstance) { - pageRendererInstance = new PageRenderer() - } - return pageRendererInstance -} +export * from './page-renderer' diff --git a/frontends/nextjs/src/lib/rendering/page/page-renderer/PageRendererUtils.ts b/frontends/nextjs/src/lib/rendering/page/page-renderer/PageRendererUtils.ts new file mode 100644 index 000000000..c9d7e0e92 --- /dev/null +++ b/frontends/nextjs/src/lib/rendering/page/page-renderer/PageRendererUtils.ts @@ -0,0 +1,54 @@ +// Auto-generated class wrapper +import { registerPage } from './functions/register-page' +import { loadPages } from './functions/load-pages' +import { getPage } from './functions/get-page' +import { getPagesByLevel } from './functions/get-pages-by-level' +import { executeLuaScript } from './functions/execute-lua-script' +import { checkPermissions } from './functions/check-permissions' +import { onPageLoad } from './functions/on-page-load' +import { onPageUnload } from './functions/on-page-unload' +import { getPageRenderer } from './functions/get-page-renderer' + +/** + * PageRendererUtils - Class wrapper for 9 functions + * + * This is a convenience wrapper. Prefer importing individual functions. + */ +export class PageRendererUtils { + static async registerPage(...args: any[]) { + return await registerPage(...args as any) + } + + static async loadPages(...args: any[]) { + return await loadPages(...args as any) + } + + static getPage(...args: any[]) { + return getPage(...args as any) + } + + static getPagesByLevel(...args: any[]) { + return getPagesByLevel(...args as any) + } + + static async executeLuaScript(...args: any[]) { + return await executeLuaScript(...args as any) + } + + static async checkPermissions(...args: any[]) { + return await checkPermissions(...args as any) + } + + static async onPageLoad(...args: any[]) { + return await onPageLoad(...args as any) + } + + static async onPageUnload(...args: any[]) { + return await onPageUnload(...args as any) + } + + static getPageRenderer(...args: any[]) { + return getPageRenderer(...args as any) + } + +} diff --git a/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/check-permissions.ts b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/check-permissions.ts new file mode 100644 index 000000000..0630cc3c2 --- /dev/null +++ b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/check-permissions.ts @@ -0,0 +1,44 @@ +import { Database } from '@/lib/database' +import type { LuaEngine } from '@/lib/lua-engine' +import { executeLuaScriptWithProfile } from '@/lib/lua/execute-lua-script-with-profile' +import type { ComponentInstance } from '@/lib/types/builder-types' +import type { User } from '@/lib/types/level-types' + +export async function checkPermissions( + page: PageDefinition, + user: User | null + ): Promise<{ allowed: boolean; reason?: string }> { + if (!page.permissions) { + return { allowed: true } + } + + if (page.permissions.requiresAuth && !user) { + return { allowed: false, reason: 'Authentication required' } + } + + if (page.permissions.requiredRole) { + const roleHierarchy = ['public', 'user', 'moderator', 'admin', 'god', 'supergod'] + const userRole = user?.role ?? 'public' + const userRoleIndex = roleHierarchy.indexOf(userRole) + const requiredRoleIndex = roleHierarchy.indexOf(page.permissions.requiredRole) + + if (requiredRoleIndex >= 0 && userRoleIndex >= 0 && userRoleIndex < requiredRoleIndex) { + return { allowed: false, reason: 'Insufficient permissions' } + } + } + + if (page.permissions.customCheck) { + try { + const result = await this.executeLuaScript(page.permissions.customCheck, { + data: { user } + }) + if (!result) { + return { allowed: false, reason: 'Custom permission check failed' } + } + } catch (error) { + return { allowed: false, reason: 'Permission check error' } + } + } + + return { allowed: true } + } diff --git a/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/execute-lua-script.ts b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/execute-lua-script.ts new file mode 100644 index 000000000..d66dc342f --- /dev/null +++ b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/execute-lua-script.ts @@ -0,0 +1,20 @@ +import { Database } from '@/lib/database' +import type { LuaEngine } from '@/lib/lua-engine' +import { executeLuaScriptWithProfile } from '@/lib/lua/execute-lua-script-with-profile' +import type { ComponentInstance } from '@/lib/types/builder-types' +import type { User } from '@/lib/types/level-types' + +export async function executeLuaScript(scriptId: string, context: any): Promise { + const scripts = await Database.getLuaScripts() + const script = scripts.find(s => s.id === scriptId) + if (!script) { + throw new Error(`Lua script not found: ${scriptId}`) + } + + const result = await executeLuaScriptWithProfile(script.code, context, script) + if (!result.success) { + throw new Error(result.error || 'Lua execution failed') + } + + return result.result + } diff --git a/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/get-page-renderer.ts b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/get-page-renderer.ts new file mode 100644 index 000000000..6ef47af43 --- /dev/null +++ b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/get-page-renderer.ts @@ -0,0 +1,12 @@ +import { Database } from '@/lib/database' +import type { LuaEngine } from '@/lib/lua-engine' +import { executeLuaScriptWithProfile } from '@/lib/lua/execute-lua-script-with-profile' +import type { ComponentInstance } from '@/lib/types/builder-types' +import type { User } from '@/lib/types/level-types' + +export function getPageRenderer(): PageRenderer { + if (!pageRendererInstance) { + pageRendererInstance = new PageRenderer() + } + return pageRendererInstance +} diff --git a/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/get-page.ts b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/get-page.ts new file mode 100644 index 000000000..c8920351f --- /dev/null +++ b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/get-page.ts @@ -0,0 +1,9 @@ +import { Database } from '@/lib/database' +import type { LuaEngine } from '@/lib/lua-engine' +import { executeLuaScriptWithProfile } from '@/lib/lua/execute-lua-script-with-profile' +import type { ComponentInstance } from '@/lib/types/builder-types' +import type { User } from '@/lib/types/level-types' + +export function getPage(id: string): PageDefinition | undefined { + return this.pages.get(id) + } diff --git a/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/get-pages-by-level.ts b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/get-pages-by-level.ts new file mode 100644 index 000000000..f7b71d6c9 --- /dev/null +++ b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/get-pages-by-level.ts @@ -0,0 +1,9 @@ +import { Database } from '@/lib/database' +import type { LuaEngine } from '@/lib/lua-engine' +import { executeLuaScriptWithProfile } from '@/lib/lua/execute-lua-script-with-profile' +import type { ComponentInstance } from '@/lib/types/builder-types' +import type { User } from '@/lib/types/level-types' + +export function getPagesByLevel(level: number): PageDefinition[] { + return Array.from(this.pages.values()).filter(p => p.level === level) + } diff --git a/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/load-pages.ts b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/load-pages.ts new file mode 100644 index 000000000..bd5686d42 --- /dev/null +++ b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/load-pages.ts @@ -0,0 +1,23 @@ +import { Database } from '@/lib/database' +import type { LuaEngine } from '@/lib/lua-engine' +import { executeLuaScriptWithProfile } from '@/lib/lua/execute-lua-script-with-profile' +import type { ComponentInstance } from '@/lib/types/builder-types' +import type { User } from '@/lib/types/level-types' + +export async function loadPages(): Promise { + const savedPages = await Database.getPages() + savedPages.forEach(page => { + const pageDef: PageDefinition = { + id: page.id, + level: page.level as 1 | 2 | 3 | 4 | 5 | 6, + title: page.title, + layout: 'default', + components: page.componentTree, + permissions: { + requiresAuth: page.requiresAuth, + requiredRole: page.requiredRole + } + } + this.pages.set(page.id, pageDef) + }) + } diff --git a/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/on-page-load.ts b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/on-page-load.ts new file mode 100644 index 000000000..91b0e236e --- /dev/null +++ b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/on-page-load.ts @@ -0,0 +1,17 @@ +import { Database } from '@/lib/database' +import type { LuaEngine } from '@/lib/lua-engine' +import { executeLuaScriptWithProfile } from '@/lib/lua/execute-lua-script-with-profile' +import type { ComponentInstance } from '@/lib/types/builder-types' +import type { User } from '@/lib/types/level-types' + +export async function onPageLoad(page: PageDefinition, context: PageContext): Promise { + if (page.luaScripts?.onLoad) { + await this.executeLuaScript(page.luaScripts.onLoad, { + data: { + user: context.user, + level: context.level, + isPreviewMode: context.isPreviewMode + } + }) + } + } diff --git a/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/on-page-unload.ts b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/on-page-unload.ts new file mode 100644 index 000000000..24dbf4308 --- /dev/null +++ b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/on-page-unload.ts @@ -0,0 +1,16 @@ +import { Database } from '@/lib/database' +import type { LuaEngine } from '@/lib/lua-engine' +import { executeLuaScriptWithProfile } from '@/lib/lua/execute-lua-script-with-profile' +import type { ComponentInstance } from '@/lib/types/builder-types' +import type { User } from '@/lib/types/level-types' + +export async function onPageUnload(page: PageDefinition, context: PageContext): Promise { + if (page.luaScripts?.onUnload) { + await this.executeLuaScript(page.luaScripts.onUnload, { + data: { + user: context.user, + level: context.level + } + }) + } + } diff --git a/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/register-page.ts b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/register-page.ts new file mode 100644 index 000000000..4d4766091 --- /dev/null +++ b/frontends/nextjs/src/lib/rendering/page/page-renderer/functions/register-page.ts @@ -0,0 +1,19 @@ +import { Database } from '@/lib/database' +import type { LuaEngine } from '@/lib/lua-engine' +import { executeLuaScriptWithProfile } from '@/lib/lua/execute-lua-script-with-profile' +import type { ComponentInstance } from '@/lib/types/builder-types' +import type { User } from '@/lib/types/level-types' + +export async function registerPage(page: PageDefinition): Promise { + this.pages.set(page.id, page) + const pageConfig = { + id: page.id, + path: `/_page_${page.id}`, + title: page.title, + level: page.level, + componentTree: page.components, + requiresAuth: page.permissions?.requiresAuth || false, + requiredRole: page.permissions?.requiredRole as any + } + await Database.addPage(pageConfig) + } diff --git a/frontends/nextjs/src/lib/rendering/page/page-renderer/index.ts b/frontends/nextjs/src/lib/rendering/page/page-renderer/index.ts new file mode 100644 index 000000000..109b0444e --- /dev/null +++ b/frontends/nextjs/src/lib/rendering/page/page-renderer/index.ts @@ -0,0 +1,11 @@ +// Auto-generated re-exports for backward compatibility + +export { registerPage } from './functions/register-page' +export { loadPages } from './functions/load-pages' +export { getPage } from './functions/get-page' +export { getPagesByLevel } from './functions/get-pages-by-level' +export { executeLuaScript } from './functions/execute-lua-script' +export { checkPermissions } from './functions/check-permissions' +export { onPageLoad } from './functions/on-page-load' +export { onPageUnload } from './functions/on-page-unload' +export { getPageRenderer } from './functions/get-page-renderer' diff --git a/tools/refactoring/auto-code-extractor-3000.ts b/tools/refactoring/auto-code-extractor-3000.ts index bfd9bcb04..34e06136d 100644 --- a/tools/refactoring/auto-code-extractor-3000.ts +++ b/tools/refactoring/auto-code-extractor-3000.ts @@ -61,12 +61,31 @@ interface FileToExtract { category: string status: 'pending' | 'completed' | 'failed' | 'skipped' error?: string + extractedFunctions?: string[] +} + +interface ExtractedFunction { + functionName: string + originalFile: string + extractedPath: string + timestamp: string +} + +interface ExtractionRegistry { + version: string + lastUpdated: string + functions: ExtractedFunction[] } class AutoCodeExtractor3000 { private options: ExtractionOptions private results: FileToExtract[] = [] private startTime: number = 0 + private extractionRegistry: ExtractionRegistry = { + version: '1.0.0', + lastUpdated: new Date().toISOString(), + functions: [] + } constructor(options: Partial = {}) { this.options = { @@ -91,6 +110,56 @@ class AutoCodeExtractor3000 { console.log(`${icons[level]} ${message}`) } + private async loadExtractionRegistry(): Promise { + try { + let rootDir = process.cwd() + if (rootDir.endsWith('/frontends/nextjs') || rootDir.endsWith('\\frontends\\nextjs')) { + rootDir = path.join(rootDir, '..', '..') + } + + const registryPath = path.join(rootDir, 'docs', 'todo', 'EXTRACTION_REGISTRY.json') + this.log(`Loading extraction registry from ${registryPath}`, 'info') + + const content = await fs.readFile(registryPath, 'utf-8') + this.extractionRegistry = JSON.parse(content) + this.log(`✅ Loaded extraction registry with ${this.extractionRegistry.functions.length} functions`, 'success') + } catch (error) { + if (error instanceof Error && 'code' in error && error.code === 'ENOENT') { + this.log('No existing extraction registry found, will create new one', 'info') + } else { + this.log(`⚠️ Warning loading registry: ${error instanceof Error ? error.message : String(error)}`, 'warning') + } + } + } + + private async saveExtractionRegistry(): Promise { + if (this.options.dryRun) { + this.log('Dry-run mode: skipping registry save', 'info') + return + } + + try { + let rootDir = process.cwd() + if (rootDir.endsWith('/frontends/nextjs') || rootDir.endsWith('\\frontends\\nextjs')) { + rootDir = path.join(rootDir, '..', '..') + } + + this.extractionRegistry.lastUpdated = new Date().toISOString() + const registryPath = path.join(rootDir, 'docs', 'todo', 'EXTRACTION_REGISTRY.json') + + this.log(`Saving extraction registry to ${registryPath}`, 'info') + this.log(`Registry contains ${this.extractionRegistry.functions.length} functions`, 'info') + + await fs.writeFile(registryPath, JSON.stringify(this.extractionRegistry, null, 2), 'utf-8') + this.log(`✅ Saved extraction registry with ${this.extractionRegistry.functions.length} functions`, 'success') + } catch (error) { + this.log(`❌ Error saving registry: ${error instanceof Error ? error.message : String(error)}`, 'error') + if (this.options.verbose && error instanceof Error && error.stack) { + console.error('Stack trace:', error.stack) + } + } + } + private async scanAndCategorizeFiles(): Promise { this.log('Scanning codebase for files exceeding 150 lines...', 'info') @@ -176,11 +245,65 @@ class AutoCodeExtractor3000 { console.log(`\n[${globalIdx}/${files.length}] Processing: ${file.path}`) try { + // Analyze file to get function names before extraction + this.log(` 🔍 Analyzing file for functions...`, 'info') + const { analyzeAstFile } = await import('./ast/analyze-ast-file') + const { functions } = await analyzeAstFile(absolutePath) + + this.log(` 📊 Found ${functions.length} functions: ${functions.map(f => f.name).join(', ') || '(none)'}`, 'info') + + if (functions.length === 0) { + file.status = 'skipped' + file.error = 'No functions found in file' + this.log(` ⏭️ Skipped - no functions to extract`, 'warning') + continue + } + + if (functions.length <= 2) { + file.status = 'skipped' + file.error = `Only ${functions.length} function(s) - not worth refactoring` + this.log(` ⏭️ Skipped - only ${functions.length} function(s)`, 'warning') + continue + } + + this.log(` 🔨 Extracting ${functions.length} functions...`, 'info') await refactor.refactorFile(absolutePath) file.status = 'completed' + + // Record extracted functions in registry + if (!this.options.dryRun && functions.length > 0) { + const basename = path.basename(absolutePath, path.extname(absolutePath)) + const dir = path.dirname(absolutePath) + + this.log(` 📝 Recording ${functions.length} functions in registry...`, 'info') + + for (const func of functions) { + const kebabName = func.name.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '') + const extractedPath = path.join(dir, basename, 'functions', `${kebabName}.ts`) + + this.extractionRegistry.functions.push({ + functionName: func.name, + originalFile: file.path, + extractedPath: extractedPath.replace(rootDir + '/', ''), + timestamp: new Date().toISOString() + }) + } + + file.extractedFunctions = functions.map(f => f.name) + this.log(` ✅ Recorded ${functions.length} functions in registry`, 'success') + } + this.log(`Successfully extracted ${file.path}`, 'success') } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error) + const errorStack = error instanceof Error ? error.stack : undefined + + this.log(` ❌ Error: ${errorMsg}`, 'error') + + if (this.options.verbose && errorStack) { + console.error(' Stack trace:', errorStack) + } + if (errorMsg.includes('skipping') || errorMsg.includes('No functions')) { file.status = 'skipped' file.error = errorMsg @@ -290,6 +413,10 @@ class AutoCodeExtractor3000 { const failed = this.results.filter(f => f.status === 'failed').length const skipped = this.results.filter(f => f.status === 'skipped').length const duration = (Date.now() - this.startTime) / 1000 + + const totalFunctionsExtracted = this.results + .filter(f => f.extractedFunctions) + .reduce((sum, f) => sum + (f.extractedFunctions?.length || 0), 0) console.log('\n' + '='.repeat(70)) console.log('🎉 AUTO CODE EXTRACTOR 3000™ - SUMMARY') @@ -299,6 +426,15 @@ class AutoCodeExtractor3000 { console.log(`✅ Successfully Extracted: ${completed}`) console.log(`⏭️ Skipped: ${skipped}`) console.log(`❌ Failed: ${failed}`) + console.log(`📝 Functions Extracted: ${totalFunctionsExtracted}`) + console.log(`🗃️ Registry Total: ${this.extractionRegistry.functions.length} functions`) + + if (skipped > 0) { + console.log('\n⏭️ Skipped Files:') + this.results + .filter(f => f.status === 'skipped') + .forEach(f => console.log(` - ${f.path}: ${f.error}`)) + } if (failed > 0) { console.log('\n❌ Failed Files:') @@ -313,6 +449,13 @@ class AutoCodeExtractor3000 { } else { console.log('\n💾 Changes have been written to disk') console.log(' Review the changes and run tests before committing') + + if (totalFunctionsExtracted > 0) { + console.log(`\n📚 Extraction Registry:`) + console.log(` - ${totalFunctionsExtracted} new functions recorded`) + console.log(` - ${this.extractionRegistry.functions.length} total functions tracked`) + console.log(` - Registry saved to: docs/todo/EXTRACTION_REGISTRY.json`) + } } console.log('\n📝 Next Steps:') @@ -336,6 +479,9 @@ class AutoCodeExtractor3000 { console.log(`Batch Size: ${this.options.batchSize} files`) console.log('='.repeat(70) + '\n') + // Load existing extraction registry + await this.loadExtractionRegistry() + // Phase 1: Scan and categorize console.log('PHASE 1: SCANNING & EXTRACTION') console.log('='.repeat(70) + '\n') @@ -382,6 +528,7 @@ class AutoCodeExtractor3000 { // Post-processing await this.runLinting() await this.runTests() + await this.saveExtractionRegistry() await this.updateProgressReport() await this.saveResults()