opencroc 1.6.9 → 1.8.0
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/dist/cli/index.js +2520 -53
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +379 -1
- package/dist/index.js +2115 -35
- package/dist/index.js.map +1 -1
- package/dist/web/index-studio.html +804 -0
- package/dist/web/index-v2-pixel.html +1571 -0
- package/dist/web/index.html +517 -1512
- package/dist/web/js/agents.js +465 -0
- package/dist/web/js/camera.js +125 -0
- package/dist/web/js/dataviz.js +288 -0
- package/dist/web/js/effects.js +345 -0
- package/dist/web/js/engine.js +489 -0
- package/dist/web/js/office.js +816 -0
- package/dist/web/js/state.js +37 -0
- package/dist/web/js/ui.js +384 -0
- package/package.json +9 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../src/parsers/controller-parser.ts","../src/index.ts","../src/config.ts","../src/adapters/sequelize-adapter.ts","../src/adapters/llm-provider.ts","../src/adapters/llm/openai-provider.ts","../src/adapters/llm/zhipu-provider.ts","../src/adapters/llm/ollama-provider.ts","../src/pipeline/index.ts","../src/parsers/model-parser.ts","../src/parsers/association-parser.ts","../src/analyzers/api-chain-analyzer.ts","../src/generators/er-diagram-generator.ts","../src/generators/test-code-generator.ts","../src/validators/config-validator.ts","../src/validators/schema-validator.ts","../src/validators/semantic-validator.ts","../src/validators/dryrun-validator.ts","../src/parsers/dto-parser.ts","../src/generators/mock-data-generator.ts","../src/analyzers/impact-reporter.ts","../src/planners/chain-planner.ts","../src/tools/ai-config-suggester.ts","../src/tools/enhanced-ai-suggester.ts","../src/tools/auto-fixer.ts","../src/tools/baseline-comparator.ts","../src/tools/preset-loader.ts","../src/self-healing/index.ts","../src/llm/index.ts","../src/llm/openai.ts","../src/llm/ollama.ts","../src/self-healing/dialog-loop-runner.ts","../src/self-healing/controlled-fixer.ts","../src/self-healing/auto-fix-generator.ts","../src/adapters/sequelize.ts","../src/adapters/typeorm.ts","../src/adapters/prisma.ts","../src/adapters/drizzle.ts","../src/adapters/registry.ts","../src/plugins/index.ts","../src/ci/index.ts","../src/reporters/index.ts","../src/reporters/checklist-reporter.ts","../src/reporters/workorder-reporter.ts","../src/reporters/token-reporter.ts","../src/dashboard/index.ts","../src/vscode/index.ts","../src/runtime/index.ts","../src/runtime/playwright-config-generator.ts","../src/runtime/global-setup-generator.ts","../src/runtime/global-teardown-generator.ts","../src/runtime/auth-setup-generator.ts","../src/runtime/resilient-fetch.ts","../src/runtime/network-monitor.ts","../src/runtime/dynamic-route-resolver.ts","../src/runtime/log-completion-waiter.ts","../src/runtime/critical-api-rules.ts","../src/orchestrator/index.ts","../src/orchestrator/reporter.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n type CallExpression,\r\n type SourceFile,\r\n Node,\r\n type PropertyAccessExpression,\r\n type Decorator,\r\n type MethodDeclaration,\r\n type ObjectLiteralExpression,\r\n} from 'ts-morph';\r\nimport type { ApiEndpoint } from '../types.js';\r\n\r\nexport interface ControllerParser {\r\n parseFile(filePath: string): Promise<ApiEndpoint[]>;\r\n parseDirectory(dirPath: string): Promise<ApiEndpoint[]>;\r\n}\r\n\r\nconst HTTP_METHODS = new Set(['get', 'post', 'put', 'delete', 'patch']);\r\n\r\nconst METHOD_MAP: Record<string, string> = {\r\n get: 'GET', post: 'POST', put: 'PUT', delete: 'DELETE', patch: 'PATCH',\r\n};\r\n\r\nconst NEST_HTTP_DECORATORS = new Set(['get', 'post', 'put', 'delete', 'patch']);\r\n\r\n/**\r\n * Parse a single Controller file and extract API endpoints.\r\n */\r\nexport function parseControllerFile(filePath: string): ApiEndpoint[] {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return [];\r\n\r\n try {\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const endpoints: ApiEndpoint[] = [];\r\n endpoints.push(...extractRouterCalls(sourceFile));\r\n endpoints.push(...extractBaseCrudRoutes(sourceFile));\r\n endpoints.push(...extractNestControllerRoutes(sourceFile));\r\n\r\n return deduplicateEndpoints(endpoints);\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\n/**\r\n * Parse all Controller files in a directory.\r\n */\r\nexport function parseControllerDirectory(dirPath: string): ApiEndpoint[] {\r\n const absoluteDir = path.resolve(dirPath);\r\n if (!fs.existsSync(absoluteDir)) return [];\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) =>\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts',\r\n );\r\n\r\n const endpoints: ApiEndpoint[] = [];\r\n for (const file of files) {\r\n endpoints.push(...parseControllerFile(path.join(absoluteDir, file)));\r\n }\r\n return deduplicateEndpoints(endpoints);\r\n}\r\n\r\nfunction extractRouterCalls(sourceFile: SourceFile): ApiEndpoint[] {\r\n const endpoints: ApiEndpoint[] = [];\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\r\n\r\n const propAccess = expr as PropertyAccessExpression;\r\n const methodName = propAccess.getName().toLowerCase();\r\n if (!HTTP_METHODS.has(methodName)) continue;\r\n\r\n const objectText = propAccess.getExpression().getText().trim();\r\n if (!isRouterLike(objectText)) continue;\r\n\r\n const args = call.getArguments();\r\n if (args.length === 0) continue;\r\n\r\n const routePath = resolveRoutePath(args[0], sourceFile);\r\n if (!routePath) continue;\r\n\r\n endpoints.push({\r\n method: METHOD_MAP[methodName],\r\n path: routePath,\r\n pathParams: extractPathParams(routePath),\r\n queryParams: [],\r\n bodyFields: [],\r\n responseFields: [],\r\n relatedTables: [],\r\n description: extractDescription(call),\r\n });\r\n }\r\n return endpoints;\r\n}\r\n\r\nfunction isRouterLike(text: string): boolean {\r\n return text === 'router' || text === 'this.router';\r\n}\r\n\r\nfunction extractBaseCrudRoutes(sourceFile: SourceFile): ApiEndpoint[] {\r\n const endpoints: ApiEndpoint[] = [];\r\n\r\n let isBaseCrud = false;\r\n for (const cls of sourceFile.getClasses()) {\r\n const heritage = cls.getExtends();\r\n if (heritage?.getText().includes('BaseCrudController')) {\r\n isBaseCrud = true;\r\n break;\r\n }\r\n }\r\n if (!isBaseCrud) return endpoints;\r\n\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n let resourcePath: string | null = null;\r\n\r\n for (const call of calls) {\r\n const exprText = call.getExpression().getText();\r\n if (\r\n (exprText === 'super.registerRoutes' || exprText.endsWith('.registerRoutes')) &&\r\n !exprText.includes('Custom')\r\n ) {\r\n const args = call.getArguments();\r\n if (args.length >= 2) resourcePath = extractStringLiteral(args[1]);\r\n }\r\n }\r\n if (!resourcePath) return endpoints;\r\n\r\n const basePath = `/v1/:tenantId/${resourcePath}`;\r\n const crudRoutes: Array<{ method: string; path: string; desc: string }> = [\r\n { method: 'GET', path: basePath, desc: `List ${resourcePath}` },\r\n { method: 'GET', path: `${basePath}/:id`, desc: `Get ${resourcePath} by ID` },\r\n { method: 'POST', path: basePath, desc: `Create ${resourcePath}` },\r\n { method: 'PUT', path: `${basePath}/:id`, desc: `Update ${resourcePath}` },\r\n { method: 'DELETE', path: `${basePath}/:id`, desc: `Delete ${resourcePath}` },\r\n { method: 'POST', path: `${basePath}/batch-delete`, desc: `Batch delete ${resourcePath}` },\r\n ];\r\n\r\n for (const route of crudRoutes) {\r\n endpoints.push({\r\n method: route.method,\r\n path: route.path,\r\n pathParams: extractPathParams(route.path),\r\n queryParams: [],\r\n bodyFields: [],\r\n responseFields: [],\r\n relatedTables: [],\r\n description: route.desc,\r\n });\r\n }\r\n return endpoints;\r\n}\r\n\r\nfunction extractNestControllerRoutes(sourceFile: SourceFile): ApiEndpoint[] {\r\n const endpoints: ApiEndpoint[] = [];\r\n\r\n for (const cls of sourceFile.getClasses()) {\r\n const controllerDecorator = cls.getDecorators().find((d) => d.getName().toLowerCase() === 'controller');\r\n if (!controllerDecorator) continue;\r\n\r\n const controllerBasePath = normalizeRoutePath(extractDecoratorPath(controllerDecorator, sourceFile) ?? '');\r\n\r\n for (const methodDecl of cls.getMethods()) {\r\n const requestMapping = extractRequestMapping(methodDecl, sourceFile);\r\n if (requestMapping) {\r\n const fullPath = joinRoutePath(controllerBasePath, normalizeRoutePath(requestMapping.path));\r\n endpoints.push({\r\n method: requestMapping.method,\r\n path: fullPath,\r\n pathParams: extractPathParams(fullPath),\r\n queryParams: [],\r\n bodyFields: [],\r\n responseFields: [],\r\n relatedTables: [],\r\n description: extractMethodDescription(methodDecl),\r\n });\r\n continue;\r\n }\r\n\r\n const httpDecorator = methodDecl.getDecorators().find((d) => NEST_HTTP_DECORATORS.has(d.getName().toLowerCase()));\r\n if (!httpDecorator) continue;\r\n\r\n const methodName = httpDecorator.getName().toLowerCase();\r\n const method = METHOD_MAP[methodName];\r\n if (!method) continue;\r\n\r\n const methodPath = normalizeRoutePath(extractDecoratorPath(httpDecorator, sourceFile) ?? '');\r\n const fullPath = joinRoutePath(controllerBasePath, methodPath);\r\n\r\n endpoints.push({\r\n method,\r\n path: fullPath,\r\n pathParams: extractPathParams(fullPath),\r\n queryParams: [],\r\n bodyFields: [],\r\n responseFields: [],\r\n relatedTables: [],\r\n description: extractMethodDescription(methodDecl),\r\n });\r\n }\r\n }\r\n\r\n return endpoints;\r\n}\r\n\r\n/**\r\n * Infer related database table names from Service file imports.\r\n */\r\nexport function inferRelatedTables(servicePaths: string[]): string[] {\r\n const tables = new Set<string>();\r\n for (const sp of servicePaths) {\r\n const absolutePath = path.resolve(sp);\r\n if (!fs.existsSync(absolutePath)) continue;\r\n try {\r\n const content = fs.readFileSync(absolutePath, 'utf-8');\r\n const importRegex = /import\\s*\\{([^}]+)\\}\\s*from\\s*['\"][^'\"]*models[^'\"]*['\"]/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = importRegex.exec(content)) !== null) {\r\n const names = match[1].split(',').map((s) => s.trim());\r\n for (const name of names) {\r\n const cleanName = name.replace(/\\s+as\\s+\\w+/, '').trim();\r\n if (cleanName) tables.add(pascalToSnake(cleanName));\r\n }\r\n }\r\n } catch {\r\n // skip\r\n }\r\n }\r\n return Array.from(tables);\r\n}\r\n\r\nfunction resolveRoutePath(node: Node, sourceFile: SourceFile): string | null {\r\n const kind = node.getKind();\r\n if (kind === SyntaxKind.StringLiteral) return node.getText().slice(1, -1);\r\n if (kind === SyntaxKind.TemplateExpression || kind === SyntaxKind.NoSubstitutionTemplateLiteral) {\r\n return resolveTemplateLiteral(node, sourceFile);\r\n }\r\n if (kind === SyntaxKind.Identifier) {\r\n return resolveVariableValue(sourceFile, node.getText().trim());\r\n }\r\n return null;\r\n}\r\n\r\nfunction extractDecoratorPath(decorator: Decorator, sourceFile: SourceFile): string | null {\r\n const args = decorator.getArguments();\r\n if (args.length === 0) return '';\r\n\r\n const firstArg = args[0];\r\n if (firstArg.getKind() === SyntaxKind.ObjectLiteralExpression) {\r\n return extractPathFromObjectLiteral(firstArg as ObjectLiteralExpression, sourceFile);\r\n }\r\n\r\n return resolveRoutePath(firstArg, sourceFile);\r\n}\r\n\r\nfunction extractPathFromObjectLiteral(node: ObjectLiteralExpression, sourceFile: SourceFile): string | null {\r\n const pathProp = node.getProperty('path');\r\n if (!pathProp || !Node.isPropertyAssignment(pathProp)) return null;\r\n const initializer = pathProp.getInitializer();\r\n if (!initializer) return null;\r\n return resolveRoutePath(initializer, sourceFile);\r\n}\r\n\r\nfunction extractRequestMapping(\r\n methodDecl: MethodDeclaration,\r\n sourceFile: SourceFile,\r\n): { method: string; path: string } | null {\r\n const decorator = methodDecl.getDecorators().find((d) => d.getName().toLowerCase() === 'requestmapping');\r\n if (!decorator) return null;\r\n\r\n const args = decorator.getArguments();\r\n if (args.length === 0) return null;\r\n const firstArg = args[0];\r\n if (firstArg.getKind() !== SyntaxKind.ObjectLiteralExpression) return null;\r\n\r\n const obj = firstArg as ObjectLiteralExpression;\r\n const methodProp = obj.getProperty('method');\r\n let method = 'GET';\r\n if (methodProp && Node.isPropertyAssignment(methodProp)) {\r\n const init = methodProp.getInitializer();\r\n const methodText = init?.getText() || '';\r\n const normalized = methodText\r\n .replace(/['\"`]/g, '')\r\n .split('.')\r\n .pop()\r\n ?.toUpperCase();\r\n if (normalized && ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(normalized)) {\r\n method = normalized;\r\n }\r\n }\r\n\r\n const pathValue = extractPathFromObjectLiteral(obj, sourceFile) ?? '';\r\n return { method, path: pathValue };\r\n}\r\n\r\nfunction normalizeRoutePath(routePath: string): string {\r\n const cleaned = routePath.trim();\r\n if (!cleaned || cleaned === '/') return '';\r\n return `/${cleaned.replace(/^\\/+|\\/+$/g, '')}`;\r\n}\r\n\r\nfunction joinRoutePath(basePath: string, childPath: string): string {\r\n const joined = `${basePath}${childPath}`.replace(/\\/+/g, '/');\r\n return joined || '/';\r\n}\r\n\r\nfunction extractMethodDescription(methodDecl: MethodDeclaration): string {\r\n const docs = methodDecl.getJsDocs();\r\n if (docs.length > 0) {\r\n const desc = docs[0].getDescription().trim();\r\n if (desc) return desc;\r\n }\r\n return '';\r\n}\r\n\r\nfunction resolveTemplateLiteral(node: Node, sourceFile: SourceFile): string {\r\n let result = node.getText().slice(1, -1);\r\n result = result.replace(/\\$\\{([^}]+)\\}/g, (_match, expr: string) => {\r\n const resolved = resolveVariableValue(sourceFile, expr.trim());\r\n return resolved || `{${expr.trim()}}`;\r\n });\r\n return result;\r\n}\r\n\r\nfunction resolveVariableValue(sourceFile: SourceFile, varName: string): string | null {\r\n for (const decl of sourceFile.getDescendantsOfKind(SyntaxKind.VariableDeclaration)) {\r\n if (decl.getName() === varName) {\r\n const init = decl.getInitializer();\r\n if (!init) continue;\r\n const t = init.getText().trim();\r\n if ((t.startsWith(\"'\") && t.endsWith(\"'\")) || (t.startsWith('\"') && t.endsWith('\"')))\r\n return t.slice(1, -1);\r\n if (t.startsWith('`') && t.endsWith('`'))\r\n return resolveTemplateLiteral(init, sourceFile);\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction extractPathParams(routePath: string): string[] {\r\n const params: string[] = [];\r\n const regex = /:(\\w+)/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = regex.exec(routePath)) !== null) params.push(match[1]);\r\n return params;\r\n}\r\n\r\nfunction extractDescription(call: CallExpression): string {\r\n let current: Node = call;\r\n while (\r\n current.getParent() &&\r\n current.getParent()!.getKind() !== SyntaxKind.SourceFile &&\r\n current.getParent()!.getKind() !== SyntaxKind.Block\r\n ) {\r\n current = current.getParent()!;\r\n }\r\n const fullText = current.getFullText();\r\n const leadingText = fullText.substring(0, fullText.indexOf(current.getText()));\r\n const jsdocMatch = leadingText.match(/\\/\\*\\*[\\s\\S]*?\\*\\s+(.+?)(?:\\n|\\*\\/)/);\r\n if (jsdocMatch) return jsdocMatch[1].replace(/^\\*\\s*/, '').trim();\r\n const lineMatch = leadingText.match(/\\/\\/\\s*(.+)/);\r\n if (lineMatch) return lineMatch[1].trim();\r\n return '';\r\n}\r\n\r\nfunction extractStringLiteral(node: Node): string | null {\r\n const t = node.getText().trim();\r\n if ((t.startsWith(\"'\") && t.endsWith(\"'\")) || (t.startsWith('\"') && t.endsWith('\"')))\r\n return t.slice(1, -1);\r\n return null;\r\n}\r\n\r\nfunction pascalToSnake(name: string): string {\r\n return name.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\r\n}\r\n\r\nfunction deduplicateEndpoints(endpoints: ApiEndpoint[]): ApiEndpoint[] {\r\n const seen = new Map<string, ApiEndpoint>();\r\n for (const ep of endpoints) {\r\n const key = `${ep.method}:${ep.path}`;\r\n if (!seen.has(key)) {\r\n seen.set(key, ep);\r\n } else {\r\n const existing = seen.get(key)!;\r\n const merged = new Set([...existing.relatedTables, ...ep.relatedTables]);\r\n existing.relatedTables = Array.from(merged);\r\n if (!existing.description && ep.description) existing.description = ep.description;\r\n }\r\n }\r\n return Array.from(seen.values());\r\n}\r\n\r\nexport function createControllerParser(): ControllerParser {\r\n return {\r\n async parseFile(filePath: string) {\r\n return parseControllerFile(filePath);\r\n },\r\n async parseDirectory(dirPath: string) {\r\n return parseControllerDirectory(dirPath);\r\n },\r\n };\r\n}\r\n","// OpenCroc — AI-native E2E Testing Framework\r\n// Public API\r\n\r\n// --- Core Types ---\r\nexport type {\r\n OpenCrocConfig,\r\n ResolvedConfig,\r\n ModuleDefinition,\r\n RouteEntry,\r\n FieldSchema,\r\n TableSchema,\r\n IndexSchema,\r\n ForeignKeyRelation,\r\n ApiEndpoint,\r\n ApiDependency,\r\n DirectedAcyclicGraph,\r\n ApiChainAnalysisResult,\r\n TestStep,\r\n TestChain,\r\n ChainPlanResult,\r\n GeneratedTestFile,\r\n PipelineRunResult,\r\n ERDiagramResult,\r\n ChainFailureResult,\r\n ImpactReport,\r\n ValidationError,\r\n SelfHealingResult,\r\n FixOutcome,\r\n RuntimeConfig,\r\n HookConfig,\r\n ExecutionConfig,\r\n FixScope,\r\n DialogLoopConfig,\r\n TestFailureInfo,\r\n IterationResult,\r\n DialogLoopSummary,\r\n ControlledFixOptions,\r\n ControlledFixOutcome,\r\n AIAttributionResult,\r\n AutoFixPROptions,\r\n AutoFixPRResult,\r\n FailureCategory,\r\n TestResultRecord,\r\n LogCompletionRecord,\r\n FailureSummary,\r\n BackendDomainItem,\r\n LogCompletionSummary,\r\n WorkorderItem,\r\n TokenUsageEntry,\r\n TokenUsageSummary,\r\n // Sprint 2-3 types\r\n ModuleTestConfig,\r\n SeedStep,\r\n ModuleConfigErrorType,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n LayerValidationResult,\r\n ModuleConfigValidationResult,\r\n ModuleConfigValidationContext,\r\n DTOInfo,\r\n DTOFieldInfo,\r\n ValidatorRule,\r\n ModuleMetadata,\r\n FixContext,\r\n FixHistoryEntry,\r\n FixResult,\r\n} from './types.js';\r\n\r\n// --- Config ---\r\nexport { defineConfig } from './config.js';\r\n\r\n// --- Pipeline ---\r\nexport { createPipeline } from './pipeline/index.js';\r\n\r\n// --- Parsers ---\r\nexport { createModelParser, parseModelFile, parseModuleModels } from './parsers/model-parser.js';\r\nexport { createControllerParser, parseControllerFile, parseControllerDirectory, inferRelatedTables } from './parsers/controller-parser.js';\r\nexport { createAssociationParser, parseAssociationFile, buildClassToTableMap, classNameToTableName } from './parsers/association-parser.js';\r\nexport { parseDTOs, parseValidatorRules, scanModuleMetadata } from './parsers/dto-parser.js';\r\n\r\n// --- Generators ---\r\nexport { createTestCodeGenerator } from './generators/test-code-generator.js';\r\nexport { createMockDataGenerator } from './generators/mock-data-generator.js';\r\nexport { createERDiagramGenerator } from './generators/er-diagram-generator.js';\r\n\r\n// --- Analyzers ---\r\nexport { createApiChainAnalyzer, inferDependencies, buildGraph, detectCycles, topologicalSort } from './analyzers/api-chain-analyzer.js';\r\nexport { createImpactReporter } from './analyzers/impact-reporter.js';\r\n\r\n// --- Planners ---\r\nexport { createChainPlanner, createLlmChainPlanner } from './planners/chain-planner.js';\r\n\r\n// --- Validators ---\r\nexport { validateConfig, validateModuleConfig, formatValidationResult } from './validators/config-validator.js';\r\nexport { validateSchema } from './validators/schema-validator.js';\r\nexport { validateSemantic } from './validators/semantic-validator.js';\r\nexport { validateDryrun } from './validators/dryrun-validator.js';\r\n\r\n// --- Tools ---\r\nexport { generateModuleConfig, generateAllModuleConfigs, recoverJSON } from './tools/ai-config-suggester.js';\r\nexport { generateEnhancedConfig } from './tools/enhanced-ai-suggester.js';\r\nexport { autoFix } from './tools/auto-fixer.js';\r\nexport { parsePlaywrightReport, buildTestRunSummary, compareTestRuns, formatComparisonReport } from './tools/baseline-comparator.js';\r\nexport { loadModulePresets, getModulePreset, listModulePresets } from './tools/preset-loader.js';\r\n\r\n// --- Self-Healing ---\r\nexport { createSelfHealingLoop, categorizeFailure, analyzeFailureWithLLM } from './self-healing/index.js';\r\nexport { runDialogLoop, createJsonResultParser } from './self-healing/index.js';\r\nexport type { TestRunner, ResultParser, FixApplier, DialogLoopOptions } from './self-healing/index.js';\r\nexport { applyControlledFix } from './self-healing/index.js';\r\nexport type { ConfigValidator, ConfigFixer, PRGenerator, FsOps, ControlledFixerOptions } from './self-healing/index.js';\r\nexport { generateFixPR } from './self-healing/index.js';\r\nexport type { GitExecutor, PatchWriter } from './self-healing/index.js';\r\n\r\n// --- LLM ---\r\nexport { createLlmProvider, createOpenAIProvider, createOllamaProvider, createTokenTracker, SYSTEM_PROMPTS } from './llm/index.js';\r\n\r\n// --- Adapters ---\r\nexport type { BackendAdapter, LlmProvider } from './adapters/types.js';\r\nexport { createSequelizeAdapter } from './adapters/sequelize.js';\r\nexport { createTypeORMAdapter } from './adapters/typeorm.js';\r\nexport { createPrismaAdapter } from './adapters/prisma.js';\r\nexport { createDrizzleAdapter, parseDrizzleFile, parseDrizzleDirectory } from './adapters/drizzle.js';\r\nexport { createAdapter, detectAdapter, resolveAdapter } from './adapters/registry.js';\r\n\r\n// --- Plugins ---\r\nexport type { OpenCrocPlugin, PluginRegistry } from './plugins/types.js';\r\nexport { createPluginRegistry, definePlugin } from './plugins/index.js';\r\n\r\n// --- CI Templates ---\r\nexport { generateCiTemplate, listCiPlatforms, generateGitHubActionsTemplate, generateGitLabCITemplate } from './ci/index.js';\r\n\r\n// --- Reporters ---\r\nexport type { ReportOutput, BuildWorkordersOptions } from './reporters/index.js';\r\nexport { generateReports, generateHtmlReport, generateJsonReport, generateMarkdownReport } from './reporters/index.js';\r\nexport { classifyFailure, buildFailureSummary, aggregateLogCompletion, parseApiDomain, buildBackendChecklist, renderChecklistMarkdown } from './reporters/index.js';\r\nexport { buildWorkorders, renderWorkordersMarkdown } from './reporters/index.js';\r\nexport { TokenTracker, renderTokenReportMarkdown } from './reporters/index.js';\r\n\r\n// --- Visual Dashboard ---\r\nexport type { DashboardData, DashboardOutput } from './dashboard/index.js';\r\nexport {\r\n buildDashboardDataFromPipeline,\r\n buildDashboardDataFromReportJson,\r\n generateVisualDashboardHtml,\r\n generateVisualDashboard,\r\n} from './dashboard/index.js';\r\n\r\n// --- VSCode Extension Scaffold ---\r\nexport { COMMANDS as VSCODE_COMMANDS, generateExtensionManifest, generateExtensionEntrypoint, buildModuleTree, buildStatusTree } from './vscode/index.js';\r\n\r\n// --- Runtime Infrastructure ---\r\nexport { generatePlaywrightConfig, generateGlobalSetup, generateGlobalTeardown, generateAuthSetup } from './runtime/index.js';\r\nexport { resilientFetch, waitForBackend } from './runtime/resilient-fetch.js';\r\nexport { NetworkMonitor } from './runtime/network-monitor.js';\r\nexport { extractParamNames, extractParamsFromHref, buildPath, extractIdFromText, resolveFromSeedData } from './runtime/dynamic-route-resolver.js';\r\nexport type { AttemptRecord, ResilientFetchOptions, ResilientFetchResult } from './runtime/resilient-fetch.js';\r\nexport type { NetworkError, ApiRecord, NetworkMonitorOptions } from './runtime/network-monitor.js';\r\nexport type { ResolvedRoute } from './runtime/dynamic-route-resolver.js';\r\nexport { selectCandidates, selectCandidatesFromLogs, mergeCandidates, waitForLogCompletion } from './runtime/log-completion-waiter.js';\r\nexport { createRulesEngine } from './runtime/critical-api-rules.js';\r\nexport type { CandidateApiRequest, LogCompletionResult, LogEntry, LogPollerOptions } from './runtime/log-completion-waiter.js';\r\nexport type { CriticalApiRule, ApiRuleViolation, ApiRecordForRules } from './runtime/critical-api-rules.js';\r\n\r\n// --- Orchestration ---\r\nexport { createOrchestrator } from './orchestrator/index.js';\r\nexport { writeOrchestrationSummary, printOrchestrationSummary } from './orchestrator/reporter.js';\r\nexport type {\r\n PhaseStatus,\r\n PhaseResult,\r\n OrchestrationOptions,\r\n OrchestrationPhase,\r\n ExecutionMetrics,\r\n OrchestrationSummary,\r\n} from './orchestrator/index.js';\r\nexport type { OrchestrationReportOptions } from './orchestrator/reporter.js';\r\n","import * as path from 'node:path';\r\nimport type { OpenCrocConfig, ResolvedConfig, BackendAdapter, LlmProvider } from './types.js';\r\nimport { createSequelizeAdapter } from './adapters/sequelize-adapter.js';\r\nimport { createLlmProvider } from './adapters/llm-provider.js';\r\n\r\n/**\r\n * Define an OpenCroc configuration with type checking.\r\n *\r\n * @example\r\n * ```ts\r\n * // opencroc.config.ts\r\n * import { defineConfig } from 'opencroc';\r\n *\r\n * export default defineConfig({\r\n * backendRoot: './backend',\r\n * adapter: 'sequelize',\r\n * llm: {\r\n * provider: 'openai',\r\n * model: 'gpt-4o-mini',\r\n * },\r\n * });\r\n * ```\r\n */\r\nexport function defineConfig(config: OpenCrocConfig): OpenCrocConfig {\r\n return config;\r\n}\r\n\r\n/**\r\n * Load config from opencroc.config.ts using cosmiconfig.\r\n * Falls back to default config if no file found.\r\n */\r\nexport async function loadConfig(searchFrom?: string): Promise<OpenCrocConfig> {\r\n const { cosmiconfig } = await import('cosmiconfig');\r\n const explorer = cosmiconfig('opencroc', {\r\n searchPlaces: [\r\n 'opencroc.config.ts',\r\n 'opencroc.config.js',\r\n 'opencroc.config.mjs',\r\n 'opencroc.config.cjs',\r\n '.opencrocrc.json',\r\n '.opencrocrc.yaml',\r\n '.opencrocrc.yml',\r\n ],\r\n });\r\n\r\n const result = await explorer.search(searchFrom);\r\n if (!result || result.isEmpty) {\r\n return { backendRoot: './backend' };\r\n }\r\n\r\n // cosmiconfig returns the raw export; handle default export\r\n const raw = result.config;\r\n return typeof raw === 'object' && raw !== null && 'default' in raw\r\n ? (raw as { default: OpenCrocConfig }).default\r\n : raw as OpenCrocConfig;\r\n}\r\n\r\n/**\r\n * Resolve a user config into a fully-resolved config with all defaults filled.\r\n */\r\nexport function resolveConfig(config: OpenCrocConfig): ResolvedConfig {\r\n const resolvedAdapter: string | BackendAdapter =\r\n config.adapter ?? createSequelizeAdapter();\r\n\r\n const resolvedLlmProvider: LlmProvider | undefined =\r\n config.llm ? createLlmProvider(config.llm) : undefined;\r\n\r\n return {\r\n _resolved: true,\r\n backendRoot: path.resolve(config.backendRoot),\r\n outDir: config.outDir ?? './opencroc-output',\r\n adapter: typeof resolvedAdapter === 'string' ? resolveAdapterByName(resolvedAdapter) : resolvedAdapter,\r\n llm: config.llm ?? { provider: 'openai' },\r\n playwright: config.playwright ?? {},\r\n modules: config.modules ?? [],\r\n steps: config.steps ?? ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'],\r\n selfHealing: config.selfHealing ?? { enabled: true, maxIterations: 3 },\r\n report: config.report ?? { format: ['html'] },\r\n execution: config.execution ?? {},\r\n runtime: config.runtime ?? {},\r\n _llmProvider: resolvedLlmProvider,\r\n } as ResolvedConfig;\r\n}\r\n\r\nfunction resolveAdapterByName(name: string): BackendAdapter {\r\n switch (name) {\r\n case 'sequelize':\r\n return createSequelizeAdapter();\r\n case 'typeorm':\r\n case 'prisma':\r\n throw new Error(`Adapter \"${name}\" is not yet implemented. Use a custom BackendAdapter instead.`);\r\n default:\r\n throw new Error(`Unknown adapter: \"${name}\". Supported: sequelize, typeorm, prisma.`);\r\n }\r\n}\r\n","/**\r\n * Sequelize Backend Adapter\r\n *\r\n * Implements BackendAdapter for Sequelize ORM projects.\r\n * Uses ts-morph to parse Model.init() calls, association definitions, and controller routes.\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n type CallExpression,\r\n type ObjectLiteralExpression,\r\n type PropertyAssignment,\r\n type Node,\r\n type SourceFile,\r\n type PropertyAccessExpression,\r\n} from 'ts-morph';\r\nimport type {\r\n BackendAdapter,\r\n TableSchema,\r\n FieldSchema,\r\n IndexSchema,\r\n ForeignKeyRelation,\r\n RouteEntry,\r\n} from '../types.js';\r\n\r\n// ============================================================\r\n// Factory\r\n// ============================================================\r\n\r\nexport function createSequelizeAdapter(): BackendAdapter {\r\n return {\r\n name: 'sequelize',\r\n\r\n async parseModels(dir: string): Promise<TableSchema[]> {\r\n return parseModelsFromDir(dir);\r\n },\r\n\r\n async parseAssociations(file: string): Promise<ForeignKeyRelation[]> {\r\n return parseAssociationsFromFile(file);\r\n },\r\n\r\n async parseControllers(dir: string): Promise<RouteEntry[]> {\r\n return parseControllersFromDir(dir);\r\n },\r\n };\r\n}\r\n\r\n// ============================================================\r\n// Model Parsing\r\n// ============================================================\r\n\r\nfunction parseModelsFromDir(modelDir: string): TableSchema[] {\r\n const absoluteDir = path.resolve(modelDir);\r\n if (!fs.existsSync(absoluteDir)) return [];\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) => {\r\n return (\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts' &&\r\n f !== 'associations.ts'\r\n );\r\n });\r\n\r\n const schemas: TableSchema[] = [];\r\n for (const file of files) {\r\n try {\r\n const schema = parseModelFile(path.join(absoluteDir, file));\r\n if (schema) schemas.push(schema);\r\n } catch {\r\n // Skip files that fail to parse\r\n }\r\n }\r\n return schemas;\r\n}\r\n\r\nfunction parseModelFile(filePath: string): TableSchema | null {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return null;\r\n\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const initCall = findInitCall(sourceFile);\r\n if (!initCall) return null;\r\n\r\n const args = initCall.getArguments();\r\n if (args.length < 2) return null;\r\n\r\n const fields = parseFieldDefinitions(args[0]);\r\n const { tableName, indexes } = parseOptions(args[1]);\r\n if (!tableName) return null;\r\n\r\n // Derive className from file name\r\n const className = path.basename(filePath, '.ts');\r\n\r\n return { tableName, className, fields, indexes };\r\n}\r\n\r\nfunction findInitCall(sourceFile: SourceFile): CallExpression | null {\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() === SyntaxKind.PropertyAccessExpression) {\r\n const propAccess = expr.asKindOrThrow(SyntaxKind.PropertyAccessExpression);\r\n if (propAccess.getName() === 'init') return call;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction parseFieldDefinitions(fieldsNode: Node): FieldSchema[] {\r\n const fields: FieldSchema[] = [];\r\n if (fieldsNode.getKind() !== SyntaxKind.ObjectLiteralExpression) return fields;\r\n\r\n const objLiteral = fieldsNode as ObjectLiteralExpression;\r\n for (const prop of objLiteral.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const fieldName = propAssign.getName();\r\n const initializer = propAssign.getInitializer();\r\n if (!initializer || initializer.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\r\n\r\n fields.push(parseFieldObject(fieldName, initializer as ObjectLiteralExpression));\r\n }\r\n return fields;\r\n}\r\n\r\nfunction parseFieldObject(fieldName: string, fieldObj: ObjectLiteralExpression): FieldSchema {\r\n const field: FieldSchema = { name: fieldName, type: 'STRING', allowNull: true, primaryKey: false };\r\n\r\n for (const prop of fieldObj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const key = propAssign.getName();\r\n const init = propAssign.getInitializer();\r\n if (!init) continue;\r\n\r\n switch (key) {\r\n case 'type':\r\n field.type = extractDataType(init);\r\n break;\r\n case 'allowNull':\r\n field.allowNull = extractBooleanValue(init);\r\n break;\r\n case 'primaryKey':\r\n field.primaryKey = extractBooleanValue(init);\r\n break;\r\n case 'defaultValue':\r\n field.defaultValue = extractDefaultValue(init);\r\n break;\r\n case 'unique':\r\n field.unique = extractBooleanValue(init);\r\n break;\r\n case 'comment': {\r\n const text = init.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"'))) {\r\n field.comment = text.slice(1, -1);\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n return field;\r\n}\r\n\r\nfunction extractDataType(node: Node): string {\r\n const text = node.getText().trim();\r\n const callMatch = text.match(/^DataTypes\\.(\\w+)\\((.+)\\)$/);\r\n if (callMatch) return `${callMatch[1]}(${callMatch[2]})`;\r\n const propMatch = text.match(/^DataTypes\\.(\\w+)$/);\r\n if (propMatch) return propMatch[1];\r\n return text;\r\n}\r\n\r\nfunction extractBooleanValue(node: Node): boolean {\r\n return node.getText().trim() === 'true';\r\n}\r\n\r\nfunction extractDefaultValue(node: Node): unknown {\r\n const text = node.getText().trim();\r\n if (text === 'DataTypes.NOW') return 'DataTypes.NOW';\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"'))) {\r\n return text.slice(1, -1);\r\n }\r\n if (/^-?\\d+(\\.\\d+)?$/.test(text)) return Number(text);\r\n if (text === 'true') return true;\r\n if (text === 'false') return false;\r\n if (text === 'null') return null;\r\n return text;\r\n}\r\n\r\nfunction parseOptions(optionsNode: Node): { tableName: string | null; indexes: IndexSchema[] } {\r\n let tableName: string | null = null;\r\n let indexes: IndexSchema[] = [];\r\n\r\n if (optionsNode.getKind() !== SyntaxKind.ObjectLiteralExpression) return { tableName, indexes };\r\n\r\n const objLiteral = optionsNode as ObjectLiteralExpression;\r\n for (const prop of objLiteral.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const key = propAssign.getName();\r\n const init = propAssign.getInitializer();\r\n if (!init) continue;\r\n\r\n if (key === 'tableName') tableName = extractStringValue(init);\r\n else if (key === 'indexes') indexes = parseIndexes(init);\r\n }\r\n return { tableName, indexes };\r\n}\r\n\r\nfunction extractStringValue(node: Node): string | null {\r\n const text = node.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"'))) {\r\n return text.slice(1, -1);\r\n }\r\n return null;\r\n}\r\n\r\nfunction parseIndexes(node: Node): IndexSchema[] {\r\n const indexes: IndexSchema[] = [];\r\n if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return indexes;\r\n\r\n const arr = node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);\r\n for (const el of arr.getElements()) {\r\n if (el.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\r\n const idx = parseIndexObject(el as ObjectLiteralExpression);\r\n if (idx) indexes.push(idx);\r\n }\r\n return indexes;\r\n}\r\n\r\nfunction parseIndexObject(obj: ObjectLiteralExpression): IndexSchema | null {\r\n let name: string | undefined;\r\n let fields: string[] = [];\r\n let unique = false;\r\n\r\n for (const prop of obj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const key = propAssign.getName();\r\n const init = propAssign.getInitializer();\r\n if (!init) continue;\r\n\r\n if (key === 'name') name = extractStringValue(init) ?? undefined;\r\n else if (key === 'fields') fields = extractStringArray(init);\r\n else if (key === 'unique') unique = extractBooleanValue(init);\r\n }\r\n\r\n if (fields.length === 0) return null;\r\n return { name, fields, unique };\r\n}\r\n\r\nfunction extractStringArray(node: Node): string[] {\r\n if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return [];\r\n const arr = node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);\r\n const result: string[] = [];\r\n for (const el of arr.getElements()) {\r\n const text = el.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"'))) {\r\n result.push(text.slice(1, -1));\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n// ============================================================\r\n// Association Parsing\r\n// ============================================================\r\n\r\nfunction parseAssociationsFromFile(filePath: string): ForeignKeyRelation[] {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return [];\r\n\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n\r\n const seen = new Map<string, ForeignKeyRelation>();\r\n\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\r\n\r\n const propAccess = expr as PropertyAccessExpression;\r\n const methodName = propAccess.getName();\r\n if (!['hasMany', 'belongsTo', 'hasOne', 'belongsToMany'].includes(methodName)) continue;\r\n\r\n const sourceClass = propAccess.getExpression().getText().trim();\r\n const args = call.getArguments();\r\n if (args.length < 1) continue;\r\n\r\n const targetClass = args[0].getText().trim();\r\n let foreignKey = '';\r\n\r\n if (args.length >= 2 && args[1].getKind() === SyntaxKind.ObjectLiteralExpression) {\r\n foreignKey = extractObjStringProp(args[1] as ObjectLiteralExpression, 'foreignKey');\r\n }\r\n\r\n const relation: ForeignKeyRelation = {\r\n sourceTable: pascalToSnake(sourceClass),\r\n targetTable: pascalToSnake(targetClass),\r\n sourceField: methodName === 'belongsTo' ? foreignKey || 'id' : 'id',\r\n targetField: methodName === 'belongsTo' ? 'id' : foreignKey || 'id',\r\n cardinality: methodName === 'hasMany' ? '1:N' : methodName === 'belongsTo' ? 'N:1' : '1:1',\r\n };\r\n\r\n const key = `${relation.sourceTable}|${relation.targetTable}|${foreignKey}`;\r\n if (!seen.has(key)) seen.set(key, relation);\r\n }\r\n\r\n return Array.from(seen.values());\r\n}\r\n\r\nfunction extractObjStringProp(obj: ObjectLiteralExpression, propName: string): string {\r\n for (const prop of obj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const pa = prop as PropertyAssignment;\r\n if (pa.getName() !== propName) continue;\r\n const init = pa.getInitializer();\r\n if (!init) continue;\r\n const text = init.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"'))) {\r\n return text.slice(1, -1);\r\n }\r\n return text;\r\n }\r\n return '';\r\n}\r\n\r\nfunction pascalToSnake(name: string): string {\r\n return name.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\r\n}\r\n\r\n// ============================================================\r\n// Controller Parsing\r\n// ============================================================\r\n\r\nconst HTTP_METHODS = new Set(['get', 'post', 'put', 'delete', 'patch']);\r\n\r\nfunction parseControllersFromDir(controllerDir: string): RouteEntry[] {\r\n const absoluteDir = path.resolve(controllerDir);\r\n if (!fs.existsSync(absoluteDir)) return [];\r\n\r\n const stat = fs.statSync(absoluteDir);\r\n const files: string[] = [];\r\n\r\n if (stat.isDirectory()) {\r\n const entries = fs.readdirSync(absoluteDir);\r\n for (const entry of entries) {\r\n if (entry.endsWith('.ts') && !entry.endsWith('.test.ts') && !entry.endsWith('.spec.ts')) {\r\n files.push(path.join(absoluteDir, entry));\r\n }\r\n }\r\n } else if (stat.isFile()) {\r\n files.push(absoluteDir);\r\n }\r\n\r\n const allRoutes: RouteEntry[] = [];\r\n for (const file of files) {\r\n try {\r\n allRoutes.push(...parseControllerFile(file));\r\n } catch {\r\n // Skip files that fail to parse\r\n }\r\n }\r\n\r\n return deduplicateRoutes(allRoutes);\r\n}\r\n\r\nfunction parseControllerFile(filePath: string): RouteEntry[] {\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(filePath);\r\n const routes: RouteEntry[] = [];\r\n\r\n // Extract router.get/post/put/delete calls\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\r\n\r\n const propAccess = expr as PropertyAccessExpression;\r\n const methodName = propAccess.getName().toLowerCase();\r\n if (!HTTP_METHODS.has(methodName)) continue;\r\n\r\n const objectText = propAccess.getExpression().getText().trim();\r\n if (objectText !== 'router' && objectText !== 'this.router') continue;\r\n\r\n const args = call.getArguments();\r\n if (args.length === 0) continue;\r\n\r\n const routePath = resolveStringArg(args[0]);\r\n if (!routePath) continue;\r\n\r\n // Try to extract handler name from second argument\r\n let handler = '';\r\n if (args.length >= 2) {\r\n handler = args[1].getText().trim();\r\n }\r\n\r\n routes.push({\r\n method: methodName.toUpperCase(),\r\n path: routePath,\r\n handler,\r\n controllerClass: path.basename(filePath, '.ts'),\r\n });\r\n }\r\n\r\n // Check for BaseCrudController\r\n routes.push(...extractBaseCrudRoutes(sourceFile, filePath));\r\n\r\n return routes;\r\n}\r\n\r\nfunction extractBaseCrudRoutes(sourceFile: SourceFile, filePath: string): RouteEntry[] {\r\n const routes: RouteEntry[] = [];\r\n const classes = sourceFile.getClasses();\r\n let isBaseCrud = false;\r\n\r\n for (const cls of classes) {\r\n const heritage = cls.getExtends();\r\n if (heritage?.getText().includes('BaseCrudController')) {\r\n isBaseCrud = true;\r\n break;\r\n }\r\n }\r\n if (!isBaseCrud) return routes;\r\n\r\n // Find super.registerRoutes(router, 'resourcePath')\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n let resourcePath: string | null = null;\r\n\r\n for (const call of calls) {\r\n const exprText = call.getExpression().getText();\r\n if (\r\n (exprText === 'super.registerRoutes' || exprText.endsWith('.registerRoutes')) &&\r\n !exprText.includes('Custom')\r\n ) {\r\n const args = call.getArguments();\r\n if (args.length >= 2) resourcePath = resolveStringArg(args[1]);\r\n }\r\n }\r\n\r\n if (!resourcePath) return routes;\r\n const controllerClass = path.basename(filePath, '.ts');\r\n const basePath = `/v1/:tenantId/${resourcePath}`;\r\n\r\n const crudOps = [\r\n { method: 'GET', path: basePath, handler: 'list' },\r\n { method: 'GET', path: `${basePath}/:id`, handler: 'getById' },\r\n { method: 'POST', path: basePath, handler: 'create' },\r\n { method: 'PUT', path: `${basePath}/:id`, handler: 'update' },\r\n { method: 'DELETE', path: `${basePath}/:id`, handler: 'delete' },\r\n { method: 'POST', path: `${basePath}/batch-delete`, handler: 'batchDelete' },\r\n ];\r\n\r\n for (const op of crudOps) {\r\n routes.push({ method: op.method, path: op.path, handler: op.handler, controllerClass });\r\n }\r\n return routes;\r\n}\r\n\r\nfunction resolveStringArg(node: Node): string | null {\r\n const kind = node.getKind();\r\n if (kind === SyntaxKind.StringLiteral) {\r\n const text = node.getText();\r\n return text.slice(1, -1);\r\n }\r\n if (kind === SyntaxKind.NoSubstitutionTemplateLiteral) {\r\n const text = node.getText();\r\n return text.slice(1, -1);\r\n }\r\n if (kind === SyntaxKind.TemplateExpression) {\r\n // Best-effort resolve template literals\r\n const sourceFile = node.getSourceFile();\r\n let result = node.getText().slice(1, -1);\r\n result = result.replace(/\\$\\{([^}]+)\\}/g, (_match, expr: string) => {\r\n const resolved = resolveVariable(sourceFile, expr.trim());\r\n return resolved || `{${expr.trim()}}`;\r\n });\r\n return result;\r\n }\r\n if (kind === SyntaxKind.Identifier) {\r\n return resolveVariable(node.getSourceFile(), node.getText().trim());\r\n }\r\n return null;\r\n}\r\n\r\nfunction resolveVariable(sourceFile: SourceFile, varName: string): string | null {\r\n const varDecls = sourceFile.getDescendantsOfKind(SyntaxKind.VariableDeclaration);\r\n for (const decl of varDecls) {\r\n if (decl.getName() === varName) {\r\n const init = decl.getInitializer();\r\n if (!init) continue;\r\n const text = init.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"'))) {\r\n return text.slice(1, -1);\r\n }\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction deduplicateRoutes(routes: RouteEntry[]): RouteEntry[] {\r\n const seen = new Map<string, RouteEntry>();\r\n for (const r of routes) {\r\n const key = `${r.method}:${r.path}`;\r\n if (!seen.has(key)) seen.set(key, r);\r\n }\r\n return Array.from(seen.values());\r\n}\r\n","/**\r\n * LLM Provider Factory\r\n *\r\n * Creates the appropriate LLM provider based on config.\r\n */\r\n\r\nimport type { LlmProvider, LlmConfig } from '../types.js';\r\nimport { createOpenAIProvider } from './llm/openai-provider.js';\r\nimport { createZhipuProvider } from './llm/zhipu-provider.js';\r\nimport { createOllamaProvider } from './llm/ollama-provider.js';\r\n\r\nexport function createLlmProvider(config: LlmConfig): LlmProvider {\r\n switch (config.provider) {\r\n case 'openai':\r\n return createOpenAIProvider(config);\r\n case 'zhipu':\r\n return createZhipuProvider(config);\r\n case 'ollama':\r\n return createOllamaProvider(config);\r\n case 'custom':\r\n throw new Error('Custom LLM provider must be passed directly as a LlmProvider instance.');\r\n default:\r\n throw new Error(`Unknown LLM provider: ${config.provider}`);\r\n }\r\n}\r\n\r\nexport { createOpenAIProvider } from './llm/openai-provider.js';\r\nexport { createZhipuProvider } from './llm/zhipu-provider.js';\r\nexport { createOllamaProvider } from './llm/ollama-provider.js';\r\n","/**\r\n * OpenAI LLM Provider\r\n */\r\n\r\nimport type { LlmProvider, LlmConfig } from '../../types.js';\r\n\r\nexport function createOpenAIProvider(config: LlmConfig): LlmProvider {\r\n const baseUrl = config.baseUrl || 'https://api.openai.com/v1';\r\n const model = config.model || 'gpt-4o-mini';\r\n\r\n return {\r\n name: 'openai',\r\n\r\n async chat(messages) {\r\n const apiKey = config.apiKey || process.env.OPENCROC_LLM_API_KEY || process.env.OPENAI_API_KEY;\r\n if (!apiKey) throw new Error('OpenAI API key is required. Set llm.apiKey or OPENAI_API_KEY env var.');\r\n\r\n const response = await fetch(`${baseUrl}/chat/completions`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Authorization': `Bearer ${apiKey}`,\r\n },\r\n body: JSON.stringify({\r\n model,\r\n messages,\r\n max_tokens: config.maxTokens || 4096,\r\n temperature: config.temperature ?? 0.1,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const text = await response.text();\r\n throw new Error(`OpenAI API error ${response.status}: ${text}`);\r\n }\r\n\r\n const data = await response.json() as { choices: Array<{ message: { content: string } }> };\r\n return data.choices[0]?.message?.content || '';\r\n },\r\n\r\n estimateTokens(text) {\r\n // Rough approximation: ~4 chars per token for English, ~2 for CJK\r\n return Math.ceil(text.length / 3);\r\n },\r\n };\r\n}\r\n","/**\r\n * Zhipu (智谱) LLM Provider\r\n */\r\n\r\nimport type { LlmProvider, LlmConfig } from '../../types.js';\r\n\r\nexport function createZhipuProvider(config: LlmConfig): LlmProvider {\r\n const baseUrl = config.baseUrl || 'https://open.bigmodel.cn/api/paas/v4';\r\n const model = config.model || 'glm-4-flash';\r\n\r\n return {\r\n name: 'zhipu',\r\n\r\n async chat(messages) {\r\n const apiKey = config.apiKey || process.env.OPENCROC_LLM_API_KEY || process.env.ZHIPU_API_KEY;\r\n if (!apiKey) throw new Error('Zhipu API key is required. Set llm.apiKey or ZHIPU_API_KEY env var.');\r\n\r\n const response = await fetch(`${baseUrl}/chat/completions`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Authorization': `Bearer ${apiKey}`,\r\n },\r\n body: JSON.stringify({\r\n model,\r\n messages,\r\n max_tokens: config.maxTokens || 4096,\r\n temperature: config.temperature ?? 0.1,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const text = await response.text();\r\n throw new Error(`Zhipu API error ${response.status}: ${text}`);\r\n }\r\n\r\n const data = await response.json() as { choices: Array<{ message: { content: string } }> };\r\n return data.choices[0]?.message?.content || '';\r\n },\r\n\r\n estimateTokens(text) {\r\n // CJK-heavy: ~2 chars per token\r\n return Math.ceil(text.length / 2);\r\n },\r\n };\r\n}\r\n","/**\r\n * Ollama (Local) LLM Provider\r\n */\r\n\r\nimport type { LlmProvider, LlmConfig } from '../../types.js';\r\n\r\nexport function createOllamaProvider(config: LlmConfig): LlmProvider {\r\n const baseUrl = config.baseUrl || 'http://localhost:11434';\r\n const model = config.model || 'llama3.1';\r\n\r\n return {\r\n name: 'ollama',\r\n\r\n async chat(messages) {\r\n const response = await fetch(`${baseUrl}/api/chat`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n model,\r\n messages,\r\n stream: false,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const text = await response.text();\r\n throw new Error(`Ollama API error ${response.status}: ${text}`);\r\n }\r\n\r\n const data = await response.json() as { message?: { content: string } };\r\n return data.message?.content || '';\r\n },\r\n\r\n estimateTokens(text) {\r\n return Math.ceil(text.length / 4);\r\n },\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport type {\r\n OpenCrocConfig,\r\n PipelineRunResult,\r\n PipelineStep,\r\n ERDiagramResult,\r\n ChainPlanResult,\r\n} from '../types.js';\r\nimport { parseModuleModels } from '../parsers/model-parser.js';\r\nimport { parseControllerDirectory } from '../parsers/controller-parser.js';\r\nimport { parseAssociationFile } from '../parsers/association-parser.js';\r\nimport { createApiChainAnalyzer, topologicalSort } from '../analyzers/api-chain-analyzer.js';\r\nimport { createERDiagramGenerator } from '../generators/er-diagram-generator.js';\r\nimport { createTestCodeGenerator } from '../generators/test-code-generator.js';\r\nimport { validateConfig } from '../validators/config-validator.js';\r\n\r\nexport interface Pipeline {\r\n run(steps?: PipelineStep[]): Promise<PipelineRunResult>;\r\n}\r\n\r\nconst ALL_STEPS: PipelineStep[] = ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'];\r\n\r\nexport function createPipeline(config: OpenCrocConfig): Pipeline {\r\n return {\r\n async run(steps) {\r\n const startTime = Date.now();\r\n const activeSteps = steps || config.steps || ALL_STEPS;\r\n\r\n const result: PipelineRunResult = {\r\n modules: [],\r\n erDiagrams: new Map(),\r\n chainPlans: new Map(),\r\n generatedFiles: [],\r\n validationErrors: [],\r\n duration: 0,\r\n };\r\n\r\n const backendRoot = path.resolve(config.backendRoot);\r\n\r\n // Smart discovery: find models/ and controllers/ in common locations\r\n const findDir = (name: string): string | null => {\r\n const candidates = [\r\n path.join(backendRoot, name), // ./models\r\n path.join(backendRoot, 'src', name), // ./src/models\r\n path.join(backendRoot, 'backend', 'src', name), // ./backend/src/models\r\n path.join(backendRoot, 'backend', name), // ./backend/models\r\n path.join(backendRoot, 'server', 'src', name), // ./server/src/models\r\n path.join(backendRoot, 'app', name), // ./app/models\r\n ];\r\n for (const c of candidates) {\r\n if (fs.existsSync(c)) return c;\r\n }\r\n return null;\r\n };\r\n\r\n const modelsRoot = findDir('models');\r\n const controllersRoot = findDir('controllers');\r\n\r\n // Step 1: Scan — discover modules\r\n if (activeSteps.includes('scan')) {\r\n if (modelsRoot) {\r\n // Discover modules from subdirectories\r\n const dirs = fs.readdirSync(modelsRoot, { withFileTypes: true })\r\n .filter((d) => d.isDirectory())\r\n .map((d) => d.name);\r\n\r\n const moduleFilter = config.modules;\r\n for (const dir of dirs) {\r\n if (moduleFilter && !moduleFilter.includes(dir)) continue;\r\n result.modules.push(dir);\r\n }\r\n\r\n // If no subdirectories, treat root as single \"default\" module\r\n if (result.modules.length === 0) {\r\n result.modules.push('default');\r\n } else {\r\n // Also include root-level model files as \"default\" module\r\n const rootFiles = fs.readdirSync(modelsRoot)\r\n .filter((f) => f.endsWith('.ts') && !f.endsWith('.test.ts') && f !== 'index.ts');\r\n if (rootFiles.length > 0) {\r\n result.modules.unshift('default');\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Helper: resolve model dir for a module\r\n const resolveModelDir = (_backendRoot: string, mod: string): string =>\r\n mod === 'default'\r\n ? (modelsRoot || path.join(backendRoot, 'models'))\r\n : path.join(modelsRoot || path.join(backendRoot, 'models'), mod);\r\n\r\n // Helper: resolve controller dir for a module\r\n const resolveControllerDir = (_backendRoot: string, mod: string): string =>\r\n mod === 'default'\r\n ? (controllersRoot || path.join(backendRoot, 'controllers'))\r\n : path.join(controllersRoot || path.join(backendRoot, 'controllers'), mod);\r\n\r\n // Step 2: ER Diagram — parse models and generate relationship graphs\r\n if (activeSteps.includes('er-diagram')) {\r\n const erGen = createERDiagramGenerator();\r\n const backendRoot = path.resolve(config.backendRoot);\r\n\r\n for (const mod of result.modules) {\r\n const modelDir = resolveModelDir(backendRoot, mod);\r\n\r\n // For flat layouts, scan all model files for embedded associations\r\n const tables = fs.existsSync(modelDir) ? parseModuleModels(modelDir) : [];\r\n const relations: import('../types.js').ForeignKeyRelation[] = [];\r\n\r\n // Check for dedicated associations.ts first\r\n const assocFile = path.join(modelDir, 'associations.ts');\r\n if (fs.existsSync(assocFile)) {\r\n relations.push(...parseAssociationFile(assocFile));\r\n }\r\n\r\n // Also scan model files for embedded associations (belongsTo/hasMany at end of file)\r\n if (fs.existsSync(modelDir)) {\r\n const modelFiles = fs.readdirSync(modelDir)\r\n .filter((f) => f.endsWith('.ts') && !f.endsWith('.test.ts') && f !== 'index.ts' && f !== 'associations.ts');\r\n for (const file of modelFiles) {\r\n try {\r\n const embedded = parseAssociationFile(path.join(modelDir, file));\r\n relations.push(...embedded);\r\n } catch {\r\n // skip files that fail to parse\r\n }\r\n }\r\n }\r\n\r\n const erResult: ERDiagramResult = erGen.generate(tables, relations);\r\n result.erDiagrams.set(mod, erResult);\r\n }\r\n }\r\n\r\n // Step 3: API Chain — analyze controller routes and build dependency DAG\r\n if (activeSteps.includes('api-chain')) {\r\n const chainAnalyzer = createApiChainAnalyzer();\r\n const backendRoot = path.resolve(config.backendRoot);\r\n\r\n for (const mod of result.modules) {\r\n const controllerDir = resolveControllerDir(backendRoot, mod);\r\n const endpoints = fs.existsSync(controllerDir)\r\n ? parseControllerDirectory(controllerDir)\r\n : [];\r\n\r\n const analysis = chainAnalyzer.analyze(endpoints);\r\n analysis.moduleName = mod;\r\n\r\n if (analysis.hasCycles) {\r\n for (const warning of analysis.cycleWarnings) {\r\n result.validationErrors.push({\r\n module: mod,\r\n field: 'api-chain',\r\n message: warning,\r\n severity: 'warning',\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Step 4: Plan — generate test chains from dependency analysis\r\n if (activeSteps.includes('plan')) {\r\n const backendRoot = path.resolve(config.backendRoot);\r\n const chainAnalyzer = createApiChainAnalyzer();\r\n\r\n for (const mod of result.modules) {\r\n const controllerDir = resolveControllerDir(backendRoot, mod);\r\n const endpoints = fs.existsSync(controllerDir)\r\n ? parseControllerDirectory(controllerDir)\r\n : [];\r\n\r\n const analysis = chainAnalyzer.analyze(endpoints);\r\n const topoOrder = topologicalSort(analysis.dag);\r\n\r\n // Group by resource to create chains\r\n const chains = generateChainPlan(mod, endpoints, topoOrder);\r\n result.chainPlans.set(mod, chains);\r\n }\r\n }\r\n\r\n // Step 5: Codegen — emit Playwright test files from chain plans\r\n if (activeSteps.includes('codegen')) {\r\n const testGen = createTestCodeGenerator();\r\n const outDir = config.outDir || './opencroc-output';\r\n\r\n for (const [_mod, plan] of result.chainPlans) {\r\n const files = testGen.generate(plan.chains);\r\n for (const file of files) {\r\n file.filePath = path.join(outDir, file.filePath);\r\n }\r\n result.generatedFiles.push(...files);\r\n }\r\n }\r\n\r\n // Step 6: Validate — run validation on generated configs\r\n if (activeSteps.includes('validate')) {\r\n const configErrors = validateConfig(config as unknown as Record<string, unknown>);\r\n result.validationErrors.push(...configErrors);\r\n }\r\n\r\n result.duration = Date.now() - startTime;\r\n return result;\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Generate a basic chain plan from endpoints and topological order.\r\n */\r\nfunction generateChainPlan(\r\n moduleName: string,\r\n endpoints: import('../types.js').ApiEndpoint[],\r\n _topoOrder: string[],\r\n): ChainPlanResult {\r\n // Group endpoints by resource (first non-param path segment)\r\n const groups = new Map<string, import('../types.js').ApiEndpoint[]>();\r\n\r\n for (const ep of endpoints) {\r\n const segments = ep.path.split('/').filter((s) => s && !s.startsWith(':'));\r\n const resource = segments[segments.length - 1] || 'default';\r\n if (!groups.has(resource)) groups.set(resource, []);\r\n groups.get(resource)!.push(ep);\r\n }\r\n\r\n const chains: import('../types.js').TestChain[] = [];\r\n let totalSteps = 0;\r\n\r\n for (const [resource, eps] of groups) {\r\n const steps: import('../types.js').TestStep[] = eps.map((ep, i) => ({\r\n order: i + 1,\r\n action: ep.method,\r\n endpoint: ep,\r\n description: ep.description || `${ep.method} ${ep.path}`,\r\n assertions: [],\r\n }));\r\n\r\n chains.push({ name: `${resource} CRUD chain`, module: moduleName, steps });\r\n totalSteps += steps.length;\r\n }\r\n\r\n return { chains, totalSteps };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n type CallExpression,\r\n type ObjectLiteralExpression,\r\n type PropertyAssignment,\r\n type Node,\r\n} from 'ts-morph';\r\nimport type { TableSchema, FieldSchema, IndexSchema } from '../types.js';\r\n\r\nexport interface ModelParser {\r\n parseFile(filePath: string): Promise<TableSchema | null>;\r\n parseDirectory(dirPath: string): Promise<TableSchema[]>;\r\n}\r\n\r\n/**\r\n * Parse a single Sequelize Model file and extract TableSchema.\r\n */\r\nexport function parseModelFile(filePath: string): TableSchema | null {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return null;\r\n\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const initCall = findInitCall(sourceFile);\r\n if (!initCall) return null;\r\n\r\n const args = initCall.getArguments();\r\n if (args.length < 2) return null;\r\n\r\n const fields = parseFieldDefinitions(args[0]);\r\n const { tableName, indexes } = parseOptions(args[1]);\r\n\r\n if (!tableName) return null;\r\n\r\n return { tableName, fields, indexes };\r\n}\r\n\r\n/**\r\n * Batch parse all Model files in a directory.\r\n */\r\nexport function parseModuleModels(modelDir: string): TableSchema[] {\r\n const absoluteDir = path.resolve(modelDir);\r\n if (!fs.existsSync(absoluteDir)) return [];\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) =>\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts' &&\r\n f !== 'associations.ts',\r\n );\r\n\r\n const schemas: TableSchema[] = [];\r\n for (const file of files) {\r\n try {\r\n const schema = parseModelFile(path.join(absoluteDir, file));\r\n if (schema) schemas.push(schema);\r\n } catch {\r\n // skip unparseable files\r\n }\r\n }\r\n return schemas;\r\n}\r\n\r\nfunction findInitCall(sourceFile: Node): CallExpression | null {\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() === SyntaxKind.PropertyAccessExpression) {\r\n const propAccess = expr.asKindOrThrow(SyntaxKind.PropertyAccessExpression);\r\n if (propAccess.getName() === 'init') return call;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction parseFieldDefinitions(fieldsNode: Node): FieldSchema[] {\r\n const fields: FieldSchema[] = [];\r\n if (fieldsNode.getKind() !== SyntaxKind.ObjectLiteralExpression) return fields;\r\n\r\n const objLiteral = fieldsNode as ObjectLiteralExpression;\r\n for (const prop of objLiteral.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const initializer = propAssign.getInitializer();\r\n if (!initializer || initializer.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\r\n fields.push(parseFieldObject(propAssign.getName(), initializer as ObjectLiteralExpression));\r\n }\r\n return fields;\r\n}\r\n\r\nfunction parseFieldObject(fieldName: string, fieldObj: ObjectLiteralExpression): FieldSchema {\r\n const field: FieldSchema = { name: fieldName, type: 'STRING', allowNull: true, primaryKey: false };\r\n\r\n for (const prop of fieldObj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const key = propAssign.getName();\r\n const init = propAssign.getInitializer();\r\n if (!init) continue;\r\n\r\n switch (key) {\r\n case 'type': field.type = extractDataType(init); break;\r\n case 'allowNull': field.allowNull = init.getText().trim() === 'true'; break;\r\n case 'primaryKey': field.primaryKey = init.getText().trim() === 'true'; break;\r\n case 'defaultValue': field.defaultValue = extractDefaultValue(init); break;\r\n }\r\n }\r\n return field;\r\n}\r\n\r\nfunction extractDataType(node: Node): string {\r\n const text = node.getText().trim();\r\n const callMatch = text.match(/^DataTypes\\.(\\w+)\\((.+)\\)$/);\r\n if (callMatch) return `${callMatch[1]}(${callMatch[2]})`;\r\n const propMatch = text.match(/^DataTypes\\.(\\w+)$/);\r\n if (propMatch) return propMatch[1];\r\n return text;\r\n}\r\n\r\nfunction extractDefaultValue(node: Node): unknown {\r\n const text = node.getText().trim();\r\n if (text === 'DataTypes.NOW') return 'DataTypes.NOW';\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\r\n return text.slice(1, -1);\r\n if (/^-?\\d+(\\.\\d+)?$/.test(text)) return Number(text);\r\n if (text === 'true') return true;\r\n if (text === 'false') return false;\r\n if (text === 'null') return null;\r\n return text;\r\n}\r\n\r\nfunction parseOptions(optionsNode: Node): { tableName: string | null; indexes: IndexSchema[] } {\r\n let tableName: string | null = null;\r\n let indexes: IndexSchema[] = [];\r\n\r\n if (optionsNode.getKind() !== SyntaxKind.ObjectLiteralExpression) return { tableName, indexes };\r\n\r\n const objLiteral = optionsNode as ObjectLiteralExpression;\r\n for (const prop of objLiteral.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const key = propAssign.getName();\r\n const init = propAssign.getInitializer();\r\n if (!init) continue;\r\n\r\n if (key === 'tableName') tableName = extractStringValue(init);\r\n if (key === 'indexes') indexes = parseIndexes(init);\r\n }\r\n return { tableName, indexes };\r\n}\r\n\r\nfunction extractStringValue(node: Node): string | null {\r\n const text = node.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\r\n return text.slice(1, -1);\r\n return null;\r\n}\r\n\r\nfunction parseIndexes(node: Node): IndexSchema[] {\r\n if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return [];\r\n const arr = node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);\r\n const indexes: IndexSchema[] = [];\r\n for (const el of arr.getElements()) {\r\n if (el.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\r\n const idx = parseIndexObject(el as ObjectLiteralExpression);\r\n if (idx) indexes.push(idx);\r\n }\r\n return indexes;\r\n}\r\n\r\nfunction parseIndexObject(obj: ObjectLiteralExpression): IndexSchema | null {\r\n let name = '';\r\n let fields: string[] = [];\r\n let unique = false;\r\n\r\n for (const prop of obj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const pa = prop as PropertyAssignment;\r\n const init = pa.getInitializer();\r\n if (!init) continue;\r\n switch (pa.getName()) {\r\n case 'name': name = extractStringValue(init) || ''; break;\r\n case 'fields': fields = extractStringArray(init); break;\r\n case 'unique': unique = init.getText().trim() === 'true'; break;\r\n }\r\n }\r\n if (!name || fields.length === 0) return null;\r\n return { name, fields, unique };\r\n}\r\n\r\nfunction extractStringArray(node: Node): string[] {\r\n if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return [];\r\n const arr = node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);\r\n return arr.getElements()\r\n .map((el) => el.getText().trim())\r\n .filter((t) => (t.startsWith(\"'\") || t.startsWith('\"')))\r\n .map((t) => t.slice(1, -1));\r\n}\r\n\r\nexport function createModelParser(): ModelParser {\r\n return {\r\n async parseFile(filePath: string) {\r\n return parseModelFile(filePath);\r\n },\r\n async parseDirectory(dirPath: string) {\r\n return parseModuleModels(dirPath);\r\n },\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n type ObjectLiteralExpression,\r\n type PropertyAssignment,\r\n type SourceFile,\r\n} from 'ts-morph';\r\nimport type { ForeignKeyRelation } from '../types.js';\r\nimport { parseModelFile } from './model-parser.js';\r\n\r\nexport interface AssociationParser {\r\n parseFile(filePath: string): Promise<ForeignKeyRelation[]>;\r\n}\r\n\r\ninterface RawAssociation {\r\n sourceClass: string;\r\n targetClass: string;\r\n foreignKey: string;\r\n type: 'hasMany' | 'belongsTo' | 'hasOne';\r\n importPath?: string;\r\n}\r\n\r\n/**\r\n * Parse an associations.ts file to extract all foreign key relations.\r\n */\r\nexport function parseAssociationFile(\r\n filePath: string,\r\n classToTableMap?: Map<string, string>,\r\n moduleTablePrefix?: string,\r\n): ForeignKeyRelation[] {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return [];\r\n\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const importPathMap = collectImportPaths(sourceFile);\r\n const rawAssociations = extractAssociationCalls(sourceFile, importPathMap);\r\n if (rawAssociations.length === 0) return [];\r\n\r\n return deduplicateRelations(rawAssociations, classToTableMap, moduleTablePrefix);\r\n}\r\n\r\n/**\r\n * Build className → tableName map from Model files in a directory.\r\n */\r\nexport function buildClassToTableMap(modelDir: string): Map<string, string> {\r\n const map = new Map<string, string>();\r\n const absoluteDir = path.resolve(modelDir);\r\n if (!fs.existsSync(absoluteDir)) return map;\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) =>\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts' &&\r\n f !== 'associations.ts',\r\n );\r\n\r\n for (const file of files) {\r\n try {\r\n const schema = parseModelFile(path.join(absoluteDir, file));\r\n if (schema) {\r\n const className = file.replace('.ts', '');\r\n map.set(className, schema.tableName);\r\n }\r\n } catch {\r\n // skip\r\n }\r\n }\r\n return map;\r\n}\r\n\r\nfunction collectImportPaths(sourceFile: SourceFile): Map<string, string> {\r\n const map = new Map<string, string>();\r\n for (const decl of sourceFile.getImportDeclarations()) {\r\n const moduleSpecifier = decl.getModuleSpecifierValue();\r\n for (const named of decl.getNamedImports()) {\r\n map.set(named.getName(), moduleSpecifier);\r\n }\r\n }\r\n return map;\r\n}\r\n\r\nfunction extractAssociationCalls(\r\n sourceFile: SourceFile,\r\n importPathMap: Map<string, string>,\r\n): RawAssociation[] {\r\n const associations: RawAssociation[] = [];\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\r\n\r\n const propAccess = expr.asKindOrThrow(SyntaxKind.PropertyAccessExpression);\r\n const methodName = propAccess.getName();\r\n if (methodName !== 'hasMany' && methodName !== 'belongsTo' && methodName !== 'hasOne') continue;\r\n\r\n const sourceClass = propAccess.getExpression().getText().trim();\r\n const args = call.getArguments();\r\n if (args.length < 1) continue;\r\n\r\n const targetClass = args[0].getText().trim();\r\n let foreignKey = '';\r\n\r\n if (args.length >= 2 && args[1].getKind() === SyntaxKind.ObjectLiteralExpression) {\r\n foreignKey = extractStringProperty(args[1] as ObjectLiteralExpression, 'foreignKey');\r\n }\r\n\r\n associations.push({\r\n sourceClass,\r\n targetClass,\r\n foreignKey,\r\n type: methodName as RawAssociation['type'],\r\n importPath: importPathMap.get(targetClass),\r\n });\r\n }\r\n return associations;\r\n}\r\n\r\nfunction extractStringProperty(obj: ObjectLiteralExpression, propertyName: string): string {\r\n for (const prop of obj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const pa = prop as PropertyAssignment;\r\n if (pa.getName() !== propertyName) continue;\r\n const init = pa.getInitializer();\r\n if (!init) continue;\r\n const text = init.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\r\n return text.slice(1, -1);\r\n return text;\r\n }\r\n return '';\r\n}\r\n\r\nexport function classNameToTableName(className: string): string {\r\n return className.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\r\n}\r\n\r\nfunction resolveTableName(className: string, classToTableMap?: Map<string, string>): string {\r\n if (classToTableMap?.has(className)) return classToTableMap.get(className)!;\r\n return classNameToTableName(className);\r\n}\r\n\r\nfunction isCrossModuleRef(\r\n targetTableName: string,\r\n importPath: string | undefined,\r\n moduleTablePrefix?: string,\r\n): boolean {\r\n if (moduleTablePrefix) return !targetTableName.startsWith(moduleTablePrefix);\r\n if (importPath) {\r\n const upLevels = (importPath.match(/\\.\\.\\//g) || []).length;\r\n return upLevels >= 2;\r\n }\r\n return false;\r\n}\r\n\r\nfunction deduplicateRelations(\r\n rawAssociations: RawAssociation[],\r\n classToTableMap?: Map<string, string>,\r\n moduleTablePrefix?: string,\r\n): ForeignKeyRelation[] {\r\n const seen = new Map<string, ForeignKeyRelation>();\r\n\r\n for (const raw of rawAssociations) {\r\n const sourceTable = resolveTableName(raw.sourceClass, classToTableMap);\r\n const targetTable = resolveTableName(raw.targetClass, classToTableMap);\r\n const crossModule = isCrossModuleRef(targetTable, raw.importPath, moduleTablePrefix);\r\n\r\n let parentTable: string;\r\n let childTable: string;\r\n let cardinality: ForeignKeyRelation['cardinality'];\r\n\r\n switch (raw.type) {\r\n case 'hasMany':\r\n parentTable = sourceTable; childTable = targetTable; cardinality = '1:N'; break;\r\n case 'belongsTo':\r\n parentTable = targetTable; childTable = sourceTable; cardinality = 'N:1'; break;\r\n case 'hasOne':\r\n parentTable = sourceTable; childTable = targetTable; cardinality = '1:1'; break;\r\n }\r\n\r\n const dedupeKey = `${parentTable}|${childTable}|${raw.foreignKey}`;\r\n if (seen.has(dedupeKey)) {\r\n const existing = seen.get(dedupeKey)!;\r\n if (existing.cardinality === 'N:1' && (cardinality === '1:N' || cardinality === '1:1')) {\r\n seen.set(dedupeKey, {\r\n sourceTable: parentTable, sourceField: 'id',\r\n targetTable: childTable, targetField: raw.foreignKey,\r\n cardinality, isCrossModule: crossModule || existing.isCrossModule,\r\n });\r\n }\r\n } else {\r\n seen.set(dedupeKey, {\r\n sourceTable: parentTable, sourceField: 'id',\r\n targetTable: childTable, targetField: raw.foreignKey,\r\n cardinality, isCrossModule: crossModule,\r\n });\r\n }\r\n }\r\n return Array.from(seen.values());\r\n}\r\n\r\nexport function createAssociationParser(): AssociationParser {\r\n return {\r\n async parseFile(filePath: string) {\r\n return parseAssociationFile(filePath);\r\n },\r\n };\r\n}\r\n","import type {\r\n ApiEndpoint,\r\n ApiDependency,\r\n ApiChainAnalysisResult,\r\n DirectedAcyclicGraph,\r\n} from '../types.js';\r\n\r\nconst EXCLUDED_PARAMS = new Set(['tenantId']);\r\n\r\nconst enum Color { WHITE = 0, GRAY = 1, BLACK = 2 }\r\n\r\nfunction toNodeKey(endpoint: ApiEndpoint): string {\r\n return `${endpoint.method} ${endpoint.path}`;\r\n}\r\n\r\nfunction paramToResourceHint(param: string): string {\r\n const stripped = param.endsWith('Id') ? param.slice(0, -2) : param;\r\n return stripped.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');\r\n}\r\n\r\nfunction postProducesResource(postEndpoint: ApiEndpoint, resourceHint: string): boolean {\r\n const segments = postEndpoint.path.split('/').filter((s) => s && !s.startsWith(':'));\r\n if (segments.length === 0) return false;\r\n\r\n const lastSegment = segments[segments.length - 1].toLowerCase();\r\n if (lastSegment.includes(resourceHint)) return true;\r\n\r\n const parts = lastSegment.split('-');\r\n if (parts.some((p) => p === resourceHint || p.startsWith(resourceHint))) return true;\r\n\r\n if (resourceHint.length <= 4) {\r\n const abbreviation = parts.map((p) => p[0]).join('');\r\n if (abbreviation.startsWith(resourceHint)) return true;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Infer API dependencies via path parameter matching.\r\n * POST endpoints produce IDs; GET/PUT/DELETE endpoints consume them.\r\n */\r\nexport function inferDependencies(endpoints: ApiEndpoint[]): ApiDependency[] {\r\n const dependencies: ApiDependency[] = [];\r\n const postEndpoints = endpoints.filter((ep) => ep.method === 'POST');\r\n\r\n for (const consumer of endpoints) {\r\n const consumedParams = consumer.pathParams.filter((p) => !EXCLUDED_PARAMS.has(p));\r\n if (consumedParams.length === 0) continue;\r\n\r\n for (const param of consumedParams) {\r\n if (param === 'id') {\r\n const basePath = consumer.path.replace(/\\/:id(\\/.*)?$/, '');\r\n const producer = postEndpoints.find((ep) => ep.path === basePath);\r\n if (producer && toNodeKey(producer) !== toNodeKey(consumer)) {\r\n dependencies.push({ from: consumer, to: producer, paramMapping: { [`:${param}`]: 'response.data.id' } });\r\n }\r\n continue;\r\n }\r\n\r\n const resourceHint = paramToResourceHint(param);\r\n if (!resourceHint) continue;\r\n\r\n const producer = postEndpoints.find((ep) => postProducesResource(ep, resourceHint));\r\n if (producer && toNodeKey(producer) !== toNodeKey(consumer)) {\r\n dependencies.push({ from: consumer, to: producer, paramMapping: { [`:${param}`]: 'response.data.id' } });\r\n }\r\n }\r\n }\r\n return deduplicateDependencies(dependencies);\r\n}\r\n\r\nfunction deduplicateDependencies(deps: ApiDependency[]): ApiDependency[] {\r\n const map = new Map<string, ApiDependency>();\r\n for (const dep of deps) {\r\n const key = `${toNodeKey(dep.from)}→${toNodeKey(dep.to)}`;\r\n if (map.has(key)) {\r\n Object.assign(map.get(key)!.paramMapping, dep.paramMapping);\r\n } else {\r\n map.set(key, { ...dep, paramMapping: { ...dep.paramMapping } });\r\n }\r\n }\r\n return Array.from(map.values());\r\n}\r\n\r\n/**\r\n * Build a directed graph from endpoints and their dependencies.\r\n */\r\nexport function buildGraph(\r\n endpoints: ApiEndpoint[],\r\n dependencies: ApiDependency[],\r\n): DirectedAcyclicGraph {\r\n const nodeSet = new Set<string>();\r\n for (const ep of endpoints) nodeSet.add(toNodeKey(ep));\r\n\r\n const edges: Array<{ from: string; to: string; label?: string }> = [];\r\n for (const dep of dependencies) {\r\n edges.push({\r\n from: toNodeKey(dep.from),\r\n to: toNodeKey(dep.to),\r\n label: Object.keys(dep.paramMapping).join(', ') || undefined,\r\n });\r\n }\r\n return { nodes: Array.from(nodeSet), edges };\r\n}\r\n\r\n/**\r\n * Detect cycles in a directed graph using DFS coloring.\r\n */\r\nexport function detectCycles(dag: DirectedAcyclicGraph): string[] {\r\n const adjacency = new Map<string, string[]>();\r\n for (const node of dag.nodes) adjacency.set(node, []);\r\n for (const edge of dag.edges) adjacency.get(edge.from)?.push(edge.to);\r\n\r\n const color = new Map<string, Color>();\r\n for (const node of dag.nodes) color.set(node, Color.WHITE);\r\n\r\n const warnings: string[] = [];\r\n const path: string[] = [];\r\n\r\n function dfs(node: string): void {\r\n color.set(node, Color.GRAY);\r\n path.push(node);\r\n for (const neighbor of adjacency.get(node) || []) {\r\n const nc = color.get(neighbor);\r\n if (nc === Color.GRAY) {\r\n const cycleStart = path.indexOf(neighbor);\r\n warnings.push(`Cycle detected: ${path.slice(cycleStart).concat(neighbor).join(' → ')}`);\r\n } else if (nc === Color.WHITE) {\r\n dfs(neighbor);\r\n }\r\n }\r\n path.pop();\r\n color.set(node, Color.BLACK);\r\n }\r\n\r\n for (const node of dag.nodes) {\r\n if (color.get(node) === Color.WHITE) dfs(node);\r\n }\r\n return warnings;\r\n}\r\n\r\n/**\r\n * Topological sort using Kahn's algorithm.\r\n */\r\nexport function topologicalSort(dag: DirectedAcyclicGraph): string[] {\r\n const inDegree = new Map<string, number>();\r\n const adjacency = new Map<string, string[]>();\r\n\r\n for (const node of dag.nodes) { inDegree.set(node, 0); adjacency.set(node, []); }\r\n for (const edge of dag.edges) {\r\n adjacency.get(edge.from)?.push(edge.to);\r\n inDegree.set(edge.to, (inDegree.get(edge.to) || 0) + 1);\r\n }\r\n\r\n const queue: string[] = [];\r\n for (const [node, degree] of inDegree) {\r\n if (degree === 0) queue.push(node);\r\n }\r\n\r\n const sorted: string[] = [];\r\n while (queue.length > 0) {\r\n const node = queue.shift()!;\r\n sorted.push(node);\r\n for (const neighbor of adjacency.get(node) || []) {\r\n const nd = (inDegree.get(neighbor) || 1) - 1;\r\n inDegree.set(neighbor, nd);\r\n if (nd === 0) queue.push(neighbor);\r\n }\r\n }\r\n return sorted;\r\n}\r\n\r\nexport interface ApiChainAnalyzer {\r\n analyze(endpoints: ApiEndpoint[]): ApiChainAnalysisResult;\r\n}\r\n\r\n/**\r\n * Analyze API endpoints: infer dependencies, build DAG, detect cycles, topological sort.\r\n */\r\nexport function createApiChainAnalyzer(): ApiChainAnalyzer {\r\n return {\r\n analyze(endpoints: ApiEndpoint[]): ApiChainAnalysisResult {\r\n const dependencies = inferDependencies(endpoints);\r\n const dag = buildGraph(endpoints, dependencies);\r\n const cycleWarnings = detectCycles(dag);\r\n\r\n return {\r\n moduleName: '',\r\n endpoints,\r\n dependencies,\r\n dag,\r\n hasCycles: cycleWarnings.length > 0,\r\n cycleWarnings,\r\n };\r\n },\r\n };\r\n}\r\n","import type { ERDiagramResult, TableSchema, ForeignKeyRelation } from '../types.js';\r\n\r\nexport interface ERDiagramGenerator {\r\n generate(tables: TableSchema[], relations: ForeignKeyRelation[]): ERDiagramResult;\r\n}\r\n\r\n/**\r\n * Map field type string to a short Mermaid ER type label.\r\n */\r\nfunction toMermaidType(fieldType: string): string {\r\n const upper = fieldType.toUpperCase();\r\n if (upper.startsWith('STRING')) return 'string';\r\n if (upper === 'BIGINT' || upper === 'INTEGER') return 'bigint';\r\n if (upper === 'BOOLEAN') return 'boolean';\r\n if (upper.startsWith('DATE') || upper === 'NOW') return 'datetime';\r\n if (upper === 'JSON' || upper === 'JSONB') return 'json';\r\n if (upper === 'TEXT') return 'text';\r\n if (upper === 'FLOAT' || upper === 'DOUBLE' || upper === 'DECIMAL') return 'float';\r\n if (upper === 'UUID') return 'uuid';\r\n if (upper.startsWith('ENUM')) return 'enum';\r\n return 'string';\r\n}\r\n\r\n/**\r\n * Mermaid requires entity names without special characters.\r\n */\r\nfunction sanitizeEntityName(name: string): string {\r\n return name.replace(/[^a-zA-Z0-9_]/g, '_');\r\n}\r\n\r\n/**\r\n * Generate Mermaid ER diagram syntax from parsed schemas and relations.\r\n */\r\nfunction generateMermaidER(tables: TableSchema[], relations: ForeignKeyRelation[]): string {\r\n const lines: string[] = ['erDiagram'];\r\n\r\n // Entity blocks\r\n for (const table of tables) {\r\n const entityName = sanitizeEntityName(table.tableName);\r\n lines.push(` ${entityName} {`);\r\n for (const field of table.fields) {\r\n const mType = toMermaidType(field.type);\r\n const pk = field.primaryKey ? 'PK' : '';\r\n const comment = field.comment ? ` \"${field.comment}\"` : '';\r\n lines.push(` ${mType} ${field.name}${pk ? ' ' + pk : ''}${comment}`);\r\n }\r\n lines.push(' }');\r\n }\r\n\r\n // Relationships\r\n const tableNames = new Set(tables.map((t) => t.tableName));\r\n for (const rel of relations) {\r\n if (!tableNames.has(rel.sourceTable) || !tableNames.has(rel.targetTable)) continue;\r\n\r\n const src = sanitizeEntityName(rel.sourceTable);\r\n const tgt = sanitizeEntityName(rel.targetTable);\r\n const linkStyle = rel.isCrossModule ? '..' : '--';\r\n\r\n let cardinality: string;\r\n switch (rel.cardinality) {\r\n case '1:N': cardinality = `||${linkStyle}o{`; break;\r\n case 'N:1': cardinality = `}o${linkStyle}||`; break;\r\n case '1:1': cardinality = `||${linkStyle}||`; break;\r\n default: cardinality = `||${linkStyle}o{`;\r\n }\r\n\r\n lines.push(` ${src} ${cardinality} ${tgt} : \"${rel.targetField}\"`);\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\nexport function createERDiagramGenerator(): ERDiagramGenerator {\r\n return {\r\n generate(tables: TableSchema[], relations: ForeignKeyRelation[]): ERDiagramResult {\r\n const mermaidText = generateMermaidER(tables, relations);\r\n return { tables, relations, mermaidText };\r\n },\r\n };\r\n}\r\n","import type { GeneratedTestFile, TestChain, TestStep } from '../types.js';\r\n\r\nexport interface TestCodeGenerator {\r\n generate(chains: TestChain[]): GeneratedTestFile[];\r\n}\r\n\r\n/**\r\n * Resolve a path parameter from the available createdIds.\r\n */\r\nfunction resolvePathParam(param: string, ids: string[]): string {\r\n // Try direct match (e.g., 'kbId' → look for 'kbId' in ids)\r\n if (ids.includes(param)) return `createdIds['${param}']`;\r\n // Try with 'Id' suffix stripped\r\n const stripped = param.endsWith('Id') ? param.slice(0, -2) : param;\r\n if (ids.includes(stripped)) return `createdIds['${stripped}']`;\r\n // Generic id\r\n if (param === 'id') return `createdIds['id']`;\r\n return `createdIds['${param}'] || '1'`;\r\n}\r\n\r\n/**\r\n * Generate URL building code for a test step.\r\n */\r\nfunction buildUrlCode(step: TestStep): string {\r\n const pathParams = step.endpoint.pathParams;\r\n if (pathParams.length === 0) return `const url = '${step.endpoint.path}';`;\r\n\r\n let urlTemplate = step.endpoint.path;\r\n const replacements: string[] = [];\r\n for (const param of pathParams) {\r\n urlTemplate = urlTemplate.replace(`:${param}`, `\\${${resolvePathParam(param, pathParams)}}`);\r\n replacements.push(param);\r\n }\r\n return `const url = \\`${urlTemplate}\\`;`;\r\n}\r\n\r\n/**\r\n * Generate assertion code for a test step.\r\n */\r\nfunction generateAssertions(step: TestStep): string[] {\r\n const lines: string[] = [];\r\n if (step.assertions.length > 0) {\r\n for (const assertion of step.assertions) {\r\n lines.push(` expect(${assertion}).toBeTruthy();`);\r\n }\r\n } else {\r\n // Default assertions\r\n if (step.endpoint.method === 'POST') {\r\n lines.push(' expect(response.status()).toBeLessThan(400);');\r\n lines.push(' const body = await response.json();');\r\n lines.push(\" if (body.data?.id) createdIds['id'] = body.data.id;\");\r\n } else if (step.endpoint.method === 'GET') {\r\n lines.push(' expect(response.ok()).toBeTruthy();');\r\n } else if (step.endpoint.method === 'DELETE') {\r\n lines.push(' expect(response.status()).toBeLessThan(400);');\r\n } else {\r\n lines.push(' expect(response.status()).toBeLessThan(400);');\r\n }\r\n }\r\n return lines;\r\n}\r\n\r\n/**\r\n * Generate a single Playwright test file from a test chain.\r\n */\r\nfunction generateTestFile(chain: TestChain): string {\r\n const lines: string[] = [];\r\n\r\n lines.push(`import { test, expect } from '@playwright/test';`);\r\n lines.push('');\r\n lines.push(`test.describe('${chain.name}', () => {`);\r\n lines.push(\" const createdIds: Record<string, string> = {};\");\r\n lines.push('');\r\n\r\n for (const step of chain.steps) {\r\n lines.push(` test('Step ${step.order}: ${step.description}', async ({ request }) => {`);\r\n lines.push(` // ${step.action}: ${step.endpoint.method} ${step.endpoint.path}`);\r\n lines.push(` ${buildUrlCode(step)}`);\r\n lines.push('');\r\n\r\n if (step.endpoint.method === 'GET') {\r\n lines.push(' const response = await request.get(url);');\r\n } else if (step.endpoint.method === 'POST') {\r\n lines.push(' const response = await request.post(url, { data: {} });');\r\n } else if (step.endpoint.method === 'PUT') {\r\n lines.push(' const response = await request.put(url, { data: {} });');\r\n } else if (step.endpoint.method === 'DELETE') {\r\n lines.push(' const response = await request.delete(url);');\r\n } else if (step.endpoint.method === 'PATCH') {\r\n lines.push(' const response = await request.patch(url, { data: {} });');\r\n }\r\n\r\n lines.push('');\r\n lines.push(...generateAssertions(step));\r\n lines.push(' });');\r\n lines.push('');\r\n }\r\n\r\n lines.push('});');\r\n return lines.join('\\n');\r\n}\r\n\r\nexport function createTestCodeGenerator(): TestCodeGenerator {\r\n return {\r\n generate(chains: TestChain[]): GeneratedTestFile[] {\r\n return chains.map((chain) => ({\r\n filePath: `${chain.module}/${chain.name.replace(/\\s+/g, '-').toLowerCase()}.spec.ts`,\r\n content: generateTestFile(chain),\r\n module: chain.module,\r\n chain: chain.name,\r\n }));\r\n },\r\n };\r\n}\r\n","import type {\r\n ValidationError,\r\n ModuleTestConfig,\r\n ModuleConfigValidationContext,\r\n ModuleConfigValidationResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n} from '../types.js';\r\nimport { validateSchema } from './schema-validator.js';\r\nimport { validateSemantic } from './semantic-validator.js';\r\nimport { validateDryrun } from './dryrun-validator.js';\r\n\r\nconst REQUIRED_FIELDS = ['backendRoot'];\r\n\r\nconst VALID_ADAPTERS = ['sequelize', 'typeorm', 'prisma', 'drizzle'];\r\nconst VALID_STEPS = ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'];\r\nconst VALID_LLM_PROVIDERS = ['openai', 'zhipu', 'ollama', 'custom'];\r\nconst VALID_REPORT_FORMATS = ['html', 'json', 'markdown'];\r\nconst VALID_HEAL_MODES = ['config-only', 'config-and-source'];\r\n\r\n/**\r\n * Validate an OpenCroc configuration object.\r\n * Returns an array of ValidationErrors (empty = valid).\r\n */\r\nexport function validateConfig(config: Record<string, unknown>): ValidationError[] {\r\n const errors: ValidationError[] = [];\r\n\r\n // Required fields\r\n for (const field of REQUIRED_FIELDS) {\r\n if (!config[field]) {\r\n errors.push({\r\n module: 'config',\r\n field,\r\n message: `Missing required field: ${field}`,\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n\r\n // backendRoot must be a string\r\n if (config.backendRoot && typeof config.backendRoot !== 'string') {\r\n errors.push({\r\n module: 'config',\r\n field: 'backendRoot',\r\n message: 'backendRoot must be a string path',\r\n severity: 'error',\r\n });\r\n }\r\n\r\n // adapter validation\r\n if (config.adapter && typeof config.adapter === 'string') {\r\n if (!VALID_ADAPTERS.includes(config.adapter)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'adapter',\r\n message: `Invalid adapter: ${config.adapter}. Must be one of: ${VALID_ADAPTERS.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n\r\n // steps validation\r\n if (config.steps && Array.isArray(config.steps)) {\r\n for (const step of config.steps) {\r\n if (!VALID_STEPS.includes(step as string)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'steps',\r\n message: `Invalid pipeline step: ${step}. Must be one of: ${VALID_STEPS.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n }\r\n\r\n // LLM config validation\r\n if (config.llm && typeof config.llm === 'object') {\r\n const llm = config.llm as Record<string, unknown>;\r\n if (llm.provider && !VALID_LLM_PROVIDERS.includes(llm.provider as string)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'llm.provider',\r\n message: `Invalid LLM provider: ${llm.provider}. Must be one of: ${VALID_LLM_PROVIDERS.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n if (llm.provider && llm.provider !== 'ollama' && !llm.apiKey) {\r\n errors.push({\r\n module: 'config',\r\n field: 'llm.apiKey',\r\n message: 'LLM apiKey is required for cloud providers',\r\n severity: 'warning',\r\n });\r\n }\r\n }\r\n\r\n // Report config validation\r\n if (config.report && typeof config.report === 'object') {\r\n const report = config.report as Record<string, unknown>;\r\n if (report.format && Array.isArray(report.format)) {\r\n for (const fmt of report.format) {\r\n if (!VALID_REPORT_FORMATS.includes(fmt as string)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'report.format',\r\n message: `Invalid report format: ${fmt}. Must be one of: ${VALID_REPORT_FORMATS.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Self-healing config validation\r\n if (config.selfHealing && typeof config.selfHealing === 'object') {\r\n const sh = config.selfHealing as Record<string, unknown>;\r\n if (sh.mode && !VALID_HEAL_MODES.includes(sh.mode as string)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'selfHealing.mode',\r\n message: `Invalid self-healing mode: ${sh.mode}. Must be one of: ${VALID_HEAL_MODES.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n if (sh.maxIterations && (typeof sh.maxIterations !== 'number' || sh.maxIterations < 1)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'selfHealing.maxIterations',\r\n message: 'maxIterations must be a positive number',\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n\r\n // Execution hooks validation\r\n if (config.execution && typeof config.execution === 'object') {\r\n const execution = config.execution as Record<string, unknown>;\r\n const hookFields = ['setupHook', 'authHook', 'teardownHook'];\r\n\r\n for (const hookField of hookFields) {\r\n const hook = execution[hookField];\r\n if (hook === undefined) continue;\r\n\r\n if (typeof hook === 'string') continue;\r\n\r\n if (typeof hook !== 'object' || hook === null) {\r\n errors.push({\r\n module: 'config',\r\n field: `execution.${hookField}`,\r\n message: `${hookField} must be a string command or an object { command, args?, cwd? }`,\r\n severity: 'error',\r\n });\r\n continue;\r\n }\r\n\r\n const hookObj = hook as Record<string, unknown>;\r\n if (typeof hookObj.command !== 'string' || hookObj.command.trim() === '') {\r\n errors.push({\r\n module: 'config',\r\n field: `execution.${hookField}.command`,\r\n message: 'command is required and must be a non-empty string',\r\n severity: 'error',\r\n });\r\n }\r\n\r\n if (hookObj.args !== undefined && (!Array.isArray(hookObj.args) || hookObj.args.some((a) => typeof a !== 'string'))) {\r\n errors.push({\r\n module: 'config',\r\n field: `execution.${hookField}.args`,\r\n message: 'args must be an array of strings',\r\n severity: 'error',\r\n });\r\n }\r\n\r\n if (hookObj.cwd !== undefined && typeof hookObj.cwd !== 'string') {\r\n errors.push({\r\n module: 'config',\r\n field: `execution.${hookField}.cwd`,\r\n message: 'cwd must be a string path',\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n }\r\n\r\n return errors;\r\n}\r\n\r\n// ============================================================\r\n// Three-Layer Module Config Validator\r\n// ============================================================\r\n\r\nexport interface ValidateModuleConfigOptions {\r\n stopOnFailure?: boolean;\r\n skipLayers?: Array<'schema' | 'semantic' | 'dryrun'>;\r\n}\r\n\r\nexport function validateModuleConfig(\r\n config: unknown,\r\n context?: ModuleConfigValidationContext,\r\n options?: ValidateModuleConfigOptions,\r\n): ModuleConfigValidationResult {\r\n const stopOnFailure = options?.stopOnFailure ?? true;\r\n const skipLayers = new Set(options?.skipLayers ?? []);\r\n\r\n const allErrors: ModuleConfigValidationError[] = [];\r\n const allWarnings: ModuleConfigValidationWarning[] = [];\r\n const result: ModuleConfigValidationResult = {\r\n passed: false,\r\n errors: allErrors,\r\n warnings: allWarnings,\r\n };\r\n\r\n if (!skipLayers.has('schema')) {\r\n const schemaResult = validateSchema(config);\r\n result.schemaResult = schemaResult;\r\n allErrors.push(...schemaResult.errors);\r\n allWarnings.push(...schemaResult.warnings);\r\n\r\n if (!schemaResult.passed) {\r\n result.failedAtLayer = 'schema';\r\n if (stopOnFailure) return result;\r\n } else {\r\n result.lastPassedLayer = 'schema';\r\n }\r\n }\r\n\r\n const validConfig = config as ModuleTestConfig;\r\n\r\n if (!skipLayers.has('semantic')) {\r\n if (!context) {\r\n allWarnings.push({ layer: 'semantic', path: '', message: 'ValidationContext not provided, skipping semantic validation' });\r\n } else {\r\n const semanticResult = validateSemantic(validConfig, context);\r\n result.semanticResult = semanticResult;\r\n allErrors.push(...semanticResult.errors);\r\n allWarnings.push(...semanticResult.warnings);\r\n\r\n if (!semanticResult.passed) {\r\n result.failedAtLayer = result.failedAtLayer || 'semantic';\r\n if (stopOnFailure) return result;\r\n } else {\r\n result.lastPassedLayer = 'semantic';\r\n }\r\n }\r\n }\r\n\r\n if (!skipLayers.has('dryrun')) {\r\n if (!context) {\r\n allWarnings.push({ layer: 'dryrun', path: '', message: 'ValidationContext not provided, skipping dry-run validation' });\r\n } else {\r\n const dryrunResult = validateDryrun(validConfig, context);\r\n result.dryrunResult = dryrunResult;\r\n allErrors.push(...dryrunResult.errors);\r\n allWarnings.push(...dryrunResult.warnings);\r\n\r\n if (!dryrunResult.passed) {\r\n result.failedAtLayer = result.failedAtLayer || 'dryrun';\r\n } else {\r\n result.lastPassedLayer = 'dryrun';\r\n }\r\n }\r\n }\r\n\r\n result.passed = allErrors.length === 0;\r\n return result;\r\n}\r\n\r\nexport function formatValidationResult(result: ModuleConfigValidationResult): string {\r\n const lines: string[] = [];\r\n lines.push(result.passed ? '\\u2705 Validation PASSED' : '\\u274c Validation FAILED');\r\n if (result.failedAtLayer) lines.push(` Failed at layer: ${result.failedAtLayer}`);\r\n if (result.lastPassedLayer) lines.push(` Last passed layer: ${result.lastPassedLayer}`);\r\n\r\n if (result.errors.length > 0) {\r\n lines.push('', `Errors (${result.errors.length}):`);\r\n for (const err of result.errors) {\r\n lines.push(` [${err.layer}] ${err.path}: ${err.message}`);\r\n if (err.suggestion) lines.push(` \\ud83d\\udca1 ${err.suggestion}`);\r\n }\r\n }\r\n\r\n if (result.warnings.length > 0) {\r\n lines.push('', `Warnings (${result.warnings.length}):`);\r\n for (const warn of result.warnings) {\r\n lines.push(` [${warn.layer}] ${warn.path}: ${warn.message}`);\r\n }\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n","/**\r\n * Schema Validator — Layer 1 of three-layer module config validation.\r\n * Checks structural integrity, field types, format conventions.\r\n */\r\n\r\nimport type {\r\n LayerValidationResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n} from '../types.js';\r\n\r\nconst VALID_HTTP_METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'] as const;\r\n\r\nexport function validateSchema(config: unknown): LayerValidationResult {\r\n const errors: ModuleConfigValidationError[] = [];\r\n const warnings: ModuleConfigValidationWarning[] = [];\r\n\r\n if (config === null || config === undefined || typeof config !== 'object') {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: '', message: 'Config must be a non-null object' });\r\n return { passed: false, layer: 'schema', errors, warnings };\r\n }\r\n\r\n const cfg = config as Record<string, unknown>;\r\n\r\n // Required top-level fields\r\n const required: Array<{ name: string; type: string }> = [\r\n { name: 'moduleName', type: 'string' },\r\n { name: 'version', type: 'string' },\r\n { name: 'generatedAt', type: 'string' },\r\n { name: 'bodyTemplates', type: 'object' },\r\n { name: 'paramRewrites', type: 'object' },\r\n { name: 'idAliases', type: 'array' },\r\n { name: 'seed', type: 'array' },\r\n ];\r\n\r\n for (const f of required) {\r\n if (cfg[f.name] === undefined || cfg[f.name] === null) {\r\n errors.push({\r\n layer: 'schema', type: 'missing-field', path: f.name,\r\n message: `Required field '${f.name}' is missing`,\r\n suggestion: `Add '${f.name}' field of type ${f.type}`,\r\n });\r\n }\r\n }\r\n\r\n // Field type checks\r\n validateFieldTypes(cfg, errors);\r\n\r\n // bodyTemplates structure\r\n if (cfg.bodyTemplates && typeof cfg.bodyTemplates === 'object' && !Array.isArray(cfg.bodyTemplates)) {\r\n validateBodyTemplates(cfg.bodyTemplates as Record<string, unknown>, errors, warnings);\r\n }\r\n\r\n // paramRewrites structure\r\n if (cfg.paramRewrites && typeof cfg.paramRewrites === 'object' && !Array.isArray(cfg.paramRewrites)) {\r\n validateParamRewrites(cfg.paramRewrites as Record<string, unknown>, errors, warnings);\r\n }\r\n\r\n // idAliases structure\r\n if (Array.isArray(cfg.idAliases)) {\r\n validateIdAliases(cfg.idAliases, errors);\r\n }\r\n\r\n // seed array\r\n if (Array.isArray(cfg.seed)) {\r\n validateSeedArray(cfg.seed, errors, warnings);\r\n }\r\n\r\n // version format\r\n if (typeof cfg.version === 'string' && !/^\\d+\\.\\d+(\\.\\d+)?$/.test(cfg.version)) {\r\n warnings.push({ layer: 'schema', path: 'version', message: `Version '${cfg.version}' does not follow semver format` });\r\n }\r\n\r\n return { passed: errors.length === 0, layer: 'schema', errors, warnings };\r\n}\r\n\r\nfunction validateFieldTypes(cfg: Record<string, unknown>, errors: ModuleConfigValidationError[]): void {\r\n if (cfg.moduleName !== undefined && typeof cfg.moduleName !== 'string') {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'moduleName', message: `'moduleName' must be a string` });\r\n } else if (typeof cfg.moduleName === 'string' && cfg.moduleName.trim() === '') {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: 'moduleName', message: \"'moduleName' must not be empty\" });\r\n }\r\n\r\n if (cfg.bodyTemplates !== undefined && (typeof cfg.bodyTemplates !== 'object' || Array.isArray(cfg.bodyTemplates))) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'bodyTemplates', message: \"'bodyTemplates' must be a plain object\" });\r\n }\r\n if (cfg.paramRewrites !== undefined && (typeof cfg.paramRewrites !== 'object' || Array.isArray(cfg.paramRewrites))) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'paramRewrites', message: \"'paramRewrites' must be a plain object\" });\r\n }\r\n if (cfg.idAliases !== undefined && !Array.isArray(cfg.idAliases)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'idAliases', message: \"'idAliases' must be an array\" });\r\n }\r\n if (cfg.seed !== undefined && !Array.isArray(cfg.seed)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'seed', message: \"'seed' must be an array\" });\r\n }\r\n}\r\n\r\nfunction validateBodyTemplates(\r\n templates: Record<string, unknown>,\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (const [key, value] of Object.entries(templates)) {\r\n const p = `bodyTemplates.${key}`;\r\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: p, message: `Body template '${key}' must be a plain object` });\r\n continue;\r\n }\r\n if (!/^(GET|POST|PUT|PATCH|DELETE)\\s+\\//.test(key)) {\r\n warnings.push({ layer: 'schema', path: p, message: `Body template key '${key}' should follow format 'METHOD /path'` });\r\n }\r\n if (Object.keys(value).length === 0) {\r\n warnings.push({ layer: 'schema', path: p, message: `Body template '${key}' is empty` });\r\n }\r\n }\r\n}\r\n\r\nfunction validateParamRewrites(\r\n rewrites: Record<string, unknown>,\r\n errors: ModuleConfigValidationError[],\r\n _warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (const [key, value] of Object.entries(rewrites)) {\r\n const p = `paramRewrites.${key}`;\r\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: p, message: `Param rewrite '${key}' must be a plain object` });\r\n continue;\r\n }\r\n for (const [paramName, paramValue] of Object.entries(value as Record<string, unknown>)) {\r\n if (typeof paramValue !== 'string') {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: `${p}.${paramName}`, message: `Param rewrite value for '${paramName}' must be a string` });\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction validateIdAliases(aliases: unknown[], errors: ModuleConfigValidationError[]): void {\r\n for (let i = 0; i < aliases.length; i++) {\r\n const alias = aliases[i] as Record<string, unknown> | null;\r\n const p = `idAliases[${i}]`;\r\n if (typeof alias !== 'object' || alias === null) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: p, message: `idAlias at index ${i} must be an object` });\r\n continue;\r\n }\r\n if (typeof alias.pathPattern !== 'string') {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.pathPattern`, message: `idAlias at index ${i} must have a string 'pathPattern'` });\r\n }\r\n if (typeof alias.alias !== 'string') {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.alias`, message: `idAlias at index ${i} must have a string 'alias'` });\r\n }\r\n }\r\n}\r\n\r\nfunction validateSeedArray(\r\n seed: unknown[],\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n if (seed.length === 0) {\r\n warnings.push({ layer: 'schema', path: 'seed', message: 'Seed array is empty, no setup steps will be executed' });\r\n return;\r\n }\r\n\r\n const capturedVars = new Set<string>();\r\n const stepNumbers = new Set<number>();\r\n\r\n for (let i = 0; i < seed.length; i++) {\r\n const step = seed[i] as Record<string, unknown> | null;\r\n const p = `seed[${i}]`;\r\n if (typeof step !== 'object' || step === null) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: p, message: `Seed step at index ${i} must be an object` });\r\n continue;\r\n }\r\n\r\n // step number\r\n if (step.step === undefined) {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.step`, message: `Seed step at index ${i} is missing 'step' number` });\r\n } else if (typeof step.step !== 'number' || !Number.isInteger(step.step)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: `${p}.step`, message: `'step' must be an integer` });\r\n } else {\r\n if (stepNumbers.has(step.step)) {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: `${p}.step`, message: `Duplicate step number ${step.step}` });\r\n }\r\n stepNumbers.add(step.step);\r\n }\r\n\r\n // method\r\n if (step.method === undefined) {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.method`, message: `Seed step at index ${i} is missing 'method'` });\r\n } else if (typeof step.method !== 'string' || !(VALID_HTTP_METHODS as readonly string[]).includes(step.method)) {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: `${p}.method`, message: `'method' must be one of ${VALID_HTTP_METHODS.join(', ')}` });\r\n }\r\n\r\n // path\r\n if (step.path === undefined) {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.path`, message: `Seed step at index ${i} is missing 'path'` });\r\n } else if (typeof step.path !== 'string' || !(step.path as string).startsWith('/')) {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: `${p}.path`, message: `'path' must start with '/'` });\r\n }\r\n\r\n // required\r\n if (step.required === undefined) {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.required`, message: `Seed step at index ${i} is missing 'required'` });\r\n }\r\n\r\n // body\r\n if (step.body !== undefined && (typeof step.body !== 'object' || step.body === null || Array.isArray(step.body))) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: `${p}.body`, message: `'body' must be a plain object` });\r\n } else if (step.body === undefined && typeof step.method === 'string' && ['POST', 'PUT', 'PATCH'].includes(step.method)) {\r\n warnings.push({ layer: 'schema', path: `${p}.body`, message: `${step.method} step at index ${i} has no body template` });\r\n }\r\n\r\n // captureAs uniqueness\r\n if (typeof step.captureAs === 'string') {\r\n if (capturedVars.has(step.captureAs)) {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: `${p}.captureAs`, message: `Duplicate captureAs variable '${step.captureAs}'` });\r\n }\r\n capturedVars.add(step.captureAs);\r\n }\r\n\r\n // dependsOn reference check\r\n if (Array.isArray(step.dependsOn)) {\r\n for (const dep of step.dependsOn) {\r\n if (typeof dep === 'string' && !capturedVars.has(dep)) {\r\n errors.push({\r\n layer: 'schema', type: 'dependency-missing', path: `${p}.dependsOn`,\r\n message: `Seed step ${step.step ?? i} depends on '${dep}' not captured by any preceding step`,\r\n suggestion: `Ensure a preceding step has captureAs: '${dep}'`,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * Semantic Validator — Layer 2 of three-layer module config validation.\r\n * Checks that config matches actual source code (routes, DTO fields, dependencies).\r\n */\r\n\r\nimport type {\r\n ModuleTestConfig,\r\n SeedStep,\r\n ApiEndpoint,\r\n DTOInfo,\r\n ModuleConfigValidationContext,\r\n LayerValidationResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n} from '../types.js';\r\n\r\nexport function validateSemantic(\r\n config: ModuleTestConfig,\r\n context: ModuleConfigValidationContext,\r\n): LayerValidationResult {\r\n const errors: ModuleConfigValidationError[] = [];\r\n const warnings: ModuleConfigValidationWarning[] = [];\r\n\r\n validateBodyTemplatesSemantic(config, context, errors, warnings);\r\n validateParamRewritesSemantic(config, context, errors, warnings);\r\n validateIdAliasesSemantic(config, context, warnings);\r\n validateSeedRoutesSemantic(config, context, errors);\r\n validateSeedDependenciesSemantic(config, errors, warnings);\r\n\r\n return { passed: errors.length === 0, layer: 'semantic', errors, warnings };\r\n}\r\n\r\n// ============================================================\r\n// Helpers\r\n// ============================================================\r\n\r\nfunction normalizePath(p: string): string {\r\n return p.replace(/\\/+$/, '').replace(/\\/+/g, '/');\r\n}\r\n\r\nfunction extractPathParams(routePath: string): string[] {\r\n const params: string[] = [];\r\n const regex = /:(\\w+)/g;\r\n let match;\r\n while ((match = regex.exec(routePath)) !== null) params.push(match[1]);\r\n return params;\r\n}\r\n\r\nfunction findMatchingEndpoint(\r\n method: string, configPath: string, endpoints: ApiEndpoint[],\r\n): ApiEndpoint | undefined {\r\n const normalized = normalizePath(configPath);\r\n return endpoints.find((ep) => {\r\n if (ep.method !== method.toUpperCase()) return false;\r\n const epNorm = normalizePath(ep.path);\r\n if (epNorm === normalized) return true;\r\n const cSegs = normalized.split('/');\r\n const eSegs = epNorm.split('/');\r\n if (cSegs.length !== eSegs.length) return false;\r\n return cSegs.every((seg, idx) => seg === eSegs[idx] || seg.startsWith(':') || eSegs[idx].startsWith(':'));\r\n });\r\n}\r\n\r\nfunction findMatchingDTO(method: string, dtos: DTOInfo[]): DTOInfo | undefined {\r\n if (dtos.length === 0) return undefined;\r\n if (['POST'].includes(method)) return dtos.find((d) => /Create|Input|Request/.test(d.name));\r\n if (['PUT', 'PATCH'].includes(method)) return dtos.find((d) => /Update/.test(d.name)) || dtos.find((d) => /Create|Input/.test(d.name));\r\n if (['GET'].includes(method)) return dtos.find((d) => /Query|List|Params/.test(d.name));\r\n return undefined;\r\n}\r\n\r\n// ============================================================\r\n// Validators\r\n// ============================================================\r\n\r\nfunction validateBodyTemplatesSemantic(\r\n config: ModuleTestConfig,\r\n ctx: ModuleConfigValidationContext,\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (const [key, body] of Object.entries(config.bodyTemplates)) {\r\n const p = `bodyTemplates.${key}`;\r\n const spaceIdx = key.indexOf(' ');\r\n if (spaceIdx === -1) continue;\r\n\r\n const method = key.substring(0, spaceIdx).toUpperCase();\r\n const routePath = key.substring(spaceIdx + 1);\r\n\r\n const endpoint = findMatchingEndpoint(method, routePath, ctx.endpoints);\r\n if (!endpoint) {\r\n errors.push({\r\n layer: 'semantic', type: 'interface-not-found', path: p,\r\n message: `Route '${method} ${routePath}' in bodyTemplates does not match any parsed API endpoint`,\r\n suggestion: `Check that the controller defines ${method} ${routePath}`,\r\n });\r\n continue;\r\n }\r\n\r\n const bodyFields = Object.keys(body);\r\n if (bodyFields.length === 0) continue;\r\n\r\n const dto = findMatchingDTO(method, ctx.dtos);\r\n if (!dto) {\r\n warnings.push({ layer: 'semantic', path: p, message: `No matching DTO found for '${method} ${routePath}', cannot verify field completeness` });\r\n continue;\r\n }\r\n\r\n const dtoFieldNames = new Set(dto.fields.map((f) => f.name));\r\n for (const fieldName of bodyFields) {\r\n if (!dtoFieldNames.has(fieldName)) {\r\n warnings.push({ layer: 'semantic', path: `${p}.${fieldName}`, message: `Field '${fieldName}' in body template not found in DTO '${dto.name}'` });\r\n }\r\n }\r\n\r\n const bodyFieldSet = new Set(bodyFields);\r\n for (const field of dto.fields) {\r\n if (field.required && !field.isSystemField && !bodyFieldSet.has(field.name)) {\r\n warnings.push({ layer: 'semantic', path: p, message: `Required DTO field '${field.name}' (from ${dto.name}) not present in body template` });\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction validateParamRewritesSemantic(\r\n config: ModuleTestConfig,\r\n ctx: ModuleConfigValidationContext,\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (const [key, mapping] of Object.entries(config.paramRewrites)) {\r\n const p = `paramRewrites.${key}`;\r\n const spaceIdx = key.indexOf(' ');\r\n if (spaceIdx === -1) continue;\r\n\r\n const method = key.substring(0, spaceIdx).toUpperCase();\r\n const routePath = key.substring(spaceIdx + 1);\r\n\r\n const endpoint = findMatchingEndpoint(method, routePath, ctx.endpoints);\r\n if (!endpoint) {\r\n errors.push({ layer: 'semantic', type: 'param-mapping-invalid', path: p, message: `Route '${method} ${routePath}' in paramRewrites does not match any parsed API endpoint` });\r\n continue;\r\n }\r\n\r\n const actualParams = new Set(extractPathParams(endpoint.path));\r\n for (const paramName of Object.keys(mapping)) {\r\n if (!actualParams.has(paramName)) {\r\n warnings.push({ layer: 'semantic', path: `${p}.${paramName}`, message: `Param '${paramName}' in paramRewrites not found in route path params [${[...actualParams].join(', ')}]` });\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction validateIdAliasesSemantic(\r\n config: ModuleTestConfig,\r\n ctx: ModuleConfigValidationContext,\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (let i = 0; i < config.idAliases.length; i++) {\r\n const alias = config.idAliases[i];\r\n const matched = ctx.endpoints.some((ep) => {\r\n try { return new RegExp(alias.pathPattern).test(ep.path); } catch { return ep.path.includes(alias.pathPattern); }\r\n });\r\n if (!matched) {\r\n warnings.push({ layer: 'semantic', path: `idAliases[${i}].pathPattern`, message: `idAlias pathPattern '${alias.pathPattern}' does not match any known API route` });\r\n }\r\n }\r\n}\r\n\r\nfunction validateSeedRoutesSemantic(\r\n config: ModuleTestConfig,\r\n ctx: ModuleConfigValidationContext,\r\n errors: ModuleConfigValidationError[],\r\n): void {\r\n for (let i = 0; i < config.seed.length; i++) {\r\n const step = config.seed[i];\r\n const endpoint = findMatchingEndpoint(step.method, step.path, ctx.endpoints);\r\n if (!endpoint) {\r\n errors.push({\r\n layer: 'semantic', type: 'interface-not-found', path: `seed[${i}].path`,\r\n message: `Seed step ${step.step}: route '${step.method} ${step.path}' does not match any parsed API endpoint`,\r\n suggestion: `Verify that '${step.method} ${step.path}' exists in the module controllers`,\r\n });\r\n }\r\n }\r\n}\r\n\r\nfunction validateSeedDependenciesSemantic(\r\n config: ModuleTestConfig,\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n if (config.seed.length === 0) return;\r\n\r\n const capturedSet = new Set<string>();\r\n const variablePattern = /\\{\\{(\\w+)\\}\\}|\\$\\{(\\w+)\\}/g;\r\n\r\n for (let i = 0; i < config.seed.length; i++) {\r\n const step = config.seed[i];\r\n\r\n // Check body variable references\r\n if (step.body) {\r\n const bodyStr = JSON.stringify(step.body);\r\n variablePattern.lastIndex = 0;\r\n let match;\r\n while ((match = variablePattern.exec(bodyStr)) !== null) {\r\n const varName = match[1] || match[2];\r\n if (!capturedSet.has(varName)) {\r\n warnings.push({ layer: 'semantic', path: `seed[${i}].body`, message: `Body references variable '${varName}' which may not be captured by a preceding seed step` });\r\n }\r\n }\r\n }\r\n\r\n // Check path variable references\r\n if (step.path) {\r\n variablePattern.lastIndex = 0;\r\n let match;\r\n while ((match = variablePattern.exec(step.path)) !== null) {\r\n const varName = match[1] || match[2];\r\n if (!capturedSet.has(varName)) {\r\n warnings.push({ layer: 'semantic', path: `seed[${i}].path`, message: `Path references variable '${varName}' which may not be captured by a preceding seed step` });\r\n }\r\n }\r\n }\r\n\r\n if (step.captureAs) capturedSet.add(step.captureAs);\r\n }\r\n\r\n // Cycle detection via DFS\r\n detectDependencyCycle(config.seed, errors);\r\n}\r\n\r\nfunction detectDependencyCycle(seed: SeedStep[], errors: ModuleConfigValidationError[]): void {\r\n const graph = new Map<string, string[]>();\r\n for (const step of seed) {\r\n if (step.captureAs) {\r\n graph.set(step.captureAs, step.dependsOn || []);\r\n }\r\n }\r\n\r\n const visited = new Set<string>();\r\n const inStack = new Set<string>();\r\n\r\n function dfs(node: string): boolean {\r\n if (inStack.has(node)) return true;\r\n if (visited.has(node)) return false;\r\n visited.add(node);\r\n inStack.add(node);\r\n for (const neighbor of graph.get(node) || []) {\r\n if (dfs(neighbor)) {\r\n errors.push({ layer: 'semantic', type: 'dependency-cycle', path: 'seed', message: `Circular dependency detected involving '${node}' → '${neighbor}'` });\r\n return true;\r\n }\r\n }\r\n inStack.delete(node);\r\n return false;\r\n }\r\n\r\n for (const node of graph.keys()) {\r\n if (!visited.has(node)) dfs(node);\r\n }\r\n}\r\n","/**\r\n * Dry-run Validator — Layer 3 of three-layer module config validation.\r\n * Generates temporary TypeScript code from config and runs ts-morph compile check.\r\n */\r\n\r\nimport { Project, DiagnosticCategory } from 'ts-morph';\r\nimport type {\r\n ModuleTestConfig,\r\n ModuleConfigValidationContext,\r\n LayerValidationResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n} from '../types.js';\r\n\r\nexport function validateDryrun(\r\n config: ModuleTestConfig,\r\n _context: ModuleConfigValidationContext,\r\n): LayerValidationResult {\r\n const errors: ModuleConfigValidationError[] = [];\r\n const warnings: ModuleConfigValidationWarning[] = [];\r\n\r\n const project = new Project({\r\n compilerOptions: {\r\n strict: false,\r\n noEmit: true,\r\n target: 2, // ES2015\r\n module: 1, // CommonJS\r\n esModuleInterop: true,\r\n skipLibCheck: true,\r\n },\r\n useInMemoryFileSystem: true,\r\n });\r\n\r\n // Add helper type declarations\r\n project.createSourceFile(\r\n '__helpers.d.ts',\r\n `\r\ndeclare function apiRequest(\r\n method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH',\r\n path: string,\r\n body?: Record<string, any>,\r\n params?: Record<string, string>\r\n): Promise<{ status: number; data: any }>;\r\ndeclare function captureId(response: { data: any }, field?: string): string;\r\ndeclare const tenantId: string;\r\ndeclare const captured: Record<string, string>;\r\n`,\r\n );\r\n\r\n // Generate and check bodyTemplates test code\r\n const bodyCode = generateBodyTemplateTestCode(config);\r\n if (bodyCode) {\r\n const bodyFile = project.createSourceFile('__dryrun_body_test.ts', bodyCode);\r\n for (const diag of bodyFile.getPreEmitDiagnostics()) {\r\n const msg = diag.getMessageText();\r\n const msgStr = typeof msg === 'string' ? msg : msg.getMessageText();\r\n const line = diag.getLineNumber();\r\n const location = line ? `bodyTemplates (line ${line})` : 'bodyTemplates';\r\n\r\n if (diag.getCategory() === DiagnosticCategory.Error) {\r\n errors.push({\r\n layer: 'dryrun', type: 'compile-error', path: location,\r\n message: `TypeScript compile error: ${msgStr}`,\r\n suggestion: 'Fix the body template that causes this type error',\r\n });\r\n } else if (diag.getCategory() === DiagnosticCategory.Warning) {\r\n warnings.push({ layer: 'dryrun', path: location, message: `TypeScript warning: ${msgStr}` });\r\n }\r\n }\r\n }\r\n\r\n // Generate and check seed test code\r\n const seedCode = generateSeedTestCode(config);\r\n if (seedCode) {\r\n const seedFile = project.createSourceFile('__dryrun_seed_test.ts', seedCode);\r\n for (const diag of seedFile.getPreEmitDiagnostics()) {\r\n const msg = diag.getMessageText();\r\n const msgStr = typeof msg === 'string' ? msg : msg.getMessageText();\r\n const line = diag.getLineNumber();\r\n const location = line ? `seed (line ${line})` : 'seed';\r\n\r\n if (diag.getCategory() === DiagnosticCategory.Error) {\r\n errors.push({\r\n layer: 'dryrun', type: 'compile-error', path: location,\r\n message: `TypeScript compile error: ${msgStr}`,\r\n suggestion: 'Fix the seed step that causes this type error',\r\n });\r\n } else if (diag.getCategory() === DiagnosticCategory.Warning) {\r\n warnings.push({ layer: 'dryrun', path: location, message: `TypeScript warning: ${msgStr}` });\r\n }\r\n }\r\n }\r\n\r\n return { passed: errors.length === 0, layer: 'dryrun', errors, warnings };\r\n}\r\n\r\nfunction generateBodyTemplateTestCode(config: ModuleTestConfig): string | null {\r\n if (!config.bodyTemplates || Object.keys(config.bodyTemplates).length === 0) return null;\r\n\r\n const lines = ['async function testBodyTemplates() {'];\r\n let idx = 0;\r\n for (const [key, body] of Object.entries(config.bodyTemplates)) {\r\n const spaceIdx = key.indexOf(' ');\r\n if (spaceIdx === -1) continue;\r\n const method = key.substring(0, spaceIdx);\r\n const routePath = key.substring(spaceIdx + 1);\r\n\r\n lines.push(` const body_${idx} = ${JSON.stringify(body, null, 2)};`);\r\n lines.push(` const result_${idx} = await apiRequest('${method}', '${routePath}', body_${idx});`);\r\n lines.push(` if (result_${idx}.status !== 200 && result_${idx}.status !== 201) {`);\r\n lines.push(` throw new Error('Unexpected status: ' + result_${idx}.status);`);\r\n lines.push(' }');\r\n idx++;\r\n }\r\n lines.push('}');\r\n return lines.join('\\n');\r\n}\r\n\r\nfunction generateSeedTestCode(config: ModuleTestConfig): string | null {\r\n if (!config.seed || config.seed.length === 0) return null;\r\n\r\n const lines = [\r\n 'async function testSeedSteps() {',\r\n ' const captured: Record<string, string> = {};',\r\n '',\r\n ];\r\n\r\n for (const step of config.seed) {\r\n if (step.body) {\r\n lines.push(` const body_step${step.step} = ${JSON.stringify(step.body, null, 2)};`);\r\n lines.push(` const result_step${step.step} = await apiRequest('${step.method}', '${step.path}', body_step${step.step});`);\r\n } else {\r\n lines.push(` const result_step${step.step} = await apiRequest('${step.method}', '${step.path}');`);\r\n }\r\n\r\n if (step.captureAs) {\r\n lines.push(` captured['${step.captureAs}'] = captureId(result_step${step.step});`);\r\n }\r\n\r\n if (step.required) {\r\n lines.push(` if (result_step${step.step}.status >= 400) {`);\r\n lines.push(` throw new Error('${step.failureMessage || `Required step ${step.step} failed`}');`);\r\n lines.push(' }');\r\n }\r\n lines.push('');\r\n }\r\n\r\n lines.push('}');\r\n return lines.join('\\n');\r\n}\r\n","/**\r\n * DTO / TypeScript Interface Parser\r\n *\r\n * Uses ts-morph to parse TypeScript interfaces from Service and Model files,\r\n * extracting field info (name, type, required, enum values) and\r\n * express-validator rules from Controller files.\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n type InterfaceDeclaration,\r\n type PropertySignature,\r\n type SourceFile,\r\n type Node,\r\n type PropertyAccessExpression,\r\n} from 'ts-morph';\r\nimport type { DTOInfo, DTOFieldInfo, ValidatorRule, ModuleMetadata } from '../types.js';\r\n\r\n// ============================================================\r\n// System fields (auto-generated, not user-editable)\r\n// ============================================================\r\n\r\nconst SYSTEM_FIELDS = new Set([\r\n 'id', 'tenant_id', 'tenantId',\r\n 'created_at', 'createdAt', 'updated_at', 'updatedAt',\r\n 'created_by', 'createdBy', 'updated_by', 'updatedBy',\r\n]);\r\n\r\n// ============================================================\r\n// Core exports\r\n// ============================================================\r\n\r\n/**\r\n * Parse DTOs (TypeScript interfaces) from Service and Model files.\r\n *\r\n * @param filePaths Files to scan (Service / Model .ts files)\r\n * @param options.dtoNamePatterns Regex patterns to match DTO interface names\r\n */\r\nexport function parseDTOs(\r\n filePaths: string[],\r\n options?: { dtoNamePatterns?: RegExp[] },\r\n): DTOInfo[] {\r\n const patterns = options?.dtoNamePatterns ?? [\r\n /DTO$/i, /Query$/i, /Params$/i, /Attributes$/i, /Input$/i, /Request$/i,\r\n ];\r\n\r\n const allDTOs: DTOInfo[] = [];\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n\r\n for (const filePath of filePaths) {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) continue;\r\n\r\n try {\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n const interfaces = sourceFile.getInterfaces();\r\n\r\n for (const iface of interfaces) {\r\n const name = iface.getName();\r\n const matchesPattern = patterns.some((p) => p.test(name));\r\n if (!matchesPattern) continue;\r\n\r\n const dto = parseInterfaceToDTO(iface, absolutePath);\r\n if (dto) allDTOs.push(dto);\r\n }\r\n } catch (err) {\r\n console.warn(`[dto-parser] Failed to parse ${filePath}:`, (err as Error).message);\r\n }\r\n }\r\n\r\n return deduplicateDTOs(allDTOs);\r\n}\r\n\r\n/**\r\n * Parse express-validator rules from Controller files.\r\n *\r\n * Scans router.get/post/put/delete calls for middleware arrays containing\r\n * body('field').notEmpty(), param('field').isInt(), etc.\r\n *\r\n * @returns Map<routeKey, ValidatorRule[]> routeKey = \"METHOD /path\"\r\n */\r\nexport function parseValidatorRules(\r\n controllerPaths: string[],\r\n): Map<string, ValidatorRule[]> {\r\n const result = new Map<string, ValidatorRule[]>();\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n\r\n for (const filePath of controllerPaths) {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) continue;\r\n\r\n try {\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n const routeRules = extractValidatorRulesFromSource(sourceFile);\r\n\r\n for (const [routeKey, rules] of routeRules) {\r\n result.set(routeKey, rules);\r\n }\r\n } catch (err) {\r\n console.warn(`[dto-parser] Failed to parse validators in ${filePath}:`, (err as Error).message);\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Scan a module comprehensively, returning enhanced ModuleMetadata.\r\n */\r\nexport function scanModuleMetadata(\r\n moduleName: string,\r\n servicePaths: string[],\r\n controllerPaths: string[],\r\n modelDir?: string,\r\n): ModuleMetadata {\r\n const allFilePaths = [...servicePaths];\r\n\r\n if (modelDir) {\r\n const absoluteModelDir = path.resolve(modelDir);\r\n if (fs.existsSync(absoluteModelDir)) {\r\n const modelFiles = fs\r\n .readdirSync(absoluteModelDir)\r\n .filter((f) =>\r\n f.endsWith('.ts') && !f.endsWith('.test.ts') && f !== 'index.ts' && f !== 'associations.ts',\r\n )\r\n .map((f) => path.join(absoluteModelDir, f));\r\n allFilePaths.push(...modelFiles);\r\n }\r\n }\r\n\r\n const dtos = parseDTOs(allFilePaths);\r\n const validatorRules = parseValidatorRules(controllerPaths);\r\n\r\n return { moduleName, dtos, validatorRules, timestamp: new Date().toISOString() };\r\n}\r\n\r\n// ============================================================\r\n// Interface parsing internals\r\n// ============================================================\r\n\r\nfunction parseInterfaceToDTO(iface: InterfaceDeclaration, sourcePath: string): DTOInfo | null {\r\n const fields: DTOFieldInfo[] = [];\r\n\r\n const extendsClause = iface.getExtends();\r\n const extendsName = extendsClause.length > 0 ? extendsClause[0].getText() : undefined;\r\n\r\n for (const prop of iface.getProperties()) {\r\n const field = parsePropertyToField(prop);\r\n if (field) fields.push(field);\r\n }\r\n\r\n if (fields.length === 0) return null;\r\n\r\n return { name: iface.getName(), sourcePath, fields, extends: extendsName };\r\n}\r\n\r\nfunction parsePropertyToField(prop: PropertySignature): DTOFieldInfo | null {\r\n const name = prop.getName();\r\n const typeNode = prop.getTypeNode();\r\n if (!typeNode) return null;\r\n\r\n const { baseType, enumValues } = resolveType(typeNode.getText().trim());\r\n\r\n return {\r\n name,\r\n type: baseType,\r\n required: !prop.hasQuestionToken(),\r\n enumValues: enumValues.length > 0 ? enumValues : undefined,\r\n isSystemField: SYSTEM_FIELDS.has(name),\r\n };\r\n}\r\n\r\nfunction resolveType(typeText: string): { baseType: string; enumValues: string[] } {\r\n const cleaned = typeText.split('|').map((t) => t.trim()).filter((t) => t !== 'null' && t !== 'undefined');\r\n\r\n // String literal union: 'TEXT' | 'IMAGE'\r\n const stringLiterals = cleaned.filter((t) => /^['\"].*['\"]$/.test(t));\r\n if (stringLiterals.length > 0 && stringLiterals.length === cleaned.length) {\r\n return { baseType: 'string', enumValues: stringLiterals.map((t) => t.replace(/^['\"]|['\"]$/g, '')) };\r\n }\r\n\r\n // Number literal union: 0 | 1 | 2\r\n const numberLiterals = cleaned.filter((t) => /^\\d+$/.test(t));\r\n if (numberLiterals.length > 0 && numberLiterals.length === cleaned.length) {\r\n return { baseType: 'number', enumValues: numberLiterals };\r\n }\r\n\r\n if (cleaned.length === 1) return { baseType: cleaned[0], enumValues: [] };\r\n return { baseType: cleaned[0] || typeText, enumValues: [] };\r\n}\r\n\r\n// ============================================================\r\n// express-validator rule extraction\r\n// ============================================================\r\n\r\nfunction extractValidatorRulesFromSource(sourceFile: SourceFile): Map<string, ValidatorRule[]> {\r\n const result = new Map<string, ValidatorRule[]>();\r\n const HTTP_METHODS = new Set(['get', 'post', 'put', 'delete', 'patch']);\r\n const METHOD_MAP: Record<string, string> = { get: 'GET', post: 'POST', put: 'PUT', delete: 'DELETE', patch: 'PATCH' };\r\n\r\n const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n\r\n for (const call of callExpressions) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\r\n\r\n const propAccess = expr as PropertyAccessExpression;\r\n const methodName = propAccess.getName().toLowerCase();\r\n if (!HTTP_METHODS.has(methodName)) continue;\r\n\r\n const objectText = propAccess.getExpression().getText().trim();\r\n if (objectText !== 'router' && objectText !== 'this.router') continue;\r\n\r\n const args = call.getArguments();\r\n if (args.length < 2) continue;\r\n\r\n const routePath = resolveArgText(args[0]);\r\n if (!routePath) continue;\r\n\r\n const validatorRules: ValidatorRule[] = [];\r\n for (let i = 1; i < args.length; i++) {\r\n const arg = args[i];\r\n if (arg.getKind() === SyntaxKind.ArrayLiteralExpression) {\r\n const elements = arg.asKindOrThrow(SyntaxKind.ArrayLiteralExpression).getElements();\r\n for (const element of elements) {\r\n const rule = parseValidatorChain(element);\r\n if (rule) validatorRules.push(rule);\r\n }\r\n }\r\n }\r\n\r\n if (validatorRules.length > 0) {\r\n result.set(`${METHOD_MAP[methodName]} ${routePath}`, validatorRules);\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction parseValidatorChain(node: Node): ValidatorRule | null {\r\n const text = node.getText().trim();\r\n\r\n const sourceMatch = text.match(/^(body|param|query)\\(\\s*['\"](\\w+)['\"]\\s*\\)/);\r\n if (!sourceMatch) return null;\r\n\r\n const source = sourceMatch[1] as 'body' | 'param' | 'query';\r\n const field = sourceMatch[2];\r\n const rules: string[] = [];\r\n\r\n const chainRegex = /\\.(\\w+)\\(([^)]*)\\)/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = chainRegex.exec(text)) !== null) {\r\n const method = match[1];\r\n const args = match[2].trim();\r\n if (method === 'withMessage' || method === 'bail') continue;\r\n\r\n if (method === 'isIn') {\r\n const valuesMatch = args.match(/\\[([^\\]]+)\\]/);\r\n if (valuesMatch) {\r\n const values = valuesMatch[1].split(',').map((v) => v.trim().replace(/^['\"]|['\"]$/g, ''));\r\n rules.push(`isIn(${values.join(',')})`);\r\n }\r\n } else if (method === 'optional') {\r\n rules.push('optional');\r\n } else {\r\n rules.push(method);\r\n }\r\n }\r\n\r\n return { field, source, rules };\r\n}\r\n\r\nfunction resolveArgText(node: Node): string | null {\r\n const text = node.getText().trim();\r\n\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"'))) {\r\n return text.slice(1, -1);\r\n }\r\n\r\n if (text.startsWith('`') && text.endsWith('`')) {\r\n return text.slice(1, -1).replace(/\\$\\{[^}]+\\}/g, (m) => m);\r\n }\r\n\r\n return null;\r\n}\r\n\r\n// ============================================================\r\n// Helpers\r\n// ============================================================\r\n\r\nfunction deduplicateDTOs(dtos: DTOInfo[]): DTOInfo[] {\r\n const seen = new Map<string, DTOInfo>();\r\n for (const dto of dtos) {\r\n if (!seen.has(dto.name)) seen.set(dto.name, dto);\r\n }\r\n return Array.from(seen.values());\r\n}\r\n","import type { TableSchema } from '../types.js';\r\n\r\nexport interface MockDataGenerator {\r\n generateForTable(schema: TableSchema): Record<string, unknown>;\r\n generateForTables(schemas: TableSchema[]): Map<string, Record<string, unknown>[]>;\r\n}\r\n\r\nfunction randomInt(min: number, max: number): number {\r\n return Math.floor(Math.random() * (max - min + 1)) + min;\r\n}\r\n\r\nfunction randomString(prefix: string, fieldName: string): string {\r\n const ts = Date.now().toString(36);\r\n const rand = Math.random().toString(36).slice(2, 6);\r\n return `${prefix}${fieldName}_${ts}_${rand}`;\r\n}\r\n\r\nfunction generateUUID(): string {\r\n const hex = () => Math.random().toString(16).slice(2, 6);\r\n return `${hex()}${hex()}-${hex()}-4${hex().slice(1)}-${(8 + randomInt(0, 3)).toString(16)}${hex().slice(1)}-${hex()}${hex()}${hex()}`;\r\n}\r\n\r\n/**\r\n * Generate a mock value based on field type and constraints.\r\n */\r\nfunction generateFieldValue(\r\n fieldName: string,\r\n fieldType: string,\r\n isForeignKey: boolean,\r\n parentTable?: string,\r\n): unknown {\r\n const upper = fieldType.toUpperCase();\r\n\r\n if (isForeignKey && parentTable) {\r\n return `{{parentRecordIds.${parentTable}}}`;\r\n }\r\n\r\n if (upper.startsWith('STRING') || upper === 'TEXT') return randomString('test_', fieldName);\r\n if (upper === 'BIGINT' || upper === 'INTEGER') return randomInt(1, 999999);\r\n if (upper === 'BOOLEAN') return true;\r\n if (upper.startsWith('DATE') || upper === 'NOW') return new Date().toISOString();\r\n if (upper === 'UUID') return generateUUID();\r\n if (upper.startsWith('ENUM')) return 'ACTIVE';\r\n if (upper === 'JSON' || upper === 'JSONB') return {};\r\n if (upper === 'FLOAT' || upper === 'DOUBLE' || upper === 'DECIMAL') return Math.round(Math.random() * 10000) / 100;\r\n\r\n return randomString('val_', fieldName);\r\n}\r\n\r\nexport function createMockDataGenerator(): MockDataGenerator {\r\n return {\r\n generateForTable(schema: TableSchema): Record<string, unknown> {\r\n const record: Record<string, unknown> = {};\r\n const ts = Date.now().toString(36);\r\n const rand = Math.random().toString(36).slice(2, 6);\r\n\r\n for (const field of schema.fields) {\r\n // Skip auto-generated primary keys\r\n if (field.primaryKey) continue;\r\n // Skip fields with default values\r\n if (field.defaultValue !== undefined) continue;\r\n\r\n // Detect foreign key fields (ending with _id)\r\n const isForeignKey = field.name.endsWith('_id') && !field.primaryKey;\r\n const parentTable = isForeignKey\r\n ? field.name.replace(/_id$/, '')\r\n : undefined;\r\n\r\n let value = generateFieldValue(field.name, field.type, isForeignKey, parentTable);\r\n\r\n // Unique constraint: append suffix\r\n if (field.unique && typeof value === 'string') {\r\n value = `${value}__e2e_test_${ts}_${rand}`;\r\n }\r\n\r\n record[field.name] = value;\r\n }\r\n return record;\r\n },\r\n\r\n generateForTables(schemas: TableSchema[]): Map<string, Record<string, unknown>[]> {\r\n const result = new Map<string, Record<string, unknown>[]>();\r\n for (const schema of schemas) {\r\n const record = this.generateForTable(schema);\r\n result.set(schema.tableName, [record]);\r\n }\r\n return result;\r\n },\r\n };\r\n}\r\n","import type {\r\n ChainFailureResult,\r\n ERDiagramResult,\r\n ApiChainAnalysisResult,\r\n ApiEndpoint,\r\n ForeignKeyRelation,\r\n ImpactReport,\r\n} from '../types.js';\r\n\r\nconst MAX_BFS_DEPTH = 5;\r\n\r\n/**\r\n * Extract table names from an error chain path string.\r\n * Path format: \"POST /path → field → table_name → GET /path\"\r\n */\r\nfunction extractTablesFromErrorChain(errorChainPath: string): string[] {\r\n const segments = errorChainPath.split('→').map((s) => s.trim());\r\n return segments.filter((s) => !s.includes('/') && !s.includes(' ') && s.includes('_'));\r\n}\r\n\r\n/**\r\n * Build bidirectional table adjacency from foreign key relations.\r\n */\r\nfunction buildTableAdjacency(relations: ForeignKeyRelation[]): Map<string, Set<string>> {\r\n const adj = new Map<string, Set<string>>();\r\n for (const rel of relations) {\r\n if (!adj.has(rel.sourceTable)) adj.set(rel.sourceTable, new Set());\r\n if (!adj.has(rel.targetTable)) adj.set(rel.targetTable, new Set());\r\n adj.get(rel.sourceTable)!.add(rel.targetTable);\r\n adj.get(rel.targetTable)!.add(rel.sourceTable);\r\n }\r\n return adj;\r\n}\r\n\r\n/**\r\n * BFS traversal from seed tables along foreign key relations.\r\n */\r\nfunction bfsTraversal(\r\n seedTables: string[],\r\n adjacency: Map<string, Set<string>>,\r\n maxDepth: number = MAX_BFS_DEPTH,\r\n): string[] {\r\n const visited = new Set<string>();\r\n const queue: Array<{ table: string; depth: number }> = [];\r\n\r\n for (const t of seedTables) {\r\n if (adjacency.has(t)) {\r\n queue.push({ table: t, depth: 0 });\r\n visited.add(t);\r\n }\r\n }\r\n\r\n while (queue.length > 0) {\r\n const { table, depth } = queue.shift()!;\r\n if (depth >= maxDepth) continue;\r\n\r\n for (const neighbor of adjacency.get(table) || []) {\r\n if (!visited.has(neighbor)) {\r\n visited.add(neighbor);\r\n queue.push({ table: neighbor, depth: depth + 1 });\r\n }\r\n }\r\n }\r\n return Array.from(visited);\r\n}\r\n\r\n/**\r\n * Find API endpoints that reference any of the given tables.\r\n */\r\nfunction findAffectedEndpoints(\r\n tables: string[],\r\n analysisResults: ApiChainAnalysisResult[],\r\n): ApiEndpoint[] {\r\n const tableSet = new Set(tables);\r\n const affected: ApiEndpoint[] = [];\r\n\r\n for (const result of analysisResults) {\r\n for (const ep of result.endpoints) {\r\n if (ep.relatedTables.some((t) => tableSet.has(t))) {\r\n affected.push(ep);\r\n }\r\n }\r\n }\r\n return affected;\r\n}\r\n\r\n/**\r\n * Generate a Mermaid flowchart from impact data.\r\n */\r\nfunction generateMermaidDiagram(\r\n seedTables: string[],\r\n affectedTables: string[],\r\n relations: ForeignKeyRelation[],\r\n): string {\r\n const relevantTables = new Set([...seedTables, ...affectedTables]);\r\n const lines: string[] = ['flowchart TD'];\r\n\r\n const seedSet = new Set(seedTables);\r\n for (const t of relevantTables) {\r\n const label = seedSet.has(t) ? `${t}:::error` : t;\r\n lines.push(` ${sanitizeId(t)}[\"${label}\"]`);\r\n }\r\n\r\n for (const rel of relations) {\r\n if (relevantTables.has(rel.sourceTable) && relevantTables.has(rel.targetTable)) {\r\n const arrow = rel.isCrossModule ? '-.->' : '-->';\r\n lines.push(` ${sanitizeId(rel.sourceTable)} ${arrow}|${rel.targetField}| ${sanitizeId(rel.targetTable)}`);\r\n }\r\n }\r\n\r\n lines.push(' classDef error fill:#f96,stroke:#333,stroke-width:2px');\r\n return lines.join('\\n');\r\n}\r\n\r\nfunction sanitizeId(name: string): string {\r\n return name.replace(/[^a-zA-Z0-9_]/g, '_');\r\n}\r\n\r\nexport interface ImpactReporter {\r\n analyze(\r\n failures: ChainFailureResult[],\r\n erDiagrams: Map<string, ERDiagramResult>,\r\n analysisResults: ApiChainAnalysisResult[],\r\n ): ImpactReport;\r\n}\r\n\r\nexport function createImpactReporter(): ImpactReporter {\r\n return {\r\n analyze(\r\n failures: ChainFailureResult[],\r\n erDiagrams: Map<string, ERDiagramResult>,\r\n analysisResults: ApiChainAnalysisResult[],\r\n ): ImpactReport {\r\n // Collect all relations\r\n const allRelations: ForeignKeyRelation[] = [];\r\n for (const er of erDiagrams.values()) {\r\n allRelations.push(...er.relations);\r\n }\r\n\r\n // Extract seed tables from failure error chain paths\r\n const seedTables: string[] = [];\r\n for (const failure of failures) {\r\n if (failure.errorChainPath) {\r\n seedTables.push(...extractTablesFromErrorChain(failure.errorChainPath));\r\n }\r\n }\r\n\r\n // BFS to find all affected tables\r\n const adjacency = buildTableAdjacency(allRelations);\r\n const affectedTables = bfsTraversal(seedTables, adjacency);\r\n\r\n // Find affected endpoints\r\n const affectedEndpoints = findAffectedEndpoints(affectedTables, analysisResults);\r\n\r\n // Determine affected modules\r\n const affectedModules = [...new Set(analysisResults\r\n .filter((r) => r.endpoints.some((ep) => affectedEndpoints.includes(ep)))\r\n .map((r) => r.moduleName))];\r\n\r\n // Affected chains\r\n const affectedChains = failures.map((f) => f.chain);\r\n\r\n // Generate Mermaid diagram\r\n const mermaidText = generateMermaidDiagram(seedTables, affectedTables, allRelations);\r\n\r\n // Severity based on affected API count\r\n const count = affectedEndpoints.length;\r\n const severity = count > 10 ? 'critical' : count > 5 ? 'high' : count > 2 ? 'medium' : 'low';\r\n\r\n return {\r\n affectedModules,\r\n affectedChains,\r\n affectedEndpoints,\r\n affectedTables,\r\n severity,\r\n mermaidText,\r\n };\r\n },\r\n };\r\n}\r\n","/**\r\n * Chain Planner\r\n *\r\n * Rule-based test chain planning:\r\n * - Groups endpoints by resource path\r\n * - Applies chain templates (CRUD, nested, batch, status, error handling)\r\n * - Uses greedy algorithm for optimal coverage selection\r\n * - Detects shared setup steps\r\n */\r\n\r\nimport type {\r\n ApiEndpoint,\r\n ApiChainAnalysisResult,\r\n TestStep,\r\n TestChain,\r\n ChainPlanResult,\r\n LlmProvider,\r\n} from '../types.js';\r\nimport { topologicalSort } from '../analyzers/api-chain-analyzer.js';\r\n\r\n// ============================================================\r\n// Constants\r\n// ============================================================\r\n\r\nconst MIN_CHAINS = 3;\r\nconst MAX_CHAINS = 10;\r\nconst COVERAGE_TARGET = 0.8;\r\nconst SMALL_MODULE_THRESHOLD = 3;\r\n\r\n// ============================================================\r\n// Helpers\r\n// ============================================================\r\n\r\nfunction endpointKey(ep: ApiEndpoint): string {\r\n return `${ep.method} ${ep.path}`;\r\n}\r\n\r\nfunction basePath(ep: ApiEndpoint): string {\r\n return ep.path.replace(/\\/:[^/]+/g, '');\r\n}\r\n\r\nfunction groupByResource(endpoints: ApiEndpoint[]): Map<string, ApiEndpoint[]> {\r\n const groups = new Map<string, ApiEndpoint[]>();\r\n for (const ep of endpoints) {\r\n const base = basePath(ep);\r\n if (!groups.has(base)) groups.set(base, []);\r\n groups.get(base)!.push(ep);\r\n }\r\n return groups;\r\n}\r\n\r\nfunction isListEndpoint(ep: ApiEndpoint): boolean {\r\n if (ep.method !== 'GET') return false;\r\n const params = (ep.pathParams ?? []).filter((p) => p !== 'tenantId');\r\n return params.length === 0;\r\n}\r\n\r\nfunction isDetailEndpoint(ep: ApiEndpoint): boolean {\r\n if (ep.method !== 'GET') return false;\r\n const params = (ep.pathParams ?? []).filter((p) => p !== 'tenantId');\r\n return params.length > 0;\r\n}\r\n\r\nfunction inferAction(ep: ApiEndpoint): string {\r\n switch (ep.method) {\r\n case 'POST': return 'create';\r\n case 'GET': return 'read';\r\n case 'PUT':\r\n case 'PATCH': return 'update';\r\n case 'DELETE': return 'delete';\r\n default: return 'read';\r\n }\r\n}\r\n\r\nfunction buildDescription(ep: ApiEndpoint, action: string, parentKey?: string): string {\r\n const parts = [`${action} ${ep.method} ${ep.path}`];\r\n if (parentKey) parts.push(`(depends on ${parentKey})`);\r\n for (const param of ep.pathParams ?? []) {\r\n if (param === 'tenantId') parts.push(`${param}: config.tenantId`);\r\n }\r\n return parts.join(' ');\r\n}\r\n\r\nfunction buildAssertions(ep: ApiEndpoint, action: string): string[] {\r\n switch (action) {\r\n case 'create': return ['响应状态码 200/201', '响应 data.id 非空'];\r\n case 'read':\r\n return isListEndpoint(ep)\r\n ? ['响应状态码 200', '响应 data 为数组']\r\n : ['响应状态码 200', '响应 data.id 与请求参数一致'];\r\n case 'update': return ['响应状态码 200', '更新字段值已变更'];\r\n case 'delete': return ['响应状态码 200/204', '再次 GET 返回 404 或空'];\r\n case 'verify': return ['验证数据一致性'];\r\n default: return ['响应状态码 200'];\r\n }\r\n}\r\n\r\nfunction createStep(order: number, ep: ApiEndpoint, action: string, parentKey?: string): TestStep {\r\n return {\r\n order,\r\n endpoint: ep,\r\n action,\r\n description: buildDescription(ep, action, parentKey),\r\n assertions: buildAssertions(ep, action),\r\n };\r\n}\r\n\r\n// ============================================================\r\n// Internal chain type (extends public TestChain with planning fields)\r\n// ============================================================\r\n\r\ninterface InternalChain {\r\n name: string;\r\n module: string;\r\n priority: 'P0' | 'P1' | 'P2';\r\n steps: TestStep[];\r\n coverageApis: string[];\r\n}\r\n\r\nfunction toPublicChain(c: InternalChain): TestChain {\r\n return { name: c.name, module: c.module, steps: c.steps };\r\n}\r\n\r\n// ============================================================\r\n// Chain templates\r\n// ============================================================\r\n\r\ninterface ChainTemplate {\r\n pattern: string;\r\n priority: 'P0' | 'P1' | 'P2';\r\n generate(name: string, endpoints: ApiEndpoint[], groups: Map<string, ApiEndpoint[]>, topo: string[]): InternalChain | null;\r\n}\r\n\r\nfunction crudFullCycleTemplate(): ChainTemplate {\r\n return {\r\n pattern: 'crud-full-cycle',\r\n priority: 'P0',\r\n generate(name, _endpoints, groups) {\r\n let best: ApiEndpoint[] = [];\r\n for (const group of groups.values()) {\r\n if (group.length > best.length) best = group;\r\n }\r\n if (best.length === 0) return null;\r\n\r\n const post = best.find((e) => e.method === 'POST');\r\n const getD = best.find(isDetailEndpoint);\r\n const put = best.find((e) => e.method === 'PUT' || e.method === 'PATCH');\r\n const del = best.find((e) => e.method === 'DELETE');\r\n if (!post) return null;\r\n\r\n const steps: TestStep[] = [];\r\n const pk = 'step_1';\r\n steps.push(createStep(steps.length + 1, post, 'create'));\r\n if (getD) steps.push(createStep(steps.length + 1, getD, 'read', pk));\r\n if (put) steps.push(createStep(steps.length + 1, put, 'update', pk));\r\n if (getD) steps.push(createStep(steps.length + 1, getD, 'verify', pk));\r\n if (del) steps.push(createStep(steps.length + 1, del, 'delete', pk));\r\n\r\n return {\r\n name: `${name}-crud-full-cycle`,\r\n module: name,\r\n priority: 'P0',\r\n steps,\r\n coverageApis: [...new Set(steps.map((s) => endpointKey(s.endpoint)))],\r\n };\r\n },\r\n };\r\n}\r\n\r\nfunction listFilterTemplate(): ChainTemplate {\r\n return {\r\n pattern: 'list-filter',\r\n priority: 'P1',\r\n generate(name, endpoints) {\r\n const lists = endpoints.filter(isListEndpoint);\r\n if (lists.length === 0) return null;\r\n const steps = lists.slice(0, 2).map((ep, i) => createStep(i + 1, ep, 'read'));\r\n return {\r\n name: `${name}-list-filter`,\r\n module: name,\r\n priority: 'P1',\r\n steps,\r\n coverageApis: [...new Set(steps.map((s) => endpointKey(s.endpoint)))],\r\n };\r\n },\r\n };\r\n}\r\n\r\nfunction nestedResourceTemplate(): ChainTemplate {\r\n return {\r\n pattern: 'nested-resource',\r\n priority: 'P0',\r\n generate(name, _endpoints, groups) {\r\n const entries = Array.from(groups.entries());\r\n if (entries.length < 2) return null;\r\n entries.sort((a, b) => a[0].split('/').length - b[0].split('/').length);\r\n\r\n const parentPost = entries[0][1].find((e) => e.method === 'POST');\r\n const childPost = entries[1][1].find((e) => e.method === 'POST');\r\n const childGet = entries[1][1].find((e) => isDetailEndpoint(e) || isListEndpoint(e));\r\n const childDel = entries[1][1].find((e) => e.method === 'DELETE');\r\n const parentDel = entries[0][1].find((e) => e.method === 'DELETE');\r\n if (!parentPost || !childPost) return null;\r\n\r\n const steps: TestStep[] = [];\r\n steps.push(createStep(steps.length + 1, parentPost, 'setup'));\r\n steps.push(createStep(steps.length + 1, childPost, 'create', 'step_1'));\r\n if (childGet) steps.push(createStep(steps.length + 1, childGet, 'read', 'step_2'));\r\n if (childDel) steps.push(createStep(steps.length + 1, childDel, 'cleanup', 'step_2'));\r\n if (parentDel) steps.push(createStep(steps.length + 1, parentDel, 'cleanup', 'step_1'));\r\n\r\n return {\r\n name: `${name}-nested-resource`,\r\n module: name,\r\n priority: 'P0',\r\n steps,\r\n coverageApis: [...new Set(steps.map((s) => endpointKey(s.endpoint)))],\r\n };\r\n },\r\n };\r\n}\r\n\r\nfunction batchOperationTemplate(): ChainTemplate {\r\n return {\r\n pattern: 'batch-operation',\r\n priority: 'P1',\r\n generate(name, endpoints) {\r\n const batch = endpoints.filter((ep) =>\r\n ep.path.toLowerCase().includes('batch') || ep.path.toLowerCase().includes('bulk'),\r\n );\r\n if (batch.length === 0) return null;\r\n const steps = batch.slice(0, 3).map((ep, i) => createStep(i + 1, ep, inferAction(ep)));\r\n return {\r\n name: `${name}-batch-operation`,\r\n module: name,\r\n priority: 'P1',\r\n steps,\r\n coverageApis: [...new Set(steps.map((s) => endpointKey(s.endpoint)))],\r\n };\r\n },\r\n };\r\n}\r\n\r\nfunction errorHandlingTemplate(): ChainTemplate {\r\n return {\r\n pattern: 'error-handling',\r\n priority: 'P2',\r\n generate(name, endpoints) {\r\n const post = endpoints.find((ep) => ep.method === 'POST');\r\n if (!post) return null;\r\n return {\r\n name: `${name}-error-handling`,\r\n module: name,\r\n priority: 'P2',\r\n steps: [{\r\n order: 1,\r\n endpoint: post,\r\n action: 'verify',\r\n description: `verify ${post.method} ${post.path} with invalid data`,\r\n assertions: ['响应状态码 400', '响应包含错误信息'],\r\n }],\r\n coverageApis: [endpointKey(post)],\r\n };\r\n },\r\n };\r\n}\r\n\r\nfunction topoOrderTemplate(): ChainTemplate {\r\n return {\r\n pattern: 'topo-order-walk',\r\n priority: 'P1',\r\n generate(name, endpoints, _groups, topo) {\r\n if (topo.length === 0) return null;\r\n const epMap = new Map(endpoints.map((ep) => [endpointKey(ep), ep]));\r\n const steps: TestStep[] = [];\r\n for (const key of topo.slice(0, 6)) {\r\n const ep = epMap.get(key);\r\n if (ep) steps.push(createStep(steps.length + 1, ep, inferAction(ep)));\r\n }\r\n if (steps.length === 0) return null;\r\n return {\r\n name: `${name}-topo-order-walk`,\r\n module: name,\r\n priority: 'P1',\r\n steps,\r\n coverageApis: [...new Set(steps.map((s) => endpointKey(s.endpoint)))],\r\n };\r\n },\r\n };\r\n}\r\n\r\n// ============================================================\r\n// Greedy coverage selection\r\n// ============================================================\r\n\r\nfunction greedySelectChains(\r\n candidates: InternalChain[],\r\n allKeys: Set<string>,\r\n targetCount: number,\r\n coverageTarget: number,\r\n): InternalChain[] {\r\n const selected: InternalChain[] = [];\r\n const covered = new Set<string>();\r\n const remaining = [...candidates];\r\n\r\n const pOrder: Record<string, number> = { P0: 0, P1: 1, P2: 2 };\r\n remaining.sort((a, b) => pOrder[a.priority] - pOrder[b.priority] || b.coverageApis.length - a.coverageApis.length);\r\n\r\n while (selected.length < targetCount && remaining.length > 0) {\r\n let bestIdx = -1, bestScore = -1;\r\n for (let i = 0; i < remaining.length; i++) {\r\n const newApis = remaining[i].coverageApis.filter((a) => !covered.has(a));\r\n const score = remaining[i].priority === 'P0' ? newApis.length * 1.5 : newApis.length;\r\n if (score > bestScore) { bestScore = score; bestIdx = i; }\r\n }\r\n if (bestIdx === -1 || bestScore <= 0) break;\r\n\r\n const chosen = remaining.splice(bestIdx, 1)[0];\r\n selected.push(chosen);\r\n chosen.coverageApis.forEach((a) => covered.add(a));\r\n\r\n if (allKeys.size > 0 && covered.size / allKeys.size >= coverageTarget && selected.length >= MIN_CHAINS) break;\r\n }\r\n return selected;\r\n}\r\n\r\n// ============================================================\r\n// Shared setup detection\r\n// ============================================================\r\n\r\nfunction detectSharedSetups(chains: InternalChain[], moduleName: string): InternalChain[] {\r\n const firstSteps = new Map<string, { ep: ApiEndpoint; count: number }>();\r\n for (const chain of chains) {\r\n if (chain.steps.length === 0) continue;\r\n const first = chain.steps[0];\r\n if (first.action === 'create' || first.action === 'setup') {\r\n const key = endpointKey(first.endpoint);\r\n const e = firstSteps.get(key);\r\n if (e) e.count++;\r\n else firstSteps.set(key, { ep: first.endpoint, count: 1 });\r\n }\r\n }\r\n\r\n const setups: InternalChain[] = [];\r\n for (const [key, { ep, count }] of firstSteps) {\r\n if (count >= 2) {\r\n const setupName = `${moduleName}-shared-setup-${setups.length + 1}`;\r\n setups.push({\r\n name: setupName,\r\n module: moduleName,\r\n priority: 'P0',\r\n steps: [createStep(1, ep, 'setup')],\r\n coverageApis: [key],\r\n });\r\n }\r\n }\r\n return setups;\r\n}\r\n\r\n// ============================================================\r\n// Public API\r\n// ============================================================\r\n\r\nexport interface ChainPlanner {\r\n planForModule(moduleName: string, analysis: ApiChainAnalysisResult): ChainPlanResult;\r\n}\r\n\r\nexport function createChainPlanner(): ChainPlanner {\r\n return {\r\n planForModule(moduleName, analysis) {\r\n const { endpoints, dag } = analysis;\r\n\r\n // Small module shortcut\r\n if (endpoints.length < SMALL_MODULE_THRESHOLD) {\r\n if (endpoints.length === 0) {\r\n return { chains: [], totalSteps: 0 };\r\n }\r\n const steps = endpoints.map((ep, i) => createStep(i + 1, ep, inferAction(ep)));\r\n return {\r\n chains: [{ name: `${moduleName}-basic-flow`, module: moduleName, steps }],\r\n totalSteps: steps.length,\r\n };\r\n }\r\n\r\n // Full planning\r\n const topoOrder = topologicalSort(dag);\r\n const groups = groupByResource(endpoints);\r\n\r\n // Generate candidates from templates\r\n const templates: ChainTemplate[] = [\r\n crudFullCycleTemplate(),\r\n listFilterTemplate(),\r\n nestedResourceTemplate(),\r\n batchOperationTemplate(),\r\n errorHandlingTemplate(),\r\n topoOrderTemplate(),\r\n ];\r\n\r\n const candidates: InternalChain[] = [];\r\n for (const t of templates) {\r\n const chain = t.generate(moduleName, endpoints, groups, topoOrder);\r\n if (chain && chain.steps.length > 0) candidates.push(chain);\r\n }\r\n\r\n // Supplement uncovered endpoints\r\n const coveredSet = new Set<string>();\r\n for (const c of candidates) c.coverageApis.forEach((a) => coveredSet.add(a));\r\n const uncovered = endpoints.filter((ep) => !coveredSet.has(endpointKey(ep)));\r\n if (uncovered.length > 0) {\r\n const steps = uncovered.slice(0, 5).map((ep, i) => createStep(i + 1, ep, inferAction(ep)));\r\n candidates.push({\r\n name: `${moduleName}-supplement`,\r\n module: moduleName,\r\n priority: 'P2',\r\n steps,\r\n coverageApis: [...new Set(steps.map((s) => endpointKey(s.endpoint)))],\r\n });\r\n }\r\n\r\n // Greedy selection\r\n const allKeys = new Set(endpoints.map(endpointKey));\r\n const targetCount = Math.min(MAX_CHAINS, Math.max(MIN_CHAINS, candidates.length));\r\n const selected = greedySelectChains(candidates, allKeys, targetCount, COVERAGE_TARGET);\r\n\r\n // Shared setups\r\n detectSharedSetups(selected, moduleName);\r\n\r\n const totalSteps = selected.reduce((sum, c) => sum + c.steps.length, 0);\r\n return { chains: selected.map(toPublicChain), totalSteps };\r\n },\r\n };\r\n}\r\n\r\n// ============================================================\r\n// LLM-Enhanced Chain Planner\r\n// ============================================================\r\n\r\nexport interface LlmChainPlanner extends ChainPlanner {\r\n planForModuleWithLLM(\r\n moduleName: string,\r\n analysis: ApiChainAnalysisResult,\r\n llmProvider: LlmProvider,\r\n ): Promise<ChainPlanResult>;\r\n}\r\n\r\n/**\r\n * Create a chain planner with optional LLM constraint reasoning.\r\n *\r\n * The LLM is used to:\r\n * 1. Infer business constraints that rule-based templates cannot detect\r\n * 2. Prioritize chains based on domain understanding\r\n * 3. Suggest additional edge-case chains\r\n */\r\nexport function createLlmChainPlanner(): LlmChainPlanner {\r\n const basePlanner = createChainPlanner();\r\n\r\n return {\r\n planForModule: basePlanner.planForModule,\r\n\r\n async planForModuleWithLLM(moduleName, analysis, llmProvider) {\r\n // Step 1: Get rule-based plan\r\n const basePlan = basePlanner.planForModule(moduleName, analysis);\r\n\r\n // Step 2: Ask LLM to evaluate and enhance\r\n const endpointSummary = analysis.endpoints\r\n .map((e) => `${e.method} ${e.path}`)\r\n .join('\\n');\r\n\r\n const chainSummary = basePlan.chains\r\n .map((c) => `- ${c.name}: ${c.steps.length} steps`)\r\n .join('\\n');\r\n\r\n const system = `You are a test planning expert. Given a module's API endpoints and existing test chains,\r\nsuggest improvements. Output a JSON object with:\r\n{\r\n \"priorityAdjustments\": [{ \"chainName\": \"...\", \"newPriority\": \"P0|P1|P2\", \"reason\": \"...\" }],\r\n \"additionalChains\": [{ \"name\": \"...\", \"description\": \"...\", \"priority\": \"P0|P1|P2\", \"endpointKeys\": [\"GET /path\", ...] }],\r\n \"insights\": \"brief text about business constraints or edge cases\"\r\n}\r\nOnly return JSON. No explanation.`;\r\n\r\n const user = `Module: ${moduleName}\r\n\r\nAPI Endpoints:\r\n${endpointSummary}\r\n\r\nExisting Chains:\r\n${chainSummary}\r\n\r\nCoverage: ${basePlan.totalSteps} total steps\r\nCycles detected: ${analysis.hasCycles}\r\n\r\nSuggest improvements (JSON):`;\r\n\r\n try {\r\n const raw = await llmProvider.chat([\r\n { role: 'system', content: system },\r\n { role: 'user', content: user },\r\n ]);\r\n\r\n const jsonMatch = raw.match(/\\{[\\s\\S]*\\}/);\r\n if (!jsonMatch) return basePlan;\r\n\r\n const suggestions = JSON.parse(jsonMatch[0]);\r\n\r\n // Apply priority adjustments (stored as metadata, not on public type)\r\n // Skip - remote TestChain doesn't have priority field\r\n\r\n // Add suggested chains (if they cover uncovered endpoints)\r\n if (Array.isArray(suggestions.additionalChains)) {\r\n const covered = new Set<string>();\r\n for (const c of basePlan.chains) {\r\n for (const s of c.steps) covered.add(endpointKey(s.endpoint));\r\n }\r\n\r\n for (const suggestion of suggestions.additionalChains) {\r\n if (!suggestion.endpointKeys || !Array.isArray(suggestion.endpointKeys)) continue;\r\n\r\n const newApis = suggestion.endpointKeys.filter((k: string) => !covered.has(k));\r\n if (newApis.length === 0) continue;\r\n\r\n const steps: TestStep[] = [];\r\n for (const key of newApis) {\r\n const ep = analysis.endpoints.find((e) => `${e.method} ${e.path}` === key);\r\n if (ep) {\r\n steps.push(createStep(steps.length + 1, ep, inferAction(ep)));\r\n covered.add(key);\r\n }\r\n }\r\n\r\n if (steps.length > 0) {\r\n basePlan.chains.push({\r\n name: suggestion.name || `${moduleName}-llm-suggested`,\r\n module: moduleName,\r\n steps,\r\n });\r\n basePlan.totalSteps += steps.length;\r\n }\r\n }\r\n }\r\n\r\n return basePlan;\r\n } catch {\r\n // LLM failed, fall back to rule-based plan\r\n return basePlan;\r\n }\r\n },\r\n };\r\n}\r\n","/**\r\n * AI Config Suggester — AI-driven module test config generation.\r\n *\r\n * Uses LlmProvider to analyze parsed API endpoints and generate:\r\n * - bodyTemplates (request body for POST/PUT/PATCH endpoints)\r\n * - paramRewrites (semantic parameter name mapping)\r\n * - seed steps (data setup sequence with dependency ordering)\r\n */\r\n\r\nimport type {\r\n LlmProvider,\r\n ApiEndpoint,\r\n ModuleTestConfig,\r\n SeedStep,\r\n ModuleConfigValidationContext,\r\n} from '../types.js';\r\nimport { validateModuleConfig } from '../validators/config-validator.js';\r\n\r\n// ============================================================\r\n// Types\r\n// ============================================================\r\n\r\nexport interface GenerateConfigOptions {\r\n moduleName: string;\r\n endpoints: ApiEndpoint[];\r\n llmProvider: LlmProvider;\r\n /** Max validation+fix retries (default 3) */\r\n maxRetries?: number;\r\n /** Dry-run: don't write to disk */\r\n dryRun?: boolean;\r\n /** Validation context for semantic checking */\r\n validationContext?: ModuleConfigValidationContext;\r\n}\r\n\r\nexport interface GenerateConfigResult {\r\n success: boolean;\r\n config?: ModuleTestConfig;\r\n error?: string;\r\n retries: number;\r\n}\r\n\r\n// ============================================================\r\n// JSON Recovery\r\n// ============================================================\r\n\r\nexport function recoverJSON(text: string): string {\r\n // Direct parse\r\n try { JSON.parse(text.trim()); return text.trim(); } catch { /* recovery fallthrough */ }\r\n\r\n // Markdown code block\r\n const codeBlock = text.match(/```(?:json|javascript|ts)?\\s*\\n?([\\s\\S]*?)\\n?\\s*```/);\r\n if (codeBlock) {\r\n try { JSON.parse(codeBlock[1].trim()); return codeBlock[1].trim(); } catch { /* recovery fallthrough */ }\r\n }\r\n\r\n // Extract outermost {} or []\r\n const braceStart = text.indexOf('{');\r\n const braceEnd = text.lastIndexOf('}');\r\n const bracketStart = text.indexOf('[');\r\n const bracketEnd = text.lastIndexOf(']');\r\n\r\n const tryParse = (start: number, end: number): string | null => {\r\n if (start === -1 || end <= start) return null;\r\n let candidate = text.slice(start, end + 1);\r\n candidate = candidate.replace(/,\\s*([}\\]])/g, '$1');\r\n try { JSON.parse(candidate); return candidate; } catch { return null; }\r\n };\r\n\r\n // Try [] first if it appears earlier\r\n if (bracketStart !== -1 && (braceStart === -1 || bracketStart < braceStart)) {\r\n const r = tryParse(bracketStart, bracketEnd) ?? tryParse(braceStart, braceEnd);\r\n if (r) return r;\r\n } else {\r\n const r = tryParse(braceStart, braceEnd) ?? tryParse(bracketStart, bracketEnd);\r\n if (r) return r;\r\n }\r\n\r\n // Fix trailing commas + unquoted keys + single quotes\r\n const cleaned = text.trim()\r\n .replace(/^```(?:json|javascript|ts)?\\s*\\n?/m, '')\r\n .replace(/\\n?\\s*```\\s*$/m, '')\r\n .trim()\r\n .replace(/,\\s*([}\\]])/g, '$1')\r\n .replace(/([{,]\\s*)(\\w+)\\s*:/g, (_m, prefix, key) => `${prefix}\"${key}\":`)\r\n .replace(/'/g, '\"');\r\n\r\n try { JSON.parse(cleaned); return cleaned; } catch { /* recovery fallthrough */ }\r\n\r\n throw new Error('JSON recovery failed: unable to extract valid JSON from AI response');\r\n}\r\n\r\n// ============================================================\r\n// LLM Prompt Helpers\r\n// ============================================================\r\n\r\nasync function llmChat(llm: LlmProvider, system: string, user: string): Promise<string> {\r\n return llm.chat([\r\n { role: 'system', content: system },\r\n { role: 'user', content: user },\r\n ]);\r\n}\r\n\r\nasync function generateBodyTemplates(\r\n moduleName: string,\r\n endpoints: ApiEndpoint[],\r\n llm: LlmProvider,\r\n): Promise<Record<string, Record<string, unknown>>> {\r\n const writeEndpoints = endpoints\r\n .filter((e) => ['POST', 'PUT', 'PATCH'].includes(e.method))\r\n .map((e) => `${e.method} ${e.path}${e.bodyFields?.length ? ` → [${e.bodyFields.join(', ')}]` : ''}`)\r\n .join('\\n');\r\n\r\n if (!writeEndpoints) return {};\r\n\r\n const system = `You are a test config expert. Generate test body templates for API endpoints.\r\nRules:\r\n1. String fields: \"__e2e_{fieldName}_{timestamp}\" format\r\n2. Enum fields: choose a reasonable value\r\n3. Number fields: use reasonable defaults\r\n4. Boolean fields: default true\r\n5. Only return valid JSON object. No explanation.\r\n\r\nOutput format: { \"POST /path\": { \"field1\": \"value1\" } }`;\r\n\r\n const user = `Module: ${moduleName}\\n\\nWrite endpoints:\\n${writeEndpoints}\\n\\nGenerate body templates (JSON):`;\r\n\r\n try {\r\n const raw = await llmChat(llm, system, user);\r\n return JSON.parse(recoverJSON(raw));\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nasync function generateParamRewrites(\r\n moduleName: string,\r\n endpoints: ApiEndpoint[],\r\n llm: LlmProvider,\r\n): Promise<Record<string, Record<string, string>>> {\r\n const paramEndpoints = endpoints\r\n .filter((e) => e.pathParams && e.pathParams.length > 0)\r\n .map((e) => `${e.method} ${e.path} → params: [${e.pathParams!.join(', ')}]`)\r\n .join('\\n');\r\n\r\n if (!paramEndpoints) return {};\r\n\r\n const system = `You are an API path analysis expert. Map generic :id parameters to semantic names.\r\nRules:\r\n1. Map generic :id to semantic names based on the preceding path segment\r\n2. /categories/:id → categoryId, /users/:id → userId\r\n3. Only return valid JSON object. No explanation.\r\n\r\nOutput format: { \"GET /path/:id\": { \"id\": \"semanticId\" } }`;\r\n\r\n const user = `Module: ${moduleName}\\n\\nEndpoints with path params:\\n${paramEndpoints}\\n\\nGenerate param rewrites (JSON):`;\r\n\r\n try {\r\n const raw = await llmChat(llm, system, user);\r\n return JSON.parse(recoverJSON(raw));\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nasync function generateSeedConfig(\r\n moduleName: string,\r\n endpoints: ApiEndpoint[],\r\n bodyTemplates: Record<string, Record<string, unknown>>,\r\n llm: LlmProvider,\r\n): Promise<SeedStep[]> {\r\n const allEndpoints = endpoints.map((e) => `${e.method} ${e.path}`).join('\\n');\r\n\r\n const system = `You are a test data dependency analysis expert. Generate beforeAll seed steps.\r\nRules:\r\n1. Use only existing API paths from the endpoint list\r\n2. Main resources must be created before sub-resources\r\n3. Use captureAs to mark IDs to capture (e.g. \"kbId\")\r\n4. dependsOn must reference previously captured variables\r\n5. required: true for essential steps\r\n6. step numbers start from 1\r\n7. Only return valid JSON array. No explanation.\r\n\r\nOutput format: [{ \"step\": 1, \"method\": \"POST\", \"path\": \"/path\", \"body\": {}, \"captureAs\": \"id\", \"required\": true, \"dependsOn\": [] }]`;\r\n\r\n const user = `Module: ${moduleName}\\n\\nAPI endpoints:\\n${allEndpoints}\\n\\nBody templates:\\n${JSON.stringify(bodyTemplates, null, 2)}\\n\\nGenerate seed config (JSON array):`;\r\n\r\n try {\r\n const raw = await llmChat(llm, system, user);\r\n const parsed = JSON.parse(recoverJSON(raw));\r\n return Array.isArray(parsed) ? parsed : [];\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\n// ============================================================\r\n// Config Validation + AI Fix\r\n// ============================================================\r\n\r\ninterface InternalValidationResult {\r\n valid: boolean;\r\n errors: string[];\r\n warnings: string[];\r\n}\r\n\r\nfunction internalValidate(config: ModuleTestConfig): InternalValidationResult {\r\n const result = validateModuleConfig(config, undefined, { skipLayers: ['semantic', 'dryrun'] });\r\n return {\r\n valid: result.passed,\r\n errors: result.errors.map((e) => `[${e.path}] ${e.message}`),\r\n warnings: result.warnings.map((w) => `[${w.path}] ${w.message}`),\r\n };\r\n}\r\n\r\nasync function fixConfigErrors(\r\n config: ModuleTestConfig,\r\n validation: InternalValidationResult,\r\n llm: LlmProvider,\r\n): Promise<ModuleTestConfig> {\r\n if (validation.valid) return config;\r\n\r\n const system = `You are a config repair expert. Fix the validation errors in this config.\r\nRules:\r\n1. Fix all listed errors\r\n2. Keep the overall structure intact\r\n3. Only return the fixed complete config as JSON. No explanation.`;\r\n\r\n const user = `Original config:\\n${JSON.stringify(config, null, 2)}\\n\\nErrors:\\n${validation.errors.join('\\n')}\\n\\nFix and return complete JSON:`;\r\n\r\n try {\r\n const raw = await llmChat(llm, system, user);\r\n return JSON.parse(recoverJSON(raw));\r\n } catch {\r\n return config;\r\n }\r\n}\r\n\r\n// ============================================================\r\n// Main Flow\r\n// ============================================================\r\n\r\n/**\r\n * Generate a module test config using AI analysis of endpoints.\r\n */\r\nexport async function generateModuleConfig(\r\n options: GenerateConfigOptions,\r\n): Promise<GenerateConfigResult> {\r\n const { moduleName, endpoints, llmProvider, maxRetries = 3 } = options;\r\n let retries = 0;\r\n\r\n console.log(`[ai-config-suggester] Generating config for \"${moduleName}\"...`);\r\n\r\n if (endpoints.length === 0) {\r\n return { success: false, error: `No endpoints found for module: ${moduleName}`, retries: 0 };\r\n }\r\n\r\n // AI generation\r\n const bodyTemplates = await generateBodyTemplates(moduleName, endpoints, llmProvider);\r\n const paramRewrites = await generateParamRewrites(moduleName, endpoints, llmProvider);\r\n const seed = await generateSeedConfig(moduleName, endpoints, bodyTemplates, llmProvider);\r\n\r\n let config: ModuleTestConfig = {\r\n moduleName,\r\n version: '1.0.0',\r\n generatedAt: new Date().toISOString(),\r\n bodyTemplates,\r\n paramRewrites,\r\n idAliases: [],\r\n specialUrls: {},\r\n seed,\r\n };\r\n\r\n // Validation + fix loop\r\n while (retries < maxRetries) {\r\n const validation = internalValidate(config);\r\n if (validation.valid) {\r\n console.log(`[ai-config-suggester] ✓ Config validated`);\r\n return { success: true, config, retries };\r\n }\r\n\r\n console.warn(`[ai-config-suggester] Validation failed (attempt ${retries + 1}), fixing...`);\r\n config = await fixConfigErrors(config, validation, llmProvider);\r\n retries++;\r\n }\r\n\r\n return {\r\n success: false,\r\n config,\r\n error: `Config validation failed after ${maxRetries} retries`,\r\n retries,\r\n };\r\n}\r\n\r\n/**\r\n * Batch generate configs for multiple modules.\r\n */\r\nexport async function generateAllModuleConfigs(\r\n moduleNames: string[],\r\n endpoints: Map<string, ApiEndpoint[]>,\r\n llmProvider: LlmProvider,\r\n options?: Partial<GenerateConfigOptions>,\r\n): Promise<Map<string, GenerateConfigResult>> {\r\n const results = new Map<string, GenerateConfigResult>();\r\n\r\n for (const moduleName of moduleNames) {\r\n const eps = endpoints.get(moduleName) || [];\r\n const result = await generateModuleConfig({\r\n moduleName,\r\n endpoints: eps,\r\n llmProvider,\r\n ...options,\r\n });\r\n results.set(moduleName, result);\r\n }\r\n\r\n const successCount = Array.from(results.values()).filter((r) => r.success).length;\r\n console.log(`[ai-config-suggester] Summary: ${successCount}/${moduleNames.length} succeeded`);\r\n\r\n return results;\r\n}\r\n","/**\r\n * Enhanced AI Config Suggester — improved config generation with:\r\n * - Richer prompts using DTO field info and validation rules\r\n * - JSON recovery with fallback strategies\r\n * - Retry with previous failure context\r\n * - Three-layer validation integration\r\n */\r\n\r\nimport type {\r\n LlmProvider,\r\n ApiEndpoint,\r\n ModuleTestConfig,\r\n SeedStep,\r\n DTOInfo,\r\n} from '../types.js';\r\nimport { recoverJSON } from './ai-config-suggester.js';\r\n\r\n// ============================================================\r\n// Types\r\n// ============================================================\r\n\r\nexport interface EnhancedGenerateOptions {\r\n moduleName: string;\r\n endpoints: ApiEndpoint[];\r\n llmProvider: LlmProvider;\r\n /** DTO info for richer prompts */\r\n dtos?: DTOInfo[];\r\n /** Example config for few-shot learning */\r\n exampleConfig?: ModuleTestConfig;\r\n /** Temperature (default 0.1) */\r\n temperature?: number;\r\n /** Max retries per phase (default 3) */\r\n maxRetries?: number;\r\n /** Single call timeout in ms (default 30000) */\r\n timeout?: number;\r\n /** Dry-run: preview only */\r\n dryRun?: boolean;\r\n}\r\n\r\nexport interface EnhancedGenerateResult {\r\n success: boolean;\r\n config?: ModuleTestConfig;\r\n attempts: AttemptRecord[];\r\n error?: string;\r\n}\r\n\r\nexport interface AttemptRecord {\r\n attempt: number;\r\n phase: 'body' | 'param' | 'seed' | 'full';\r\n rawResponse?: string;\r\n parsedJson?: unknown;\r\n error?: string;\r\n durationMs: number;\r\n}\r\n\r\n// ============================================================\r\n// AI Call with Retry\r\n// ============================================================\r\n\r\nasync function callAIWithRetry(\r\n llm: LlmProvider,\r\n systemPrompt: string,\r\n userPrompt: string,\r\n opts: { maxRetries: number; timeout: number; phase: string },\r\n): Promise<{ json: unknown; attempts: AttemptRecord[] }> {\r\n const attempts: AttemptRecord[] = [];\r\n let lastError = '';\r\n let currentUserPrompt = userPrompt;\r\n\r\n for (let i = 0; i < opts.maxRetries; i++) {\r\n const startTime = Date.now();\r\n try {\r\n const raw = await Promise.race([\r\n llm.chat([\r\n { role: 'system', content: systemPrompt },\r\n { role: 'user', content: currentUserPrompt },\r\n ]),\r\n new Promise<never>((_, reject) =>\r\n setTimeout(() => reject(new Error('AI request timeout')), opts.timeout),\r\n ),\r\n ]);\r\n\r\n const jsonStr = recoverJSON(raw);\r\n const parsed = JSON.parse(jsonStr);\r\n\r\n attempts.push({\r\n attempt: i + 1,\r\n phase: opts.phase as AttemptRecord['phase'],\r\n rawResponse: raw.substring(0, 500),\r\n parsedJson: parsed,\r\n durationMs: Date.now() - startTime,\r\n });\r\n\r\n return { json: parsed, attempts };\r\n } catch (err: unknown) {\r\n lastError = (err as Error).message || String(err);\r\n attempts.push({\r\n attempt: i + 1,\r\n phase: opts.phase as AttemptRecord['phase'],\r\n error: lastError,\r\n durationMs: Date.now() - startTime,\r\n });\r\n\r\n if (i < opts.maxRetries - 1) {\r\n currentUserPrompt += `\\n\\n[Retry ${i + 1}] Previous call failed: ${lastError}. Please regenerate.`;\r\n }\r\n }\r\n }\r\n\r\n throw Object.assign(\r\n new Error(`AI call failed after ${opts.maxRetries} retries: ${lastError}`),\r\n { attempts },\r\n );\r\n}\r\n\r\n// ============================================================\r\n// Prompt Builders\r\n// ============================================================\r\n\r\nfunction buildBodyTemplatePrompt(\r\n options: EnhancedGenerateOptions,\r\n previousError?: string,\r\n): { system: string; user: string } {\r\n const { moduleName, endpoints, dtos } = options;\r\n\r\n const dtoSummary = (dtos || [])\r\n .map((dto) => {\r\n const fields = dto.fields\r\n .filter((f) => !f.isSystemField)\r\n .map((f) => {\r\n let desc = ` - ${f.name}: ${f.type}`;\r\n if (f.required) desc += ' (required)';\r\n if (f.enumValues?.length) desc += ` [${f.enumValues.join(', ')}]`;\r\n return desc;\r\n })\r\n .join('\\n');\r\n return `${dto.name}${dto.extends ? ` extends ${dto.extends}` : ''}:\\n${fields}`;\r\n })\r\n .join('\\n\\n');\r\n\r\n const writeEndpoints = endpoints\r\n .filter((e) => ['POST', 'PUT', 'PATCH'].includes(e.method))\r\n .map((e) => `${e.method} ${e.path}${e.bodyFields?.length ? ` → body: [${e.bodyFields.join(', ')}]` : ''}`)\r\n .join('\\n');\r\n\r\n const system = `You are an E2E test config expert. Generate test body templates based on API endpoints and DTO definitions.\r\n\r\nStrict rules:\r\n1. String fields: \"__e2e_{fieldName}_{timestamp}\" format\r\n2. Enum fields: use the first declared value from DTO\r\n3. Number fields: reasonable defaults (1, 10, 100)\r\n4. Boolean fields: true\r\n5. Required fields must not be omitted\r\n6. Do not invent fields not in the DTO\r\n7. Output ONLY strict JSON, no explanation\r\n\r\nOutput format: { \"POST /path\": { \"field1\": \"value1\", \"field2\": 123 } }`;\r\n\r\n let user = `Module: ${moduleName}\r\n\r\n=== Write Endpoints ===\r\n${writeEndpoints || '(none)'}\r\n\r\n=== DTO Definitions ===\r\n${dtoSummary || '(no DTOs found)'}`;\r\n\r\n if (options.exampleConfig?.bodyTemplates) {\r\n user += `\\n\\n=== Example (verified) ===\\n${JSON.stringify(options.exampleConfig.bodyTemplates, null, 2)}`;\r\n }\r\n\r\n if (previousError) {\r\n user += `\\n\\n=== Previous failure reason ===\\n${previousError}\\nPlease fix and regenerate.`;\r\n }\r\n\r\n user += '\\n\\nGenerate body templates (strict JSON):';\r\n\r\n return { system, user };\r\n}\r\n\r\nfunction buildParamRewritePrompt(\r\n options: EnhancedGenerateOptions,\r\n): { system: string; user: string } {\r\n const { moduleName, endpoints } = options;\r\n\r\n const paramEndpoints = endpoints\r\n .filter((e) => e.pathParams && e.pathParams.length > 0)\r\n .map((e) => `${e.method} ${e.path} → params: [${e.pathParams!.join(', ')}]`)\r\n .join('\\n');\r\n\r\n const system = `You are an API path analysis expert. Map generic :id parameters to semantic names.\r\nRules:\r\n1. Map :id to semantic names based on path segment: /categories/:id → categoryId\r\n2. Only process paths with :id or similar generic params\r\n3. Output ONLY strict JSON. No explanation.\r\n\r\nOutput format: { \"GET /path/:id\": { \"id\": \"semanticId\" } }`;\r\n\r\n const user = `Module: ${moduleName}\\n\\nEndpoints with path params:\\n${paramEndpoints || '(none)'}\\n\\nGenerate param rewrites (strict JSON):`;\r\n\r\n return { system, user };\r\n}\r\n\r\nfunction buildSeedPrompt(\r\n options: EnhancedGenerateOptions,\r\n bodyTemplates: Record<string, Record<string, unknown>>,\r\n): { system: string; user: string } {\r\n const { moduleName, endpoints, dtos } = options;\r\n\r\n const allEndpoints = endpoints.map((e) => `${e.method} ${e.path}`).join('\\n');\r\n\r\n const dtoSummary = (dtos || [])\r\n .map((dto) => {\r\n const fields = dto.fields\r\n .filter((f) => !f.isSystemField)\r\n .map((f) => `${f.name}(${f.type}${f.required ? ',required' : ''})`)\r\n .join(', ');\r\n return `${dto.name}: [${fields}]`;\r\n })\r\n .join('\\n');\r\n\r\n const system = `You are a test data dependency analysis expert. Generate beforeAll seed steps.\r\n\r\nStrict rules:\r\n1. Use only existing API paths from the endpoint list\r\n2. Main resources first, then sub-resources\r\n3. Use captureAs to mark IDs to capture\r\n4. dependsOn must reference previously captured variables\r\n5. required: true for essential steps\r\n6. body must match DTO definitions\r\n7. step numbers from 1, consecutive\r\n8. Output ONLY strict JSON array. No explanation.\r\n\r\nOutput format: [{ \"step\": 1, \"method\": \"POST\", \"path\": \"/path\", \"body\": {}, \"captureAs\": \"id\", \"required\": true, \"dependsOn\": [], \"failureMessage\": \"...\" }]`;\r\n\r\n let user = `Module: ${moduleName}\r\n\r\n=== All API Endpoints ===\r\n${allEndpoints}\r\n\r\n=== DTO Definitions ===\r\n${dtoSummary || '(no DTOs)'}\r\n\r\n=== Generated Body Templates ===\r\n${JSON.stringify(bodyTemplates, null, 2)}`;\r\n\r\n user += '\\n\\nGenerate seed config (strict JSON array):';\r\n\r\n return { system, user };\r\n}\r\n\r\n// ============================================================\r\n// ID Alias Derivation\r\n// ============================================================\r\n\r\nfunction deriveIdAliases(\r\n paramRewrites: Record<string, Record<string, string>>,\r\n): Array<{ pathPattern: string; alias: string }> {\r\n const aliases: Array<{ pathPattern: string; alias: string }> = [];\r\n const seen = new Set<string>();\r\n\r\n for (const [key, mapping] of Object.entries(paramRewrites)) {\r\n const spaceIdx = key.indexOf(' ');\r\n if (spaceIdx === -1) continue;\r\n const routePath = key.substring(spaceIdx + 1);\r\n\r\n for (const [param, alias] of Object.entries(mapping)) {\r\n if (param === 'id' && !seen.has(alias)) {\r\n const segments = routePath.split('/');\r\n const idIdx = segments.findIndex((s) => s === `:${param}`);\r\n if (idIdx > 0) {\r\n aliases.push({ pathPattern: segments[idIdx - 1], alias });\r\n seen.add(alias);\r\n }\r\n }\r\n }\r\n }\r\n\r\n return aliases;\r\n}\r\n\r\n// ============================================================\r\n// Main Flow\r\n// ============================================================\r\n\r\n/**\r\n * Generate module test config with enhanced prompts and retry logic.\r\n */\r\nexport async function generateEnhancedConfig(\r\n options: EnhancedGenerateOptions,\r\n): Promise<EnhancedGenerateResult> {\r\n const {\r\n moduleName,\r\n llmProvider,\r\n maxRetries = 3,\r\n timeout = 30000,\r\n } = options;\r\n\r\n const allAttempts: AttemptRecord[] = [];\r\n\r\n console.log(`[enhanced-suggester] Generating config for \"${moduleName}\"...`);\r\n console.log(`[enhanced-suggester] ${options.dtos?.length ?? 0} DTOs, ${options.endpoints.length} endpoints`);\r\n\r\n try {\r\n // Step 1: bodyTemplates\r\n const bodyPrompt = buildBodyTemplatePrompt(options);\r\n const bodyResult = await callAIWithRetry(llmProvider, bodyPrompt.system, bodyPrompt.user, {\r\n maxRetries, timeout, phase: 'body',\r\n });\r\n allAttempts.push(...bodyResult.attempts);\r\n const bodyTemplates: Record<string, Record<string, unknown>> =\r\n typeof bodyResult.json === 'object' && !Array.isArray(bodyResult.json)\r\n ? bodyResult.json as Record<string, Record<string, unknown>>\r\n : {};\r\n\r\n // Step 2: paramRewrites\r\n const paramPrompt = buildParamRewritePrompt(options);\r\n const paramResult = await callAIWithRetry(llmProvider, paramPrompt.system, paramPrompt.user, {\r\n maxRetries, timeout, phase: 'param',\r\n });\r\n allAttempts.push(...paramResult.attempts);\r\n const paramRewrites: Record<string, Record<string, string>> =\r\n typeof paramResult.json === 'object' && !Array.isArray(paramResult.json)\r\n ? paramResult.json as Record<string, Record<string, string>>\r\n : {};\r\n\r\n // Step 3: seed\r\n const seedPrompt = buildSeedPrompt(options, bodyTemplates);\r\n const seedResult = await callAIWithRetry(llmProvider, seedPrompt.system, seedPrompt.user, {\r\n maxRetries, timeout, phase: 'seed',\r\n });\r\n allAttempts.push(...seedResult.attempts);\r\n const seed: SeedStep[] = Array.isArray(seedResult.json) ? seedResult.json as SeedStep[] : [];\r\n\r\n const idAliases = deriveIdAliases(paramRewrites);\r\n\r\n const config: ModuleTestConfig = {\r\n moduleName,\r\n version: '1.0.0',\r\n generatedAt: new Date().toISOString(),\r\n bodyTemplates,\r\n paramRewrites,\r\n idAliases,\r\n specialUrls: {},\r\n seed,\r\n };\r\n\r\n return { success: true, config, attempts: allAttempts };\r\n } catch (err: unknown) {\r\n const errorAttempts = (err as { attempts?: AttemptRecord[] }).attempts || [];\r\n allAttempts.push(...errorAttempts);\r\n\r\n return {\r\n success: false,\r\n attempts: allAttempts,\r\n error: (err as Error).message || String(err),\r\n };\r\n }\r\n}\r\n","/**\r\n * Auto-Fixer — automatic config repair based on validation errors.\r\n *\r\n * Four fix strategies:\r\n * 1. InterfacePathMismatchFixer: find the closest matching real route\r\n * 2. MissingDtoFieldFixer: fill in missing required fields from DTO\r\n * 3. SeedDependencyOrderFixer: topological sort of seed steps\r\n * 4. ParamMappingFixer: regenerate paramRewrites from actual routes\r\n */\r\n\r\nimport type {\r\n ModuleTestConfig,\r\n SeedStep,\r\n ApiEndpoint,\r\n DTOFieldInfo,\r\n FixContext,\r\n FixHistoryEntry,\r\n FixResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationContext,\r\n} from '../types.js';\r\nimport { validateModuleConfig } from '../validators/config-validator.js';\r\n\r\n// ============================================================\r\n// Strategy Interface\r\n// ============================================================\r\n\r\ninterface FixStrategy {\r\n name: string;\r\n applies: (error: ModuleConfigValidationError) => boolean;\r\n fix: (config: ModuleTestConfig, error: ModuleConfigValidationError, context: FixContext) => ModuleTestConfig;\r\n priority: number;\r\n}\r\n\r\n// ============================================================\r\n// Utils\r\n// ============================================================\r\n\r\nfunction deepClone<T>(obj: T): T {\r\n return JSON.parse(JSON.stringify(obj));\r\n}\r\n\r\nfunction pathSimilarity(a: string, b: string): number {\r\n const segA = a.split('/').filter(Boolean);\r\n const segB = b.split('/').filter(Boolean);\r\n let matches = 0;\r\n const maxLen = Math.max(segA.length, segB.length);\r\n if (maxLen === 0) return 1;\r\n for (let i = 0; i < Math.min(segA.length, segB.length); i++) {\r\n if (segA[i] === segB[i]) matches++;\r\n else if (segA[i].startsWith(':') || segB[i].startsWith(':')) matches += 0.5;\r\n }\r\n return matches / maxLen;\r\n}\r\n\r\nfunction findMostSimilarEndpoint(method: string, brokenPath: string, endpoints: ApiEndpoint[]): ApiEndpoint | undefined {\r\n const sameMethod = endpoints.filter((e) => e.method === method);\r\n let bestScore = 0;\r\n let bestMatch: ApiEndpoint | undefined;\r\n for (const ep of sameMethod) {\r\n const score = pathSimilarity(brokenPath, ep.path);\r\n if (score > bestScore) { bestScore = score; bestMatch = ep; }\r\n }\r\n return bestScore >= 0.5 ? bestMatch : undefined;\r\n}\r\n\r\nfunction segmentToIdName(segment: string): string {\r\n const clean = segment.replace(/^aigc-/, '');\r\n const parts = clean.split('-');\r\n if (parts.length === 1) return parts[0].replace(/s$/, '') + 'Id';\r\n return parts.map((p) => p[0]).join('') + 'Id';\r\n}\r\n\r\nfunction generateDefaultValue(field: DTOFieldInfo): unknown {\r\n if (field.enumValues?.length) return field.enumValues[0];\r\n switch (field.type.toLowerCase()) {\r\n case 'string': return `__e2e_${field.name}_${Date.now()}`;\r\n case 'number': return 1;\r\n case 'boolean': return true;\r\n case 'date': return new Date().toISOString();\r\n default:\r\n if (field.type.includes('[]') || field.type.includes('Array')) return [];\r\n return `__e2e_${field.name}`;\r\n }\r\n}\r\n\r\nfunction detectChangedKeys(before: ModuleTestConfig, after: ModuleTestConfig): string[] {\r\n const keys: string[] = [];\r\n const b = before as unknown as Record<string, unknown>;\r\n const a = after as unknown as Record<string, unknown>;\r\n const allKeys = new Set([...Object.keys(b), ...Object.keys(a)]);\r\n for (const key of allKeys) {\r\n if (JSON.stringify(b[key]) !== JSON.stringify(a[key])) {\r\n keys.push(key);\r\n }\r\n }\r\n return keys;\r\n}\r\n\r\n// ============================================================\r\n// Strategy 1: InterfacePathMismatchFixer\r\n// ============================================================\r\n\r\nconst interfacePathMismatchFixer: FixStrategy = {\r\n name: 'InterfacePathMismatchFixer',\r\n priority: 100,\r\n applies: (error) => error.type === 'interface-not-found' || error.type === 'param-mapping-invalid',\r\n fix: (config, error, context) => {\r\n const fixed = deepClone(config);\r\n const match = error.message.match(/['\"]?(GET|POST|PUT|DELETE|PATCH)\\s+([^'\"]+)['\"]?/);\r\n if (!match) return fixed;\r\n\r\n const [, method, brokenPath] = match;\r\n const bestMatch = findMostSimilarEndpoint(method, brokenPath, context.endpoints);\r\n if (!bestMatch) return fixed;\r\n\r\n const oldKey = `${method} ${brokenPath}`;\r\n const newKey = `${method} ${bestMatch.path}`;\r\n\r\n if (error.path.startsWith('bodyTemplates') && fixed.bodyTemplates[oldKey]) {\r\n fixed.bodyTemplates[newKey] = fixed.bodyTemplates[oldKey];\r\n delete fixed.bodyTemplates[oldKey];\r\n }\r\n if (error.path.startsWith('paramRewrites') && fixed.paramRewrites[oldKey]) {\r\n fixed.paramRewrites[newKey] = fixed.paramRewrites[oldKey];\r\n delete fixed.paramRewrites[oldKey];\r\n }\r\n if (error.path.startsWith('seed')) {\r\n for (const step of fixed.seed) {\r\n if (step.method === method && step.path === brokenPath) {\r\n step.path = bestMatch.path;\r\n }\r\n }\r\n }\r\n return fixed;\r\n },\r\n};\r\n\r\n// ============================================================\r\n// Strategy 2: MissingDtoFieldFixer\r\n// ============================================================\r\n\r\nconst missingDtoFieldFixer: FixStrategy = {\r\n name: 'MissingDtoFieldFixer',\r\n priority: 90,\r\n applies: (error) => error.type === 'field-missing' || (error.type === 'missing-field' && error.path.startsWith('bodyTemplates')),\r\n fix: (config, error, context) => {\r\n const fixed = deepClone(config);\r\n const fieldMatch = error.message.match(/field '(\\w+)'/);\r\n if (!fieldMatch) return fixed;\r\n const missingField = fieldMatch[1];\r\n\r\n const dtoMatch = error.message.match(/from (\\w+)/);\r\n const dto = dtoMatch ? context.dtos.find((d) => d.name === dtoMatch[1]) : context.dtos[0];\r\n if (!dto) return fixed;\r\n\r\n const fieldDef = dto.fields.find((f) => f.name === missingField);\r\n if (!fieldDef) return fixed;\r\n\r\n const defaultValue = generateDefaultValue(fieldDef);\r\n\r\n for (const [key, body] of Object.entries(fixed.bodyTemplates)) {\r\n const method = key.split(' ')[0];\r\n if (['POST', 'PUT', 'PATCH'].includes(method) && !(missingField in body)) {\r\n (body as Record<string, unknown>)[missingField] = defaultValue;\r\n }\r\n }\r\n return fixed;\r\n },\r\n};\r\n\r\n// ============================================================\r\n// Strategy 3: SeedDependencyOrderFixer\r\n// ============================================================\r\n\r\nconst seedDependencyOrderFixer: FixStrategy = {\r\n name: 'SeedDependencyOrderFixer',\r\n priority: 80,\r\n applies: (error) => error.type === 'dependency-missing' || error.type === 'dependency-cycle' || error.type === 'seed-order-invalid',\r\n fix: (config) => {\r\n const fixed = deepClone(config);\r\n if (!fixed.seed || fixed.seed.length === 0) return fixed;\r\n\r\n const sorted = topologicalSortSeed(fixed.seed);\r\n if (sorted) fixed.seed = sorted;\r\n return fixed;\r\n },\r\n};\r\n\r\nfunction topologicalSortSeed(seed: SeedStep[]): SeedStep[] | null {\r\n const captureToStep = new Map<string, SeedStep>();\r\n for (const step of seed) {\r\n if (step.captureAs) captureToStep.set(step.captureAs, step);\r\n }\r\n\r\n const inDegree = new Map<number, number>();\r\n const adj = new Map<number, number[]>();\r\n for (const step of seed) {\r\n inDegree.set(step.step, 0);\r\n adj.set(step.step, []);\r\n }\r\n\r\n for (const step of seed) {\r\n if (step.dependsOn) {\r\n for (const dep of step.dependsOn) {\r\n const depStep = captureToStep.get(dep);\r\n if (depStep) {\r\n adj.get(depStep.step)?.push(step.step);\r\n inDegree.set(step.step, (inDegree.get(step.step) || 0) + 1);\r\n }\r\n }\r\n }\r\n }\r\n\r\n const queue: number[] = [];\r\n for (const [stepNum, degree] of inDegree) {\r\n if (degree === 0) queue.push(stepNum);\r\n }\r\n\r\n const sorted: SeedStep[] = [];\r\n const stepMap = new Map(seed.map((s) => [s.step, s]));\r\n\r\n while (queue.length > 0) {\r\n const current = queue.shift()!;\r\n const step = stepMap.get(current);\r\n if (step) sorted.push(step);\r\n for (const next of adj.get(current) || []) {\r\n inDegree.set(next, (inDegree.get(next) || 0) - 1);\r\n if (inDegree.get(next) === 0) queue.push(next);\r\n }\r\n }\r\n\r\n if (sorted.length !== seed.length) return null; // has cycle\r\n return sorted.map((s, i) => ({ ...s, step: i + 1 }));\r\n}\r\n\r\n// ============================================================\r\n// Strategy 4: ParamMappingFixer\r\n// ============================================================\r\n\r\nconst paramMappingFixer: FixStrategy = {\r\n name: 'ParamMappingFixer',\r\n priority: 70,\r\n applies: (error) => error.type === 'param-mapping-invalid',\r\n fix: (config, _error, context) => {\r\n const fixed = deepClone(config);\r\n const newRewrites: Record<string, Record<string, string>> = {};\r\n\r\n for (const ep of context.endpoints) {\r\n if (!ep.pathParams || ep.pathParams.length === 0) continue;\r\n const key = `${ep.method} ${ep.path}`;\r\n const mapping: Record<string, string> = {};\r\n\r\n for (const param of ep.pathParams) {\r\n if (param === 'id') {\r\n const segments = ep.path.split('/');\r\n const idIdx = segments.indexOf(':id');\r\n if (idIdx > 0) {\r\n mapping[param] = segmentToIdName(segments[idIdx - 1]);\r\n }\r\n }\r\n }\r\n if (Object.keys(mapping).length > 0) newRewrites[key] = mapping;\r\n }\r\n\r\n fixed.paramRewrites = newRewrites;\r\n return fixed;\r\n },\r\n};\r\n\r\n// ============================================================\r\n// Strategy Registry (sorted by priority desc)\r\n// ============================================================\r\n\r\nconst ALL_STRATEGIES: FixStrategy[] = [\r\n interfacePathMismatchFixer,\r\n missingDtoFieldFixer,\r\n seedDependencyOrderFixer,\r\n paramMappingFixer,\r\n].sort((a, b) => b.priority - a.priority);\r\n\r\n// ============================================================\r\n// Main Fix Flow\r\n// ============================================================\r\n\r\n/**\r\n * Run automatic fix loop on a module test config.\r\n */\r\nexport function autoFix(\r\n config: ModuleTestConfig,\r\n initialErrors: ModuleConfigValidationError[],\r\n context: FixContext,\r\n validationContext?: ModuleConfigValidationContext,\r\n maxAttempts = 3,\r\n): FixResult {\r\n const history: FixHistoryEntry[] = [];\r\n let currentConfig = deepClone(config);\r\n let currentErrors = initialErrors.filter((e) => e.layer !== 'dryrun');\r\n\r\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\r\n if (currentErrors.length === 0) break;\r\n\r\n let fixApplied = false;\r\n\r\n for (const error of [...currentErrors]) {\r\n const strategy = ALL_STRATEGIES.find((s) => s.applies(error));\r\n if (!strategy) continue;\r\n\r\n const before = currentConfig;\r\n currentConfig = strategy.fix(currentConfig, error, context);\r\n fixApplied = true;\r\n\r\n history.push({\r\n timestamp: new Date().toISOString(),\r\n attempt,\r\n errorType: error.type,\r\n errorPath: error.path,\r\n errorMessage: error.message,\r\n fixerUsed: strategy.name,\r\n changedKeys: detectChangedKeys(before, currentConfig),\r\n validationPassedAfterFix: false,\r\n });\r\n }\r\n\r\n if (!fixApplied) break;\r\n\r\n // Re-validate\r\n const revalidation = validateModuleConfig(\r\n currentConfig,\r\n validationContext,\r\n { skipLayers: ['dryrun'] },\r\n );\r\n currentErrors = revalidation.errors;\r\n\r\n if (history.length > 0) {\r\n history[history.length - 1].validationPassedAfterFix = currentErrors.length === 0;\r\n }\r\n\r\n if (currentErrors.length === 0) break;\r\n }\r\n\r\n return {\r\n success: currentErrors.length === 0,\r\n config: currentConfig,\r\n totalAttempts: history.length,\r\n history,\r\n remainingErrors: currentErrors,\r\n };\r\n}\r\n","/**\r\n * Baseline Comparator — compare AI-generated test runs against hardcoded baselines.\r\n *\r\n * Workflow:\r\n * 1. Parse Playwright JSON reports from both baseline and AI-config runs\r\n * 2. Diff each test case: regression / improvement / unchanged / new / removed\r\n * 3. Generate prompt optimization suggestions from failure patterns\r\n * 4. Output formatted comparison report\r\n */\r\n\r\n\r\n\r\n// ============================================================\r\n// Types\r\n// ============================================================\r\n\r\nexport interface TestCaseResult {\r\n title: string;\r\n file: string;\r\n suite: string;\r\n status: 'passed' | 'failed' | 'skipped' | 'timedOut';\r\n durationMs: number;\r\n error?: string;\r\n}\r\n\r\nexport interface TestRunSummary {\r\n label: string;\r\n timestamp: string;\r\n modules: string[];\r\n total: number;\r\n passed: number;\r\n failed: number;\r\n skipped: number;\r\n timedOut: number;\r\n passRate: number;\r\n totalDurationMs: number;\r\n avgDurationMs: number;\r\n cases: TestCaseResult[];\r\n}\r\n\r\nexport interface CaseDiff {\r\n title: string;\r\n file: string;\r\n change: 'regression' | 'improvement' | 'unchanged' | 'new' | 'removed';\r\n baselineStatus: TestCaseResult['status'] | null;\r\n aiConfigStatus: TestCaseResult['status'] | null;\r\n durationDiffMs: number;\r\n error?: string;\r\n}\r\n\r\nexport interface PromptOptimization {\r\n category: 'seed-config' | 'body-template' | 'param-rewrite' | 'id-alias' | 'general';\r\n issue: string;\r\n suggestion: string;\r\n relatedCases: string[];\r\n}\r\n\r\nexport interface ComparisonReport {\r\n baseline: TestRunSummary;\r\n aiConfig: TestRunSummary;\r\n passRateDiff: number;\r\n /** AI pass rate >= 85% of baseline */\r\n meetsThreshold: boolean;\r\n durationChangePercent: number;\r\n /** Duration change within ±10% */\r\n durationAcceptable: boolean;\r\n diffs: CaseDiff[];\r\n regressions: CaseDiff[];\r\n improvements: CaseDiff[];\r\n promptOptimizations: PromptOptimization[];\r\n}\r\n\r\n// ============================================================\r\n// Playwright JSON Report Parsing\r\n// ============================================================\r\n\r\n/**\r\n * Parse a Playwright `--reporter=json` output into a TestRunSummary.\r\n */\r\nexport function parsePlaywrightReport(\r\n reportJson: Record<string, unknown>,\r\n label: string,\r\n modules: string[],\r\n): TestRunSummary {\r\n const cases: TestCaseResult[] = [];\r\n\r\n if (reportJson?.suites && Array.isArray(reportJson.suites)) {\r\n for (const suite of reportJson.suites) {\r\n extractCases(suite, suite.title || '', cases);\r\n }\r\n }\r\n\r\n return buildTestRunSummary(label, modules, cases);\r\n}\r\n\r\nfunction extractCases(suite: Record<string, unknown>, parentTitle: string, result: TestCaseResult[]): void {\r\n const suiteTitle = parentTitle\r\n ? `${parentTitle} > ${(suite.title as string) || ''}`\r\n : (suite.title as string) || '';\r\n\r\n if (Array.isArray(suite.specs)) {\r\n for (const spec of suite.specs) {\r\n for (const test of spec.tests || []) {\r\n for (const testResult of test.results || []) {\r\n result.push({\r\n title: spec.title || '',\r\n file: (suite.file as string) || '',\r\n suite: suiteTitle,\r\n status: normalizeStatus(testResult.status),\r\n durationMs: testResult.duration || 0,\r\n error: testResult.error?.message,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (Array.isArray(suite.suites)) {\r\n for (const child of suite.suites) {\r\n extractCases({ ...child, file: child.file || suite.file }, suiteTitle, result);\r\n }\r\n }\r\n}\r\n\r\nfunction normalizeStatus(status: string): TestCaseResult['status'] {\r\n switch (status) {\r\n case 'passed': case 'expected': return 'passed';\r\n case 'failed': case 'unexpected': return 'failed';\r\n case 'skipped': return 'skipped';\r\n case 'timedOut': return 'timedOut';\r\n default: return 'failed';\r\n }\r\n}\r\n\r\n/**\r\n * Build a TestRunSummary from raw test case results.\r\n */\r\nexport function buildTestRunSummary(label: string, modules: string[], cases: TestCaseResult[]): TestRunSummary {\r\n const passed = cases.filter((c) => c.status === 'passed').length;\r\n const failed = cases.filter((c) => c.status === 'failed').length;\r\n const skipped = cases.filter((c) => c.status === 'skipped').length;\r\n const timedOut = cases.filter((c) => c.status === 'timedOut').length;\r\n const totalDurationMs = cases.reduce((s, c) => s + c.durationMs, 0);\r\n\r\n return {\r\n label,\r\n timestamp: new Date().toISOString(),\r\n modules,\r\n total: cases.length,\r\n passed, failed, skipped, timedOut,\r\n passRate: cases.length > 0 ? passed / cases.length : 0,\r\n totalDurationMs,\r\n avgDurationMs: cases.length > 0 ? Math.round(totalDurationMs / cases.length) : 0,\r\n cases,\r\n };\r\n}\r\n\r\n// ============================================================\r\n// Comparison\r\n// ============================================================\r\n\r\n/**\r\n * Compare two test runs and produce a detailed comparison report.\r\n */\r\nexport function compareTestRuns(baseline: TestRunSummary, aiConfig: TestRunSummary): ComparisonReport {\r\n const baselineMap = new Map(baseline.cases.map((c) => [caseKey(c), c]));\r\n const aiMap = new Map(aiConfig.cases.map((c) => [caseKey(c), c]));\r\n\r\n const allKeys = new Set([...baselineMap.keys(), ...aiMap.keys()]);\r\n const diffs: CaseDiff[] = [];\r\n\r\n for (const key of allKeys) {\r\n const base = baselineMap.get(key) ?? null;\r\n const ai = aiMap.get(key) ?? null;\r\n\r\n diffs.push({\r\n title: base?.title ?? ai?.title ?? key,\r\n file: base?.file ?? ai?.file ?? '',\r\n change: classifyChange(base?.status ?? null, ai?.status ?? null),\r\n baselineStatus: base?.status ?? null,\r\n aiConfigStatus: ai?.status ?? null,\r\n durationDiffMs: (ai?.durationMs ?? 0) - (base?.durationMs ?? 0),\r\n error: ai?.error,\r\n });\r\n }\r\n\r\n const regressions = diffs.filter((d) => d.change === 'regression');\r\n const improvements = diffs.filter((d) => d.change === 'improvement');\r\n const passRateDiff = aiConfig.passRate - baseline.passRate;\r\n const meetsThreshold = baseline.passRate > 0 ? aiConfig.passRate >= baseline.passRate * 0.85 : true;\r\n const durationChangePercent = baseline.totalDurationMs > 0\r\n ? ((aiConfig.totalDurationMs - baseline.totalDurationMs) / baseline.totalDurationMs) * 100\r\n : 0;\r\n\r\n return {\r\n baseline,\r\n aiConfig,\r\n passRateDiff,\r\n meetsThreshold,\r\n durationChangePercent,\r\n durationAcceptable: Math.abs(durationChangePercent) <= 10,\r\n diffs,\r\n regressions,\r\n improvements,\r\n promptOptimizations: analyzeFailures(regressions),\r\n };\r\n}\r\n\r\nfunction caseKey(c: TestCaseResult): string {\r\n return `${c.file}::${c.title}`;\r\n}\r\n\r\nfunction classifyChange(\r\n base: TestCaseResult['status'] | null,\r\n ai: TestCaseResult['status'] | null,\r\n): CaseDiff['change'] {\r\n if (!base) return 'new';\r\n if (!ai) return 'removed';\r\n if (base === ai) return 'unchanged';\r\n if (base === 'passed' && ai !== 'passed') return 'regression';\r\n if (base !== 'passed' && ai === 'passed') return 'improvement';\r\n return 'unchanged';\r\n}\r\n\r\n// ============================================================\r\n// Failure Analysis → Prompt Optimization\r\n// ============================================================\r\n\r\nfunction analyzeFailures(regressions: CaseDiff[]): PromptOptimization[] {\r\n const optimizations: PromptOptimization[] = [];\r\n const seedKw = ['seed', 'beforeall', 'setup', 'beforeeach'];\r\n const bodyKw = ['body', 'required', 'validation', '400', 'bad request', 'field'];\r\n const paramKw = ['param', ':id', 'undefined', 'null', '404', 'not found'];\r\n\r\n const seedFails = regressions.filter((r) => r.error && seedKw.some((k) => r.error!.toLowerCase().includes(k)));\r\n const bodyFails = regressions.filter((r) => r.error && bodyKw.some((k) => r.error!.toLowerCase().includes(k)));\r\n const paramFails = regressions.filter((r) => r.error && paramKw.some((k) => r.error!.toLowerCase().includes(k)));\r\n\r\n if (seedFails.length > 0) {\r\n optimizations.push({\r\n category: 'seed-config',\r\n issue: `${seedFails.length} test(s) regressed due to seed data preparation failures`,\r\n suggestion: 'Ensure AI-generated seed paths match actual API routes and dependency order is correct.',\r\n relatedCases: seedFails.map((r) => r.title),\r\n });\r\n }\r\n\r\n if (bodyFails.length > 0) {\r\n optimizations.push({\r\n category: 'body-template',\r\n issue: `${bodyFails.length} test(s) regressed due to incomplete body templates`,\r\n suggestion: 'List all required fields in prompts, include DTO enum constraints.',\r\n relatedCases: bodyFails.map((r) => r.title),\r\n });\r\n }\r\n\r\n if (paramFails.length > 0) {\r\n optimizations.push({\r\n category: 'param-rewrite',\r\n issue: `${paramFails.length} test(s) regressed due to parameter mapping errors`,\r\n suggestion: 'Explicitly define :id → semantic name mappings in prompts.',\r\n relatedCases: paramFails.map((r) => r.title),\r\n });\r\n }\r\n\r\n const other = regressions.filter(\r\n (r) => !seedFails.includes(r) && !bodyFails.includes(r) && !paramFails.includes(r),\r\n );\r\n if (other.length > 0) {\r\n optimizations.push({\r\n category: 'general',\r\n issue: `${other.length} test(s) regressed due to other reasons`,\r\n suggestion: 'Inspect individual error messages for business logic or data dependency issues.',\r\n relatedCases: other.map((r) => r.title),\r\n });\r\n }\r\n\r\n return optimizations;\r\n}\r\n\r\n// ============================================================\r\n// Report Formatting\r\n// ============================================================\r\n\r\n/**\r\n * Format a ComparisonReport into human-readable text.\r\n */\r\nexport function formatComparisonReport(report: ComparisonReport): string {\r\n const lines: string[] = [];\r\n\r\n lines.push('═'.repeat(60));\r\n lines.push(' Baseline Comparison Report');\r\n lines.push('═'.repeat(60), '');\r\n\r\n lines.push('┌─ Pass Rate ────────────────────────────────────┐');\r\n lines.push(`│ Baseline (${report.baseline.label}): ${(report.baseline.passRate * 100).toFixed(1)}% (${report.baseline.passed}/${report.baseline.total})`);\r\n lines.push(`│ AI Config (${report.aiConfig.label}): ${(report.aiConfig.passRate * 100).toFixed(1)}% (${report.aiConfig.passed}/${report.aiConfig.total})`);\r\n lines.push(`│ Diff: ${report.passRateDiff >= 0 ? '+' : ''}${(report.passRateDiff * 100).toFixed(1)}pp`);\r\n lines.push(`│ Meets threshold (≥ 85%): ${report.meetsThreshold ? '✓' : '✗'}`);\r\n lines.push('└────────────────────────────────────────────────┘', '');\r\n\r\n lines.push('┌─ Duration ─────────────────────────────────────┐');\r\n lines.push(`│ Baseline: ${(report.baseline.totalDurationMs / 1000).toFixed(2)}s`);\r\n lines.push(`│ AI Config: ${(report.aiConfig.totalDurationMs / 1000).toFixed(2)}s`);\r\n lines.push(`│ Change: ${report.durationChangePercent >= 0 ? '+' : ''}${report.durationChangePercent.toFixed(1)}%`);\r\n lines.push(`│ Acceptable (±10%): ${report.durationAcceptable ? '✓' : '✗'}`);\r\n lines.push('└────────────────────────────────────────────────┘', '');\r\n\r\n if (report.regressions.length > 0) {\r\n lines.push(`⚠ Regressions (${report.regressions.length}):`);\r\n for (const r of report.regressions) {\r\n lines.push(` ✗ ${r.title}`);\r\n if (r.error) lines.push(` Error: ${r.error.substring(0, 100)}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n if (report.improvements.length > 0) {\r\n lines.push(`✓ Improvements (${report.improvements.length}):`);\r\n for (const imp of report.improvements) lines.push(` ✓ ${imp.title}`);\r\n lines.push('');\r\n }\r\n\r\n if (report.promptOptimizations.length > 0) {\r\n lines.push('─'.repeat(60));\r\n lines.push(' Prompt Optimization Suggestions');\r\n lines.push('─'.repeat(60));\r\n for (const opt of report.promptOptimizations) {\r\n lines.push(`\\n [${opt.category}] ${opt.issue}`);\r\n lines.push(` Suggestion: ${opt.suggestion}`);\r\n lines.push(` Related: ${opt.relatedCases.join(', ')}`);\r\n }\r\n }\r\n\r\n lines.push('', '═'.repeat(60));\r\n return lines.join('\\n');\r\n}\r\n","/**\r\n * Module Config Preset Loader\r\n *\r\n * Loads pre-generated module test configs (JSON) from a directory,\r\n * validates them, and provides lookup by module name.\r\n *\r\n * This supports the 70 module configs migrated from dynamic-gen/module-configs/.\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\nimport type { ModuleTestConfig } from '../types.js';\r\nimport { validateModuleConfig } from '../validators/config-validator.js';\r\n\r\nexport interface PresetLoadResult {\r\n configs: Map<string, ModuleTestConfig>;\r\n errors: Array<{ file: string; error: string }>;\r\n totalLoaded: number;\r\n totalFailed: number;\r\n}\r\n\r\n/**\r\n * Load all module config presets from a directory.\r\n *\r\n * @param configDir - Path to directory containing *.json module configs\r\n * @param options.validate - Run schema validation on each config (default: true)\r\n * @returns Loaded configs indexed by moduleName\r\n */\r\nexport function loadModulePresets(\r\n configDir: string,\r\n options?: { validate?: boolean },\r\n): PresetLoadResult {\r\n const doValidate = options?.validate ?? true;\r\n const configs = new Map<string, ModuleTestConfig>();\r\n const errors: Array<{ file: string; error: string }> = [];\r\n\r\n const absDir = path.resolve(configDir);\r\n if (!fs.existsSync(absDir)) {\r\n return { configs, errors: [{ file: absDir, error: 'Directory does not exist' }], totalLoaded: 0, totalFailed: 1 };\r\n }\r\n\r\n const files = fs.readdirSync(absDir).filter((f) => f.endsWith('.json') && !f.includes('.fix-history'));\r\n\r\n for (const file of files) {\r\n const filePath = path.join(absDir, file);\r\n try {\r\n const content = fs.readFileSync(filePath, 'utf-8');\r\n const config: ModuleTestConfig = JSON.parse(content);\r\n\r\n if (!config.moduleName) {\r\n errors.push({ file, error: 'Missing moduleName field' });\r\n continue;\r\n }\r\n\r\n // Optional validation\r\n if (doValidate) {\r\n const result = validateModuleConfig(config, undefined, { skipLayers: ['semantic', 'dryrun'] });\r\n if (!result.passed) {\r\n const errorMsgs = result.errors.map((e) => `[${e.path}] ${e.message}`).join('; ');\r\n errors.push({ file, error: `Schema validation failed: ${errorMsgs}` });\r\n // Still load it — it's usable even with warnings\r\n }\r\n }\r\n\r\n configs.set(config.moduleName, config);\r\n } catch (err) {\r\n errors.push({ file, error: (err as Error).message });\r\n }\r\n }\r\n\r\n return {\r\n configs,\r\n errors,\r\n totalLoaded: configs.size,\r\n totalFailed: errors.length,\r\n };\r\n}\r\n\r\n/**\r\n * Get a single module config by name from a preset directory.\r\n */\r\nexport function getModulePreset(\r\n configDir: string,\r\n moduleName: string,\r\n): ModuleTestConfig | null {\r\n const filePath = path.resolve(configDir, `${moduleName}.json`);\r\n if (!fs.existsSync(filePath)) return null;\r\n\r\n try {\r\n const content = fs.readFileSync(filePath, 'utf-8');\r\n return JSON.parse(content);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * List all available module preset names from a directory.\r\n */\r\nexport function listModulePresets(configDir: string): string[] {\r\n const absDir = path.resolve(configDir);\r\n if (!fs.existsSync(absDir)) return [];\r\n\r\n return fs.readdirSync(absDir)\r\n .filter((f) => f.endsWith('.json') && !f.includes('.fix-history'))\r\n .map((f) => f.replace(/\\.json$/, ''));\r\n}\r\n","import type { SelfHealingConfig, SelfHealingResult, FixOutcome, LlmProvider } from '../types.js';\r\nimport { SYSTEM_PROMPTS } from '../llm/index.js';\r\n\r\nexport type { SelfHealingResult, FixOutcome };\r\n\r\n// Advanced Self-Healing (v1.1)\r\nexport { runDialogLoop, createJsonResultParser } from './dialog-loop-runner.js';\r\nexport type { TestRunner, ResultParser, FixApplier, DialogLoopOptions } from './dialog-loop-runner.js';\r\nexport { applyControlledFix } from './controlled-fixer.js';\r\nexport type { ConfigValidator, ConfigFixer, PRGenerator, FsOps, ControlledFixerOptions } from './controlled-fixer.js';\r\nexport { generateFixPR } from './auto-fix-generator.js';\r\nexport type { GitExecutor, PatchWriter } from './auto-fix-generator.js';\r\n\r\nexport interface SelfHealingLoop {\r\n run(testResultsDir: string): Promise<SelfHealingResult>;\r\n}\r\n\r\nexport interface SelfHealingOptions {\r\n config: SelfHealingConfig;\r\n llm?: LlmProvider;\r\n}\r\n\r\n/**\r\n * Categorize a test failure by heuristic rules.\r\n */\r\nexport function categorizeFailure(errorMessage: string): {\r\n category: string;\r\n confidence: number;\r\n} {\r\n const msg = errorMessage.toLowerCase();\r\n\r\n if (/5\\d{2}|internal server error/.test(msg))\r\n return { category: 'backend-5xx', confidence: 0.9 };\r\n if (/timeout|timed?\\s*out/.test(msg))\r\n return { category: 'timeout', confidence: 0.8 };\r\n if (/404|not found/.test(msg))\r\n return { category: 'endpoint-not-found', confidence: 0.85 };\r\n if (/4[0-2]\\d|validation|constraint/.test(msg))\r\n return { category: 'data-constraint', confidence: 0.75 };\r\n if (/econnrefused|enotfound|network/.test(msg))\r\n return { category: 'network', confidence: 0.9 };\r\n if (/selector|locator|element/.test(msg))\r\n return { category: 'frontend-render', confidence: 0.7 };\r\n if (/storage\\s*state|auth|login/.test(msg))\r\n return { category: 'test-script', confidence: 0.8 };\r\n\r\n return { category: 'unknown', confidence: 0.5 };\r\n}\r\n\r\n/**\r\n * LLM-enhanced failure analysis with heuristic fallback.\r\n */\r\nexport async function analyzeFailureWithLLM(\r\n errorMessage: string,\r\n llm?: LlmProvider,\r\n): Promise<{ rootCause: string; category: string; suggestedFix: string; confidence: number }> {\r\n // Always get heuristic result as fallback\r\n const heuristic = categorizeFailure(errorMessage);\r\n\r\n if (!llm) {\r\n return {\r\n rootCause: errorMessage,\r\n category: heuristic.category,\r\n suggestedFix: '',\r\n confidence: heuristic.confidence,\r\n };\r\n }\r\n\r\n try {\r\n const response = await llm.chat([\r\n { role: 'system', content: SYSTEM_PROMPTS.failureAnalysis },\r\n { role: 'user', content: `Analyze this test failure:\\n\\n${errorMessage}` },\r\n ]);\r\n\r\n const parsed = JSON.parse(response) as {\r\n rootCause?: string;\r\n category?: string;\r\n suggestedFix?: string;\r\n confidence?: number;\r\n };\r\n\r\n return {\r\n rootCause: parsed.rootCause || errorMessage,\r\n category: parsed.category || heuristic.category,\r\n suggestedFix: parsed.suggestedFix || '',\r\n confidence: parsed.confidence || heuristic.confidence,\r\n };\r\n } catch {\r\n // LLM failed — fall back to heuristic\r\n return {\r\n rootCause: errorMessage,\r\n category: heuristic.category,\r\n suggestedFix: '',\r\n confidence: heuristic.confidence,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Attempt a config-only fix: validate and write corrected config JSON.\r\n */\r\nasync function attemptConfigFix(\r\n _testResultsDir: string,\r\n _mode: SelfHealingConfig['mode'],\r\n _llm?: LlmProvider,\r\n): Promise<FixOutcome> {\r\n // TODO: Load module config → run autoFix validation → write corrected JSON\r\n // For now, return a no-op outcome\r\n return {\r\n success: false,\r\n scope: 'config-only',\r\n fixedItems: [],\r\n rolledBack: false,\r\n };\r\n}\r\n\r\n/**\r\n * Create a self-healing loop. Accepts an optional LLM provider for AI-enhanced analysis.\r\n */\r\nexport function createSelfHealingLoop(config: SelfHealingConfig, llm?: LlmProvider): SelfHealingLoop {\r\n return {\r\n async run(testResultsDir: string): Promise<SelfHealingResult> {\r\n const maxIterations = config.maxIterations || 3;\r\n const mode = config.mode || 'config-only';\r\n const fixed: string[] = [];\r\n const remaining: string[] = [];\r\n let iterations = 0;\r\n let totalTokensUsed = 0;\r\n\r\n for (let i = 0; i < maxIterations; i++) {\r\n iterations = i + 1;\r\n\r\n const outcome = await attemptConfigFix(testResultsDir, mode, llm);\r\n if (outcome.success) {\r\n fixed.push(...outcome.fixedItems);\r\n } else {\r\n remaining.push(`iteration-${i + 1}: no fix applied`);\r\n }\r\n\r\n // Track token usage if LLM is available\r\n if (llm) {\r\n totalTokensUsed += llm.estimateTokens(`iteration-${i + 1}`);\r\n }\r\n\r\n // If all fixed, stop early\r\n if (outcome.success && outcome.fixedItems.length > 0) break;\r\n }\r\n\r\n return {\r\n iterations,\r\n fixed,\r\n remaining,\r\n totalTokensUsed,\r\n };\r\n },\r\n };\r\n}\r\n","import type { LlmProvider, LlmConfig } from '../types.js';\r\nimport { createOpenAIProvider } from './openai.js';\r\nimport { createOllamaProvider } from './ollama.js';\r\n\r\nexport { createOpenAIProvider } from './openai.js';\r\nexport { createOllamaProvider } from './ollama.js';\r\n\r\n/**\r\n * Create an LLM provider from config.\r\n * Resolves apiKey from config or OPENCROC_LLM_API_KEY env variable.\r\n */\r\nexport function createLlmProvider(config: LlmConfig): LlmProvider {\r\n const resolved: LlmConfig = {\r\n ...config,\r\n apiKey: config.apiKey || process.env.OPENCROC_LLM_API_KEY,\r\n };\r\n\r\n switch (config.provider) {\r\n case 'openai':\r\n case 'zhipu':\r\n return createOpenAIProvider(resolved);\r\n case 'ollama':\r\n return createOllamaProvider(resolved);\r\n default:\r\n throw new Error(\r\n `Unknown LLM provider: \"${config.provider}\". Available: openai, zhipu, ollama`,\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Token usage tracker — accumulates tokens across multiple LLM calls.\r\n */\r\nexport interface TokenTracker {\r\n track(text: string): void;\r\n trackChat(messages: Array<{ role: string; content: string }>, response: string): void;\r\n total: number;\r\n reset(): void;\r\n}\r\n\r\nexport function createTokenTracker(provider: LlmProvider): TokenTracker {\r\n let total = 0;\r\n\r\n return {\r\n track(text: string) {\r\n total += provider.estimateTokens(text);\r\n },\r\n\r\n trackChat(messages: Array<{ role: string; content: string }>, response: string) {\r\n for (const msg of messages) {\r\n total += provider.estimateTokens(msg.content);\r\n }\r\n total += provider.estimateTokens(response);\r\n },\r\n\r\n get total() {\r\n return total;\r\n },\r\n\r\n reset() {\r\n total = 0;\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * System prompts for different LLM use cases in OpenCroc.\r\n */\r\nexport const SYSTEM_PROMPTS = {\r\n failureAnalysis: `You are an expert test failure analyst for an E2E testing framework.\r\nGiven a test failure error message and its context, analyze the root cause and suggest a fix.\r\nRespond in JSON format: { \"rootCause\": string, \"category\": string, \"suggestedFix\": string, \"confidence\": number }\r\nCategories: backend-5xx, timeout, endpoint-not-found, data-constraint, network, frontend-render, test-script, unknown.`,\r\n\r\n chainPlanning: `You are an API test chain planner.\r\nGiven a list of API endpoints and their dependencies, generate an optimal test execution order.\r\nConsider data dependencies, authentication requirements, and cleanup steps.\r\nRespond in JSON format: { \"chains\": [{ \"name\": string, \"steps\": [{ \"endpoint\": string, \"method\": string, \"description\": string }] }] }`,\r\n} as const;\r\n","import type { LlmProvider, LlmConfig } from '../types.js';\r\n\r\nexport interface ChatMessage {\r\n role: 'system' | 'user' | 'assistant';\r\n content: string;\r\n}\r\n\r\ninterface OpenAIResponse {\r\n choices: Array<{ message: { content: string } }>;\r\n usage?: { total_tokens: number };\r\n}\r\n\r\nconst DEFAULT_MODELS: Record<string, string> = {\r\n openai: 'gpt-4o-mini',\r\n zhipu: 'glm-4',\r\n};\r\n\r\nconst DEFAULT_BASE_URLS: Record<string, string> = {\r\n openai: 'https://api.openai.com/v1',\r\n zhipu: 'https://open.bigmodel.cn/api/paas/v4',\r\n};\r\n\r\n/**\r\n * Create an OpenAI-compatible LLM provider.\r\n * Works with OpenAI, Zhipu (GLM), and any OpenAI-compatible API.\r\n */\r\nexport function createOpenAIProvider(config: LlmConfig): LlmProvider {\r\n const provider = config.provider === 'zhipu' ? 'zhipu' : 'openai';\r\n const baseUrl = config.baseUrl || DEFAULT_BASE_URLS[provider];\r\n const model = config.model || DEFAULT_MODELS[provider];\r\n const maxTokens = config.maxTokens || 2048;\r\n const temperature = config.temperature ?? 0.3;\r\n\r\n if (!config.apiKey) {\r\n throw new Error(\r\n `API key is required for ${provider}. Set it in config or via OPENCROC_LLM_API_KEY env variable.`,\r\n );\r\n }\r\n\r\n return {\r\n name: provider,\r\n\r\n async chat(messages: Array<{ role: string; content: string }>): Promise<string> {\r\n const url = `${baseUrl}/chat/completions`;\r\n\r\n const response = await fetch(url, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Authorization': `Bearer ${config.apiKey}`,\r\n },\r\n body: JSON.stringify({\r\n model,\r\n messages,\r\n max_tokens: maxTokens,\r\n temperature,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => 'unknown error');\r\n throw new Error(`LLM API error (${response.status}): ${errorText}`);\r\n }\r\n\r\n const data = (await response.json()) as OpenAIResponse;\r\n const content = data.choices?.[0]?.message?.content;\r\n if (!content) {\r\n throw new Error('LLM returned empty response');\r\n }\r\n return content;\r\n },\r\n\r\n estimateTokens(text: string): number {\r\n // Rough estimate: ~4 chars per token for English, ~2 for CJK\r\n const cjkChars = (text.match(/[\\u4e00-\\u9fff\\u3000-\\u303f]/g) || []).length;\r\n const otherChars = text.length - cjkChars;\r\n return Math.ceil(otherChars / 4 + cjkChars / 2);\r\n },\r\n };\r\n}\r\n","import type { LlmProvider, LlmConfig } from '../types.js';\r\n\r\ninterface OllamaResponse {\r\n message: { content: string };\r\n}\r\n\r\n/**\r\n * Create an Ollama LLM provider for local model inference.\r\n */\r\nexport function createOllamaProvider(config: LlmConfig): LlmProvider {\r\n const baseUrl = config.baseUrl || 'http://localhost:11434';\r\n const model = config.model || 'llama3';\r\n\r\n return {\r\n name: 'ollama',\r\n\r\n async chat(messages: Array<{ role: string; content: string }>): Promise<string> {\r\n const url = `${baseUrl}/api/chat`;\r\n\r\n const response = await fetch(url, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n model,\r\n messages,\r\n stream: false,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => 'unknown error');\r\n throw new Error(`Ollama API error (${response.status}): ${errorText}`);\r\n }\r\n\r\n const data = (await response.json()) as OllamaResponse;\r\n const content = data.message?.content;\r\n if (!content) {\r\n throw new Error('Ollama returned empty response');\r\n }\r\n return content;\r\n },\r\n\r\n estimateTokens(text: string): number {\r\n // Same rough estimate as OpenAI provider\r\n const cjkChars = (text.match(/[\\u4e00-\\u9fff\\u3000-\\u303f]/g) || []).length;\r\n const otherChars = text.length - cjkChars;\r\n return Math.ceil(otherChars / 4 + cjkChars / 2);\r\n },\r\n };\r\n}\r\n","/**\r\n * Dialog Loop Runner — multi-iteration self-healing loop.\r\n *\r\n * Runs tests, parses results, applies controlled fixes, and reruns\r\n * until all tests pass or the maximum iteration count is reached.\r\n * Tracks error history to avoid infinite loops on recurring failures.\r\n */\r\n\r\nimport type {\r\n DialogLoopConfig,\r\n TestFailureInfo,\r\n IterationResult,\r\n DialogLoopSummary,\r\n ControlledFixOutcome,\r\n} from '../types.js';\r\n\r\n// ===== Abstractions for testability =====\r\n\r\nexport interface TestRunner {\r\n run(): Promise<{ stdout: string; exitCode: number }>;\r\n}\r\n\r\nexport interface ResultParser {\r\n parse(stdout: string): TestFailureInfo[];\r\n countTotal(stdout: string): number;\r\n}\r\n\r\nexport interface FixApplier {\r\n apply(failure: TestFailureInfo): Promise<ControlledFixOutcome>;\r\n}\r\n\r\n// ===== Defaults =====\r\n\r\nconst DEFAULTS: Required<DialogLoopConfig> = {\r\n maxIterations: 3,\r\n pollIntervalMs: 10_000,\r\n sameErrorThreshold: 2,\r\n autoRerunOnFix: true,\r\n};\r\n\r\n// ===== JSON result parser (reads Playwright JSON output) =====\r\n\r\nexport function createJsonResultParser(): ResultParser {\r\n return {\r\n parse(stdout: string): TestFailureInfo[] {\r\n const failures: TestFailureInfo[] = [];\r\n // Match pass/fail summary from Playwright output\r\n const lines = stdout.split('\\n');\r\n for (const line of lines) {\r\n // Playwright format: \" ✘ [chromium] › test.spec.ts:10:5 › suite › title\"\r\n // or stderr lines with \"Error:\" prefix\r\n const failMatch = line.match(/[✘✗×]\\s+.*?›\\s+(.+)/);\r\n if (failMatch) {\r\n failures.push({\r\n title: failMatch[1].trim(),\r\n error: failMatch[1].trim(),\r\n });\r\n }\r\n }\r\n return failures;\r\n },\r\n countTotal(stdout: string): number {\r\n // Match \"X passed\" or \"X failed\" from Playwright summary\r\n let total = 0;\r\n const passMatch = stdout.match(/(\\d+)\\s+passed/);\r\n const failMatch = stdout.match(/(\\d+)\\s+failed/);\r\n if (passMatch) total += parseInt(passMatch[1], 10);\r\n if (failMatch) total += parseInt(failMatch[1], 10);\r\n return total || 1; // at least 1 to avoid division by zero\r\n },\r\n };\r\n}\r\n\r\n// ===== Dialog Loop =====\r\n\r\nexport interface DialogLoopOptions {\r\n runner: TestRunner;\r\n parser: ResultParser;\r\n fixer: FixApplier;\r\n config?: DialogLoopConfig;\r\n onIteration?: (result: IterationResult) => void;\r\n}\r\n\r\nexport async function runDialogLoop(options: DialogLoopOptions): Promise<DialogLoopSummary> {\r\n const cfg = { ...DEFAULTS, ...options.config };\r\n const { runner, parser, fixer } = options;\r\n\r\n const history: IterationResult[] = [];\r\n const errorTracker = new Map<string, number>();\r\n\r\n for (let iteration = 1; iteration <= cfg.maxIterations + 1; iteration++) {\r\n const iterStart = Date.now();\r\n\r\n // Step 1: Run tests\r\n const { stdout } = await runner.run();\r\n\r\n // Step 2: Parse results\r\n const failures = parser.parse(stdout);\r\n const totalTests = parser.countTotal(stdout);\r\n const passed = totalTests - failures.length;\r\n\r\n const iterResult: IterationResult = {\r\n iteration,\r\n totalTests,\r\n passed,\r\n failed: failures.length,\r\n failedTests: failures.map(f => f.title),\r\n fixesApplied: [],\r\n durationMs: 0,\r\n };\r\n\r\n // Step 3: All passed → success\r\n if (failures.length === 0) {\r\n iterResult.durationMs = Date.now() - iterStart;\r\n history.push(iterResult);\r\n options.onIteration?.(iterResult);\r\n break;\r\n }\r\n\r\n // Step 4: Max iterations exceeded\r\n if (iteration > cfg.maxIterations) {\r\n iterResult.durationMs = Date.now() - iterStart;\r\n history.push(iterResult);\r\n options.onIteration?.(iterResult);\r\n break;\r\n }\r\n\r\n // Step 5: Filter out repeated errors beyond threshold\r\n const newFailures = failures.filter(f => {\r\n const key = `${f.title}::${f.error}`;\r\n const count = (errorTracker.get(key) ?? 0) + 1;\r\n errorTracker.set(key, count);\r\n return count <= cfg.sameErrorThreshold;\r\n });\r\n\r\n if (newFailures.length === 0) {\r\n iterResult.durationMs = Date.now() - iterStart;\r\n history.push(iterResult);\r\n options.onIteration?.(iterResult);\r\n break;\r\n }\r\n\r\n // Step 6: Apply controlled fixes\r\n for (const failure of newFailures) {\r\n const outcome = await fixer.apply(failure);\r\n if (outcome.success) {\r\n iterResult.fixesApplied.push(failure.title);\r\n }\r\n }\r\n\r\n iterResult.durationMs = Date.now() - iterStart;\r\n history.push(iterResult);\r\n options.onIteration?.(iterResult);\r\n\r\n // Step 7: If any fixes applied and autoRerun, continue loop\r\n if (iterResult.fixesApplied.length === 0 || !cfg.autoRerunOnFix) {\r\n break;\r\n }\r\n }\r\n\r\n const final = history[history.length - 1];\r\n const totalFixesApplied = history.reduce((sum, h) => sum + h.fixesApplied.length, 0);\r\n\r\n return {\r\n iterations: history,\r\n finalPassed: final?.passed ?? 0,\r\n finalFailed: final?.failed ?? 0,\r\n totalFixesApplied,\r\n success: (final?.failed ?? 1) === 0,\r\n };\r\n}\r\n","/**\r\n * Controlled Fixer — two-phase fix engine with safety guarantees.\r\n *\r\n * Phase A (config-only): backup → validate → fix → dry-run → write → verify → cleanup.\r\n * Phase B (config-and-source): generates a draft PR with the AI-suggested code patch.\r\n *\r\n * All mutations are reversible — failures trigger automatic rollback.\r\n */\r\n\r\nimport { existsSync, copyFileSync, readFileSync, writeFileSync, mkdirSync, unlinkSync } from 'node:fs';\r\nimport { dirname } from 'node:path';\r\nimport type {\r\n FixScope,\r\n ControlledFixOptions,\r\n ControlledFixOutcome,\r\n AIAttributionResult,\r\n} from '../types.js';\r\n\r\n// ===== Abstractions for testability =====\r\n\r\nexport interface ConfigValidator {\r\n validate(configContent: string): { passed: boolean; errors: string[] };\r\n}\r\n\r\nexport interface ConfigFixer {\r\n fix(configContent: string, errors: string[]): { success: boolean; fixedContent: string; fixedItems: string[]; remainingErrors: string[] };\r\n}\r\n\r\nexport interface PRGenerator {\r\n generate(attribution: AIAttributionResult): Promise<string>;\r\n}\r\n\r\n// ===== FS abstraction (injectable for tests) =====\r\n\r\nexport interface FsOps {\r\n exists(path: string): boolean;\r\n read(path: string): string;\r\n write(path: string, content: string): void;\r\n copy(src: string, dest: string): void;\r\n remove(path: string): void;\r\n mkdirp(dir: string): void;\r\n}\r\n\r\nconst defaultFs: FsOps = {\r\n exists: existsSync,\r\n read: (p) => readFileSync(p, 'utf-8'),\r\n write: (p, c) => { mkdirSync(dirname(p), { recursive: true }); writeFileSync(p, c, 'utf-8'); },\r\n copy: copyFileSync,\r\n remove: unlinkSync,\r\n mkdirp: (d) => mkdirSync(d, { recursive: true }),\r\n};\r\n\r\n// ===== Core =====\r\n\r\nexport interface ControlledFixerOptions {\r\n configPath: string;\r\n validator: ConfigValidator;\r\n fixer: ConfigFixer;\r\n prGenerator?: PRGenerator;\r\n attribution?: AIAttributionResult;\r\n fs?: FsOps;\r\n options?: ControlledFixOptions;\r\n}\r\n\r\nexport async function applyControlledFix(opts: ControlledFixerOptions): Promise<ControlledFixOutcome> {\r\n const fs = opts.fs ?? defaultFs;\r\n const scope: FixScope = opts.options?.scope ?? 'config-only';\r\n const dryRun = opts.options?.dryRun ?? true;\r\n const verify = opts.options?.verify ?? true;\r\n const configPath = opts.configPath;\r\n const backupPath = configPath + '.backup';\r\n\r\n // --- Phase A: Config-only fix ---\r\n\r\n // Load config\r\n if (!fs.exists(configPath)) {\r\n return { success: false, scope, fixedItems: [], rolledBack: false, error: `Config file not found: ${configPath}` };\r\n }\r\n\r\n const originalContent = fs.read(configPath);\r\n\r\n // Backup before mutation\r\n fs.write(backupPath, originalContent);\r\n\r\n // Validate current config\r\n const validation = opts.validator.validate(originalContent);\r\n\r\n if (validation.passed) {\r\n // No errors to fix\r\n cleanup(fs, backupPath);\r\n return { success: true, scope, fixedItems: [], rolledBack: false };\r\n }\r\n\r\n // Attempt fix\r\n let fixResult: ReturnType<ConfigFixer['fix']>;\r\n try {\r\n fixResult = opts.fixer.fix(originalContent, validation.errors);\r\n } catch (err) {\r\n rollback(fs, backupPath, configPath);\r\n return { success: false, scope, fixedItems: [], rolledBack: true, error: `Fix threw: ${err instanceof Error ? err.message : String(err)}` };\r\n }\r\n\r\n if (!fixResult.success) {\r\n rollback(fs, backupPath, configPath);\r\n return { success: false, scope, fixedItems: fixResult.fixedItems, rolledBack: true, error: `Remaining errors: ${fixResult.remainingErrors.join('; ')}` };\r\n }\r\n\r\n // Dry-run: validate fixed content before writing\r\n if (dryRun) {\r\n const dryValidation = opts.validator.validate(fixResult.fixedContent);\r\n if (!dryValidation.passed) {\r\n rollback(fs, backupPath, configPath);\r\n return { success: false, scope, fixedItems: fixResult.fixedItems, rolledBack: true, error: `Dry-run validation failed: ${dryValidation.errors.join('; ')}` };\r\n }\r\n }\r\n\r\n // Write fixed content\r\n fs.write(configPath, fixResult.fixedContent);\r\n\r\n // Verify after write\r\n if (verify) {\r\n const reloaded = fs.read(configPath);\r\n const postValidation = opts.validator.validate(reloaded);\r\n if (!postValidation.passed) {\r\n rollback(fs, backupPath, configPath);\r\n return { success: false, scope, fixedItems: fixResult.fixedItems, rolledBack: true, error: `Post-write verification failed: ${postValidation.errors.join('; ')}` };\r\n }\r\n }\r\n\r\n // Phase A success — clean up backup\r\n cleanup(fs, backupPath);\r\n\r\n // --- Phase B: Config-and-source (optional) ---\r\n let prUrl: string | undefined;\r\n if (scope === 'config-and-source' && opts.attribution && opts.prGenerator) {\r\n try {\r\n prUrl = await opts.prGenerator.generate(opts.attribution);\r\n } catch {\r\n // PR generation failure is non-fatal; config fix already succeeded\r\n }\r\n }\r\n\r\n return { success: true, scope, fixedItems: fixResult.fixedItems, rolledBack: false, prUrl };\r\n}\r\n\r\nfunction rollback(fs: FsOps, backupPath: string, configPath: string): void {\r\n if (fs.exists(backupPath)) {\r\n const backup = fs.read(backupPath);\r\n fs.write(configPath, backup);\r\n fs.remove(backupPath);\r\n }\r\n}\r\n\r\nfunction cleanup(fs: FsOps, backupPath: string): void {\r\n if (fs.exists(backupPath)) {\r\n fs.remove(backupPath);\r\n }\r\n}\r\n","/**\r\n * Auto-Fix PR Generator — creates draft PRs from AI attribution results.\r\n *\r\n * Flow: create branch → write patch → git apply → commit → push → gh pr create --draft.\r\n * All PRs are draft-only as a safety invariant.\r\n */\r\n\r\nimport type { AIAttributionResult, AutoFixPROptions, AutoFixPRResult } from '../types.js';\r\n\r\n// ===== Executor abstraction (injectable for tests) =====\r\n\r\nexport interface GitExecutor {\r\n exec(command: string, args: string[]): Promise<{ stdout: string; exitCode: number }>;\r\n}\r\n\r\nexport interface PatchWriter {\r\n write(path: string, content: string): Promise<void>;\r\n mkdir(dir: string): Promise<void>;\r\n}\r\n\r\n// ===== Defaults =====\r\n\r\nconst DEFAULT_OPTIONS: Required<AutoFixPROptions> = {\r\n branchPrefix: 'autofix/',\r\n baseBranch: 'main',\r\n draftOnly: true,\r\n};\r\n\r\n// ===== Core =====\r\n\r\nexport async function generateFixPR(\r\n attribution: AIAttributionResult,\r\n git: GitExecutor,\r\n patchWriter: PatchWriter,\r\n options?: AutoFixPROptions,\r\n): Promise<AutoFixPRResult> {\r\n const opts = { ...DEFAULT_OPTIONS, ...options };\r\n const ts = new Date().toISOString().replace(/[:.]/g, '-');\r\n const branch = `${opts.branchPrefix}${ts}`;\r\n const patchFile = `report/patch-${ts}.patch`;\r\n\r\n // Create branch\r\n await git.exec('git', ['checkout', '-b', branch]);\r\n\r\n // Write patch\r\n await patchWriter.mkdir('report');\r\n await patchWriter.write(patchFile, attribution.fixSuggestion.codePatch);\r\n\r\n // Apply patch (non-fatal if fails)\r\n try {\r\n await git.exec('git', ['apply', patchFile]);\r\n } catch {\r\n // Patch may not apply cleanly — continue anyway\r\n }\r\n\r\n // Stage, commit, push\r\n await git.exec('git', ['add', '.']);\r\n await git.exec('git', ['commit', '-m', `fix: AI auto-patch for \"${attribution.testName}\"`]);\r\n await git.exec('git', ['push', 'origin', branch]);\r\n\r\n // Create draft PR (always draft for safety)\r\n const prArgs = [\r\n 'pr', 'create', '--draft',\r\n '--title', `[AI Fix] ${attribution.testName}`,\r\n '--body', buildPRBody(attribution),\r\n ];\r\n const { stdout: prUrl } = await git.exec('gh', prArgs);\r\n\r\n // Return to base branch\r\n await git.exec('git', ['checkout', opts.baseBranch]);\r\n\r\n return { prUrl: prUrl.trim(), branch, patchFile };\r\n}\r\n\r\nfunction buildPRBody(a: AIAttributionResult): string {\r\n return [\r\n '## AI Auto-Fix PR',\r\n '',\r\n `**Test:** ${a.testName}`,\r\n `**Category:** ${a.category} | **Severity:** ${a.severity} | **Confidence:** ${(a.confidence * 100).toFixed(0)}%`,\r\n '',\r\n '### Root Cause',\r\n a.rootCause,\r\n '',\r\n '### Fix',\r\n a.fixSuggestion.description,\r\n '',\r\n '---',\r\n '> This PR was auto-generated by AI and **must be reviewed before merging**.',\r\n ].join('\\n');\r\n}\r\n","import type { BackendAdapter } from '../types.js';\r\nimport { parseModuleModels } from '../parsers/model-parser.js';\r\nimport { parseAssociationFile } from '../parsers/association-parser.js';\r\nimport { parseControllerDirectory } from '../parsers/controller-parser.js';\r\nimport type { TableSchema, ForeignKeyRelation, RouteEntry } from '../types.js';\r\n\r\nexport function createSequelizeAdapter(): BackendAdapter {\r\n return {\r\n name: 'sequelize',\r\n\r\n async parseModels(dir: string): Promise<TableSchema[]> {\r\n return parseModuleModels(dir);\r\n },\r\n\r\n async parseAssociations(file: string): Promise<ForeignKeyRelation[]> {\r\n return parseAssociationFile(file);\r\n },\r\n\r\n async parseControllers(dir: string): Promise<RouteEntry[]> {\r\n const endpoints = parseControllerDirectory(dir);\r\n return endpoints.map((ep) => ({\r\n method: ep.method,\r\n path: ep.path,\r\n handler: '',\r\n controllerClass: '',\r\n }));\r\n },\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport {\r\n Project,\r\n type ClassDeclaration,\r\n type PropertyDeclaration,\r\n} from 'ts-morph';\r\nimport type { BackendAdapter, TableSchema, FieldSchema, ForeignKeyRelation, RouteEntry } from '../types.js';\r\n\r\n// TypeORM decorator → field type mapping\r\nconst TYPEORM_TYPE_MAP: Record<string, string> = {\r\n 'PrimaryGeneratedColumn': 'BIGINT',\r\n 'PrimaryColumn': 'BIGINT',\r\n 'CreateDateColumn': 'DATE',\r\n 'UpdateDateColumn': 'DATE',\r\n 'DeleteDateColumn': 'DATE',\r\n 'VersionColumn': 'INTEGER',\r\n};\r\n\r\nconst TYPEORM_COLUMN_TYPE_MAP: Record<string, string> = {\r\n 'varchar': 'STRING',\r\n 'text': 'TEXT',\r\n 'int': 'INTEGER',\r\n 'integer': 'INTEGER',\r\n 'bigint': 'BIGINT',\r\n 'float': 'FLOAT',\r\n 'double': 'DOUBLE',\r\n 'decimal': 'DECIMAL',\r\n 'boolean': 'BOOLEAN',\r\n 'bool': 'BOOLEAN',\r\n 'date': 'DATEONLY',\r\n 'datetime': 'DATE',\r\n 'timestamp': 'DATE',\r\n 'json': 'JSON',\r\n 'jsonb': 'JSONB',\r\n 'enum': 'ENUM',\r\n 'uuid': 'UUID',\r\n};\r\n\r\nfunction tsTypeToFieldType(tsType: string): string {\r\n const t = tsType.toLowerCase().trim();\r\n if (t === 'string') return 'STRING';\r\n if (t === 'number') return 'INTEGER';\r\n if (t === 'boolean') return 'BOOLEAN';\r\n if (t === 'date') return 'DATE';\r\n return 'STRING';\r\n}\r\n\r\nfunction classNameToTableName(name: string): string {\r\n return name.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\r\n}\r\n\r\nfunction extractDecoratorStringArg(decoratorText: string): string | undefined {\r\n const match = decoratorText.match(/\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/);\r\n return match?.[1];\r\n}\r\n\r\nfunction extractDecoratorObjectArg(decoratorText: string): Record<string, string> {\r\n const result: Record<string, string> = {};\r\n const objMatch = decoratorText.match(/\\(\\s*\\{([^}]*)\\}\\s*\\)/);\r\n if (!objMatch) return result;\r\n const body = objMatch[1];\r\n const pairs = body.matchAll(/(\\w+)\\s*:\\s*['\"]([^'\"]*)['\"]/g);\r\n for (const pair of pairs) {\r\n result[pair[1]] = pair[2];\r\n }\r\n // Also match non-string values like nullable: true\r\n const boolPairs = body.matchAll(/(\\w+)\\s*:\\s*(true|false)/g);\r\n for (const pair of boolPairs) {\r\n result[pair[1]] = pair[2];\r\n }\r\n return result;\r\n}\r\n\r\nexport function parseTypeORMFile(filePath: string): TableSchema | null {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return null;\r\n\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const classes = sourceFile.getClasses();\r\n for (const cls of classes) {\r\n const entityDecorator = cls.getDecorator('Entity');\r\n if (!entityDecorator) continue;\r\n\r\n const tableName = extractDecoratorStringArg(entityDecorator.getText())\r\n || extractDecoratorObjectArg(entityDecorator.getText()).name\r\n || classNameToTableName(cls.getName() || 'unknown');\r\n\r\n const fields = extractTypeORMFields(cls);\r\n return { tableName, className: cls.getName(), fields };\r\n }\r\n return null;\r\n}\r\n\r\nfunction extractTypeORMFields(cls: ClassDeclaration): FieldSchema[] {\r\n const fields: FieldSchema[] = [];\r\n\r\n for (const prop of cls.getProperties()) {\r\n const field = parseTypeORMProperty(prop);\r\n if (field) fields.push(field);\r\n }\r\n return fields;\r\n}\r\n\r\nfunction parseTypeORMProperty(prop: PropertyDeclaration): FieldSchema | null {\r\n const decorators = prop.getDecorators();\r\n if (decorators.length === 0) return null;\r\n\r\n const name = prop.getName();\r\n let type = 'STRING';\r\n let primaryKey = false;\r\n let allowNull = true;\r\n let unique = false;\r\n\r\n for (const dec of decorators) {\r\n const decName = dec.getName();\r\n const decText = dec.getText();\r\n\r\n if (decName === 'PrimaryGeneratedColumn' || decName === 'PrimaryColumn') {\r\n primaryKey = true;\r\n type = TYPEORM_TYPE_MAP[decName] || 'BIGINT';\r\n allowNull = false;\r\n const argType = extractDecoratorStringArg(decText);\r\n if (argType === 'uuid') type = 'UUID';\r\n if (argType === 'increment') type = 'BIGINT';\r\n }\r\n\r\n if (decName === 'Column') {\r\n const objArgs = extractDecoratorObjectArg(decText);\r\n if (objArgs.type && TYPEORM_COLUMN_TYPE_MAP[objArgs.type]) {\r\n type = TYPEORM_COLUMN_TYPE_MAP[objArgs.type];\r\n } else {\r\n const simpleType = extractDecoratorStringArg(decText);\r\n if (simpleType && TYPEORM_COLUMN_TYPE_MAP[simpleType]) {\r\n type = TYPEORM_COLUMN_TYPE_MAP[simpleType];\r\n }\r\n }\r\n if (objArgs.nullable === 'false') allowNull = false;\r\n if (objArgs.unique === 'true') unique = true;\r\n\r\n // Fall back to TS type annotation\r\n if (type === 'STRING') {\r\n const tsType = prop.getType().getText();\r\n type = tsTypeToFieldType(tsType);\r\n }\r\n }\r\n\r\n if (decName in TYPEORM_TYPE_MAP) {\r\n type = TYPEORM_TYPE_MAP[decName];\r\n }\r\n\r\n if (decName === 'CreateDateColumn' || decName === 'UpdateDateColumn' || decName === 'DeleteDateColumn') {\r\n allowNull = true;\r\n }\r\n }\r\n\r\n // Skip properties without any recognized TypeORM decorator\r\n const recognizedDecorators = ['Column', 'PrimaryGeneratedColumn', 'PrimaryColumn',\r\n 'CreateDateColumn', 'UpdateDateColumn', 'DeleteDateColumn', 'VersionColumn',\r\n 'ManyToOne', 'OneToMany', 'OneToOne', 'ManyToMany', 'JoinColumn', 'JoinTable'];\r\n const hasRecognized = decorators.some((d) => recognizedDecorators.includes(d.getName()));\r\n if (!hasRecognized) return null;\r\n\r\n // Skip relation-only properties (no Column)\r\n const isRelationOnly = decorators.every((d) =>\r\n ['ManyToOne', 'OneToMany', 'OneToOne', 'ManyToMany', 'JoinColumn', 'JoinTable'].includes(d.getName()),\r\n );\r\n if (isRelationOnly) return null;\r\n\r\n return { name, type, allowNull, primaryKey, unique };\r\n}\r\n\r\nexport function parseTypeORMAssociations(filePath: string): ForeignKeyRelation[] {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return [];\r\n\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const relations: ForeignKeyRelation[] = [];\r\n for (const cls of sourceFile.getClasses()) {\r\n const entityDecorator = cls.getDecorator('Entity');\r\n if (!entityDecorator) continue;\r\n\r\n const sourceTable = extractDecoratorStringArg(entityDecorator.getText())\r\n || classNameToTableName(cls.getName() || 'unknown');\r\n\r\n for (const prop of cls.getProperties()) {\r\n const rel = extractRelationFromProperty(prop, sourceTable);\r\n if (rel) relations.push(rel);\r\n }\r\n }\r\n return relations;\r\n}\r\n\r\nfunction extractRelationFromProperty(\r\n prop: PropertyDeclaration,\r\n sourceTable: string,\r\n): ForeignKeyRelation | null {\r\n const decorators = prop.getDecorators();\r\n\r\n for (const dec of decorators) {\r\n const decName = dec.getName();\r\n const decText = dec.getText();\r\n\r\n if (decName === 'ManyToOne') {\r\n const targetClass = extractRelationTarget(decText);\r\n if (!targetClass) continue;\r\n const targetTable = classNameToTableName(targetClass);\r\n const fkField = findJoinColumnField(decorators) || `${prop.getName()}_id`;\r\n return {\r\n sourceTable, sourceField: fkField,\r\n targetTable, targetField: 'id',\r\n cardinality: 'N:1',\r\n };\r\n }\r\n\r\n if (decName === 'OneToMany') {\r\n const targetClass = extractRelationTarget(decText);\r\n if (!targetClass) continue;\r\n const targetTable = classNameToTableName(targetClass);\r\n return {\r\n sourceTable, sourceField: 'id',\r\n targetTable, targetField: `${classNameToTableName(sourceTable)}_id`,\r\n cardinality: '1:N',\r\n };\r\n }\r\n\r\n if (decName === 'OneToOne') {\r\n const targetClass = extractRelationTarget(decText);\r\n if (!targetClass) continue;\r\n const targetTable = classNameToTableName(targetClass);\r\n return {\r\n sourceTable, sourceField: 'id',\r\n targetTable, targetField: `${classNameToTableName(sourceTable)}_id`,\r\n cardinality: '1:1',\r\n };\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction extractRelationTarget(decoratorText: string): string | null {\r\n // @ManyToOne(() => User, ...) or @ManyToOne(type => User, ...)\r\n const match = decoratorText.match(/\\(\\s*(?:\\(\\)\\s*=>|type\\s*=>|\\w+\\s*=>)\\s*(\\w+)/);\r\n return match?.[1] || null;\r\n}\r\n\r\nfunction findJoinColumnField(decorators: ReturnType<PropertyDeclaration['getDecorators']>): string | null {\r\n for (const dec of decorators) {\r\n if (dec.getName() === 'JoinColumn') {\r\n const args = extractDecoratorObjectArg(dec.getText());\r\n if (args.name) return args.name;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nexport function parseTypeORMDirectory(dir: string): TableSchema[] {\r\n const absoluteDir = path.resolve(dir);\r\n if (!fs.existsSync(absoluteDir)) return [];\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) =>\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts',\r\n );\r\n\r\n const schemas: TableSchema[] = [];\r\n for (const file of files) {\r\n try {\r\n const schema = parseTypeORMFile(path.join(absoluteDir, file));\r\n if (schema) schemas.push(schema);\r\n } catch {\r\n // skip\r\n }\r\n }\r\n return schemas;\r\n}\r\n\r\nexport function parseTypeORMAssociationsFromDir(dir: string): ForeignKeyRelation[] {\r\n const absoluteDir = path.resolve(dir);\r\n if (!fs.existsSync(absoluteDir)) return [];\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) =>\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts',\r\n );\r\n\r\n const relations: ForeignKeyRelation[] = [];\r\n for (const file of files) {\r\n try {\r\n relations.push(...parseTypeORMAssociations(path.join(absoluteDir, file)));\r\n } catch {\r\n // skip\r\n }\r\n }\r\n return relations;\r\n}\r\n\r\nexport function createTypeORMAdapter(): BackendAdapter {\r\n return {\r\n name: 'typeorm',\r\n\r\n async parseModels(dir: string): Promise<TableSchema[]> {\r\n return parseTypeORMDirectory(dir);\r\n },\r\n\r\n async parseAssociations(file: string): Promise<ForeignKeyRelation[]> {\r\n // TypeORM embeds relations in entity files, so parse the directory\r\n const dir = path.dirname(file);\r\n return parseTypeORMAssociationsFromDir(dir);\r\n },\r\n\r\n async parseControllers(dir: string): Promise<RouteEntry[]> {\r\n // Controller parsing is framework-agnostic (Express/Koa router patterns)\r\n const { parseControllerDirectory } = await import('../parsers/controller-parser.js');\r\n const endpoints = parseControllerDirectory(dir);\r\n return endpoints.map((ep) => ({\r\n method: ep.method,\r\n path: ep.path,\r\n handler: '',\r\n controllerClass: '',\r\n }));\r\n },\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport type { BackendAdapter, TableSchema, FieldSchema, ForeignKeyRelation, RouteEntry } from '../types.js';\r\n\r\n// Prisma scalar → generic field type mapping\r\nconst PRISMA_TYPE_MAP: Record<string, string> = {\r\n 'String': 'STRING',\r\n 'Int': 'INTEGER',\r\n 'BigInt': 'BIGINT',\r\n 'Float': 'FLOAT',\r\n 'Decimal': 'DECIMAL',\r\n 'Boolean': 'BOOLEAN',\r\n 'DateTime': 'DATE',\r\n 'Json': 'JSON',\r\n 'Bytes': 'BLOB',\r\n};\r\n\r\ninterface PrismaModel {\r\n name: string;\r\n fields: PrismaField[];\r\n tableName?: string;\r\n}\r\n\r\ninterface PrismaField {\r\n name: string;\r\n type: string;\r\n isOptional: boolean;\r\n isList: boolean;\r\n isId: boolean;\r\n isUnique: boolean;\r\n isUpdatedAt: boolean;\r\n defaultValue?: string;\r\n relation?: { name?: string; fields?: string[]; references?: string[] };\r\n nativeType?: string;\r\n mapName?: string;\r\n}\r\n\r\n/**\r\n * Parse a .prisma schema file into models.\r\n */\r\nexport function parsePrismaSchema(content: string): PrismaModel[] {\r\n const models: PrismaModel[] = [];\r\n const modelRegex = /model\\s+(\\w+)\\s*\\{([^}]*)\\}/g;\r\n let match: RegExpExecArray | null;\r\n\r\n while ((match = modelRegex.exec(content)) !== null) {\r\n const modelName = match[1];\r\n const body = match[2];\r\n const fields = parsePrismaFields(body);\r\n const mapDirective = body.match(/@@map\\([\"']([^\"']+)[\"']\\)/);\r\n models.push({\r\n name: modelName,\r\n fields,\r\n tableName: mapDirective?.[1],\r\n });\r\n }\r\n return models;\r\n}\r\n\r\nfunction parsePrismaFields(body: string): PrismaField[] {\r\n const fields: PrismaField[] = [];\r\n const lines = body.split('\\n').map((l) => l.trim()).filter((l) => l && !l.startsWith('//') && !l.startsWith('@@'));\r\n\r\n for (const line of lines) {\r\n const field = parsePrismaFieldLine(line);\r\n if (field) fields.push(field);\r\n }\r\n return fields;\r\n}\r\n\r\nfunction parsePrismaFieldLine(line: string): PrismaField | null {\r\n // field_name Type? @attributes\r\n const match = line.match(/^(\\w+)\\s+(\\w+)(\\[\\])?\\??/);\r\n if (!match) return null;\r\n\r\n const name = match[1];\r\n const rawType = match[2];\r\n const isList = !!match[3];\r\n const isOptional = line.includes('?');\r\n\r\n const field: PrismaField = {\r\n name,\r\n type: rawType,\r\n isOptional,\r\n isList,\r\n isId: /@id\\b/.test(line),\r\n isUnique: /@unique\\b/.test(line),\r\n isUpdatedAt: /@updatedAt\\b/.test(line),\r\n };\r\n\r\n // @default(...)\r\n const defaultMatch = line.match(/@default\\(([^)]+)\\)/);\r\n if (defaultMatch) field.defaultValue = defaultMatch[1];\r\n\r\n // @map(\"...\")\r\n const mapMatch = line.match(/@map\\([\"']([^\"']+)[\"']\\)/);\r\n if (mapMatch) field.mapName = mapMatch[1];\r\n\r\n // @db.VarChar(255) etc.\r\n const nativeMatch = line.match(/@db\\.(\\w+(?:\\([^)]*\\))?)/);\r\n if (nativeMatch) field.nativeType = nativeMatch[1];\r\n\r\n // @relation(...)\r\n const relMatch = line.match(/@relation\\(([^)]*)\\)/);\r\n if (relMatch) {\r\n field.relation = parseRelationDirective(relMatch[1]);\r\n }\r\n\r\n return field;\r\n}\r\n\r\nfunction parseRelationDirective(content: string): PrismaField['relation'] {\r\n const rel: NonNullable<PrismaField['relation']> = {};\r\n\r\n const nameMatch = content.match(/(?:name:\\s*)?[\"']([^\"']+)[\"']/);\r\n if (nameMatch) rel.name = nameMatch[1];\r\n\r\n const fieldsMatch = content.match(/fields:\\s*\\[([^\\]]+)\\]/);\r\n if (fieldsMatch) {\r\n rel.fields = fieldsMatch[1].split(',').map((s) => s.trim());\r\n }\r\n\r\n const refsMatch = content.match(/references:\\s*\\[([^\\]]+)\\]/);\r\n if (refsMatch) {\r\n rel.references = refsMatch[1].split(',').map((s) => s.trim());\r\n }\r\n\r\n return rel;\r\n}\r\n\r\nfunction modelNameToTableName(name: string): string {\r\n return name.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\r\n}\r\n\r\nexport function prismaModelsToSchemas(models: PrismaModel[]): TableSchema[] {\r\n return models.map((model) => {\r\n const tableName = model.tableName || modelNameToTableName(model.name);\r\n const fields: FieldSchema[] = [];\r\n\r\n for (const f of model.fields) {\r\n // Skip relation fields (other model types or lists)\r\n if (f.isList) continue;\r\n if (!PRISMA_TYPE_MAP[f.type] && !f.relation) continue;\r\n // Skip pure relation references (no scalar counterpart)\r\n if (!PRISMA_TYPE_MAP[f.type] && f.relation && !f.relation.fields) continue;\r\n\r\n const fieldType = PRISMA_TYPE_MAP[f.type] || 'STRING';\r\n fields.push({\r\n name: f.mapName || f.name,\r\n type: fieldType,\r\n allowNull: f.isOptional,\r\n primaryKey: f.isId,\r\n unique: f.isUnique,\r\n defaultValue: f.defaultValue,\r\n });\r\n }\r\n\r\n return { tableName, className: model.name, fields };\r\n });\r\n}\r\n\r\nexport function prismaModelsToRelations(models: PrismaModel[]): ForeignKeyRelation[] {\r\n const relations: ForeignKeyRelation[] = [];\r\n const seen = new Set<string>();\r\n\r\n for (const model of models) {\r\n const sourceTable = model.tableName || modelNameToTableName(model.name);\r\n\r\n for (const field of model.fields) {\r\n if (!field.relation?.fields || !field.relation?.references) continue;\r\n\r\n const targetModel = models.find((m) => m.name === field.type);\r\n const targetTable = targetModel\r\n ? (targetModel.tableName || modelNameToTableName(targetModel.name))\r\n : modelNameToTableName(field.type);\r\n\r\n const sourceField = field.relation.fields[0];\r\n const targetField = field.relation.references[0];\r\n\r\n const key = `${sourceTable}|${sourceField}|${targetTable}|${targetField}`;\r\n if (seen.has(key)) continue;\r\n seen.add(key);\r\n\r\n // Determine cardinality: field with @relation + fields is the \"many\" side\r\n const isList = field.isList;\r\n relations.push({\r\n sourceTable,\r\n sourceField,\r\n targetTable,\r\n targetField,\r\n cardinality: isList ? '1:N' : 'N:1',\r\n });\r\n }\r\n }\r\n return relations;\r\n}\r\n\r\nexport function parsePrismaFile(filePath: string): { schemas: TableSchema[]; relations: ForeignKeyRelation[] } {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return { schemas: [], relations: [] };\r\n\r\n const content = fs.readFileSync(absolutePath, 'utf-8');\r\n const models = parsePrismaSchema(content);\r\n return {\r\n schemas: prismaModelsToSchemas(models),\r\n relations: prismaModelsToRelations(models),\r\n };\r\n}\r\n\r\nfunction findPrismaSchemaFile(dir: string): string | null {\r\n // Look for schema.prisma in dir, dir/prisma, or project root/prisma\r\n const candidates = [\r\n path.join(dir, 'schema.prisma'),\r\n path.join(dir, 'prisma', 'schema.prisma'),\r\n path.join(dir, '..', 'prisma', 'schema.prisma'),\r\n ];\r\n for (const c of candidates) {\r\n if (fs.existsSync(c)) return c;\r\n }\r\n return null;\r\n}\r\n\r\nexport function createPrismaAdapter(): BackendAdapter {\r\n return {\r\n name: 'prisma',\r\n\r\n async parseModels(dir: string): Promise<TableSchema[]> {\r\n const schemaFile = findPrismaSchemaFile(dir);\r\n if (!schemaFile) return [];\r\n const { schemas } = parsePrismaFile(schemaFile);\r\n return schemas;\r\n },\r\n\r\n async parseAssociations(file: string): Promise<ForeignKeyRelation[]> {\r\n // For Prisma, associations are in the schema file itself\r\n const schemaFile = findPrismaSchemaFile(path.dirname(file)) || file;\r\n const { relations } = parsePrismaFile(schemaFile);\r\n return relations;\r\n },\r\n\r\n async parseControllers(dir: string): Promise<RouteEntry[]> {\r\n const { parseControllerDirectory } = await import('../parsers/controller-parser.js');\r\n const endpoints = parseControllerDirectory(dir);\r\n return endpoints.map((ep) => ({\r\n method: ep.method,\r\n path: ep.path,\r\n handler: '',\r\n controllerClass: '',\r\n }));\r\n },\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n Node,\r\n type SourceFile,\r\n type CallExpression,\r\n type ObjectLiteralExpression,\r\n type PropertyAccessExpression,\r\n} from 'ts-morph';\r\nimport type { BackendAdapter, TableSchema, FieldSchema, ForeignKeyRelation, RouteEntry } from '../types.js';\r\n\r\n// Drizzle column constructor name → generic field type\r\nconst DRIZZLE_TYPE_MAP: Record<string, string> = {\r\n // integer family\r\n int: 'INTEGER',\r\n integer: 'INTEGER',\r\n serial: 'INTEGER',\r\n smallint: 'INTEGER',\r\n tinyint: 'INTEGER',\r\n mediumint: 'INTEGER',\r\n bigint: 'BIGINT',\r\n bigserial: 'BIGINT',\r\n // float / decimal\r\n real: 'FLOAT',\r\n float: 'FLOAT',\r\n doublePrecision: 'FLOAT',\r\n double: 'FLOAT',\r\n numeric: 'DECIMAL',\r\n decimal: 'DECIMAL',\r\n // string\r\n varchar: 'STRING',\r\n char: 'STRING',\r\n nvarchar: 'STRING',\r\n text: 'TEXT',\r\n // boolean\r\n boolean: 'BOOLEAN',\r\n bool: 'BOOLEAN',\r\n // date / time\r\n date: 'DATE',\r\n datetime: 'DATE',\r\n timestamp: 'DATE',\r\n timestamptz: 'DATE',\r\n time: 'TIME',\r\n // json\r\n json: 'JSON',\r\n jsonb: 'JSON',\r\n // binary / misc\r\n blob: 'BLOB',\r\n bytea: 'BLOB',\r\n uuid: 'STRING',\r\n};\r\n\r\nconst TABLE_FUNCTIONS = new Set(['pgTable', 'mysqlTable', 'sqliteTable']);\r\n\r\ninterface DrizzleColumn {\r\n varName: string;\r\n sqlName: string;\r\n type: string;\r\n isPrimary: boolean;\r\n isNotNull: boolean;\r\n isUnique: boolean;\r\n defaultValue?: string;\r\n referencesExpr?: string;\r\n}\r\n\r\ninterface DrizzleTable {\r\n varName: string;\r\n tableName: string;\r\n columns: DrizzleColumn[];\r\n}\r\n\r\nfunction findTableCalls(sourceFile: SourceFile): DrizzleTable[] {\r\n const tables: DrizzleTable[] = [];\r\n const varDecls = sourceFile.getDescendantsOfKind(SyntaxKind.VariableDeclaration);\r\n\r\n for (const decl of varDecls) {\r\n const init = decl.getInitializer();\r\n if (!init || init.getKind() !== SyntaxKind.CallExpression) continue;\r\n\r\n const call = init as CallExpression;\r\n const funcName = call.getExpression().getText().trim();\r\n if (!TABLE_FUNCTIONS.has(funcName)) continue;\r\n\r\n const args = call.getArguments();\r\n if (args.length < 2) continue;\r\n\r\n // 1st arg: SQL table name\r\n const nameArg = args[0];\r\n if (nameArg.getKind() !== SyntaxKind.StringLiteral) continue;\r\n const tableName = nameArg.getText().slice(1, -1);\r\n\r\n // 2nd arg: column definitions object\r\n const colsArg = args[1];\r\n if (colsArg.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\r\n\r\n const columns = parseColumnObject(colsArg as ObjectLiteralExpression);\r\n tables.push({ varName: decl.getName(), tableName, columns });\r\n }\r\n\r\n return tables;\r\n}\r\n\r\nfunction parseColumnObject(obj: ObjectLiteralExpression): DrizzleColumn[] {\r\n const columns: DrizzleColumn[] = [];\r\n for (const prop of obj.getProperties()) {\r\n if (!Node.isPropertyAssignment(prop)) continue;\r\n const varName = prop.getName();\r\n const val = prop.getInitializer();\r\n if (!val) continue;\r\n const col = parseColumnChain(val, varName);\r\n if (col) columns.push(col);\r\n }\r\n return columns;\r\n}\r\n\r\nfunction parseColumnChain(expr: Node, varName: string): DrizzleColumn | null {\r\n // Flatten method chain from root outward: root call → chained calls\r\n const chain: CallExpression[] = [];\r\n let current: Node = expr;\r\n\r\n while (current.getKind() === SyntaxKind.CallExpression) {\r\n chain.unshift(current as CallExpression);\r\n const callee = (current as CallExpression).getExpression();\r\n if (callee.getKind() === SyntaxKind.PropertyAccessExpression) {\r\n current = (callee as PropertyAccessExpression).getExpression();\r\n } else {\r\n break;\r\n }\r\n }\r\n\r\n if (chain.length === 0) return null;\r\n\r\n // Root call determines the column type: e.g. varchar('col_name', { length: 255 })\r\n const root = chain[0];\r\n const rootFuncName = root.getExpression().getText().trim().split('.').pop() ?? '';\r\n const drizzleType = DRIZZLE_TYPE_MAP[rootFuncName];\r\n if (!drizzleType) return null;\r\n\r\n const rootArgs = root.getArguments();\r\n const sqlName =\r\n rootArgs.length > 0 && rootArgs[0].getKind() === SyntaxKind.StringLiteral\r\n ? rootArgs[0].getText().slice(1, -1)\r\n : varName;\r\n\r\n const col: DrizzleColumn = {\r\n varName,\r\n sqlName,\r\n type: drizzleType,\r\n isPrimary: false,\r\n isNotNull: false,\r\n isUnique: false,\r\n };\r\n\r\n // Walk remaining chain for modifiers\r\n for (let i = 1; i < chain.length; i++) {\r\n const call = chain[i];\r\n const callee = call.getExpression();\r\n if (callee.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\r\n const methodName = (callee as PropertyAccessExpression).getName();\r\n\r\n switch (methodName) {\r\n case 'primaryKey':\r\n col.isPrimary = true;\r\n col.isNotNull = true;\r\n break;\r\n case 'notNull':\r\n col.isNotNull = true;\r\n break;\r\n case 'unique':\r\n col.isUnique = true;\r\n break;\r\n case 'default':\r\n case 'defaultNow': {\r\n const args = call.getArguments();\r\n col.defaultValue = args.length > 0 ? args[0].getText() : 'now()';\r\n break;\r\n }\r\n case 'references': {\r\n const args = call.getArguments();\r\n if (args.length > 0) col.referencesExpr = args[0].getText();\r\n break;\r\n }\r\n }\r\n }\r\n\r\n return col;\r\n}\r\n\r\nfunction resolveRelations(tables: DrizzleTable[]): ForeignKeyRelation[] {\r\n const relations: ForeignKeyRelation[] = [];\r\n const varToTableName = new Map<string, string>();\r\n const varColToSqlCol = new Map<string, string>();\r\n\r\n for (const t of tables) {\r\n varToTableName.set(t.varName, t.tableName);\r\n for (const c of t.columns) {\r\n varColToSqlCol.set(`${t.varName}.${c.varName}`, c.sqlName);\r\n }\r\n }\r\n\r\n for (const t of tables) {\r\n for (const col of t.columns) {\r\n if (!col.referencesExpr) continue;\r\n // Extract target from arrow function: () => targetTable.targetCol\r\n const arrowMatch = col.referencesExpr.match(/=>\\s*(\\w+)\\.(\\w+)/);\r\n if (!arrowMatch) continue;\r\n const targetVarName = arrowMatch[1];\r\n const targetColVarName = arrowMatch[2];\r\n const targetTable = varToTableName.get(targetVarName);\r\n if (!targetTable) continue;\r\n const targetCol = varColToSqlCol.get(`${targetVarName}.${targetColVarName}`) ?? targetColVarName;\r\n\r\n relations.push({\r\n sourceTable: t.tableName,\r\n sourceField: col.sqlName,\r\n targetTable,\r\n targetField: targetCol,\r\n cardinality: 'N:1',\r\n });\r\n }\r\n }\r\n\r\n return relations;\r\n}\r\n\r\nexport function parseDrizzleFile(filePath: string): { schemas: TableSchema[]; relations: ForeignKeyRelation[] } {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return { schemas: [], relations: [] };\r\n\r\n try {\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n const tables = findTableCalls(sourceFile);\r\n\r\n const schemas: TableSchema[] = tables.map((t) => ({\r\n tableName: t.tableName,\r\n className: t.varName,\r\n fields: t.columns.map((c): FieldSchema => ({\r\n name: c.sqlName,\r\n type: c.type,\r\n allowNull: !c.isNotNull && !c.isPrimary,\r\n primaryKey: c.isPrimary,\r\n unique: c.isUnique,\r\n defaultValue: c.defaultValue,\r\n })),\r\n }));\r\n\r\n return { schemas, relations: resolveRelations(tables) };\r\n } catch {\r\n return { schemas: [], relations: [] };\r\n }\r\n}\r\n\r\nexport function parseDrizzleDirectory(dirPath: string): { schemas: TableSchema[]; relations: ForeignKeyRelation[] } {\r\n const absoluteDir = path.resolve(dirPath);\r\n if (!fs.existsSync(absoluteDir)) return { schemas: [], relations: [] };\r\n\r\n const files = fs.readdirSync(absoluteDir).filter(\r\n (f) => f.endsWith('.ts') && !f.endsWith('.test.ts') && !f.endsWith('.spec.ts') && f !== 'index.ts',\r\n );\r\n\r\n const allSchemas: TableSchema[] = [];\r\n const allRelations: ForeignKeyRelation[] = [];\r\n for (const file of files) {\r\n const result = parseDrizzleFile(path.join(absoluteDir, file));\r\n allSchemas.push(...result.schemas);\r\n allRelations.push(...result.relations);\r\n }\r\n return { schemas: allSchemas, relations: allRelations };\r\n}\r\n\r\nexport function createDrizzleAdapter(): BackendAdapter {\r\n return {\r\n name: 'drizzle',\r\n\r\n async parseModels(dir: string): Promise<TableSchema[]> {\r\n return parseDrizzleDirectory(dir).schemas;\r\n },\r\n\r\n async parseAssociations(dir: string): Promise<ForeignKeyRelation[]> {\r\n return parseDrizzleDirectory(dir).relations;\r\n },\r\n\r\n async parseControllers(dir: string): Promise<RouteEntry[]> {\r\n const { parseControllerDirectory } = await import('../parsers/controller-parser.js');\r\n const endpoints = parseControllerDirectory(dir);\r\n return endpoints.map((ep) => ({\r\n method: ep.method,\r\n path: ep.path,\r\n handler: '',\r\n controllerClass: '',\r\n }));\r\n },\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport type { BackendAdapter } from '../types.js';\r\nimport { createSequelizeAdapter } from './sequelize.js';\r\nimport { createTypeORMAdapter } from './typeorm.js';\r\nimport { createPrismaAdapter } from './prisma.js';\r\nimport { createDrizzleAdapter } from './drizzle.js';\r\n\r\nconst ADAPTER_FACTORIES: Record<string, () => BackendAdapter> = {\r\n sequelize: createSequelizeAdapter,\r\n typeorm: createTypeORMAdapter,\r\n prisma: createPrismaAdapter,\r\n drizzle: createDrizzleAdapter,\r\n};\r\n\r\n/**\r\n * Create an adapter by name.\r\n */\r\nexport function createAdapter(name: string): BackendAdapter {\r\n const factory = ADAPTER_FACTORIES[name];\r\n if (!factory) {\r\n throw new Error(`Unknown adapter: \"${name}\". Available: ${Object.keys(ADAPTER_FACTORIES).join(', ')}`);\r\n }\r\n return factory();\r\n}\r\n\r\n/**\r\n * Auto-detect the ORM adapter from project structure.\r\n *\r\n * Detection order:\r\n * 1. Prisma — if `prisma/schema.prisma` exists\r\n * 2. TypeORM — if any .ts file has `@Entity` decorator\r\n * 3. Sequelize — default fallback (`.init()` pattern)\r\n */\r\nexport function detectAdapter(backendRoot: string): string {\r\n const root = path.resolve(backendRoot);\r\n\r\n // Check for Prisma\r\n const prismaLocations = [\r\n path.join(root, 'prisma', 'schema.prisma'),\r\n path.join(root, 'schema.prisma'),\r\n path.join(root, '..', 'prisma', 'schema.prisma'),\r\n ];\r\n for (const loc of prismaLocations) {\r\n if (fs.existsSync(loc)) return 'prisma';\r\n }\r\n\r\n // Check for TypeORM / Drizzle — scan models directory\r\n const modelsDir = path.join(root, 'models');\r\n if (fs.existsSync(modelsDir)) {\r\n try {\r\n const files = fs.readdirSync(modelsDir, { recursive: true });\r\n for (const file of files) {\r\n const filePath = path.join(modelsDir, String(file));\r\n if (!filePath.endsWith('.ts')) continue;\r\n try {\r\n const content = fs.readFileSync(filePath, 'utf-8');\r\n if (/@Entity\\s*\\(/.test(content)) return 'typeorm';\r\n if (/(?:pgTable|mysqlTable|sqliteTable)\\s*\\(/.test(content)) return 'drizzle';\r\n } catch {\r\n // skip\r\n }\r\n }\r\n } catch {\r\n // skip\r\n }\r\n }\r\n\r\n // Default to Sequelize\r\n return 'sequelize';\r\n}\r\n\r\n/**\r\n * Resolve adapter: if a string name is given, create it; if already a BackendAdapter, use it.\r\n * If 'auto', detect from project structure.\r\n */\r\nexport function resolveAdapter(\r\n adapterOrName: string | BackendAdapter | undefined,\r\n backendRoot: string,\r\n): BackendAdapter {\r\n if (typeof adapterOrName === 'object' && adapterOrName !== null) {\r\n return adapterOrName;\r\n }\r\n const name = adapterOrName === 'auto' || !adapterOrName\r\n ? detectAdapter(backendRoot)\r\n : adapterOrName;\r\n return createAdapter(name);\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\nimport type { OpenCrocPlugin, PluginRegistry } from './types.js';\r\n\r\nexport type { OpenCrocPlugin, PluginRegistry } from './types.js';\r\n\r\n/**\r\n * Create a plugin registry.\r\n *\r\n * @example\r\n * ```ts\r\n * const registry = createPluginRegistry();\r\n * registry.register({ name: 'my-plugin', beforePipeline() { console.log('go!'); } });\r\n * await registry.invoke('beforePipeline', config);\r\n * ```\r\n */\r\nexport function createPluginRegistry(): PluginRegistry {\r\n const plugins: OpenCrocPlugin[] = [];\r\n\r\n function register(plugin: OpenCrocPlugin): void {\r\n if (!plugin.name) {\r\n throw new Error('Plugin must have a name');\r\n }\r\n if (plugins.some((p) => p.name === plugin.name)) {\r\n throw new Error(`Plugin \"${plugin.name}\" is already registered`);\r\n }\r\n plugins.push(plugin);\r\n }\r\n\r\n async function unregister(name: string): Promise<void> {\r\n const idx = plugins.findIndex((p) => p.name === name);\r\n if (idx === -1) return;\r\n const plugin = plugins[idx];\r\n if (plugin.teardown) {\r\n await plugin.teardown();\r\n }\r\n plugins.splice(idx, 1);\r\n }\r\n\r\n function get(name: string): OpenCrocPlugin | undefined {\r\n return plugins.find((p) => p.name === name);\r\n }\r\n\r\n function list(): string[] {\r\n return plugins.map((p) => p.name);\r\n }\r\n\r\n async function invoke<K extends keyof OpenCrocPlugin>(\r\n hook: K,\r\n ...args: unknown[]\r\n ): Promise<void> {\r\n for (const plugin of plugins) {\r\n const fn = plugin[hook];\r\n if (typeof fn === 'function') {\r\n await (fn as (...a: unknown[]) => unknown).apply(plugin, args);\r\n }\r\n }\r\n }\r\n\r\n async function applyConfigTransforms(config: OpenCrocConfig): Promise<OpenCrocConfig> {\r\n let result = config;\r\n for (const plugin of plugins) {\r\n if (plugin.transformConfig) {\r\n result = await plugin.transformConfig(result);\r\n }\r\n }\r\n return result;\r\n }\r\n\r\n return { register, unregister, get, list, invoke, applyConfigTransforms };\r\n}\r\n\r\n/**\r\n * Helper to define a plugin with type safety.\r\n */\r\nexport function definePlugin(plugin: OpenCrocPlugin): OpenCrocPlugin {\r\n return plugin;\r\n}\r\n","/**\r\n * CI template generators for popular CI/CD platforms.\r\n *\r\n * Usage:\r\n * npx opencroc ci --platform=github\r\n * npx opencroc ci --platform=gitlab\r\n */\r\n\r\nexport interface CiTemplateOptions {\r\n /** Node.js version(s). Default: ['20.x'] */\r\n nodeVersions?: string[];\r\n /** Install command. Default: 'npm ci' */\r\n installCommand?: string;\r\n /** Whether to run self-healing. Default: false */\r\n selfHeal?: boolean;\r\n /** Custom opencroc generate args */\r\n generateArgs?: string;\r\n /** Custom opencroc test args */\r\n testArgs?: string;\r\n}\r\n\r\nexport function generateGitHubActionsTemplate(opts: CiTemplateOptions = {}): string {\r\n const nodeVersions = opts.nodeVersions ?? ['20.x'];\r\n const install = opts.installCommand ?? 'npm ci';\r\n const genArgs = opts.generateArgs ?? '--all';\r\n const testArgs = opts.testArgs ?? '';\r\n const healStep = opts.selfHeal\r\n ? `\r\n - name: Self-heal failures\r\n if: failure()\r\n run: npx opencroc heal --max-iterations 3`\r\n : '';\r\n\r\n const matrix =\r\n nodeVersions.length > 1\r\n ? `\r\n strategy:\r\n matrix:\r\n node-version: [${nodeVersions.join(', ')}]`\r\n : '';\r\n\r\n const nodeSetup =\r\n nodeVersions.length > 1\r\n ? '${{ matrix.node-version }}'\r\n : nodeVersions[0];\r\n\r\n return `# Generated by OpenCroc — AI-native E2E testing\r\n# https://github.com/opencroc/opencroc\r\n\r\nname: OpenCroc E2E\r\n\r\non:\r\n push:\r\n branches: [main]\r\n pull_request:\r\n branches: [main]\r\n\r\njobs:\r\n e2e:\r\n runs-on: ubuntu-latest${matrix}\r\n steps:\r\n - uses: actions/checkout@v4\r\n\r\n - uses: actions/setup-node@v4\r\n with:\r\n node-version: '${nodeSetup}'\r\n\r\n - name: Install dependencies\r\n run: ${install}\r\n\r\n - name: Install Playwright browsers\r\n run: npx playwright install --with-deps chromium\r\n\r\n - name: Generate E2E tests\r\n run: npx opencroc generate ${genArgs}\r\n\r\n - name: Run E2E tests\r\n run: npx opencroc test ${testArgs}\r\n${healStep}\r\n - name: Upload test report\r\n if: always()\r\n uses: actions/upload-artifact@v4\r\n with:\r\n name: opencroc-report\r\n path: opencroc-output/\r\n retention-days: 14\r\n`;\r\n}\r\n\r\nexport function generateGitLabCITemplate(opts: CiTemplateOptions = {}): string {\r\n const install = opts.installCommand ?? 'npm ci';\r\n const genArgs = opts.generateArgs ?? '--all';\r\n const testArgs = opts.testArgs ?? '';\r\n const nodeVersion = opts.nodeVersions?.[0] ?? '20';\r\n\r\n return `# Generated by OpenCroc — AI-native E2E testing\r\n# https://github.com/opencroc/opencroc\r\n\r\nimage: node:${nodeVersion}\r\n\r\nstages:\r\n - generate\r\n - test\r\n\r\nvariables:\r\n PLAYWRIGHT_BROWSERS_PATH: \\${CI_PROJECT_DIR}/.cache/ms-playwright\r\n\r\ncache:\r\n key: \\${CI_COMMIT_REF_SLUG}\r\n paths:\r\n - node_modules/\r\n - .cache/ms-playwright/\r\n\r\ngenerate:\r\n stage: generate\r\n script:\r\n - ${install}\r\n - npx opencroc generate ${genArgs}\r\n artifacts:\r\n paths:\r\n - opencroc-output/\r\n expire_in: 1 day\r\n\r\ne2e:\r\n stage: test\r\n needs: [generate]\r\n before_script:\r\n - ${install}\r\n - npx playwright install --with-deps chromium\r\n script:\r\n - npx opencroc test ${testArgs}\r\n artifacts:\r\n when: always\r\n paths:\r\n - opencroc-output/\r\n expire_in: 14 days\r\n`;\r\n}\r\n\r\nconst TEMPLATES: Record<string, (opts: CiTemplateOptions) => string> = {\r\n github: generateGitHubActionsTemplate,\r\n gitlab: generateGitLabCITemplate,\r\n};\r\n\r\n/**\r\n * Get available CI platform names.\r\n */\r\nexport function listCiPlatforms(): string[] {\r\n return Object.keys(TEMPLATES);\r\n}\r\n\r\n/**\r\n * Generate a CI template for the given platform.\r\n */\r\nexport function generateCiTemplate(\r\n platform: string,\r\n opts: CiTemplateOptions = {},\r\n): string {\r\n const generator = TEMPLATES[platform];\r\n if (!generator) {\r\n throw new Error(\r\n `Unknown CI platform: \"${platform}\". Available: ${Object.keys(TEMPLATES).join(', ')}`,\r\n );\r\n }\r\n return generator(opts);\r\n}\r\n","import type {\r\n PipelineRunResult,\r\n ERDiagramResult,\r\n ChainPlanResult,\r\n GeneratedTestFile,\r\n ValidationError,\r\n ExecutionMetrics,\n} from '../types.js';\r\nimport type { ExecutionQualityGateResult } from '../execution/types.js';\n\r\n// ===== Reporter Types =====\r\n\r\nexport interface ReportOutput {\r\n format: 'html' | 'json' | 'markdown';\r\n content: string;\r\n filename: string;\r\n}\r\n\nexport interface ReportExecutionContext {\n metrics?: ExecutionMetrics | null;\n quality?: ExecutionQualityGateResult | null;\n}\n\r\n// ===== JSON Reporter =====\r\n\r\nexport function generateJsonReport(\n result: PipelineRunResult,\n context?: ReportExecutionContext,\n): ReportOutput {\n const serializable = {\r\n modules: result.modules,\r\n erDiagrams: Object.fromEntries(\r\n Array.from(result.erDiagrams.entries()).map(([k, v]) => [\r\n k,\r\n { tables: v.tables.length, relations: v.relations.length, mermaidText: v.mermaidText },\r\n ]),\r\n ),\r\n chainPlans: Object.fromEntries(\r\n Array.from(result.chainPlans.entries()).map(([k, v]) => [\r\n k,\r\n { chains: v.chains.length, totalSteps: v.totalSteps },\r\n ]),\r\n ),\r\n generatedFiles: result.generatedFiles.map((f) => ({\r\n filePath: f.filePath,\r\n module: f.module,\r\n chain: f.chain,\r\n })),\r\n execution: context\n ? {\n metrics: context.metrics ?? null,\n quality: context.quality ?? null,\n }\n : undefined,\n validationErrors: result.validationErrors,\r\n duration: result.duration,\r\n };\r\n\r\n return {\r\n format: 'json',\r\n content: JSON.stringify(serializable, null, 2),\r\n filename: 'opencroc-report.json',\r\n };\r\n}\r\n\r\n// ===== Markdown Reporter =====\r\n\r\nexport function generateMarkdownReport(\n result: PipelineRunResult,\n context?: ReportExecutionContext,\n): ReportOutput {\n const lines: string[] = [\r\n '# OpenCroc Report',\r\n '',\r\n `**Duration**: ${result.duration}ms`,\r\n `**Modules**: ${result.modules.length} (${result.modules.join(', ')})`,\r\n '',\r\n '## ER Diagrams',\r\n '',\r\n ];\r\n\r\n for (const [mod, er] of result.erDiagrams) {\r\n lines.push(`### ${mod}`);\r\n lines.push(`- Tables: ${er.tables.length}`);\r\n lines.push(`- Relations: ${er.relations.length}`);\r\n lines.push('');\r\n }\r\n\r\n lines.push('## Chain Plans', '');\r\n for (const [mod, plan] of result.chainPlans) {\r\n lines.push(`### ${mod}`);\r\n lines.push(`- Chains: ${plan.chains.length}`);\r\n lines.push(`- Total Steps: ${plan.totalSteps}`);\r\n lines.push('');\r\n }\r\n\r\n lines.push(`## Generated Files (${result.generatedFiles.length})`, '');\r\n for (const f of result.generatedFiles) {\r\n lines.push(`- \\`${f.filePath}\\` (${f.module} / ${f.chain})`);\r\n }\r\n\r\n if (result.validationErrors.length > 0) {\r\n lines.push('', '## Validation Issues', '');\r\n const errors = result.validationErrors.filter((e) => e.severity === 'error');\r\n const warnings = result.validationErrors.filter((e) => e.severity === 'warning');\r\n if (errors.length > 0) {\r\n lines.push(`### Errors (${errors.length})`, '');\r\n for (const e of errors) {\r\n lines.push(`- **[${e.module}]** ${e.field}: ${e.message}`);\r\n }\r\n }\r\n if (warnings.length > 0) {\r\n lines.push(`### Warnings (${warnings.length})`, '');\r\n for (const w of warnings) {\r\n lines.push(`- **[${w.module}]** ${w.field}: ${w.message}`);\r\n }\r\n }\r\n }\r\n\n if (context?.metrics || context?.quality) {\n lines.push('', '## Execution Quality', '');\n if (context.metrics) {\n lines.push(\n `- Passed: ${context.metrics.passed}`,\n `- Failed: ${context.metrics.failed}`,\n `- Skipped: ${context.metrics.skipped}`,\n `- TimedOut: ${context.metrics.timedOut}`,\n );\n }\n if (context.quality) {\n lines.push(\n `- Gate Level: ${context.quality.level}`,\n `- Setup Fail: ${context.quality.setupFail}`,\n `- Skip Ratio: ${(context.quality.skipRatio * 100).toFixed(2)}%`,\n `- Auth Fail Ratio: ${(context.quality.authFailRatio * 100).toFixed(2)}%`,\n `- Effective Execution Rate: ${(context.quality.effectiveExecutionRate * 100).toFixed(2)}%`,\n `- Auth Status: ${context.quality.authStatus}`,\n `- Backend Status: ${context.quality.backendStatus}`,\n );\n if (context.quality.reasons.length > 0) {\n lines.push(`- Reasons: ${context.quality.reasons.join(', ')}`);\n }\n }\n }\n\r\n lines.push('', '---', '*Generated by [OpenCroc](https://github.com/opencroc/opencroc)*');\r\n\r\n return {\r\n format: 'markdown',\r\n content: lines.join('\\n'),\r\n filename: 'opencroc-report.md',\r\n };\r\n}\r\n\r\n// ===== HTML Reporter =====\r\n\r\nfunction escapeHtml(s: string): string {\r\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\r\n}\r\n\r\nfunction erSummaryRows(erDiagrams: Map<string, ERDiagramResult>): string {\r\n const rows: string[] = [];\r\n for (const [mod, er] of erDiagrams) {\r\n rows.push(`<tr><td>${escapeHtml(mod)}</td><td>${er.tables.length}</td><td>${er.relations.length}</td></tr>`);\r\n }\r\n return rows.join('\\n');\r\n}\r\n\r\nfunction chainSummaryRows(chainPlans: Map<string, ChainPlanResult>): string {\r\n const rows: string[] = [];\r\n for (const [mod, plan] of chainPlans) {\r\n rows.push(`<tr><td>${escapeHtml(mod)}</td><td>${plan.chains.length}</td><td>${plan.totalSteps}</td></tr>`);\r\n }\r\n return rows.join('\\n');\r\n}\r\n\r\nfunction fileListRows(files: GeneratedTestFile[]): string {\r\n return files\r\n .map((f) => `<tr><td><code>${escapeHtml(f.filePath)}</code></td><td>${escapeHtml(f.module)}</td><td>${escapeHtml(f.chain)}</td></tr>`)\r\n .join('\\n');\r\n}\r\n\r\nfunction validationRows(errors: ValidationError[]): string {\r\n return errors\r\n .map(\r\n (e) =>\r\n `<tr class=\"${e.severity}\"><td><span class=\"badge ${e.severity}\">${e.severity}</span></td><td>${escapeHtml(e.module)}</td><td>${escapeHtml(e.field)}</td><td>${escapeHtml(e.message)}</td></tr>`,\r\n )\r\n .join('\\n');\r\n}\r\n\r\nexport function generateHtmlReport(\n result: PipelineRunResult,\n context?: ReportExecutionContext,\n): ReportOutput {\n const totalTables = Array.from(result.erDiagrams.values()).reduce((s, e) => s + e.tables.length, 0);\r\n const totalRelations = Array.from(result.erDiagrams.values()).reduce((s, e) => s + e.relations.length, 0);\r\n const totalChains = Array.from(result.chainPlans.values()).reduce((s, p) => s + p.chains.length, 0);\r\n const totalSteps = Array.from(result.chainPlans.values()).reduce((s, p) => s + p.totalSteps, 0);\r\n const errorCount = result.validationErrors.filter((e) => e.severity === 'error').length;\r\n const warnCount = result.validationErrors.filter((e) => e.severity === 'warning').length;\r\n\r\n const html = `<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n<meta charset=\"utf-8\" />\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\r\n<title>OpenCroc Report</title>\r\n<style>\r\n :root { --bg: #0d1117; --fg: #c9d1d9; --card: #161b22; --border: #30363d; --accent: #58a6ff; --green: #3fb950; --yellow: #d29922; --red: #f85149; }\r\n * { box-sizing: border-box; margin: 0; padding: 0; }\r\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; background: var(--bg); color: var(--fg); padding: 2rem; }\r\n h1 { color: var(--accent); margin-bottom: 0.25rem; }\r\n .subtitle { color: #8b949e; margin-bottom: 2rem; }\r\n .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin-bottom: 2rem; }\r\n .card { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 1.25rem; }\r\n .card .label { font-size: 0.85rem; color: #8b949e; }\r\n .card .value { font-size: 2rem; font-weight: 700; color: var(--accent); }\r\n .card .value.green { color: var(--green); }\r\n .card .value.yellow { color: var(--yellow); }\r\n .card .value.red { color: var(--red); }\r\n section { margin-bottom: 2rem; }\r\n h2 { color: var(--fg); border-bottom: 1px solid var(--border); padding-bottom: 0.5rem; margin-bottom: 1rem; }\r\n table { width: 100%; border-collapse: collapse; background: var(--card); border-radius: 8px; overflow: hidden; }\r\n th, td { text-align: left; padding: 0.6rem 1rem; border-bottom: 1px solid var(--border); }\r\n th { background: #21262d; color: #8b949e; font-weight: 600; font-size: 0.85rem; text-transform: uppercase; }\r\n tr:last-child td { border-bottom: none; }\r\n code { background: #21262d; padding: 0.15rem 0.4rem; border-radius: 4px; font-size: 0.85rem; }\r\n .badge { display: inline-block; padding: 0.15rem 0.5rem; border-radius: 12px; font-size: 0.75rem; font-weight: 600; text-transform: uppercase; }\r\n .badge.error { background: rgba(248,81,73,0.15); color: var(--red); }\r\n .badge.warning { background: rgba(210,153,34,0.15); color: var(--yellow); }\r\n footer { margin-top: 3rem; text-align: center; color: #484f58; font-size: 0.85rem; }\r\n footer a { color: var(--accent); text-decoration: none; }\r\n</style>\r\n</head>\r\n<body>\r\n<h1>OpenCroc Report</h1>\r\n<p class=\"subtitle\">Generated in ${result.duration}ms · ${result.modules.length} module(s)</p>\r\n\r\n<div class=\"grid\">\r\n <div class=\"card\"><div class=\"label\">Modules</div><div class=\"value\">${result.modules.length}</div></div>\r\n <div class=\"card\"><div class=\"label\">Tables</div><div class=\"value\">${totalTables}</div></div>\r\n <div class=\"card\"><div class=\"label\">Relations</div><div class=\"value\">${totalRelations}</div></div>\r\n <div class=\"card\"><div class=\"label\">Chains</div><div class=\"value\">${totalChains}</div></div>\r\n <div class=\"card\"><div class=\"label\">Steps</div><div class=\"value\">${totalSteps}</div></div>\r\n <div class=\"card\"><div class=\"label\">Files</div><div class=\"value green\">${result.generatedFiles.length}</div></div>\r\n <div class=\"card\"><div class=\"label\">Errors</div><div class=\"value${errorCount > 0 ? ' red' : ''}\">${errorCount}</div></div>\r\n <div class=\"card\"><div class=\"label\">Warnings</div><div class=\"value${warnCount > 0 ? ' yellow' : ''}\">${warnCount}</div></div>\r\n</div>\r\n\r\n<section>\r\n<h2>ER Diagrams</h2>\r\n<table>\r\n<thead><tr><th>Module</th><th>Tables</th><th>Relations</th></tr></thead>\r\n<tbody>${erSummaryRows(result.erDiagrams)}</tbody>\r\n</table>\r\n</section>\r\n\r\n<section>\r\n<h2>Chain Plans</h2>\r\n<table>\r\n<thead><tr><th>Module</th><th>Chains</th><th>Steps</th></tr></thead>\r\n<tbody>${chainSummaryRows(result.chainPlans)}</tbody>\r\n</table>\r\n</section>\r\n\r\n<section>\r\n<h2>Generated Files (${result.generatedFiles.length})</h2>\r\n<table>\r\n<thead><tr><th>File</th><th>Module</th><th>Chain</th></tr></thead>\r\n<tbody>${fileListRows(result.generatedFiles)}</tbody>\r\n</table>\r\n</section>\r\n\r\n${\n context?.quality || context?.metrics\n ? `<section>\n<h2>Execution Quality</h2>\n<table>\n<thead><tr><th>Item</th><th>Value</th></tr></thead>\n<tbody>\n${context.metrics ? `<tr><td>Passed</td><td>${context.metrics.passed}</td></tr><tr><td>Failed</td><td>${context.metrics.failed}</td></tr><tr><td>Skipped</td><td>${context.metrics.skipped}</td></tr><tr><td>TimedOut</td><td>${context.metrics.timedOut}</td></tr>` : ''}\n${context.quality ? `<tr><td>Gate Level</td><td>${escapeHtml(context.quality.level)}</td></tr><tr><td>Setup Fail</td><td>${String(context.quality.setupFail)}</td></tr><tr><td>Skip Ratio</td><td>${(context.quality.skipRatio * 100).toFixed(2)}%</td></tr><tr><td>Auth Fail Ratio</td><td>${(context.quality.authFailRatio * 100).toFixed(2)}%</td></tr><tr><td>Effective Execution Rate</td><td>${(context.quality.effectiveExecutionRate * 100).toFixed(2)}%</td></tr><tr><td>Auth Status</td><td>${escapeHtml(context.quality.authStatus)}</td></tr><tr><td>Backend Status</td><td>${escapeHtml(context.quality.backendStatus)}</td></tr><tr><td>Reasons</td><td>${escapeHtml(context.quality.reasons.join(', ') || '-')}</td></tr>` : ''}\n</tbody>\n</table>\n</section>`\n : ''\n}\n\n${\r\n result.validationErrors.length > 0\r\n ? `<section>\r\n<h2>Validation Issues (${result.validationErrors.length})</h2>\r\n<table>\r\n<thead><tr><th>Severity</th><th>Module</th><th>Field</th><th>Message</th></tr></thead>\r\n<tbody>${validationRows(result.validationErrors)}</tbody>\r\n</table>\r\n</section>`\r\n : ''\r\n}\r\n\r\n<footer>\r\n Generated by <a href=\"https://github.com/opencroc/opencroc\">OpenCroc</a>\r\n</footer>\r\n</body>\r\n</html>`;\r\n\r\n return {\r\n format: 'html',\r\n content: html,\r\n filename: 'opencroc-report.html',\r\n };\r\n}\r\n\r\n// ===== Report Orchestrator =====\r\n\r\nconst REPORTERS: Record<string, (result: PipelineRunResult, context?: ReportExecutionContext) => ReportOutput> = {\n html: generateHtmlReport,\r\n json: generateJsonReport,\r\n markdown: generateMarkdownReport,\r\n};\r\n\r\n/**\r\n * Generate reports in the specified formats.\r\n */\r\nexport function generateReports(\r\n result: PipelineRunResult,\r\n formats: ('html' | 'json' | 'markdown')[] = ['html'],\r\n context?: ReportExecutionContext,\n): ReportOutput[] {\r\n return formats.map((fmt) => {\r\n const gen = REPORTERS[fmt];\r\n if (!gen) throw new Error(`Unknown report format: \"${fmt}\". Available: ${Object.keys(REPORTERS).join(', ')}`);\r\n return gen(result, context);\n });\r\n}\r\n\r\n// ===== Advanced Reporters (v1.2) =====\r\nexport {\r\n classifyFailure,\r\n buildFailureSummary,\r\n aggregateLogCompletion,\r\n parseApiDomain,\r\n buildBackendChecklist,\r\n renderChecklistMarkdown,\r\n} from './checklist-reporter.js';\r\n\r\nexport {\r\n buildWorkorders,\r\n renderWorkordersMarkdown,\r\n} from './workorder-reporter.js';\r\nexport type { BuildWorkordersOptions } from './workorder-reporter.js';\r\n\r\nexport {\r\n TokenTracker,\r\n renderTokenReportMarkdown,\r\n} from './token-reporter.js';\r\n","/**\r\n * Checklist Reporter — generates backend fix checklists from test results.\r\n *\r\n * Groups failures by API domain, lists affected tests and endpoints,\r\n * and produces both structured data and Markdown output.\r\n */\r\n\r\nimport type {\r\n TestResultRecord,\r\n FailureCategory,\r\n FailureSummary,\r\n BackendDomainItem,\r\n LogCompletionSummary,\r\n} from '../types.js';\r\n\r\n// ===== Failure classification =====\r\n\r\nexport function classifyFailure(error?: string): FailureCategory {\r\n if (!error) return 'other';\r\n if (error.includes('[BACKEND_5XX]')) return 'backend-5xx';\r\n if (error.includes('[MIXED_5XX]')) return 'mixed-5xx';\r\n if (error.includes('[SLOW_API_FATAL]')) return 'slow-api';\r\n if (error.includes('[LOG_COMPLETION_FAIL]')) return 'log-fail';\r\n if (error.includes('[LOG_COMPLETION_TIMEOUT]')) return 'log-timeout';\r\n if (/waitForSelector|toHaveURL|Timeout/i.test(error)) return 'frontend-load';\r\n return 'other';\r\n}\r\n\r\n// ===== Failure summary =====\r\n\r\nexport function buildFailureSummary(records: TestResultRecord[]): FailureSummary {\r\n const failed = records.filter(r => r.status === 'failed');\r\n const cats = failed.map(r => classifyFailure(r.error));\r\n return {\r\n totalFailed: failed.length,\r\n backend5xx: cats.filter(c => c === 'backend-5xx').length,\r\n mixed5xx: cats.filter(c => c === 'mixed-5xx').length,\r\n slowApi: cats.filter(c => c === 'slow-api').length,\r\n logFail: cats.filter(c => c === 'log-fail').length,\r\n logTimeout: cats.filter(c => c === 'log-timeout').length,\r\n frontendLoad: cats.filter(c => c === 'frontend-load').length,\r\n other: cats.filter(c => c === 'other').length,\r\n };\r\n}\r\n\r\n// ===== Log completion aggregation =====\r\n\r\nexport function aggregateLogCompletion(records: TestResultRecord[]): LogCompletionSummary {\r\n let totalCandidates = 0;\r\n let succeeded = 0;\r\n let failed = 0;\r\n let timedOut = 0;\r\n const timedOutFreq = new Map<string, { method: string; path: string; count: number }>();\r\n\r\n for (const r of records) {\r\n const lc = r.logCompletion;\r\n if (!lc || lc.candidateCount === 0) continue;\r\n\r\n totalCandidates += lc.candidateCount;\r\n succeeded += lc.succeeded.length;\r\n failed += lc.failed.length;\r\n timedOut += lc.timedOut.length;\r\n\r\n for (const item of lc.timedOut) {\r\n const key = `${item.method}:${item.path}`;\r\n const existing = timedOutFreq.get(key);\r\n if (existing) existing.count += 1;\r\n else timedOutFreq.set(key, { method: item.method, path: item.path, count: 1 });\r\n }\r\n }\r\n\r\n const timedOutTop5 = Array.from(timedOutFreq.values())\r\n .sort((a, b) => b.count - a.count)\r\n .slice(0, 5)\r\n .map(t => ({ method: t.method, path: t.path, occurrences: t.count }));\r\n\r\n const matchRate = totalCandidates > 0 ? (succeeded + failed) / totalCandidates * 100 : 0;\r\n const effectiveRate = totalCandidates > 0 ? succeeded / totalCandidates * 100 : 0;\r\n\r\n return { totalCandidates, succeeded, failed, timedOut, matchRate, effectiveRate, timedOutTop5 };\r\n}\r\n\r\n// ===== URL extraction helpers =====\r\n\r\nfunction extractUrls(error?: string): string[] {\r\n if (!error) return [];\r\n const matched = error.match(/https?:\\/\\/[^\\s\\n]+/g);\r\n return matched ? Array.from(new Set(matched)) : [];\r\n}\r\n\r\nexport function parseApiDomain(urlStr: string): string | null {\r\n try {\r\n const u = new URL(urlStr);\r\n const segments = u.pathname.split('/').filter(Boolean);\r\n const v1Index = segments.findIndex(s => s === 'v1');\r\n if (v1Index === -1 || v1Index + 1 >= segments.length) return segments[0] || null;\r\n const afterV1 = segments.slice(v1Index + 1);\r\n if (afterV1.length === 0) return null;\r\n const first = afterV1[0];\r\n if (/^\\d+$/.test(first) && afterV1.length > 1) return afterV1[1];\r\n return first;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n// ===== Backend checklist =====\r\n\r\nexport function buildBackendChecklist(records: TestResultRecord[]): BackendDomainItem[] {\r\n const domainMap = new Map<string, { tests: Set<string>; endpoints: Set<string> }>();\r\n const failed = records.filter(r => r.status === 'failed');\r\n\r\n for (const item of failed) {\r\n const cat = classifyFailure(item.error);\r\n if (cat !== 'backend-5xx' && cat !== 'mixed-5xx') continue;\r\n const urls = extractUrls(item.error);\r\n for (const url of urls) {\r\n const domain = parseApiDomain(url);\r\n if (!domain) continue;\r\n const current = domainMap.get(domain) ?? { tests: new Set<string>(), endpoints: new Set<string>() };\r\n current.tests.add(item.title);\r\n current.endpoints.add(url);\r\n domainMap.set(domain, current);\r\n }\r\n }\r\n\r\n return Array.from(domainMap.entries())\r\n .map(([domain, v]) => ({\r\n domain,\r\n tests: Array.from(v.tests).sort(),\r\n endpoints: Array.from(v.endpoints).sort(),\r\n }))\r\n .sort((a, b) => b.tests.length - a.tests.length || a.domain.localeCompare(b.domain));\r\n}\r\n\r\n// ===== Markdown renderer =====\r\n\r\nexport function renderChecklistMarkdown(\r\n items: BackendDomainItem[],\r\n summary: FailureSummary,\r\n logSummary?: LogCompletionSummary,\r\n): string {\r\n const lines: string[] = [\r\n '# Backend Fix Checklist',\r\n '',\r\n ];\r\n\r\n if (logSummary) {\r\n lines.push(\r\n `- Log match rate: ${logSummary.matchRate.toFixed(2)}% (candidates=${logSummary.totalCandidates}, succeeded=${logSummary.succeeded}, failed=${logSummary.failed}, timedOut=${logSummary.timedOut})`,\r\n `- Effective success rate: ${logSummary.effectiveRate.toFixed(2)}%`,\r\n );\r\n }\r\n lines.push(\r\n `- Backend 5xx: ${summary.backend5xx}`,\r\n `- Mixed 5xx: ${summary.mixed5xx}`,\r\n `- Slow API: ${summary.slowApi}`,\r\n `- Log fail: ${summary.logFail}`,\r\n `- Log timeout: ${summary.logTimeout}`,\r\n `- Frontend load: ${summary.frontendLoad}`,\r\n `- Other: ${summary.other}`,\r\n '',\r\n );\r\n\r\n if (logSummary && logSummary.timedOutTop5.length > 0) {\r\n lines.push('### Timed-out APIs Top 5', '', '| # | Method | Path | Occurrences |', '|---|--------|------|-------------|');\r\n logSummary.timedOutTop5.forEach((t, i) => {\r\n lines.push(`| ${i + 1} | ${t.method} | ${t.path} | ${t.occurrences} |`);\r\n });\r\n lines.push('');\r\n }\r\n\r\n if (items.length === 0) {\r\n lines.push('No backend 5xx failures this run.');\r\n return lines.join('\\n') + '\\n';\r\n }\r\n\r\n for (const item of items) {\r\n lines.push(\r\n `## ${item.domain}`,\r\n '',\r\n `- Failed tests: ${item.tests.length}`,\r\n '- Affected tests:',\r\n );\r\n for (const t of item.tests) lines.push(` - ${t}`);\r\n lines.push('- Failed endpoints:');\r\n for (const e of item.endpoints) lines.push(` - ${e}`);\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n') + '\\n';\r\n}\r\n","/**\r\n * Workorder Reporter — auto-generates prioritized backend work orders.\r\n *\r\n * Priority rules:\r\n * - P0: ≥3 affected tests OR log completion rate < 90%\r\n * - P1: 2 affected tests\r\n * - P2: 1 affected test\r\n *\r\n * Each workorder includes objective, affected scope, and acceptance criteria.\r\n */\r\n\r\nimport type {\r\n BackendDomainItem,\r\n FailureSummary,\r\n LogCompletionSummary,\r\n WorkorderItem,\r\n} from '../types.js';\r\n\r\n// ===== Priority assignment =====\r\n\r\nfunction assignPriority(item: BackendDomainItem, isLogRate: boolean): 'P0' | 'P1' | 'P2' {\r\n if (isLogRate) return 'P0';\r\n if (item.tests.length >= 3) return 'P0';\r\n if (item.tests.length === 2) return 'P1';\r\n return 'P2';\r\n}\r\n\r\n// ===== Workorder builder =====\r\n\r\nexport interface BuildWorkordersOptions {\r\n checklist: BackendDomainItem[];\r\n summary: FailureSummary;\r\n logSummary?: LogCompletionSummary;\r\n logRateThreshold?: number;\r\n}\r\n\r\nexport function buildWorkorders(opts: BuildWorkordersOptions): WorkorderItem[] {\r\n const { checklist, logSummary, logRateThreshold = 90 } = opts;\r\n const result: WorkorderItem[] = [];\r\n let idx = 1;\r\n\r\n // Auto P0 workorder if log completion rate is below threshold\r\n if (logSummary && logSummary.totalCandidates > 0 && logSummary.matchRate < logRateThreshold) {\r\n const logItem: BackendDomainItem = {\r\n domain: 'Log Completion Standards',\r\n tests: logSummary.timedOutTop5.map(t => `${t.method} ${t.path} (×${t.occurrences})`),\r\n endpoints: logSummary.timedOutTop5.map(t => t.path),\r\n };\r\n result.push({\r\n index: idx++,\r\n domain: logItem.domain,\r\n priority: 'P0',\r\n tests: logItem.tests,\r\n endpoints: logItem.endpoints,\r\n objective: 'Add missing end-phase structured logs for timed-out APIs',\r\n acceptanceCriteria: [\r\n `Log completion match rate ≥ ${logRateThreshold}%`,\r\n 'TimedOut API count drops to 0 or only SSE/long-polling endpoints remain',\r\n ],\r\n });\r\n }\r\n\r\n // Standard workorders from checklist\r\n for (const item of checklist) {\r\n const priority = assignPriority(item, false);\r\n result.push({\r\n index: idx++,\r\n domain: item.domain,\r\n priority,\r\n tests: item.tests,\r\n endpoints: item.endpoints,\r\n objective: 'Fix 500 errors and return a valid business response',\r\n acceptanceCriteria: [\r\n 'HTTP status returns 2xx for affected endpoints',\r\n 'No [BACKEND_5XX] errors in corresponding page traversal',\r\n 'All covered tests pass',\r\n ],\r\n });\r\n }\r\n\r\n return result;\r\n}\r\n\r\n// ===== Markdown renderer =====\r\n\r\nexport function renderWorkordersMarkdown(\r\n workorders: WorkorderItem[],\r\n summary: FailureSummary,\r\n logSummary?: LogCompletionSummary,\r\n): string {\r\n const lines: string[] = [\r\n '# Backend Work Orders',\r\n '',\r\n ];\r\n\r\n if (logSummary) {\r\n lines.push(\r\n `- Log match rate: ${logSummary.matchRate.toFixed(2)}%`,\r\n `- Effective success rate: ${logSummary.effectiveRate.toFixed(2)}%`,\r\n );\r\n }\r\n lines.push(\r\n `- Total failed: ${summary.totalFailed}`,\r\n `- Backend 5xx: ${summary.backend5xx}`,\r\n `- Mixed 5xx: ${summary.mixed5xx}`,\r\n `- Slow API: ${summary.slowApi}`,\r\n `- Log fail: ${summary.logFail}`,\r\n `- Log timeout: ${summary.logTimeout}`,\r\n `- Frontend load: ${summary.frontendLoad}`,\r\n `- Other: ${summary.other}`,\r\n '',\r\n );\r\n\r\n if (workorders.length === 0) {\r\n lines.push('No backend work orders this run.');\r\n return lines.join('\\n') + '\\n';\r\n }\r\n\r\n for (const wo of workorders) {\r\n lines.push(\r\n `## Workorder ${wo.index} - ${wo.domain}`,\r\n '',\r\n `- Priority: ${wo.priority}`,\r\n `- Affected tests: ${wo.tests.length}`,\r\n '- Scope:',\r\n );\r\n for (const t of wo.tests) lines.push(` - ${t}`);\r\n if (wo.endpoints.length > 0) {\r\n lines.push('- Endpoints:');\r\n for (const e of wo.endpoints) lines.push(` - ${e}`);\r\n }\r\n lines.push(`- Objective: ${wo.objective}`);\r\n lines.push('- Acceptance criteria:');\r\n for (const c of wo.acceptanceCriteria) lines.push(` - ${c}`);\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n') + '\\n';\r\n}\r\n","/**\r\n * Token Usage Reporter — tracks and reports LLM token consumption.\r\n *\r\n * Aggregates usage entries by category and model, computes costs,\r\n * tracks budget utilization, and renders both structured data and Markdown.\r\n */\r\n\r\nimport type { TokenUsageEntry, TokenUsageSummary } from '../types.js';\r\n\r\n// ===== Token Tracker =====\r\n\r\nexport class TokenTracker {\r\n private entries: TokenUsageEntry[] = [];\r\n private budget: number | null = null;\r\n\r\n setBudget(maxTokens: number): void {\r\n this.budget = maxTokens;\r\n }\r\n\r\n record(entry: TokenUsageEntry): void {\r\n this.entries.push(entry);\r\n }\r\n\r\n reset(): void {\r\n this.entries = [];\r\n }\r\n\r\n getSummary(): TokenUsageSummary {\r\n const totalRequests = this.entries.length;\r\n let totalPromptTokens = 0;\r\n let totalCompletionTokens = 0;\r\n let totalEstimatedCost = 0;\r\n let totalLatency = 0;\r\n\r\n const byCategory: TokenUsageSummary['byCategory'] = {};\r\n const byModel: TokenUsageSummary['byModel'] = {};\r\n\r\n for (const e of this.entries) {\r\n totalPromptTokens += e.promptTokens;\r\n totalCompletionTokens += e.completionTokens;\r\n totalEstimatedCost += e.estimatedCost;\r\n totalLatency += e.latencyMs;\r\n\r\n // By category\r\n if (!byCategory[e.category]) {\r\n byCategory[e.category] = { requests: 0, promptTokens: 0, completionTokens: 0, totalTokens: 0, estimatedCost: 0 };\r\n }\r\n const cat = byCategory[e.category];\r\n cat.requests++;\r\n cat.promptTokens += e.promptTokens;\r\n cat.completionTokens += e.completionTokens;\r\n cat.totalTokens += e.promptTokens + e.completionTokens;\r\n cat.estimatedCost += e.estimatedCost;\r\n\r\n // By model\r\n if (!byModel[e.model]) {\r\n byModel[e.model] = { requests: 0, totalTokens: 0, estimatedCost: 0 };\r\n }\r\n const mod = byModel[e.model];\r\n mod.requests++;\r\n mod.totalTokens += e.promptTokens + e.completionTokens;\r\n mod.estimatedCost += e.estimatedCost;\r\n }\r\n\r\n const totalTokens = totalPromptTokens + totalCompletionTokens;\r\n const budgetUsedPercent = this.budget && this.budget > 0\r\n ? Math.round(totalTokens / this.budget * 10000) / 100\r\n : null;\r\n\r\n return {\r\n totalRequests,\r\n totalTokens,\r\n totalPromptTokens,\r\n totalCompletionTokens,\r\n totalEstimatedCost,\r\n avgLatencyMs: totalRequests > 0 ? Math.round(totalLatency / totalRequests) : 0,\r\n byCategory,\r\n byModel,\r\n budgetUsedPercent,\r\n budgetExceeded: budgetUsedPercent !== null && budgetUsedPercent > 100,\r\n };\r\n }\r\n}\r\n\r\n// ===== Markdown renderer =====\r\n\r\nexport function renderTokenReportMarkdown(summary: TokenUsageSummary): string {\r\n const lines: string[] = [\r\n '# AI Token Usage Report',\r\n '',\r\n `- Total requests: ${summary.totalRequests}`,\r\n `- Total tokens: ${summary.totalTokens.toLocaleString()}`,\r\n `- Prompt tokens: ${summary.totalPromptTokens.toLocaleString()}`,\r\n `- Completion tokens: ${summary.totalCompletionTokens.toLocaleString()}`,\r\n `- Estimated cost: ¥${summary.totalEstimatedCost.toFixed(4)}`,\r\n `- Average latency: ${summary.avgLatencyMs}ms`,\r\n ];\r\n\r\n if (summary.budgetUsedPercent !== null) {\r\n lines.push(`- Budget used: ${summary.budgetUsedPercent}%${summary.budgetExceeded ? ' **EXCEEDED**' : ''}`);\r\n }\r\n lines.push('');\r\n\r\n // By category\r\n const cats = Object.entries(summary.byCategory).sort((a, b) => b[1].totalTokens - a[1].totalTokens);\r\n if (cats.length > 0) {\r\n lines.push(\r\n '## By Category',\r\n '',\r\n '| Category | Requests | Prompt | Completion | Total | Cost |',\r\n '|----------|----------|--------|------------|-------|------|',\r\n );\r\n for (const [cat, d] of cats) {\r\n lines.push(`| ${cat} | ${d.requests} | ${d.promptTokens.toLocaleString()} | ${d.completionTokens.toLocaleString()} | ${d.totalTokens.toLocaleString()} | ¥${d.estimatedCost.toFixed(4)} |`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // By model\r\n const models = Object.entries(summary.byModel);\r\n if (models.length > 0) {\r\n lines.push(\r\n '## By Model',\r\n '',\r\n '| Model | Requests | Total Tokens | Cost |',\r\n '|-------|----------|-------------|------|',\r\n );\r\n for (const [model, d] of models) {\r\n lines.push(`| ${model} | ${d.requests} | ${d.totalTokens.toLocaleString()} | ¥${d.estimatedCost.toFixed(4)} |`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n') + '\\n';\r\n}\r\n","import type { PipelineRunResult } from '../types.js';\r\n\r\nexport interface DashboardData {\r\n generatedAt: string;\r\n durationMs: number;\r\n modules: string[];\r\n totals: {\r\n modules: number;\r\n tables: number;\r\n relations: number;\r\n chains: number;\r\n steps: number;\r\n files: number;\r\n errors: number;\r\n warnings: number;\r\n };\r\n moduleCards: Array<{\r\n module: string;\r\n tables: number;\r\n relations: number;\r\n chains: number;\r\n steps: number;\r\n }>;\r\n files: Array<{ filePath: string; module: string; chain: string }>;\r\n issues: Array<{ severity: string; module: string; field: string; message: string }>;\r\n}\r\n\r\nexport interface DashboardOutput {\r\n filename: string;\r\n content: string;\r\n}\r\n\r\nfunction escapeHtml(s: string): string {\r\n return s\r\n .replace(/&/g, '&')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n .replace(/\"/g, '"')\r\n .replace(/'/g, ''');\r\n}\r\n\r\nfunction number(v: unknown): number {\r\n return typeof v === 'number' && Number.isFinite(v) ? v : 0;\r\n}\r\n\r\nexport function buildDashboardDataFromPipeline(result: PipelineRunResult): DashboardData {\r\n const moduleCards = result.modules.map((mod) => {\r\n const er = result.erDiagrams.get(mod);\r\n const plan = result.chainPlans.get(mod);\r\n return {\r\n module: mod,\r\n tables: er?.tables.length ?? 0,\r\n relations: er?.relations.length ?? 0,\r\n chains: plan?.chains.length ?? 0,\r\n steps: plan?.totalSteps ?? 0,\r\n };\r\n });\r\n\r\n const totals = {\r\n modules: result.modules.length,\r\n tables: moduleCards.reduce((s, m) => s + m.tables, 0),\r\n relations: moduleCards.reduce((s, m) => s + m.relations, 0),\r\n chains: moduleCards.reduce((s, m) => s + m.chains, 0),\r\n steps: moduleCards.reduce((s, m) => s + m.steps, 0),\r\n files: result.generatedFiles.length,\r\n errors: result.validationErrors.filter((e) => e.severity === 'error').length,\r\n warnings: result.validationErrors.filter((e) => e.severity === 'warning').length,\r\n };\r\n\r\n return {\r\n generatedAt: new Date().toISOString(),\r\n durationMs: result.duration,\r\n modules: [...result.modules],\r\n totals,\r\n moduleCards,\r\n files: result.generatedFiles.map((f) => ({ filePath: f.filePath, module: f.module, chain: f.chain })),\r\n issues: result.validationErrors.map((e) => ({\r\n severity: e.severity,\r\n module: e.module,\r\n field: e.field,\r\n message: e.message,\r\n })),\r\n };\r\n}\r\n\r\nexport function buildDashboardDataFromReportJson(input: unknown): DashboardData {\r\n const src = (input ?? {}) as Record<string, unknown>;\r\n const modules = Array.isArray(src.modules) ? src.modules.map((m) => String(m)) : [];\r\n const er = (src.erDiagrams ?? {}) as Record<string, { tables?: unknown; relations?: unknown }>;\r\n const plans = (src.chainPlans ?? {}) as Record<string, { chains?: unknown; totalSteps?: unknown }>;\r\n const files = Array.isArray(src.generatedFiles)\r\n ? src.generatedFiles.map((f) => {\r\n const row = f as Record<string, unknown>;\r\n return {\r\n filePath: String(row.filePath ?? ''),\r\n module: String(row.module ?? ''),\r\n chain: String(row.chain ?? ''),\r\n };\r\n })\r\n : [];\r\n\r\n const rawIssues = Array.isArray(src.validationErrors) ? src.validationErrors : [];\r\n const issues = rawIssues.map((item) => {\r\n const row = item as Record<string, unknown>;\r\n return {\r\n severity: String(row.severity ?? 'warning'),\r\n module: String(row.module ?? 'unknown'),\r\n field: String(row.field ?? 'unknown'),\r\n message: String(row.message ?? ''),\r\n };\r\n });\r\n\r\n const moduleCards = modules.map((mod) => ({\r\n module: mod,\r\n tables: number(er[mod]?.tables),\r\n relations: number(er[mod]?.relations),\r\n chains: number(plans[mod]?.chains),\r\n steps: number(plans[mod]?.totalSteps),\r\n }));\r\n\r\n return {\r\n generatedAt: new Date().toISOString(),\r\n durationMs: number(src.duration),\r\n modules,\r\n totals: {\r\n modules: modules.length,\r\n tables: moduleCards.reduce((s, m) => s + m.tables, 0),\r\n relations: moduleCards.reduce((s, m) => s + m.relations, 0),\r\n chains: moduleCards.reduce((s, m) => s + m.chains, 0),\r\n steps: moduleCards.reduce((s, m) => s + m.steps, 0),\r\n files: files.length,\r\n errors: issues.filter((i) => i.severity === 'error').length,\r\n warnings: issues.filter((i) => i.severity === 'warning').length,\r\n },\r\n moduleCards,\r\n files,\r\n issues,\r\n };\r\n}\r\n\r\nexport function generateVisualDashboardHtml(data: DashboardData): string {\r\n const moduleCardHtml = data.moduleCards\r\n .map(\r\n (m) => `<article class=\"module-card reveal\">\r\n <h3>${escapeHtml(m.module)}</h3>\r\n <div class=\"meta\">${m.tables} tables · ${m.relations} relations</div>\r\n <div class=\"bars\">\r\n <div class=\"bar\"><span>Chains</span><strong>${m.chains}</strong></div>\r\n <div class=\"bar\"><span>Steps</span><strong>${m.steps}</strong></div>\r\n </div>\r\n</article>`,\r\n )\r\n .join('\\n');\r\n\r\n const fileRows = data.files\r\n .slice(0, 20)\r\n .map(\r\n (f) => `<tr><td><code>${escapeHtml(f.filePath)}</code></td><td>${escapeHtml(f.module)}</td><td>${escapeHtml(f.chain)}</td></tr>`,\r\n )\r\n .join('\\n');\r\n\r\n const issueRows = data.issues\r\n .map(\r\n (i) => `<tr class=\"${escapeHtml(i.severity)}\"><td>${escapeHtml(i.severity)}</td><td>${escapeHtml(i.module)}</td><td>${escapeHtml(i.field)}</td><td>${escapeHtml(i.message)}</td></tr>`,\r\n )\r\n .join('\\n');\r\n\r\n return `<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n <meta charset=\"utf-8\" />\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\r\n <title>OpenCroc Visual Dashboard</title>\r\n <style>\r\n @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=IBM+Plex+Mono:wght@400;500&display=swap');\r\n :root {\r\n --bg: #f4efe6;\r\n --ink: #18222c;\r\n --card: #fff8ef;\r\n --line: #d8c7b4;\r\n --accent: #0b7a75;\r\n --accent-2: #f26a2e;\r\n --ok: #2f7d32;\r\n --warn: #b7791f;\r\n --err: #c0392b;\r\n }\r\n * { box-sizing: border-box; }\r\n body {\r\n margin: 0;\r\n font-family: 'Space Grotesk', 'Segoe UI', sans-serif;\r\n color: var(--ink);\r\n background:\r\n radial-gradient(circle at 15% 10%, #f9e2c5 0%, transparent 32%),\r\n radial-gradient(circle at 85% 0%, #d3efe4 0%, transparent 28%),\r\n var(--bg);\r\n min-height: 100vh;\r\n }\r\n .wrap { max-width: 1160px; margin: 0 auto; padding: 24px 18px 40px; }\r\n .hero {\r\n border: 2px solid var(--line);\r\n border-radius: 18px;\r\n background: linear-gradient(130deg, #fff8ef 0%, #f8f2ea 45%, #f3ece3 100%);\r\n padding: 22px;\r\n box-shadow: 0 12px 24px rgba(24, 34, 44, 0.08);\r\n position: relative;\r\n overflow: hidden;\r\n }\r\n .hero::after {\r\n content: '';\r\n position: absolute;\r\n right: -42px;\r\n top: -38px;\r\n width: 160px;\r\n height: 160px;\r\n border-radius: 50%;\r\n background: conic-gradient(from 50deg, #f26a2e 0deg, #f7a35a 90deg, #0b7a75 220deg, #f26a2e 360deg);\r\n opacity: 0.14;\r\n }\r\n h1 { margin: 0; font-size: clamp(1.6rem, 3vw, 2.5rem); letter-spacing: -0.03em; }\r\n .subtitle { margin-top: 8px; font-size: 0.95rem; opacity: 0.82; }\r\n .kpi-grid {\r\n margin-top: 16px;\r\n display: grid;\r\n grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));\r\n gap: 10px;\r\n }\r\n .kpi {\r\n border: 1px solid var(--line);\r\n border-radius: 12px;\r\n padding: 10px 12px;\r\n background: #fffdf9;\r\n }\r\n .kpi .label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; opacity: 0.7; }\r\n .kpi .value { font-size: 1.45rem; font-weight: 700; margin-top: 4px; }\r\n .kpi.error .value { color: var(--err); }\r\n .kpi.warning .value { color: var(--warn); }\r\n .kpi.files .value { color: var(--accent); }\r\n\r\n .section-title {\r\n margin: 24px 0 10px;\r\n font-size: 1rem;\r\n text-transform: uppercase;\r\n letter-spacing: 0.08em;\r\n color: #344250;\r\n }\r\n\r\n .module-grid {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\r\n gap: 12px;\r\n }\r\n .module-card {\r\n border: 1px solid var(--line);\r\n border-radius: 14px;\r\n padding: 14px;\r\n background: var(--card);\r\n box-shadow: 0 8px 16px rgba(24, 34, 44, 0.06);\r\n }\r\n .module-card h3 { margin: 0 0 6px; font-size: 1.05rem; }\r\n .module-card .meta { font-size: 0.85rem; opacity: 0.78; }\r\n .bars { margin-top: 10px; display: grid; gap: 8px; }\r\n .bar { display: flex; justify-content: space-between; border-top: 1px dashed var(--line); padding-top: 7px; }\r\n\r\n table {\r\n width: 100%;\r\n border-collapse: collapse;\r\n border: 1px solid var(--line);\r\n border-radius: 12px;\r\n overflow: hidden;\r\n background: #fffdf9;\r\n font-family: 'IBM Plex Mono', 'Consolas', monospace;\r\n font-size: 0.82rem;\r\n }\r\n thead { background: #efe5d8; }\r\n th, td { text-align: left; padding: 8px 10px; border-bottom: 1px solid #eadfce; }\r\n tbody tr:last-child td { border-bottom: none; }\r\n tr.error td:first-child { color: var(--err); font-weight: 700; }\r\n tr.warning td:first-child { color: var(--warn); font-weight: 700; }\r\n\r\n code {\r\n font-family: 'IBM Plex Mono', 'Consolas', monospace;\r\n background: #f5ece0;\r\n border: 1px solid #eadfce;\r\n border-radius: 6px;\r\n padding: 1px 5px;\r\n }\r\n\r\n .reveal { opacity: 0; transform: translateY(12px); animation: rise .55s ease forwards; }\r\n .module-card.reveal:nth-child(2) { animation-delay: .06s; }\r\n .module-card.reveal:nth-child(3) { animation-delay: .12s; }\r\n .module-card.reveal:nth-child(4) { animation-delay: .18s; }\r\n .module-card.reveal:nth-child(5) { animation-delay: .24s; }\r\n @keyframes rise {\r\n to { opacity: 1; transform: translateY(0); }\r\n }\r\n\r\n @media (max-width: 700px) {\r\n .wrap { padding: 14px 12px 28px; }\r\n .hero { padding: 16px; }\r\n table { font-size: 0.76rem; }\r\n th, td { padding: 7px 8px; }\r\n }\r\n </style>\r\n</head>\r\n<body>\r\n <main class=\"wrap\">\r\n <section class=\"hero reveal\">\r\n <h1>OpenCroc Visual Dashboard</h1>\r\n <p class=\"subtitle\">Pipeline finished in ${data.durationMs}ms · Generated ${escapeHtml(data.generatedAt)}</p>\r\n <div class=\"kpi-grid\">\r\n <div class=\"kpi\"><div class=\"label\">Modules</div><div class=\"value\">${data.totals.modules}</div></div>\r\n <div class=\"kpi\"><div class=\"label\">Tables</div><div class=\"value\">${data.totals.tables}</div></div>\r\n <div class=\"kpi\"><div class=\"label\">Relations</div><div class=\"value\">${data.totals.relations}</div></div>\r\n <div class=\"kpi\"><div class=\"label\">Chains</div><div class=\"value\">${data.totals.chains}</div></div>\r\n <div class=\"kpi\"><div class=\"label\">Steps</div><div class=\"value\">${data.totals.steps}</div></div>\r\n <div class=\"kpi files\"><div class=\"label\">Files</div><div class=\"value\">${data.totals.files}</div></div>\r\n <div class=\"kpi error\"><div class=\"label\">Errors</div><div class=\"value\">${data.totals.errors}</div></div>\r\n <div class=\"kpi warning\"><div class=\"label\">Warnings</div><div class=\"value\">${data.totals.warnings}</div></div>\r\n </div>\r\n </section>\r\n\r\n <h2 class=\"section-title\">Module Health</h2>\r\n <section class=\"module-grid\">\r\n ${moduleCardHtml || '<article class=\"module-card\">No module data</article>'}\r\n </section>\r\n\r\n <h2 class=\"section-title\">Generated Files (Top 20)</h2>\r\n <section>\r\n <table>\r\n <thead><tr><th>File</th><th>Module</th><th>Chain</th></tr></thead>\r\n <tbody>${fileRows || '<tr><td colspan=\"3\">No files generated</td></tr>'}</tbody>\r\n </table>\r\n </section>\r\n\r\n <h2 class=\"section-title\">Validation Issues</h2>\r\n <section>\r\n <table>\r\n <thead><tr><th>Severity</th><th>Module</th><th>Field</th><th>Message</th></tr></thead>\r\n <tbody>${issueRows || '<tr><td colspan=\"4\">No validation issues</td></tr>'}</tbody>\r\n </table>\r\n </section>\r\n </main>\r\n</body>\r\n</html>`;\r\n}\r\n\r\nexport function generateVisualDashboard(result: PipelineRunResult): DashboardOutput {\r\n const data = buildDashboardDataFromPipeline(result);\r\n return {\r\n filename: 'opencroc-dashboard.html',\r\n content: generateVisualDashboardHtml(data),\r\n };\r\n}\r\n","/**\r\n * VSCode extension scaffold for OpenCroc.\r\n *\r\n * This module provides the extension activation logic, command definitions,\r\n * and tree view data provider for the OpenCroc sidebar panel.\r\n *\r\n * To build:\r\n * 1. Copy `vscode-extension/` from the opencroc repo\r\n * 2. Run `npm install && npm run compile`\r\n * 3. Press F5 in VS Code to launch the Extension Development Host\r\n */\r\n\r\n// ===== Extension Manifest Types (subset of vscode.d.ts for portability) =====\r\n\r\nexport interface ExtensionCommand {\r\n command: string;\r\n title: string;\r\n category: string;\r\n}\r\n\r\nexport interface TreeItem {\r\n label: string;\r\n description?: string;\r\n tooltip?: string;\r\n iconId?: string;\r\n children?: TreeItem[];\r\n command?: string;\r\n}\r\n\r\n// ===== Commands =====\r\n\r\nexport const EXTENSION_ID = 'opencroc.opencroc';\r\n\r\nexport const COMMANDS: ExtensionCommand[] = [\r\n { command: 'opencroc.init', title: 'Initialize Project', category: 'OpenCroc' },\r\n { command: 'opencroc.generate', title: 'Generate Tests', category: 'OpenCroc' },\r\n { command: 'opencroc.generateModule', title: 'Generate Tests for Module...', category: 'OpenCroc' },\r\n { command: 'opencroc.test', title: 'Run Tests', category: 'OpenCroc' },\r\n { command: 'opencroc.testModule', title: 'Run Tests for Module...', category: 'OpenCroc' },\r\n { command: 'opencroc.validate', title: 'Validate Configuration', category: 'OpenCroc' },\r\n { command: 'opencroc.heal', title: 'Self-Heal Failures', category: 'OpenCroc' },\r\n { command: 'opencroc.openReport', title: 'Open Report', category: 'OpenCroc' },\r\n { command: 'opencroc.ci', title: 'Generate CI Template', category: 'OpenCroc' },\r\n];\r\n\r\n// ===== Tree View Data =====\r\n\r\nexport function buildModuleTree(modules: string[]): TreeItem[] {\r\n return modules.map((mod) => ({\r\n label: mod,\r\n description: 'module',\r\n iconId: 'symbol-module',\r\n children: [\r\n { label: 'Generate Tests', command: 'opencroc.generateModule', iconId: 'play' },\r\n { label: 'Run Tests', command: 'opencroc.testModule', iconId: 'testing-run-icon' },\r\n { label: 'View ER Diagram', command: 'opencroc.openReport', iconId: 'graph' },\r\n ],\r\n }));\r\n}\r\n\r\nexport function buildStatusTree(stats: {\r\n modules: number;\r\n tables: number;\r\n relations: number;\r\n generatedFiles: number;\r\n errors: number;\r\n}): TreeItem[] {\r\n return [\r\n { label: `Modules: ${stats.modules}`, iconId: 'symbol-module' },\r\n { label: `Tables: ${stats.tables}`, iconId: 'database' },\r\n { label: `Relations: ${stats.relations}`, iconId: 'git-merge' },\r\n { label: `Generated: ${stats.generatedFiles} files`, iconId: 'file-code' },\r\n {\r\n label: stats.errors > 0 ? `Errors: ${stats.errors}` : 'No errors',\r\n iconId: stats.errors > 0 ? 'error' : 'pass',\r\n },\r\n ];\r\n}\r\n\r\n// ===== Package.json Generator =====\r\n\r\nexport function generateExtensionManifest(): Record<string, unknown> {\r\n return {\r\n name: 'opencroc',\r\n displayName: 'OpenCroc',\r\n description: 'AI-native E2E testing — generate, run, and self-heal tests from VS Code',\r\n version: '0.1.0',\r\n publisher: 'opencroc',\r\n license: 'MIT',\r\n repository: { type: 'git', url: 'https://github.com/opencroc/opencroc' },\r\n engines: { vscode: '^1.85.0' },\r\n categories: ['Testing'],\r\n keywords: ['e2e', 'testing', 'playwright', 'ai', 'self-healing'],\r\n activationEvents: ['workspaceContains:opencroc.config.ts', 'workspaceContains:opencroc.config.js'],\r\n main: './out/extension.js',\r\n contributes: {\r\n commands: COMMANDS.map((c) => ({\r\n command: c.command,\r\n title: c.title,\r\n category: c.category,\r\n })),\r\n viewsContainers: {\r\n activitybar: [\r\n {\r\n id: 'opencroc',\r\n title: 'OpenCroc',\r\n icon: 'resources/opencroc.svg',\r\n },\r\n ],\r\n },\r\n views: {\r\n opencroc: [\r\n { id: 'opencroc.status', name: 'Status' },\r\n { id: 'opencroc.modules', name: 'Modules' },\r\n ],\r\n },\r\n configuration: {\r\n title: 'OpenCroc',\r\n properties: {\r\n 'opencroc.autoGenerate': {\r\n type: 'boolean',\r\n default: false,\r\n description: 'Automatically regenerate tests on file save',\r\n },\r\n 'opencroc.reportFormat': {\r\n type: 'string',\r\n default: 'html',\r\n enum: ['html', 'json', 'markdown'],\r\n description: 'Default report format',\r\n },\r\n },\r\n },\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Generate the extension's entry point (activation function).\r\n * Returns TypeScript source code for `src/extension.ts`.\r\n */\r\nexport function generateExtensionEntrypoint(): string {\r\n return `import * as vscode from 'vscode';\r\nimport { exec } from 'child_process';\r\nimport { promisify } from 'util';\r\n\r\nconst run = promisify(exec);\r\n\r\nexport function activate(context: vscode.ExtensionContext) {\r\n const outputChannel = vscode.window.createOutputChannel('OpenCroc');\r\n\r\n async function runCommand(cmd: string) {\r\n const workspaceFolder = vscode.workspace.workspaceFolders?.[0];\r\n if (!workspaceFolder) {\r\n vscode.window.showErrorMessage('No workspace folder open');\r\n return;\r\n }\r\n outputChannel.show();\r\n outputChannel.appendLine(\\`> \\${cmd}\\`);\r\n try {\r\n const { stdout, stderr } = await run(cmd, { cwd: workspaceFolder.uri.fsPath });\r\n if (stdout) outputChannel.appendLine(stdout);\r\n if (stderr) outputChannel.appendLine(stderr);\r\n vscode.window.showInformationMessage(\\`OpenCroc: \\${cmd} completed\\`);\r\n } catch (err: unknown) {\r\n const message = err instanceof Error ? err.message : String(err);\r\n outputChannel.appendLine(\\`Error: \\${message}\\`);\r\n vscode.window.showErrorMessage(\\`OpenCroc: \\${message}\\`);\r\n }\r\n }\r\n\r\n context.subscriptions.push(\r\n vscode.commands.registerCommand('opencroc.init', () => runCommand('npx opencroc init --yes')),\r\n vscode.commands.registerCommand('opencroc.generate', () => runCommand('npx opencroc generate --all')),\r\n vscode.commands.registerCommand('opencroc.test', () => runCommand('npx opencroc test')),\r\n vscode.commands.registerCommand('opencroc.validate', () => runCommand('npx opencroc validate')),\r\n vscode.commands.registerCommand('opencroc.heal', () => runCommand('npx opencroc heal')),\r\n vscode.commands.registerCommand('opencroc.ci', async () => {\r\n const platform = await vscode.window.showQuickPick(['github', 'gitlab'], {\r\n placeHolder: 'Select CI platform',\r\n });\r\n if (platform) {\r\n await runCommand(\\`npx opencroc ci --platform=\\${platform}\\`);\r\n }\r\n }),\r\n vscode.commands.registerCommand('opencroc.generateModule', async () => {\r\n const mod = await vscode.window.showInputBox({ prompt: 'Module name' });\r\n if (mod) await runCommand(\\`npx opencroc generate --module=\\${mod}\\`);\r\n }),\r\n vscode.commands.registerCommand('opencroc.testModule', async () => {\r\n const mod = await vscode.window.showInputBox({ prompt: 'Module name' });\r\n if (mod) await runCommand(\\`npx opencroc test --module=\\${mod}\\`);\r\n }),\r\n );\r\n\r\n outputChannel.appendLine('OpenCroc extension activated');\r\n}\r\n\r\nexport function deactivate() {}\r\n`;\r\n}\r\n","export { generatePlaywrightConfig } from './playwright-config-generator.js';\r\nexport { generateGlobalSetup } from './global-setup-generator.js';\r\nexport { generateGlobalTeardown } from './global-teardown-generator.js';\r\nexport { generateAuthSetup } from './auth-setup-generator.js';\r\nexport { resilientFetch, waitForBackend } from './resilient-fetch.js';\r\nexport { NetworkMonitor } from './network-monitor.js';\r\nexport {\r\n extractParamNames,\r\n extractParamsFromHref,\r\n buildPath,\r\n extractIdFromText,\r\n resolveFromSeedData,\r\n} from './dynamic-route-resolver.js';\r\nexport {\r\n selectCandidates,\r\n selectCandidatesFromLogs,\r\n mergeCandidates,\r\n waitForLogCompletion,\r\n} from './log-completion-waiter.js';\r\nexport { createRulesEngine } from './critical-api-rules.js';\r\n","import type { OpenCrocConfig } from '../types.js';\r\n\r\n/**\r\n * Generate playwright.config.ts content based on OpenCroc config.\r\n */\r\nexport function generatePlaywrightConfig(config: OpenCrocConfig): string {\r\n const pw = config.playwright ?? {};\r\n const rt = config.runtime ?? {};\r\n const outDir = config.outDir || './opencroc-output';\r\n\r\n const baseURL = pw.baseURL ? `'${pw.baseURL}'` : \"process.env.BASE_URL || 'http://localhost:3000'\";\r\n const timeout = pw.timeout ?? 30_000;\r\n const workers = pw.workers ?? (null as number | null); // null → use expression\r\n const retries = pw.retries ?? (null as number | null);\r\n const actionTimeout = pw.actionTimeout ?? 10_000;\r\n const navigationTimeout = pw.navigationTimeout ?? timeout;\r\n const storageState = rt.auth?.storageStatePath || 'playwright/.auth/user.json';\r\n\r\n const hasAuth = !!(rt.auth?.loginUrl);\r\n\r\n const lines: string[] = [];\r\n lines.push(`import { defineConfig, devices } from '@playwright/test';`);\r\n lines.push('');\r\n lines.push('export default defineConfig({');\r\n lines.push(` testDir: '${outDir}',`);\r\n lines.push(` testMatch: ['**/*.spec.ts', '**/*.test.ts'],`);\r\n lines.push(` fullyParallel: false,`);\r\n lines.push(` forbidOnly: !!process.env.CI,`);\r\n lines.push(` retries: ${retries !== null ? retries : 'process.env.CI ? 1 : 0'},`);\r\n lines.push(` workers: ${workers !== null ? workers : 'process.env.CI ? 4 : 2'},`);\r\n lines.push(` timeout: ${timeout},`);\r\n lines.push(` globalSetup: './global-setup.ts',`);\r\n lines.push(` globalTeardown: './global-teardown.ts',`);\r\n lines.push(` reporter: [['list'], ['html', { open: 'never' }]],`);\r\n lines.push(` use: {`);\r\n lines.push(` baseURL: ${baseURL},`);\r\n lines.push(` trace: 'retain-on-failure',`);\r\n lines.push(` screenshot: 'only-on-failure',`);\r\n lines.push(` video: 'retain-on-failure',`);\r\n lines.push(` actionTimeout: ${actionTimeout},`);\r\n lines.push(` navigationTimeout: ${navigationTimeout},`);\r\n lines.push(` },`);\r\n\r\n // Projects\r\n lines.push(` projects: [`);\r\n\r\n if (hasAuth) {\r\n lines.push(` {`);\r\n lines.push(` name: 'setup',`);\r\n lines.push(` testMatch: '**/auth.setup.ts',`);\r\n lines.push(` use: { ...devices['Desktop Chrome'] },`);\r\n lines.push(` },`);\r\n lines.push(` {`);\r\n lines.push(` name: 'chromium',`);\r\n lines.push(` testIgnore: ['**/*.setup.ts'],`);\r\n lines.push(` dependencies: ['setup'],`);\r\n lines.push(` use: {`);\r\n lines.push(` ...devices['Desktop Chrome'],`);\r\n lines.push(` storageState: '${storageState}',`);\r\n lines.push(` },`);\r\n lines.push(` },`);\r\n lines.push(` {`);\r\n lines.push(` name: 'chromium-no-auth',`);\r\n lines.push(` testMatch: '**/login-flow.test.ts',`);\r\n lines.push(` testIgnore: ['**/*.setup.ts'],`);\r\n lines.push(` use: { ...devices['Desktop Chrome'] },`);\r\n lines.push(` },`);\r\n } else {\r\n lines.push(` {`);\r\n lines.push(` name: 'chromium',`);\r\n lines.push(` use: { ...devices['Desktop Chrome'] },`);\r\n lines.push(` },`);\r\n }\r\n\r\n // Extra projects from config\r\n if (rt.extraProjects) {\r\n for (const proj of rt.extraProjects) {\r\n lines.push(` {`);\r\n lines.push(` name: '${proj.name}',`);\r\n lines.push(` testMatch: '${proj.testMatch}',`);\r\n if (proj.dependencies?.length) {\r\n lines.push(` dependencies: [${proj.dependencies.map((d) => `'${d}'`).join(', ')}],`);\r\n }\r\n if (proj.useAuth !== false && hasAuth) {\r\n lines.push(` use: {`);\r\n lines.push(` ...devices['Desktop Chrome'],`);\r\n lines.push(` storageState: '${storageState}',`);\r\n lines.push(` },`);\r\n } else {\r\n lines.push(` use: { ...devices['Desktop Chrome'] },`);\r\n }\r\n lines.push(` },`);\r\n }\r\n }\r\n\r\n lines.push(` ],`);\r\n lines.push('});');\r\n lines.push('');\r\n\r\n return lines.join('\\n');\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\n\r\n/**\r\n * Generate global-setup.ts content for Playwright.\r\n * Handles backend readiness probe, seed endpoint call, and log cleanup.\r\n */\r\nexport function generateGlobalSetup(config: OpenCrocConfig): string {\r\n const pw = config.playwright ?? {};\r\n const rt = config.runtime ?? {};\r\n const baseURL = pw.baseURL || '';\r\n\r\n const hasSeedEndpoint = !!rt.db?.seedEndpoint;\r\n const hasLogEndpoint = !!rt.logEndpoint;\r\n const hasSeedFile = !!rt.db?.seedFile;\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`/**`);\r\n lines.push(` * Global setup — generated by OpenCroc.`);\r\n lines.push(` * Runs once before all test projects.`);\r\n lines.push(` */`);\r\n lines.push('');\r\n lines.push(`const BASE_URL = process.env.BASE_URL || '${baseURL || 'http://localhost:3000'}';`);\r\n lines.push('');\r\n\r\n // fetchWithRetry helper\r\n lines.push(`async function fetchWithRetry(`);\r\n lines.push(` url: string,`);\r\n lines.push(` options: RequestInit,`);\r\n lines.push(` retries = 3,`);\r\n lines.push(`): Promise<Response | null> {`);\r\n lines.push(` for (let i = 0; i < retries; i++) {`);\r\n lines.push(` try {`);\r\n lines.push(` const resp = await fetch(url, { ...options, signal: AbortSignal.timeout(10_000) });`);\r\n lines.push(` if (resp.ok) return resp;`);\r\n lines.push(` console.warn(\\`[global-setup] \\${options.method} \\${url} → \\${resp.status} (\\${i + 1}/\\${retries})\\`);`);\r\n lines.push(` } catch (err: unknown) {`);\r\n lines.push(` const msg = err instanceof Error ? err.message : String(err);`);\r\n lines.push(` console.warn(\\`[global-setup] \\${options.method} \\${url} error (\\${i + 1}/\\${retries}): \\${msg}\\`);`);\r\n lines.push(` }`);\r\n lines.push(` if (i < retries - 1) await new Promise((r) => setTimeout(r, 1000 * Math.pow(2, i)));`);\r\n lines.push(` }`);\r\n lines.push(` return null;`);\r\n lines.push(`}`);\r\n lines.push('');\r\n\r\n // waitForBackend helper\r\n lines.push(`async function waitForBackend(origin: string, timeoutMs = 30_000): Promise<void> {`);\r\n lines.push(` const start = Date.now();`);\r\n lines.push(` while (Date.now() - start < timeoutMs) {`);\r\n lines.push(` try {`);\r\n lines.push(` const res = await fetch(\\`\\${origin}/health\\`, { signal: AbortSignal.timeout(3_000) });`);\r\n lines.push(` if (res.ok) return;`);\r\n lines.push(` } catch {`);\r\n lines.push(` // not ready yet`);\r\n lines.push(` }`);\r\n lines.push(` await new Promise((r) => setTimeout(r, 1_000));`);\r\n lines.push(` }`);\r\n lines.push(` throw new Error(\\`Backend not ready after \\${timeoutMs}ms\\`);`);\r\n lines.push(`}`);\r\n lines.push('');\r\n\r\n // Main function\r\n lines.push(`export default async function globalSetup(): Promise<void> {`);\r\n lines.push(` console.log('[global-setup] Starting...');`);\r\n lines.push('');\r\n lines.push(` // Backend readiness probe`);\r\n lines.push(` try {`);\r\n lines.push(` await waitForBackend(BASE_URL, 30_000);`);\r\n lines.push(` console.log('[global-setup] Backend is ready.');`);\r\n lines.push(` } catch (e: unknown) {`);\r\n lines.push(` console.warn(\\`[global-setup] \\${e instanceof Error ? e.message : String(e)}\\`);`);\r\n lines.push(` }`);\r\n lines.push('');\r\n\r\n if (hasSeedEndpoint) {\r\n lines.push(` // Seed data via backend endpoint`);\r\n lines.push(` try {`);\r\n lines.push(` await fetchWithRetry(`);\r\n lines.push(` \\`\\${BASE_URL}${rt.db!.seedEndpoint}\\`,`);\r\n lines.push(` { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' },`);\r\n lines.push(` );`);\r\n lines.push(` console.log('[global-setup] Seed endpoint called.');`);\r\n lines.push(` } catch {`);\r\n lines.push(` console.warn('[global-setup] Seed endpoint failed.');`);\r\n lines.push(` }`);\r\n lines.push('');\r\n }\r\n\r\n if (hasLogEndpoint) {\r\n lines.push(` // Clear test logs`);\r\n lines.push(` try {`);\r\n lines.push(` await fetchWithRetry(\\`\\${BASE_URL}${rt.logEndpoint}\\`, { method: 'DELETE' });`);\r\n lines.push(` console.log('[global-setup] Test logs cleared.');`);\r\n lines.push(` } catch {`);\r\n lines.push(` console.warn('[global-setup] Failed to clear test logs.');`);\r\n lines.push(` }`);\r\n lines.push('');\r\n }\r\n\r\n if (hasSeedFile) {\r\n lines.push(` // SQL seed file execution (placeholder — wire to your DB helper)`);\r\n lines.push(` // import { executeSeedSQL } from './utils/db-helper';`);\r\n lines.push(` // await executeSeedSQL('${rt.db!.seedFile}');`);\r\n lines.push('');\r\n }\r\n\r\n lines.push(` console.log('[global-setup] Done.');`);\r\n lines.push(`}`);\r\n lines.push('');\r\n\r\n return lines.join('\\n');\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\n\r\n/**\r\n * Generate global-teardown.ts content for Playwright.\r\n * Handles cleanup endpoint call and optional SQL cleanup.\r\n */\r\nexport function generateGlobalTeardown(config: OpenCrocConfig): string {\r\n const pw = config.playwright ?? {};\r\n const rt = config.runtime ?? {};\r\n const baseURL = pw.baseURL || '';\r\n\r\n const hasCleanupEndpoint = !!rt.db?.cleanupEndpoint;\r\n const hasCleanupFile = !!rt.db?.cleanupFile;\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`/**`);\r\n lines.push(` * Global teardown — generated by OpenCroc.`);\r\n lines.push(` * Runs once after all test projects complete.`);\r\n lines.push(` */`);\r\n lines.push('');\r\n lines.push(`const BASE_URL = process.env.BASE_URL || '${baseURL || 'http://localhost:3000'}';`);\r\n lines.push('');\r\n\r\n lines.push(`export default async function globalTeardown(): Promise<void> {`);\r\n lines.push(` console.log('[global-teardown] Starting...');`);\r\n lines.push('');\r\n\r\n if (hasCleanupEndpoint) {\r\n lines.push(` // Cleanup via backend endpoint`);\r\n lines.push(` try {`);\r\n lines.push(` await fetch(\\`\\${BASE_URL}${rt.db!.cleanupEndpoint}\\`, { method: 'POST' });`);\r\n lines.push(` console.log('[global-teardown] Cleanup endpoint called.');`);\r\n lines.push(` } catch {`);\r\n lines.push(` console.warn('[global-teardown] Cleanup endpoint failed.');`);\r\n lines.push(` }`);\r\n lines.push('');\r\n }\r\n\r\n if (hasCleanupFile) {\r\n lines.push(` // SQL cleanup file execution (placeholder — wire to your DB helper)`);\r\n lines.push(` // import { executeSeedSQL } from './utils/db-helper';`);\r\n lines.push(` // await executeSeedSQL('${rt.db!.cleanupFile}');`);\r\n lines.push('');\r\n }\r\n\r\n lines.push(` console.log('[global-teardown] Done.');`);\r\n lines.push(`}`);\r\n lines.push('');\r\n\r\n return lines.join('\\n');\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\n\r\n/**\r\n * Generate auth.setup.ts content for Playwright.\r\n * Creates an authentication setup project that stores state for reuse.\r\n */\r\nexport function generateAuthSetup(config: OpenCrocConfig): string {\r\n const rt = config.runtime ?? {};\r\n const pw = config.playwright ?? {};\r\n const auth = rt.auth ?? {};\r\n const baseURL = pw.baseURL || '';\r\n const storageStatePath = auth.storageStatePath || 'playwright/.auth/user.json';\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`import { test as setup, expect } from '@playwright/test';`);\r\n lines.push(`import * as fs from 'fs/promises';`);\r\n lines.push(`import * as path from 'path';`);\r\n lines.push('');\r\n\r\n lines.push(`const authFile = '${storageStatePath}';`);\r\n lines.push('');\r\n\r\n if (auth.loginUrl) {\r\n // API-based authentication\r\n lines.push(`setup('authenticate', async ({ request }) => {`);\r\n lines.push(` const loginUrl = process.env.AUTH_LOGIN_URL || '${auth.loginUrl}';`);\r\n lines.push(` const username = process.env.AUTH_USERNAME || '${auth.username || 'admin'}';`);\r\n lines.push(` const password = process.env.AUTH_PASSWORD || '${auth.password || ''}';`);\r\n lines.push('');\r\n lines.push(` // API login`);\r\n lines.push(` const response = await request.post(loginUrl, {`);\r\n lines.push(` data: { username, password },`);\r\n lines.push(` });`);\r\n lines.push(` expect(response.ok()).toBeTruthy();`);\r\n lines.push('');\r\n lines.push(` const body = await response.json();`);\r\n lines.push(` const token = body.data?.token || body.token || '';`);\r\n lines.push(` console.log('[auth.setup] Login successful, token obtained:', !!token);`);\r\n lines.push('');\r\n lines.push(` // Save storage state with auth cookie/localStorage`);\r\n lines.push(` await fs.mkdir(path.dirname(authFile), { recursive: true });`);\r\n lines.push('');\r\n lines.push(` // Build storage state JSON`);\r\n lines.push(` const baseURL = process.env.BASE_URL || '${baseURL || 'http://localhost:3000'}';`);\r\n lines.push(` const origin = new URL(baseURL).origin;`);\r\n lines.push(` const storageState = {`);\r\n lines.push(` cookies: [],`);\r\n lines.push(` origins: [`);\r\n lines.push(` {`);\r\n lines.push(` origin,`);\r\n lines.push(` localStorage: [`);\r\n lines.push(` { name: 'token', value: token },`);\r\n lines.push(` ],`);\r\n lines.push(` },`);\r\n lines.push(` ],`);\r\n lines.push(` };`);\r\n lines.push('');\r\n lines.push(` await fs.writeFile(authFile, JSON.stringify(storageState, null, 2));`);\r\n lines.push(` console.log(\\`[auth.setup] Storage state saved → \\${authFile}\\`);`);\r\n lines.push(`});`);\r\n } else {\r\n // Browser-based authentication (placeholder)\r\n lines.push(`setup('authenticate', async ({ browser }) => {`);\r\n lines.push(` const context = await browser.newContext();`);\r\n lines.push(` const page = await context.newPage();`);\r\n lines.push('');\r\n lines.push(` // TODO: Implement your login flow here`);\r\n lines.push(` // await page.goto('/login');`);\r\n lines.push(` // await page.fill('[name=username]', 'admin');`);\r\n lines.push(` // await page.fill('[name=password]', 'password');`);\r\n lines.push(` // await page.click('button[type=submit]');`);\r\n lines.push(` // await page.waitForURL('/dashboard');`);\r\n lines.push('');\r\n lines.push(` await fs.mkdir(path.dirname(authFile), { recursive: true });`);\r\n lines.push(` await context.storageState({ path: authFile });`);\r\n lines.push(` console.log(\\`[auth.setup] Storage state saved → \\${authFile}\\`);`);\r\n lines.push('');\r\n lines.push(` await context.close();`);\r\n lines.push(`});`);\r\n }\r\n\r\n lines.push('');\r\n\r\n return lines.join('\\n');\r\n}\r\n","/**\r\n * Resilient HTTP fetch with exponential backoff retry.\r\n * Framework-level utility — no Playwright dependency required.\r\n */\r\n\r\nexport interface AttemptRecord {\r\n attempt: number;\r\n status: number;\r\n url: string;\r\n method: string;\r\n latencyMs: number;\r\n error?: string;\r\n}\r\n\r\nexport interface ResilientFetchOptions {\r\n /** HTTP method */\r\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\r\n /** Request body (will be JSON-stringified if object) */\r\n body?: string | Record<string, unknown>;\r\n /** Request headers */\r\n headers?: Record<string, string>;\r\n /** Max retry count (default: 3) */\r\n maxRetries?: number;\r\n /** Base delay in ms for exponential backoff (default: 1000) */\r\n baseDelayMs?: number;\r\n /** Per-request timeout in ms (default: 10000) */\r\n timeoutMs?: number;\r\n /** If true, throw on final failure; if false, return error result (default: false) */\r\n throwOnFailure?: boolean;\r\n}\r\n\r\nexport interface ResilientFetchResult {\r\n ok: boolean;\r\n status: number;\r\n data: unknown;\r\n attempts: AttemptRecord[];\r\n}\r\n\r\nconst RETRYABLE_STATUSES = new Set([408, 429, 500, 502, 503, 504]);\r\n\r\nfunction isRetryable(status: number): boolean {\r\n return RETRYABLE_STATUSES.has(status);\r\n}\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((r) => setTimeout(r, ms));\r\n}\r\n\r\nasync function safeJson(resp: Response): Promise<unknown> {\r\n try {\r\n return await resp.json();\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Make an HTTP request with automatic retry and exponential backoff.\r\n *\r\n * Retries on: network errors, 408, 429, 5xx.\r\n * Does NOT retry on: 4xx (except 408/429).\r\n */\r\nexport async function resilientFetch(\r\n url: string,\r\n options: ResilientFetchOptions = {},\r\n): Promise<ResilientFetchResult> {\r\n const {\r\n method = 'GET',\r\n body,\r\n headers = {},\r\n maxRetries = 3,\r\n baseDelayMs = 1000,\r\n timeoutMs = 10_000,\r\n throwOnFailure = false,\r\n } = options;\r\n\r\n const attempts: AttemptRecord[] = [];\r\n let lastStatus = 0;\r\n let lastBody: unknown = null;\r\n\r\n const requestHeaders: Record<string, string> = { ...headers };\r\n if (body && typeof body === 'object' && !requestHeaders['Content-Type']) {\r\n requestHeaders['Content-Type'] = 'application/json';\r\n }\r\n\r\n for (let i = 0; i <= maxRetries; i++) {\r\n const start = Date.now();\r\n\r\n try {\r\n const resp = await fetch(url, {\r\n method,\r\n headers: requestHeaders,\r\n body: body ? (typeof body === 'string' ? body : JSON.stringify(body)) : undefined,\r\n signal: AbortSignal.timeout(timeoutMs),\r\n });\r\n\r\n const latency = Date.now() - start;\r\n lastStatus = resp.status;\r\n lastBody = await safeJson(resp);\r\n\r\n attempts.push({ attempt: i + 1, status: lastStatus, url, method, latencyMs: latency });\r\n\r\n if (resp.ok) {\r\n return { ok: true, status: lastStatus, data: lastBody, attempts };\r\n }\r\n\r\n if (isRetryable(lastStatus) && i < maxRetries) {\r\n const delay = baseDelayMs * Math.pow(2, i);\r\n await sleep(delay);\r\n continue;\r\n }\r\n\r\n // Non-retryable error\r\n break;\r\n } catch (err) {\r\n const latency = Date.now() - start;\r\n const errMsg = err instanceof Error ? err.message : String(err);\r\n attempts.push({ attempt: i + 1, status: 0, url, method, latencyMs: latency, error: errMsg });\r\n\r\n if (i < maxRetries) {\r\n const delay = baseDelayMs * Math.pow(2, i);\r\n await sleep(delay);\r\n continue;\r\n }\r\n break;\r\n }\r\n }\r\n\r\n const result: ResilientFetchResult = { ok: false, status: lastStatus, data: lastBody, attempts };\r\n\r\n if (throwOnFailure) {\r\n const summary = attempts.map((a) => `[${a.attempt}] ${a.status || 'ERR'} ${a.latencyMs}ms`).join(', ');\r\n throw new Error(`resilientFetch failed: ${method} ${url} (${attempts.length} attempts): ${summary}`);\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Wait for a backend to become healthy by polling a health endpoint.\r\n */\r\nexport async function waitForBackend(\r\n baseUrl: string,\r\n options: { timeoutMs?: number; intervalMs?: number; healthPath?: string } = {},\r\n): Promise<void> {\r\n const { timeoutMs = 30_000, intervalMs = 1_000, healthPath = '/health' } = options;\r\n const healthUrl = new URL(healthPath, baseUrl).href;\r\n const start = Date.now();\r\n\r\n while (Date.now() - start < timeoutMs) {\r\n try {\r\n const resp = await fetch(healthUrl, { method: 'GET', signal: AbortSignal.timeout(3_000) });\r\n if (resp.ok) return;\r\n } catch {\r\n // not ready yet\r\n }\r\n await sleep(intervalMs);\r\n }\r\n\r\n throw new Error(`Backend not ready: ${healthUrl} timed out after ${timeoutMs}ms`);\r\n}\r\n","/**\r\n * Playwright network request/response monitor.\r\n * Attaches to a Page and records API calls, errors, and response times.\r\n */\r\n\r\nexport interface NetworkError {\r\n url: string;\r\n status: number;\r\n method: string;\r\n responseBody: string;\r\n requestPayload?: string;\r\n timestamp: string;\r\n pageUrl: string;\r\n}\r\n\r\nexport interface ApiRecord {\r\n url: string;\r\n status: number;\r\n method: string;\r\n durationMs: number;\r\n timestamp: string;\r\n pageUrl: string;\r\n}\r\n\r\nexport interface NetworkMonitorOptions {\r\n /** URL pattern to track (default: '/api/') */\r\n apiPattern?: string;\r\n /** Whether to capture response bodies for errors (default: true) */\r\n captureErrorBody?: boolean;\r\n}\r\n\r\n/** Minimal Playwright Page interface — avoids hard dependency on @playwright/test */\r\ninterface PlaywrightPage {\r\n url(): string;\r\n on(event: 'request', handler: (req: PlaywrightRequest) => void): void;\r\n on(event: 'response', handler: (res: PlaywrightResponse) => void): void;\r\n}\r\n\r\ninterface PlaywrightRequest {\r\n url(): string;\r\n method(): string;\r\n postData(): string | null;\r\n}\r\n\r\ninterface PlaywrightResponse {\r\n url(): string;\r\n status(): number;\r\n request(): PlaywrightRequest;\r\n text(): Promise<string>;\r\n}\r\n\r\nexport class NetworkMonitor {\r\n private errors: NetworkError[] = [];\r\n private records: ApiRecord[] = [];\r\n private requestStarts = new WeakMap<PlaywrightRequest, number>();\r\n private readonly apiPattern: string;\r\n private readonly captureErrorBody: boolean;\r\n\r\n constructor(options: NetworkMonitorOptions = {}) {\r\n this.apiPattern = options.apiPattern ?? '/api/';\r\n this.captureErrorBody = options.captureErrorBody ?? true;\r\n }\r\n\r\n /**\r\n * Attach the monitor to a Playwright Page.\r\n * Call this once per page — typically in a test fixture or beforeEach.\r\n */\r\n attach(page: PlaywrightPage): void {\r\n page.on('request', (request) => {\r\n if (request.url().includes(this.apiPattern)) {\r\n this.requestStarts.set(request, Date.now());\r\n }\r\n });\r\n\r\n page.on('response', async (response) => {\r\n const request = response.request();\r\n const isApiCall = response.url().includes(this.apiPattern);\r\n const startedAt = this.requestStarts.get(request);\r\n\r\n if (isApiCall && startedAt) {\r\n this.records.push({\r\n url: response.url(),\r\n status: response.status(),\r\n method: request.method(),\r\n durationMs: Date.now() - startedAt,\r\n timestamp: new Date().toISOString(),\r\n pageUrl: page.url(),\r\n });\r\n }\r\n\r\n if (response.status() >= 400) {\r\n let body = '';\r\n if (this.captureErrorBody) {\r\n try {\r\n body = await response.text();\r\n } catch {\r\n body = 'Unable to read';\r\n }\r\n }\r\n\r\n this.errors.push({\r\n url: response.url(),\r\n status: response.status(),\r\n method: request.method(),\r\n responseBody: body,\r\n requestPayload: request.postData() ?? undefined,\r\n timestamp: new Date().toISOString(),\r\n pageUrl: page.url(),\r\n });\r\n }\r\n });\r\n }\r\n\r\n /** All captured API records. */\r\n getRecords(): ApiRecord[] {\r\n return [...this.records];\r\n }\r\n\r\n /** All captured network errors (status >= 400). */\r\n getErrors(): NetworkError[] {\r\n return [...this.errors];\r\n }\r\n\r\n /** API calls slower than the given threshold. */\r\n getSlowRequests(thresholdMs: number): ApiRecord[] {\r\n return this.records.filter((r) => r.durationMs >= thresholdMs);\r\n }\r\n\r\n /** 5xx server errors. */\r\n get5xxErrors(): NetworkError[] {\r\n return this.errors.filter((e) => e.status >= 500);\r\n }\r\n\r\n /** 4xx client errors. */\r\n get4xxErrors(): NetworkError[] {\r\n return this.errors.filter((e) => e.status >= 400 && e.status < 500);\r\n }\r\n\r\n /** Whether any network errors have been captured. */\r\n hasErrors(): boolean {\r\n return this.errors.length > 0;\r\n }\r\n\r\n /** Reset all captured data. */\r\n clear(): void {\r\n this.errors = [];\r\n this.records = [];\r\n this.requestStarts = new WeakMap();\r\n }\r\n}\r\n","/**\r\n * Dynamic route parameter resolver.\r\n * Extracts path parameters by matching URL templates against actual hrefs.\r\n * Framework-level utility — no app-specific dependencies.\r\n */\r\n\r\nexport interface ResolvedRoute {\r\n /** Original path template (e.g. '/users/:id/detail') */\r\n originalPath: string;\r\n /** Resolved path with actual values (e.g. '/users/42/detail') */\r\n resolvedPath: string;\r\n /** Extracted parameter map (e.g. { id: '42' }) */\r\n params: Record<string, string>;\r\n /** How the parameters were resolved */\r\n resolveMethod: 'href-extraction' | 'seed-data' | 'text-extraction';\r\n}\r\n\r\n/**\r\n * Extract parameter names from a path template.\r\n * @example extractParamNames('/users/:id/posts/:postId') → ['id', 'postId']\r\n */\r\nexport function extractParamNames(pathTemplate: string): string[] {\r\n return (pathTemplate.match(/:([^/]+)/g) ?? []).map((m) => m.substring(1));\r\n}\r\n\r\n/**\r\n * Extract parameter values by matching a URL template against an actual href.\r\n * Returns null if the href doesn't match the template structure.\r\n *\r\n * @example\r\n * extractParamsFromHref('/users/:id/detail', '/users/42/detail')\r\n * // → { id: '42' }\r\n */\r\nexport function extractParamsFromHref(\r\n pathTemplate: string,\r\n href: string,\r\n): Record<string, string> | null {\r\n const templateParts = pathTemplate.split('/');\r\n const hrefParts = href.split('/');\r\n\r\n if (templateParts.length > hrefParts.length) return null;\r\n\r\n const params: Record<string, string> = {};\r\n\r\n for (let i = 0; i < templateParts.length; i++) {\r\n if (templateParts[i].startsWith(':') && hrefParts[i]) {\r\n params[templateParts[i].substring(1)] = hrefParts[i];\r\n }\r\n }\r\n\r\n const names = extractParamNames(pathTemplate);\r\n return names.every((n) => params[n]) ? params : null;\r\n}\r\n\r\n/**\r\n * Build a concrete path from a template and parameter values.\r\n *\r\n * @example\r\n * buildPath('/users/:id/posts/:postId', { id: '42', postId: '7' })\r\n * // → '/users/42/posts/7'\r\n */\r\nexport function buildPath(pathTemplate: string, params: Record<string, string>): string {\r\n let result = pathTemplate;\r\n for (const [key, value] of Object.entries(params)) {\r\n result = result.replace(`:${key}`, value);\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Try to extract an ID-like value from a text string.\r\n * Matches numeric IDs and UUIDs.\r\n */\r\nexport function extractIdFromText(text: string): string | null {\r\n const match = text.match(/\\b(\\d+|[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})\\b/i);\r\n return match?.[1] ?? null;\r\n}\r\n\r\n/**\r\n * Resolve dynamic route parameters from a seed data map.\r\n *\r\n * @param pathTemplate - URL template with :params\r\n * @param seedData - Map of route keys to param objects\r\n * @param routeKey - Optional explicit key; defaults to normalized path\r\n */\r\nexport function resolveFromSeedData(\r\n pathTemplate: string,\r\n seedData: Record<string, Record<string, string>>,\r\n routeKey?: string,\r\n): ResolvedRoute | null {\r\n const key = routeKey ?? pathTemplate.replace(/\\//g, '_').replace(/:/g, '');\r\n const params = seedData[key];\r\n if (!params) return null;\r\n\r\n return {\r\n originalPath: pathTemplate,\r\n resolvedPath: buildPath(pathTemplate, params),\r\n params,\r\n resolveMethod: 'seed-data',\r\n };\r\n}\r\n","/**\r\n * Log-driven API completion detection.\r\n *\r\n * Polls a backend log endpoint to verify that API requests have fully completed\r\n * (not just returned HTTP 200, but the backend has finished all processing).\r\n * This closes the gap between \"HTTP response received\" and \"backend actually done\".\r\n */\r\n\r\n// ===== Types =====\r\n\r\nexport interface CandidateApiRequest {\r\n /** Backend-assigned request ID (if available) */\r\n requestId?: string;\r\n /** HTTP method */\r\n method: string;\r\n /** API path (e.g. /api/users) */\r\n path: string;\r\n /** Full URL */\r\n url: string;\r\n}\r\n\r\nexport interface LogCompletionResult {\r\n /** Total candidates being tracked */\r\n candidateCount: number;\r\n /** Requests confirmed completed successfully */\r\n succeeded: CandidateApiRequest[];\r\n /** Requests confirmed completed with failure */\r\n failed: Array<{ request: CandidateApiRequest; reason: string }>;\r\n /** Requests that never got a completion log within timeout */\r\n timedOut: CandidateApiRequest[];\r\n /** Number of poll iterations performed */\r\n pollCount: number;\r\n /** Total elapsed ms */\r\n elapsedMs: number;\r\n}\r\n\r\nexport interface LogEntry {\r\n /** Backend-assigned request ID */\r\n requestId?: string;\r\n /** HTTP method */\r\n method?: string;\r\n /** API path */\r\n apiPath?: string;\r\n /** Event phase: 'start' | 'end' */\r\n eventPhase?: string;\r\n /** Event status: 'success' | 'fail' */\r\n eventStatus?: string;\r\n /** HTTP status code */\r\n status?: number;\r\n /** Nested metadata (some backends put fields here) */\r\n meta?: Record<string, unknown>;\r\n}\r\n\r\nexport interface LogPollerOptions {\r\n /** Function that fetches end-phase logs from the backend. Return parsed log entries. */\r\n fetchLogs: () => Promise<LogEntry[]>;\r\n /** Timeout in ms (default: 25000) */\r\n timeoutMs?: number;\r\n /** Initial poll delay in ms (default: 200) */\r\n initialDelayMs?: number;\r\n /** Max poll delay in ms (default: 2000) */\r\n maxDelayMs?: number;\r\n}\r\n\r\n// ===== Ignore list =====\r\n\r\nconst IGNORE_KEYWORDS = [\r\n '/health', '/metrics', '/heartbeat', '/ping', '/alive',\r\n '/beacon', '/track', '/analytics', '/poll', '/stream', '/sse',\r\n];\r\n\r\nfunction extractPath(url: string): string {\r\n try {\r\n return new URL(url).pathname;\r\n } catch {\r\n return url;\r\n }\r\n}\r\n\r\nfunction shouldIgnore(path: string): boolean {\r\n const lower = path.toLowerCase();\r\n return IGNORE_KEYWORDS.some((kw) => lower.includes(kw));\r\n}\r\n\r\n// ===== Candidate selection =====\r\n\r\nexport interface ApiResponseRecord {\r\n url: string;\r\n method: string;\r\n requestId?: string;\r\n}\r\n\r\n/**\r\n * Select candidate API requests from network-captured responses.\r\n * Deduplicates by requestId or method+path.\r\n */\r\nexport function selectCandidates(responses: ApiResponseRecord[], maxCount = 20): CandidateApiRequest[] {\r\n const unique = new Map<string, CandidateApiRequest>();\r\n\r\n for (const item of responses) {\r\n if (!item.url.includes('/api/')) continue;\r\n const path = extractPath(item.url);\r\n if (shouldIgnore(path)) continue;\r\n const method = item.method.toUpperCase();\r\n if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) continue;\r\n\r\n const key = item.requestId ? `rid:${item.requestId}` : `mp:${method}:${path}`;\r\n if (!unique.has(key)) {\r\n unique.set(key, { requestId: item.requestId, method, path, url: item.url });\r\n }\r\n }\r\n\r\n return Array.from(unique.values()).slice(0, maxCount);\r\n}\r\n\r\n/**\r\n * Select candidates from start-phase log entries.\r\n */\r\nexport function selectCandidatesFromLogs(logs: LogEntry[], maxCount = 20): CandidateApiRequest[] {\r\n const unique = new Map<string, CandidateApiRequest>();\r\n\r\n for (const log of logs) {\r\n const phase = getField(log, 'eventPhase');\r\n if (phase !== 'start') continue;\r\n\r\n const method = getField(log, 'method').toUpperCase();\r\n if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) continue;\r\n\r\n const rawPath = getField(log, 'apiPath') || getField(log, 'url');\r\n const path = extractPath(rawPath);\r\n if (!path.includes('/api/') || shouldIgnore(path)) continue;\r\n\r\n const requestId = getField(log, 'requestId') || undefined;\r\n const key = requestId ? `rid:${requestId}` : `mp:${method}:${path}`;\r\n if (!unique.has(key)) {\r\n unique.set(key, { requestId, method, path, url: rawPath });\r\n }\r\n }\r\n\r\n return Array.from(unique.values()).slice(0, maxCount);\r\n}\r\n\r\n/**\r\n * Merge multiple candidate lists, deduplicating by key.\r\n */\r\nexport function mergeCandidates(...groups: CandidateApiRequest[][]): CandidateApiRequest[] {\r\n const merged = new Map<string, CandidateApiRequest>();\r\n for (const group of groups) {\r\n for (const item of group) {\r\n const key = item.requestId ? `rid:${item.requestId}` : `mp:${item.method}:${item.path}`;\r\n if (!merged.has(key)) merged.set(key, item);\r\n }\r\n }\r\n return Array.from(merged.values()).slice(0, 30);\r\n}\r\n\r\n// ===== Log matching =====\r\n\r\nfunction getField(log: LogEntry, field: string): string {\r\n const direct = (log as Record<string, unknown>)[field];\r\n if (direct != null) return String(direct);\r\n const meta = log.meta?.[field];\r\n if (meta != null) return String(meta);\r\n return '';\r\n}\r\n\r\nfunction matchLog(request: CandidateApiRequest, logs: LogEntry[]): LogEntry | undefined {\r\n if (request.requestId) {\r\n const byId = logs.find((l) => getField(l, 'requestId') === request.requestId);\r\n if (byId) return byId;\r\n }\r\n return logs.find((l) => {\r\n const method = getField(l, 'method').toUpperCase();\r\n const apiPath = getField(l, 'apiPath') || getField(l, 'url');\r\n return method === request.method && apiPath.includes(request.path);\r\n });\r\n}\r\n\r\nfunction inferStatus(log: LogEntry): 'success' | 'fail' {\r\n const eventStatus = getField(log, 'eventStatus').toLowerCase();\r\n if (eventStatus === 'success' || eventStatus === 'fail') return eventStatus as 'success' | 'fail';\r\n const status = Number(getField(log, 'status'));\r\n if (!Number.isNaN(status) && status >= 400) return 'fail';\r\n return 'success';\r\n}\r\n\r\n// ===== Core poller =====\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((r) => setTimeout(r, ms));\r\n}\r\n\r\n/**\r\n * Poll backend logs until all candidate API requests have completion entries,\r\n * or the timeout is reached.\r\n *\r\n * @example\r\n * ```ts\r\n * const result = await waitForLogCompletion(candidates, {\r\n * fetchLogs: async () => {\r\n * const resp = await fetch(`${origin}/internal/test-logs?eventPhase=end&since=${since}`);\r\n * const body = await resp.json();\r\n * return body.data ?? [];\r\n * },\r\n * timeoutMs: 20_000,\r\n * });\r\n * ```\r\n */\r\nexport async function waitForLogCompletion(\r\n candidates: CandidateApiRequest[],\r\n options: LogPollerOptions,\r\n): Promise<LogCompletionResult> {\r\n const {\r\n fetchLogs,\r\n timeoutMs = 25_000,\r\n initialDelayMs = 200,\r\n maxDelayMs = 2_000,\r\n } = options;\r\n\r\n const pending = [...candidates];\r\n const succeeded: CandidateApiRequest[] = [];\r\n const failed: LogCompletionResult['failed'] = [];\r\n const startedAt = Date.now();\r\n let pollCount = 0;\r\n\r\n while (pending.length > 0 && Date.now() - startedAt < timeoutMs) {\r\n const logs = await fetchLogs();\r\n pollCount++;\r\n\r\n for (let i = pending.length - 1; i >= 0; i--) {\r\n const candidate = pending[i];\r\n const log = matchLog(candidate, logs);\r\n if (!log) continue;\r\n\r\n if (inferStatus(log) === 'fail') {\r\n failed.push({ request: candidate, reason: 'LOG_COMPLETION_FAIL' });\r\n } else {\r\n succeeded.push(candidate);\r\n }\r\n pending.splice(i, 1);\r\n }\r\n\r\n if (pending.length === 0) break;\r\n\r\n // Progressive backoff: 200ms → 500ms → 1s → 2s\r\n const step = pollCount;\r\n const delay = step <= 1 ? initialDelayMs : step === 2 ? 500 : Math.min(maxDelayMs, 1000 * 2 ** (step - 3));\r\n await sleep(delay);\r\n }\r\n\r\n return {\r\n candidateCount: candidates.length,\r\n succeeded,\r\n failed,\r\n timedOut: pending,\r\n pollCount,\r\n elapsedMs: Date.now() - startedAt,\r\n };\r\n}\r\n","/**\r\n * Critical API rules engine.\r\n *\r\n * Define per-endpoint validation rules with performance thresholds and\r\n * behavior flags. Evaluate captured API records against rules to surface\r\n * violations (slow responses, unexpected empty data, fatal timeouts).\r\n */\r\n\r\n// ===== Types =====\r\n\r\nexport interface CriticalApiRule {\r\n /** Route path this rule applies to (e.g. '/users/list') */\r\n routePath: string;\r\n /** Human-readable name */\r\n name: string;\r\n /** URL substring to match against captured API URLs */\r\n urlIncludes: string;\r\n /** HTTP method filter (optional; matches all if omitted) */\r\n method?: string;\r\n /** Whether an empty/null response body is acceptable (default: false) */\r\n allowEmpty?: boolean;\r\n /** Response time warning threshold in ms */\r\n warnMs?: number;\r\n /** Response time fatal threshold in ms */\r\n fatalMs?: number;\r\n}\r\n\r\nexport interface ApiRuleViolation {\r\n rule: CriticalApiRule;\r\n /** 'warn' for exceeded warnMs, 'fatal' for exceeded fatalMs, 'empty' for unexpected empty response */\r\n severity: 'warn' | 'fatal' | 'empty';\r\n /** Actual duration in ms (for timing violations) */\r\n actualMs?: number;\r\n /** Description of the violation */\r\n message: string;\r\n}\r\n\r\nexport interface ApiRecordForRules {\r\n url: string;\r\n method: string;\r\n durationMs: number;\r\n /** Response body (for empty checks) */\r\n responseBody?: string | null;\r\n}\r\n\r\n// ===== Rules registry =====\r\n\r\n/**\r\n * Create a rules engine that evaluates API records against a set of critical rules.\r\n */\r\nexport function createRulesEngine(rules: CriticalApiRule[]) {\r\n return {\r\n /** Get all rules. */\r\n getRules(): CriticalApiRule[] {\r\n return [...rules];\r\n },\r\n\r\n /** Get rules matching a specific route path. */\r\n getRulesByRoute(routePath: string): CriticalApiRule[] {\r\n return rules.filter((r) => r.routePath === routePath);\r\n },\r\n\r\n /** Get rules matching a specific URL. */\r\n getRulesByUrl(url: string): CriticalApiRule[] {\r\n return rules.filter((r) => url.includes(r.urlIncludes));\r\n },\r\n\r\n /**\r\n * Evaluate a single API record against all matching rules.\r\n * Returns violations (empty array if all rules pass).\r\n */\r\n evaluate(record: ApiRecordForRules): ApiRuleViolation[] {\r\n const violations: ApiRuleViolation[] = [];\r\n const matchingRules = rules.filter((r) => {\r\n if (!record.url.includes(r.urlIncludes)) return false;\r\n if (r.method && r.method.toUpperCase() !== record.method.toUpperCase()) return false;\r\n return true;\r\n });\r\n\r\n for (const rule of matchingRules) {\r\n // Fatal threshold check\r\n if (rule.fatalMs && record.durationMs >= rule.fatalMs) {\r\n violations.push({\r\n rule,\r\n severity: 'fatal',\r\n actualMs: record.durationMs,\r\n message: `${rule.name}: ${record.durationMs}ms exceeds fatal threshold ${rule.fatalMs}ms`,\r\n });\r\n }\r\n // Warn threshold check (only if not already fatal)\r\n else if (rule.warnMs && record.durationMs >= rule.warnMs) {\r\n violations.push({\r\n rule,\r\n severity: 'warn',\r\n actualMs: record.durationMs,\r\n message: `${rule.name}: ${record.durationMs}ms exceeds warn threshold ${rule.warnMs}ms`,\r\n });\r\n }\r\n\r\n // Empty response check\r\n if (!rule.allowEmpty) {\r\n const body = record.responseBody;\r\n if (body === null || body === undefined || body === '' || body === '{}' || body === '[]' || body === 'null') {\r\n violations.push({\r\n rule,\r\n severity: 'empty',\r\n message: `${rule.name}: response body is empty but allowEmpty=false`,\r\n });\r\n }\r\n }\r\n }\r\n\r\n return violations;\r\n },\r\n\r\n /**\r\n * Evaluate multiple API records and return all violations.\r\n */\r\n evaluateAll(records: ApiRecordForRules[]): ApiRuleViolation[] {\r\n return records.flatMap((r) => this.evaluate(r));\r\n },\r\n\r\n /**\r\n * Summary: group violations by severity.\r\n */\r\n summarize(violations: ApiRuleViolation[]): { fatal: number; warn: number; empty: number } {\r\n return {\r\n fatal: violations.filter((v) => v.severity === 'fatal').length,\r\n warn: violations.filter((v) => v.severity === 'warn').length,\r\n empty: violations.filter((v) => v.severity === 'empty').length,\r\n };\r\n },\r\n };\r\n}\r\n","/**\r\n * Full orchestration engine: generate → execute → analyze → heal → report.\r\n *\r\n * Runs a multi-phase pipeline with per-phase tracking, failure detection,\r\n * token budget management, and structured result reporting.\r\n */\r\n\r\nimport { writeFileSync, mkdirSync, existsSync, readdirSync } from 'node:fs';\r\nimport { dirname, join } from 'node:path';\r\nimport { execFileSync } from 'node:child_process';\r\nimport type {\r\n OpenCrocConfig,\r\n PipelineRunResult,\r\n SelfHealingConfig,\r\n SelfHealingResult,\r\n} from '../types.js';\r\nimport { createPipeline } from '../pipeline/index.js';\r\nimport { createSelfHealingLoop } from '../self-healing/index.js';\r\nimport { generateReports } from '../reporters/index.js';\r\nimport type { ReportOutput } from '../reporters/index.js';\r\n\r\n// ===== Types =====\r\n\r\nexport type PhaseStatus = 'success' | 'warn' | 'error' | 'skipped';\r\n\r\nexport interface PhaseResult<T = unknown> {\r\n phase: string;\r\n status: PhaseStatus;\r\n output?: T;\r\n error?: string;\r\n durationMs: number;\r\n}\r\n\r\nexport interface OrchestrationOptions {\r\n /** Which phases to run (default: all) */\r\n phases?: OrchestrationPhase[];\r\n /** Enable self-healing phase (default: false) */\r\n selfHeal?: boolean;\r\n /** Max self-healing iterations */\r\n maxHealIterations?: number;\r\n /** Report formats to generate */\r\n reportFormats?: ('html' | 'json' | 'markdown')[];\r\n /** Run Playwright in headed mode */\r\n headed?: boolean;\r\n /** Module filter */\r\n module?: string;\r\n /** LLM token budget (0 = unlimited) */\r\n tokenBudget?: number;\r\n /** Abort on phase error (default: false — continue where possible) */\r\n abortOnError?: boolean;\r\n}\r\n\r\nexport type OrchestrationPhase = 'generate' | 'execute' | 'analyze' | 'heal' | 'report';\r\n\r\nexport interface ExecutionMetrics {\r\n passed: number;\r\n failed: number;\r\n skipped: number;\r\n timedOut: number;\r\n}\r\n\r\nexport interface OrchestrationSummary {\r\n overallStatus: 'success' | 'partial-fail' | 'fatal-fail';\r\n phases: PhaseResult[];\r\n totalDurationMs: number;\r\n modules: string[];\r\n executionMetrics?: ExecutionMetrics;\r\n reports?: ReportOutput[];\r\n healingResult?: SelfHealingResult;\r\n recommendation?: string;\r\n}\r\n\r\nconst ALL_PHASES: OrchestrationPhase[] = ['generate', 'execute', 'analyze', 'heal', 'report'];\r\n\r\n// ===== Helpers =====\r\n\r\nfunction discoverTestFiles(outDir: string, moduleFilter?: string): string[] {\r\n const absDir = join(process.cwd(), outDir);\r\n if (!existsSync(absDir)) return [];\r\n\r\n const files: string[] = [];\r\n const entries = readdirSync(absDir, { withFileTypes: true, recursive: true });\r\n for (const entry of entries) {\r\n if (!entry.isFile()) continue;\r\n if (!entry.name.endsWith('.spec.ts') && !entry.name.endsWith('.test.ts')) continue;\r\n const fullPath = join(\r\n entry.parentPath || (entry as unknown as { path: string }).path || absDir,\r\n entry.name,\r\n );\r\n if (moduleFilter && !fullPath.includes(moduleFilter)) continue;\r\n files.push(fullPath);\r\n }\r\n return files;\r\n}\r\n\r\nfunction parsePlaywrightOutput(stderr: string): ExecutionMetrics {\r\n const metrics: ExecutionMetrics = { passed: 0, failed: 0, skipped: 0, timedOut: 0 };\r\n\r\n // Playwright summary line: \"X passed\", \"Y failed\", \"Z skipped\"\r\n const passedMatch = stderr.match(/(\\d+)\\s+passed/);\r\n const failedMatch = stderr.match(/(\\d+)\\s+failed/);\r\n const skippedMatch = stderr.match(/(\\d+)\\s+skipped/);\r\n const timedOutMatch = stderr.match(/(\\d+)\\s+timed?\\s*out/i);\r\n\r\n if (passedMatch) metrics.passed = parseInt(passedMatch[1], 10);\r\n if (failedMatch) metrics.failed = parseInt(failedMatch[1], 10);\r\n if (skippedMatch) metrics.skipped = parseInt(skippedMatch[1], 10);\r\n if (timedOutMatch) metrics.timedOut = parseInt(timedOutMatch[1], 10);\r\n\r\n return metrics;\r\n}\r\n\r\n// ===== Orchestrator =====\r\n\r\nexport function createOrchestrator(config: OpenCrocConfig, options: OrchestrationOptions = {}) {\r\n const {\r\n phases = ALL_PHASES,\r\n selfHeal = false,\r\n maxHealIterations = 3,\r\n reportFormats = ['html', 'json'],\r\n headed = false,\r\n module: moduleFilter,\r\n tokenBudget = 0,\r\n abortOnError = false,\r\n } = options;\r\n\r\n const outDir = config.outDir || './opencroc-output';\r\n const phaseResults: PhaseResult[] = [];\r\n let pipelineResult: PipelineRunResult | undefined;\r\n let executionMetrics: ExecutionMetrics | undefined;\r\n let healingResult: SelfHealingResult | undefined;\r\n let reports: ReportOutput[] | undefined;\r\n let tokensUsed = 0;\r\n\r\n function isBudgetExceeded(): boolean {\r\n return tokenBudget > 0 && tokensUsed >= tokenBudget;\r\n }\r\n\r\n function shouldRun(phase: OrchestrationPhase): boolean {\r\n if (phase === 'heal' && !selfHeal) return false;\r\n return phases.includes(phase);\r\n }\r\n\r\n async function runPhase<T>(\r\n name: string,\r\n fn: () => Promise<T>,\r\n ): Promise<PhaseResult<T>> {\r\n const start = Date.now();\r\n try {\r\n const output = await fn();\r\n const result: PhaseResult<T> = {\r\n phase: name,\r\n status: 'success',\r\n output,\r\n durationMs: Date.now() - start,\r\n };\r\n phaseResults.push(result);\r\n return result;\r\n } catch (err) {\r\n const result: PhaseResult<T> = {\r\n phase: name,\r\n status: 'error',\r\n error: err instanceof Error ? err.message : String(err),\r\n durationMs: Date.now() - start,\r\n };\r\n phaseResults.push(result);\r\n return result;\r\n }\r\n }\r\n\r\n function skipPhase(name: string, reason: string): PhaseResult {\r\n const result: PhaseResult = {\r\n phase: name,\r\n status: 'skipped',\r\n error: reason,\r\n durationMs: 0,\r\n };\r\n phaseResults.push(result);\r\n return result;\r\n }\r\n\r\n return {\r\n async run(): Promise<OrchestrationSummary> {\r\n const orchestrationStart = Date.now();\r\n\r\n // ── Phase 1: Generate ──\r\n if (shouldRun('generate')) {\r\n const genResult = await runPhase('generate', async () => {\r\n if (moduleFilter) config.modules = [moduleFilter];\r\n const pipeline = createPipeline(config);\r\n pipelineResult = await pipeline.run();\r\n\r\n // Write generated files\r\n for (const file of pipelineResult.generatedFiles) {\r\n const dir = dirname(file.filePath);\r\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\r\n writeFileSync(file.filePath, file.content, 'utf-8');\r\n }\r\n\r\n return pipelineResult;\r\n });\r\n\r\n if (genResult.status === 'error' && abortOnError) {\r\n return buildSummary(orchestrationStart);\r\n }\r\n }\r\n\r\n // ── Phase 2: Execute ──\r\n if (shouldRun('execute')) {\r\n const testFiles = discoverTestFiles(outDir, moduleFilter);\r\n\r\n if (testFiles.length === 0) {\r\n skipPhase('execute', 'No test files found');\r\n } else {\r\n const execResult = await runPhase('execute', async () => {\r\n const args = ['test', ...testFiles];\r\n if (!headed) args.push('--reporter=list');\r\n else args.push('--headed');\r\n\r\n const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';\r\n\r\n try {\r\n execFileSync(npxCmd, ['playwright', ...args], {\r\n cwd: process.cwd(),\r\n stdio: ['ignore', 'pipe', 'pipe'],\r\n timeout: 300_000,\r\n });\r\n return { passed: testFiles.length, failed: 0, skipped: 0, timedOut: 0 } as ExecutionMetrics;\r\n } catch (err) {\r\n const stderr = (err as { stderr?: Buffer })?.stderr?.toString() ?? '';\r\n const metrics = parsePlaywrightOutput(stderr);\r\n if (metrics.passed === 0 && metrics.failed === 0) {\r\n metrics.failed = testFiles.length;\r\n }\r\n executionMetrics = metrics;\r\n if (metrics.failed > 0) {\r\n throw new Error(`${metrics.failed} test(s) failed, ${metrics.passed} passed`, { cause: err });\r\n }\r\n return metrics;\r\n }\r\n });\r\n\r\n if (!executionMetrics && execResult.output) {\r\n executionMetrics = execResult.output as ExecutionMetrics;\r\n }\r\n\r\n if (execResult.status === 'error' && abortOnError) {\r\n return buildSummary(orchestrationStart);\r\n }\r\n }\r\n }\r\n\r\n // ── Phase 3: Analyze ──\r\n if (shouldRun('analyze')) {\r\n if (!pipelineResult || !executionMetrics || executionMetrics.failed === 0) {\r\n skipPhase('analyze', 'No failures to analyze');\r\n } else {\r\n await runPhase('analyze', async () => {\r\n // Re-run pipeline validation for failure context\r\n const pipeline = createPipeline(config);\r\n const validationResult = await pipeline.run(['validate']);\r\n return {\r\n validationErrors: validationResult.validationErrors,\r\n failedTestCount: executionMetrics!.failed,\r\n };\r\n });\r\n }\r\n }\r\n\r\n // ── Phase 4: Heal ──\r\n if (shouldRun('heal')) {\r\n if (isBudgetExceeded()) {\r\n skipPhase('heal', 'Token budget exceeded');\r\n } else if (!executionMetrics || executionMetrics.failed === 0) {\r\n skipPhase('heal', 'No failures to heal');\r\n } else {\r\n const healResult = await runPhase('heal', async () => {\r\n const healConfig: SelfHealingConfig = {\r\n enabled: true,\r\n maxIterations: maxHealIterations,\r\n mode: config.selfHealing?.mode || 'config-only',\r\n };\r\n\r\n const loop = createSelfHealingLoop(healConfig);\r\n const result = await loop.run(outDir);\r\n tokensUsed += result.totalTokensUsed;\r\n healingResult = result;\r\n return result;\r\n });\r\n\r\n if (healResult.status === 'success' && healingResult && healingResult.remaining.length > 0) {\r\n healResult.status = 'warn';\r\n phaseResults[phaseResults.length - 1] = healResult;\r\n }\r\n }\r\n }\r\n\r\n // ── Phase 5: Report ──\r\n if (shouldRun('report')) {\r\n if (!pipelineResult) {\r\n skipPhase('report', 'No pipeline results to report');\r\n } else {\r\n await runPhase('report', async () => {\r\n reports = generateReports(pipelineResult!, reportFormats);\r\n\r\n if (!existsSync(outDir)) mkdirSync(outDir, { recursive: true });\r\n for (const r of reports) {\r\n writeFileSync(join(outDir, r.filename), r.content, 'utf-8');\r\n }\r\n\r\n return reports;\r\n });\r\n }\r\n }\r\n\r\n return buildSummary(orchestrationStart);\r\n },\r\n };\r\n\r\n function buildSummary(startTime: number): OrchestrationSummary {\r\n const errorCount = phaseResults.filter((p) => p.status === 'error').length;\r\n const allSuccess = phaseResults.every((p) => p.status === 'success' || p.status === 'skipped');\r\n\r\n let overallStatus: OrchestrationSummary['overallStatus'];\r\n if (allSuccess) overallStatus = 'success';\r\n else if (errorCount > 1) overallStatus = 'fatal-fail';\r\n else overallStatus = 'partial-fail';\r\n\r\n let recommendation: string | undefined;\r\n if (executionMetrics && executionMetrics.failed > 0 && !selfHeal) {\r\n recommendation = 'Test failures detected. Consider running with --self-heal to attempt automated fixes.';\r\n } else if (healingResult && healingResult.remaining.length > 0) {\r\n recommendation = `${healingResult.remaining.length} issue(s) could not be auto-fixed. Manual review needed.`;\r\n }\r\n\r\n return {\r\n overallStatus,\r\n phases: phaseResults,\r\n totalDurationMs: Date.now() - startTime,\r\n modules: pipelineResult?.modules ?? [],\r\n executionMetrics,\r\n reports,\r\n healingResult,\r\n recommendation,\r\n };\r\n }\r\n}\r\n","/**\r\n * Orchestration summary reporter.\r\n * Writes phase-by-phase JSON and a human-readable console summary.\r\n */\r\n\r\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport type { OrchestrationSummary, PhaseResult } from './index.js';\r\n\r\nexport interface OrchestrationReportOptions {\r\n outputDir: string;\r\n module?: string;\r\n}\r\n\r\n/**\r\n * Write the orchestration summary to a JSON file.\r\n * Returns the written file path.\r\n */\r\nexport function writeOrchestrationSummary(\r\n summary: OrchestrationSummary,\r\n options: OrchestrationReportOptions,\r\n): string {\r\n const { outputDir, module: mod } = options;\r\n if (!existsSync(outputDir)) mkdirSync(outputDir, { recursive: true });\r\n\r\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\r\n const moduleName = mod ?? 'all';\r\n const filename = `orchestration-${moduleName}-${timestamp}.json`;\r\n const filePath = join(outputDir, filename);\r\n\r\n const serializable = {\r\n ...summary,\r\n phases: summary.phases.map((p) => ({\r\n phase: p.phase,\r\n status: p.status,\r\n error: p.error,\r\n durationMs: p.durationMs,\r\n })),\r\n // Strip report content to avoid massive JSON\r\n reports: summary.reports?.map((r) => ({\r\n format: r.format,\r\n filename: r.filename,\r\n })),\r\n };\r\n\r\n writeFileSync(filePath, JSON.stringify(serializable, null, 2), 'utf-8');\r\n return filePath;\r\n}\r\n\r\n/**\r\n * Format a phase result as a single console line.\r\n */\r\nfunction formatPhase(p: PhaseResult): string {\r\n const icons: Record<string, string> = {\r\n success: '✓',\r\n warn: '⚠',\r\n error: '✗',\r\n skipped: '○',\r\n };\r\n const icon = icons[p.status] ?? '?';\r\n const dur = p.durationMs > 0 ? ` (${p.durationMs}ms)` : '';\r\n const err = p.error ? ` — ${p.error}` : '';\r\n return ` ${icon} ${p.phase}${dur}${err}`;\r\n}\r\n\r\n/**\r\n * Print a human-readable console summary.\r\n */\r\nexport function printOrchestrationSummary(summary: OrchestrationSummary): string[] {\r\n const lines: string[] = [];\r\n\r\n lines.push('');\r\n lines.push(' ═══════════════════════════════════════');\r\n lines.push(' Orchestration Summary');\r\n lines.push(' ═══════════════════════════════════════');\r\n lines.push('');\r\n\r\n for (const p of summary.phases) {\r\n lines.push(formatPhase(p));\r\n }\r\n\r\n lines.push('');\r\n lines.push(` Overall : ${summary.overallStatus}`);\r\n lines.push(` Modules : ${summary.modules.join(', ') || '(none)'}`);\r\n lines.push(` Duration : ${summary.totalDurationMs}ms`);\r\n\r\n if (summary.executionMetrics) {\r\n const m = summary.executionMetrics;\r\n lines.push(` Tests : ${m.passed} passed, ${m.failed} failed, ${m.skipped} skipped`);\r\n }\r\n\r\n if (summary.healingResult) {\r\n const h = summary.healingResult;\r\n lines.push(` Healing : ${h.fixed.length} fixed, ${h.remaining.length} remaining (${h.iterations} iterations)`);\r\n }\r\n\r\n if (summary.reports) {\r\n lines.push(` Reports : ${summary.reports.map((r) => r.format).join(', ')}`);\r\n }\r\n\r\n if (summary.recommendation) {\r\n lines.push('');\r\n lines.push(` → ${summary.recommendation}`);\r\n }\r\n\r\n lines.push('');\r\n\r\n return lines;\r\n}\r\n"],"mappings":";;;;;;;;;;;AACA,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAF9B;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAAYA,SAAQ;AACpB,YAAYC,WAAU;AACtB;AAAA,EACE,WAAAC;AAAA,EACA,cAAAC;AAAA,EAGA;AAAA,OAKK;AAmBA,SAAS,oBAAoB,UAAiC;AACnE,QAAM,eAAoB,cAAQ,QAAQ;AAC1C,MAAI,CAAI,eAAW,YAAY,EAAG,QAAO,CAAC;AAE1C,MAAI;AACF,UAAM,UAAU,IAAID,SAAQ,EAAE,iBAAiB,EAAE,QAAQ,MAAM,EAAE,CAAC;AAClE,UAAM,aAAa,QAAQ,oBAAoB,YAAY;AAE3D,UAAM,YAA2B,CAAC;AAClC,cAAU,KAAK,GAAG,mBAAmB,UAAU,CAAC;AAChD,cAAU,KAAK,GAAG,sBAAsB,UAAU,CAAC;AACnD,cAAU,KAAK,GAAG,4BAA4B,UAAU,CAAC;AAEzD,WAAO,qBAAqB,SAAS;AAAA,EACvC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAKO,SAAS,yBAAyB,SAAgC;AACvE,QAAM,cAAmB,cAAQ,OAAO;AACxC,MAAI,CAAI,eAAW,WAAW,EAAG,QAAO,CAAC;AAEzC,QAAM,QAAW,gBAAY,WAAW,EAAE;AAAA,IAAO,CAAC,MAChD,EAAE,SAAS,KAAK,KAChB,CAAC,EAAE,SAAS,UAAU,KACtB,CAAC,EAAE,SAAS,UAAU,KACtB,MAAM;AAAA,EACR;AAEA,QAAM,YAA2B,CAAC;AAClC,aAAW,QAAQ,OAAO;AACxB,cAAU,KAAK,GAAG,oBAAyB,WAAK,aAAa,IAAI,CAAC,CAAC;AAAA,EACrE;AACA,SAAO,qBAAqB,SAAS;AACvC;AAEA,SAAS,mBAAmB,YAAuC;AACjE,QAAM,YAA2B,CAAC;AAClC,QAAM,QAAQ,WAAW,qBAAqBC,YAAW,cAAc;AAEvE,aAAW,QAAQ,OAAO;AACxB,UAAM,OAAO,KAAK,cAAc;AAChC,QAAI,KAAK,QAAQ,MAAMA,YAAW,yBAA0B;AAE5D,UAAM,aAAa;AACnB,UAAM,aAAa,WAAW,QAAQ,EAAE,YAAY;AACpD,QAAI,CAAC,aAAa,IAAI,UAAU,EAAG;AAEnC,UAAM,aAAa,WAAW,cAAc,EAAE,QAAQ,EAAE,KAAK;AAC7D,QAAI,CAAC,aAAa,UAAU,EAAG;AAE/B,UAAM,OAAO,KAAK,aAAa;AAC/B,QAAI,KAAK,WAAW,EAAG;AAEvB,UAAM,YAAY,iBAAiB,KAAK,CAAC,GAAG,UAAU;AACtD,QAAI,CAAC,UAAW;AAEhB,cAAU,KAAK;AAAA,MACb,QAAQ,WAAW,UAAU;AAAA,MAC7B,MAAM;AAAA,MACN,YAAY,kBAAkB,SAAS;AAAA,MACvC,aAAa,CAAC;AAAA,MACd,YAAY,CAAC;AAAA,MACb,gBAAgB,CAAC;AAAA,MACjB,eAAe,CAAC;AAAA,MAChB,aAAa,mBAAmB,IAAI;AAAA,IACtC,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,SAAS,aAAa,MAAuB;AAC3C,SAAO,SAAS,YAAY,SAAS;AACvC;AAEA,SAAS,sBAAsB,YAAuC;AACpE,QAAM,YAA2B,CAAC;AAElC,MAAI,aAAa;AACjB,aAAW,OAAO,WAAW,WAAW,GAAG;AACzC,UAAM,WAAW,IAAI,WAAW;AAChC,QAAI,UAAU,QAAQ,EAAE,SAAS,oBAAoB,GAAG;AACtD,mBAAa;AACb;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,QAAQ,WAAW,qBAAqBA,YAAW,cAAc;AACvE,MAAI,eAA8B;AAElC,aAAW,QAAQ,OAAO;AACxB,UAAM,WAAW,KAAK,cAAc,EAAE,QAAQ;AAC9C,SACG,aAAa,0BAA0B,SAAS,SAAS,iBAAiB,MAC3E,CAAC,SAAS,SAAS,QAAQ,GAC3B;AACA,YAAM,OAAO,KAAK,aAAa;AAC/B,UAAI,KAAK,UAAU,EAAG,gBAAe,qBAAqB,KAAK,CAAC,CAAC;AAAA,IACnE;AAAA,EACF;AACA,MAAI,CAAC,aAAc,QAAO;AAE1B,QAAMC,YAAW,iBAAiB,YAAY;AAC9C,QAAM,aAAoE;AAAA,IACxE,EAAE,QAAQ,OAAO,MAAMA,WAAU,MAAM,QAAQ,YAAY,GAAG;AAAA,IAC9D,EAAE,QAAQ,OAAO,MAAM,GAAGA,SAAQ,QAAQ,MAAM,OAAO,YAAY,SAAS;AAAA,IAC5E,EAAE,QAAQ,QAAQ,MAAMA,WAAU,MAAM,UAAU,YAAY,GAAG;AAAA,IACjE,EAAE,QAAQ,OAAO,MAAM,GAAGA,SAAQ,QAAQ,MAAM,UAAU,YAAY,GAAG;AAAA,IACzE,EAAE,QAAQ,UAAU,MAAM,GAAGA,SAAQ,QAAQ,MAAM,UAAU,YAAY,GAAG;AAAA,IAC5E,EAAE,QAAQ,QAAQ,MAAM,GAAGA,SAAQ,iBAAiB,MAAM,gBAAgB,YAAY,GAAG;AAAA,EAC3F;AAEA,aAAW,SAAS,YAAY;AAC9B,cAAU,KAAK;AAAA,MACb,QAAQ,MAAM;AAAA,MACd,MAAM,MAAM;AAAA,MACZ,YAAY,kBAAkB,MAAM,IAAI;AAAA,MACxC,aAAa,CAAC;AAAA,MACd,YAAY,CAAC;AAAA,MACb,gBAAgB,CAAC;AAAA,MACjB,eAAe,CAAC;AAAA,MAChB,aAAa,MAAM;AAAA,IACrB,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,SAAS,4BAA4B,YAAuC;AAC1E,QAAM,YAA2B,CAAC;AAElC,aAAW,OAAO,WAAW,WAAW,GAAG;AACzC,UAAM,sBAAsB,IAAI,cAAc,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,YAAY,MAAM,YAAY;AACtG,QAAI,CAAC,oBAAqB;AAE1B,UAAM,qBAAqB,mBAAmB,qBAAqB,qBAAqB,UAAU,KAAK,EAAE;AAEzG,eAAW,cAAc,IAAI,WAAW,GAAG;AACzC,YAAM,iBAAiB,sBAAsB,YAAY,UAAU;AACnE,UAAI,gBAAgB;AAClB,cAAMC,YAAW,cAAc,oBAAoB,mBAAmB,eAAe,IAAI,CAAC;AAC1F,kBAAU,KAAK;AAAA,UACb,QAAQ,eAAe;AAAA,UACvB,MAAMA;AAAA,UACN,YAAY,kBAAkBA,SAAQ;AAAA,UACtC,aAAa,CAAC;AAAA,UACd,YAAY,CAAC;AAAA,UACb,gBAAgB,CAAC;AAAA,UACjB,eAAe,CAAC;AAAA,UAChB,aAAa,yBAAyB,UAAU;AAAA,QAClD,CAAC;AACD;AAAA,MACF;AAEA,YAAM,gBAAgB,WAAW,cAAc,EAAE,KAAK,CAAC,MAAM,qBAAqB,IAAI,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;AAChH,UAAI,CAAC,cAAe;AAEpB,YAAM,aAAa,cAAc,QAAQ,EAAE,YAAY;AACvD,YAAM,SAAS,WAAW,UAAU;AACpC,UAAI,CAAC,OAAQ;AAEb,YAAM,aAAa,mBAAmB,qBAAqB,eAAe,UAAU,KAAK,EAAE;AAC3F,YAAM,WAAW,cAAc,oBAAoB,UAAU;AAE7D,gBAAU,KAAK;AAAA,QACb;AAAA,QACA,MAAM;AAAA,QACN,YAAY,kBAAkB,QAAQ;AAAA,QACtC,aAAa,CAAC;AAAA,QACd,YAAY,CAAC;AAAA,QACb,gBAAgB,CAAC;AAAA,QACjB,eAAe,CAAC;AAAA,QAChB,aAAa,yBAAyB,UAAU;AAAA,MAClD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,mBAAmB,cAAkC;AACnE,QAAM,SAAS,oBAAI,IAAY;AAC/B,aAAW,MAAM,cAAc;AAC7B,UAAM,eAAoB,cAAQ,EAAE;AACpC,QAAI,CAAI,eAAW,YAAY,EAAG;AAClC,QAAI;AACF,YAAM,UAAa,iBAAa,cAAc,OAAO;AACrD,YAAM,cAAc;AACpB,UAAI;AACJ,cAAQ,QAAQ,YAAY,KAAK,OAAO,OAAO,MAAM;AACnD,cAAM,QAAQ,MAAM,CAAC,EAAE,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AACrD,mBAAW,QAAQ,OAAO;AACxB,gBAAM,YAAY,KAAK,QAAQ,eAAe,EAAE,EAAE,KAAK;AACvD,cAAI,UAAW,QAAO,IAAI,cAAc,SAAS,CAAC;AAAA,QACpD;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO,MAAM,KAAK,MAAM;AAC1B;AAEA,SAAS,iBAAiB,MAAY,YAAuC;AAC3E,QAAM,OAAO,KAAK,QAAQ;AAC1B,MAAI,SAASF,YAAW,cAAe,QAAO,KAAK,QAAQ,EAAE,MAAM,GAAG,EAAE;AACxE,MAAI,SAASA,YAAW,sBAAsB,SAASA,YAAW,+BAA+B;AAC/F,WAAO,uBAAuB,MAAM,UAAU;AAAA,EAChD;AACA,MAAI,SAASA,YAAW,YAAY;AAClC,WAAO,qBAAqB,YAAY,KAAK,QAAQ,EAAE,KAAK,CAAC;AAAA,EAC/D;AACA,SAAO;AACT;AAEA,SAAS,qBAAqB,WAAsB,YAAuC;AACzF,QAAM,OAAO,UAAU,aAAa;AACpC,MAAI,KAAK,WAAW,EAAG,QAAO;AAE9B,QAAM,WAAW,KAAK,CAAC;AACvB,MAAI,SAAS,QAAQ,MAAMA,YAAW,yBAAyB;AAC7D,WAAO,6BAA6B,UAAqC,UAAU;AAAA,EACrF;AAEA,SAAO,iBAAiB,UAAU,UAAU;AAC9C;AAEA,SAAS,6BAA6B,MAA+B,YAAuC;AAC1G,QAAM,WAAW,KAAK,YAAY,MAAM;AACxC,MAAI,CAAC,YAAY,CAAC,KAAK,qBAAqB,QAAQ,EAAG,QAAO;AAC9D,QAAM,cAAc,SAAS,eAAe;AAC5C,MAAI,CAAC,YAAa,QAAO;AACzB,SAAO,iBAAiB,aAAa,UAAU;AACjD;AAEA,SAAS,sBACP,YACA,YACyC;AACzC,QAAM,YAAY,WAAW,cAAc,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,YAAY,MAAM,gBAAgB;AACvG,MAAI,CAAC,UAAW,QAAO;AAEvB,QAAM,OAAO,UAAU,aAAa;AACpC,MAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,QAAM,WAAW,KAAK,CAAC;AACvB,MAAI,SAAS,QAAQ,MAAMA,YAAW,wBAAyB,QAAO;AAEtE,QAAM,MAAM;AACZ,QAAM,aAAa,IAAI,YAAY,QAAQ;AAC3C,MAAI,SAAS;AACb,MAAI,cAAc,KAAK,qBAAqB,UAAU,GAAG;AACvD,UAAM,OAAO,WAAW,eAAe;AACvC,UAAM,aAAa,MAAM,QAAQ,KAAK;AACtC,UAAM,aAAa,WAChB,QAAQ,UAAU,EAAE,EACpB,MAAM,GAAG,EACT,IAAI,GACH,YAAY;AAChB,QAAI,cAAc,CAAC,OAAO,QAAQ,OAAO,UAAU,OAAO,EAAE,SAAS,UAAU,GAAG;AAChF,eAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,YAAY,6BAA6B,KAAK,UAAU,KAAK;AACnE,SAAO,EAAE,QAAQ,MAAM,UAAU;AACnC;AAEA,SAAS,mBAAmB,WAA2B;AACrD,QAAM,UAAU,UAAU,KAAK;AAC/B,MAAI,CAAC,WAAW,YAAY,IAAK,QAAO;AACxC,SAAO,IAAI,QAAQ,QAAQ,cAAc,EAAE,CAAC;AAC9C;AAEA,SAAS,cAAcC,WAAkB,WAA2B;AAClE,QAAM,SAAS,GAAGA,SAAQ,GAAG,SAAS,GAAG,QAAQ,QAAQ,GAAG;AAC5D,SAAO,UAAU;AACnB;AAEA,SAAS,yBAAyB,YAAuC;AACvE,QAAM,OAAO,WAAW,UAAU;AAClC,MAAI,KAAK,SAAS,GAAG;AACnB,UAAM,OAAO,KAAK,CAAC,EAAE,eAAe,EAAE,KAAK;AAC3C,QAAI,KAAM,QAAO;AAAA,EACnB;AACA,SAAO;AACT;AAEA,SAAS,uBAAuB,MAAY,YAAgC;AAC1E,MAAI,SAAS,KAAK,QAAQ,EAAE,MAAM,GAAG,EAAE;AACvC,WAAS,OAAO,QAAQ,kBAAkB,CAAC,QAAQ,SAAiB;AAClE,UAAM,WAAW,qBAAqB,YAAY,KAAK,KAAK,CAAC;AAC7D,WAAO,YAAY,IAAI,KAAK,KAAK,CAAC;AAAA,EACpC,CAAC;AACD,SAAO;AACT;AAEA,SAAS,qBAAqB,YAAwB,SAAgC;AACpF,aAAW,QAAQ,WAAW,qBAAqBD,YAAW,mBAAmB,GAAG;AAClF,QAAI,KAAK,QAAQ,MAAM,SAAS;AAC9B,YAAM,OAAO,KAAK,eAAe;AACjC,UAAI,CAAC,KAAM;AACX,YAAM,IAAI,KAAK,QAAQ,EAAE,KAAK;AAC9B,UAAK,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,KAAO,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG;AAChF,eAAO,EAAE,MAAM,GAAG,EAAE;AACtB,UAAI,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG;AACrC,eAAO,uBAAuB,MAAM,UAAU;AAAA,IAClD;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,WAA6B;AACtD,QAAM,SAAmB,CAAC;AAC1B,QAAM,QAAQ;AACd,MAAI;AACJ,UAAQ,QAAQ,MAAM,KAAK,SAAS,OAAO,KAAM,QAAO,KAAK,MAAM,CAAC,CAAC;AACrE,SAAO;AACT;AAEA,SAAS,mBAAmB,MAA8B;AACxD,MAAI,UAAgB;AACpB,SACE,QAAQ,UAAU,KAClB,QAAQ,UAAU,EAAG,QAAQ,MAAMA,YAAW,cAC9C,QAAQ,UAAU,EAAG,QAAQ,MAAMA,YAAW,OAC9C;AACA,cAAU,QAAQ,UAAU;AAAA,EAC9B;AACA,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,cAAc,SAAS,UAAU,GAAG,SAAS,QAAQ,QAAQ,QAAQ,CAAC,CAAC;AAC7E,QAAM,aAAa,YAAY,MAAM,qCAAqC;AAC1E,MAAI,WAAY,QAAO,WAAW,CAAC,EAAE,QAAQ,UAAU,EAAE,EAAE,KAAK;AAChE,QAAM,YAAY,YAAY,MAAM,aAAa;AACjD,MAAI,UAAW,QAAO,UAAU,CAAC,EAAE,KAAK;AACxC,SAAO;AACT;AAEA,SAAS,qBAAqB,MAA2B;AACvD,QAAM,IAAI,KAAK,QAAQ,EAAE,KAAK;AAC9B,MAAK,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,KAAO,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG;AAChF,WAAO,EAAE,MAAM,GAAG,EAAE;AACtB,SAAO;AACT;AAEA,SAAS,cAAc,MAAsB;AAC3C,SAAO,KAAK,QAAQ,YAAY,KAAK,EAAE,YAAY,EAAE,QAAQ,MAAM,EAAE;AACvE;AAEA,SAAS,qBAAqB,WAAyC;AACrE,QAAM,OAAO,oBAAI,IAAyB;AAC1C,aAAW,MAAM,WAAW;AAC1B,UAAM,MAAM,GAAG,GAAG,MAAM,IAAI,GAAG,IAAI;AACnC,QAAI,CAAC,KAAK,IAAI,GAAG,GAAG;AAClB,WAAK,IAAI,KAAK,EAAE;AAAA,IAClB,OAAO;AACL,YAAM,WAAW,KAAK,IAAI,GAAG;AAC7B,YAAM,SAAS,oBAAI,IAAI,CAAC,GAAG,SAAS,eAAe,GAAG,GAAG,aAAa,CAAC;AACvE,eAAS,gBAAgB,MAAM,KAAK,MAAM;AAC1C,UAAI,CAAC,SAAS,eAAe,GAAG,YAAa,UAAS,cAAc,GAAG;AAAA,IACzE;AAAA,EACF;AACA,SAAO,MAAM,KAAK,KAAK,OAAO,CAAC;AACjC;AAEO,SAAS,yBAA2C;AACzD,SAAO;AAAA,IACL,MAAM,UAAU,UAAkB;AAChC,aAAO,oBAAoB,QAAQ;AAAA,IACrC;AAAA,IACA,MAAM,eAAe,SAAiB;AACpC,aAAO,yBAAyB,OAAO;AAAA,IACzC;AAAA,EACF;AACF;AA3ZA,IAoBM,cAEA,YAIA;AA1BN;AAAA;AAAA;AAAA;AAoBA,IAAM,eAAe,oBAAI,IAAI,CAAC,OAAO,QAAQ,OAAO,UAAU,OAAO,CAAC;AAEtE,IAAM,aAAqC;AAAA,MACzC,KAAK;AAAA,MAAO,MAAM;AAAA,MAAQ,KAAK;AAAA,MAAO,QAAQ;AAAA,MAAU,OAAO;AAAA,IACjE;AAEA,IAAM,uBAAuB,oBAAI,IAAI,CAAC,OAAO,QAAQ,OAAO,UAAU,OAAO,CAAC;AAAA;AAAA;;;AC1B9E;;;ACAA;AAAA,YAAYG,WAAU;;;ACAtB;AAOA,YAAY,QAAQ;AACpB,YAAYC,WAAU;AACtB;AAAA,EACE;AAAA,EACA;AAAA,OAOK;;;AClBP;;;ACAA;;;ACAA;;;ACAA;;;ALuBO,SAAS,aAAa,QAAwC;AACnE,SAAO;AACT;;;AMzBA;AAAA,YAAYC,SAAQ;AACpB,YAAYC,WAAU;;;ACDtB;AAAA,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AACtB;AAAA,EACE,WAAAC;AAAA,EACA,cAAAC;AAAA,OAKK;AAWA,SAAS,eAAe,UAAsC;AACnE,QAAM,eAAoB,cAAQ,QAAQ;AAC1C,MAAI,CAAI,eAAW,YAAY,EAAG,QAAO;AAEzC,QAAM,UAAU,IAAID,SAAQ,EAAE,iBAAiB,EAAE,QAAQ,MAAM,EAAE,CAAC;AAClE,QAAM,aAAa,QAAQ,oBAAoB,YAAY;AAE3D,QAAM,WAAW,aAAa,UAAU;AACxC,MAAI,CAAC,SAAU,QAAO;AAEtB,QAAM,OAAO,SAAS,aAAa;AACnC,MAAI,KAAK,SAAS,EAAG,QAAO;AAE5B,QAAM,SAAS,sBAAsB,KAAK,CAAC,CAAC;AAC5C,QAAM,EAAE,WAAW,QAAQ,IAAI,aAAa,KAAK,CAAC,CAAC;AAEnD,MAAI,CAAC,UAAW,QAAO;AAEvB,SAAO,EAAE,WAAW,QAAQ,QAAQ;AACtC;AAKO,SAAS,kBAAkB,UAAiC;AACjE,QAAM,cAAmB,cAAQ,QAAQ;AACzC,MAAI,CAAI,eAAW,WAAW,EAAG,QAAO,CAAC;AAEzC,QAAM,QAAW,gBAAY,WAAW,EAAE;AAAA,IAAO,CAAC,MAChD,EAAE,SAAS,KAAK,KAChB,CAAC,EAAE,SAAS,UAAU,KACtB,CAAC,EAAE,SAAS,UAAU,KACtB,MAAM,cACN,MAAM;AAAA,EACR;AAEA,QAAM,UAAyB,CAAC;AAChC,aAAW,QAAQ,OAAO;AACxB,QAAI;AACF,YAAM,SAAS,eAAoB,WAAK,aAAa,IAAI,CAAC;AAC1D,UAAI,OAAQ,SAAQ,KAAK,MAAM;AAAA,IACjC,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,aAAa,YAAyC;AAC7D,QAAM,QAAQ,WAAW,qBAAqBC,YAAW,cAAc;AACvE,aAAW,QAAQ,OAAO;AACxB,UAAM,OAAO,KAAK,cAAc;AAChC,QAAI,KAAK,QAAQ,MAAMA,YAAW,0BAA0B;AAC1D,YAAM,aAAa,KAAK,cAAcA,YAAW,wBAAwB;AACzE,UAAI,WAAW,QAAQ,MAAM,OAAQ,QAAO;AAAA,IAC9C;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,sBAAsB,YAAiC;AAC9D,QAAM,SAAwB,CAAC;AAC/B,MAAI,WAAW,QAAQ,MAAMA,YAAW,wBAAyB,QAAO;AAExE,QAAM,aAAa;AACnB,aAAW,QAAQ,WAAW,cAAc,GAAG;AAC7C,QAAI,KAAK,QAAQ,MAAMA,YAAW,mBAAoB;AACtD,UAAM,aAAa;AACnB,UAAM,cAAc,WAAW,eAAe;AAC9C,QAAI,CAAC,eAAe,YAAY,QAAQ,MAAMA,YAAW,wBAAyB;AAClF,WAAO,KAAK,iBAAiB,WAAW,QAAQ,GAAG,WAAsC,CAAC;AAAA,EAC5F;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,WAAmB,UAAgD;AAC3F,QAAM,QAAqB,EAAE,MAAM,WAAW,MAAM,UAAU,WAAW,MAAM,YAAY,MAAM;AAEjG,aAAW,QAAQ,SAAS,cAAc,GAAG;AAC3C,QAAI,KAAK,QAAQ,MAAMA,YAAW,mBAAoB;AACtD,UAAM,aAAa;AACnB,UAAM,MAAM,WAAW,QAAQ;AAC/B,UAAM,OAAO,WAAW,eAAe;AACvC,QAAI,CAAC,KAAM;AAEX,YAAQ,KAAK;AAAA,MACX,KAAK;AAAQ,cAAM,OAAO,gBAAgB,IAAI;AAAG;AAAA,MACjD,KAAK;AAAa,cAAM,YAAY,KAAK,QAAQ,EAAE,KAAK,MAAM;AAAQ;AAAA,MACtE,KAAK;AAAc,cAAM,aAAa,KAAK,QAAQ,EAAE,KAAK,MAAM;AAAQ;AAAA,MACxE,KAAK;AAAgB,cAAM,eAAe,oBAAoB,IAAI;AAAG;AAAA,IACvE;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,MAAoB;AAC3C,QAAM,OAAO,KAAK,QAAQ,EAAE,KAAK;AACjC,QAAM,YAAY,KAAK,MAAM,4BAA4B;AACzD,MAAI,UAAW,QAAO,GAAG,UAAU,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC;AACrD,QAAM,YAAY,KAAK,MAAM,oBAAoB;AACjD,MAAI,UAAW,QAAO,UAAU,CAAC;AACjC,SAAO;AACT;AAEA,SAAS,oBAAoB,MAAqB;AAChD,QAAM,OAAO,KAAK,QAAQ,EAAE,KAAK;AACjC,MAAI,SAAS,gBAAiB,QAAO;AACrC,MAAK,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,KAAO,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG;AAC5F,WAAO,KAAK,MAAM,GAAG,EAAE;AACzB,MAAI,kBAAkB,KAAK,IAAI,EAAG,QAAO,OAAO,IAAI;AACpD,MAAI,SAAS,OAAQ,QAAO;AAC5B,MAAI,SAAS,QAAS,QAAO;AAC7B,MAAI,SAAS,OAAQ,QAAO;AAC5B,SAAO;AACT;AAEA,SAAS,aAAa,aAAyE;AAC7F,MAAI,YAA2B;AAC/B,MAAI,UAAyB,CAAC;AAE9B,MAAI,YAAY,QAAQ,MAAMA,YAAW,wBAAyB,QAAO,EAAE,WAAW,QAAQ;AAE9F,QAAM,aAAa;AACnB,aAAW,QAAQ,WAAW,cAAc,GAAG;AAC7C,QAAI,KAAK,QAAQ,MAAMA,YAAW,mBAAoB;AACtD,UAAM,aAAa;AACnB,UAAM,MAAM,WAAW,QAAQ;AAC/B,UAAM,OAAO,WAAW,eAAe;AACvC,QAAI,CAAC,KAAM;AAEX,QAAI,QAAQ,YAAa,aAAY,mBAAmB,IAAI;AAC5D,QAAI,QAAQ,UAAW,WAAU,aAAa,IAAI;AAAA,EACpD;AACA,SAAO,EAAE,WAAW,QAAQ;AAC9B;AAEA,SAAS,mBAAmB,MAA2B;AACrD,QAAM,OAAO,KAAK,QAAQ,EAAE,KAAK;AACjC,MAAK,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,KAAO,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG;AAC5F,WAAO,KAAK,MAAM,GAAG,EAAE;AACzB,SAAO;AACT;AAEA,SAAS,aAAa,MAA2B;AAC/C,MAAI,KAAK,QAAQ,MAAMA,YAAW,uBAAwB,QAAO,CAAC;AAClE,QAAM,MAAM,KAAK,cAAcA,YAAW,sBAAsB;AAChE,QAAM,UAAyB,CAAC;AAChC,aAAW,MAAM,IAAI,YAAY,GAAG;AAClC,QAAI,GAAG,QAAQ,MAAMA,YAAW,wBAAyB;AACzD,UAAM,MAAM,iBAAiB,EAA6B;AAC1D,QAAI,IAAK,SAAQ,KAAK,GAAG;AAAA,EAC3B;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,KAAkD;AAC1E,MAAI,OAAO;AACX,MAAI,SAAmB,CAAC;AACxB,MAAI,SAAS;AAEb,aAAW,QAAQ,IAAI,cAAc,GAAG;AACtC,QAAI,KAAK,QAAQ,MAAMA,YAAW,mBAAoB;AACtD,UAAM,KAAK;AACX,UAAM,OAAO,GAAG,eAAe;AAC/B,QAAI,CAAC,KAAM;AACX,YAAQ,GAAG,QAAQ,GAAG;AAAA,MACpB,KAAK;AAAQ,eAAO,mBAAmB,IAAI,KAAK;AAAI;AAAA,MACpD,KAAK;AAAU,iBAAS,mBAAmB,IAAI;AAAG;AAAA,MAClD,KAAK;AAAU,iBAAS,KAAK,QAAQ,EAAE,KAAK,MAAM;AAAQ;AAAA,IAC5D;AAAA,EACF;AACA,MAAI,CAAC,QAAQ,OAAO,WAAW,EAAG,QAAO;AACzC,SAAO,EAAE,MAAM,QAAQ,OAAO;AAChC;AAEA,SAAS,mBAAmB,MAAsB;AAChD,MAAI,KAAK,QAAQ,MAAMA,YAAW,uBAAwB,QAAO,CAAC;AAClE,QAAM,MAAM,KAAK,cAAcA,YAAW,sBAAsB;AAChE,SAAO,IAAI,YAAY,EACpB,IAAI,CAAC,OAAO,GAAG,QAAQ,EAAE,KAAK,CAAC,EAC/B,OAAO,CAAC,MAAO,EAAE,WAAW,GAAG,KAAK,EAAE,WAAW,GAAG,CAAE,EACtD,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,EAAE,CAAC;AAC9B;AAEO,SAAS,oBAAiC;AAC/C,SAAO;AAAA,IACL,MAAM,UAAU,UAAkB;AAChC,aAAO,eAAe,QAAQ;AAAA,IAChC;AAAA,IACA,MAAM,eAAe,SAAiB;AACpC,aAAO,kBAAkB,OAAO;AAAA,IAClC;AAAA,EACF;AACF;;;AD3MA;;;AEVA;AAAA,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AACtB;AAAA,EACE,WAAAC;AAAA,EACA,cAAAC;AAAA,OAIK;AAmBA,SAAS,qBACd,UACA,iBACA,mBACsB;AACtB,QAAM,eAAoB,cAAQ,QAAQ;AAC1C,MAAI,CAAI,eAAW,YAAY,EAAG,QAAO,CAAC;AAE1C,QAAM,UAAU,IAAIC,SAAQ,EAAE,iBAAiB,EAAE,QAAQ,MAAM,EAAE,CAAC;AAClE,QAAM,aAAa,QAAQ,oBAAoB,YAAY;AAE3D,QAAM,gBAAgB,mBAAmB,UAAU;AACnD,QAAM,kBAAkB,wBAAwB,YAAY,aAAa;AACzE,MAAI,gBAAgB,WAAW,EAAG,QAAO,CAAC;AAE1C,SAAO,qBAAqB,iBAAiB,iBAAiB,iBAAiB;AACjF;AAKO,SAAS,qBAAqB,UAAuC;AAC1E,QAAM,MAAM,oBAAI,IAAoB;AACpC,QAAM,cAAmB,cAAQ,QAAQ;AACzC,MAAI,CAAI,eAAW,WAAW,EAAG,QAAO;AAExC,QAAM,QAAW,gBAAY,WAAW,EAAE;AAAA,IAAO,CAAC,MAChD,EAAE,SAAS,KAAK,KAChB,CAAC,EAAE,SAAS,UAAU,KACtB,CAAC,EAAE,SAAS,UAAU,KACtB,MAAM,cACN,MAAM;AAAA,EACR;AAEA,aAAW,QAAQ,OAAO;AACxB,QAAI;AACF,YAAM,SAAS,eAAoB,WAAK,aAAa,IAAI,CAAC;AAC1D,UAAI,QAAQ;AACV,cAAM,YAAY,KAAK,QAAQ,OAAO,EAAE;AACxC,YAAI,IAAI,WAAW,OAAO,SAAS;AAAA,MACrC;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,YAA6C;AACvE,QAAM,MAAM,oBAAI,IAAoB;AACpC,aAAW,QAAQ,WAAW,sBAAsB,GAAG;AACrD,UAAM,kBAAkB,KAAK,wBAAwB;AACrD,eAAW,SAAS,KAAK,gBAAgB,GAAG;AAC1C,UAAI,IAAI,MAAM,QAAQ,GAAG,eAAe;AAAA,IAC1C;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,wBACP,YACA,eACkB;AAClB,QAAM,eAAiC,CAAC;AACxC,QAAM,QAAQ,WAAW,qBAAqBC,YAAW,cAAc;AAEvE,aAAW,QAAQ,OAAO;AACxB,UAAM,OAAO,KAAK,cAAc;AAChC,QAAI,KAAK,QAAQ,MAAMA,YAAW,yBAA0B;AAE5D,UAAM,aAAa,KAAK,cAAcA,YAAW,wBAAwB;AACzE,UAAM,aAAa,WAAW,QAAQ;AACtC,QAAI,eAAe,aAAa,eAAe,eAAe,eAAe,SAAU;AAEvF,UAAM,cAAc,WAAW,cAAc,EAAE,QAAQ,EAAE,KAAK;AAC9D,UAAM,OAAO,KAAK,aAAa;AAC/B,QAAI,KAAK,SAAS,EAAG;AAErB,UAAM,cAAc,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK;AAC3C,QAAI,aAAa;AAEjB,QAAI,KAAK,UAAU,KAAK,KAAK,CAAC,EAAE,QAAQ,MAAMA,YAAW,yBAAyB;AAChF,mBAAa,sBAAsB,KAAK,CAAC,GAA8B,YAAY;AAAA,IACrF;AAEA,iBAAa,KAAK;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN,YAAY,cAAc,IAAI,WAAW;AAAA,IAC3C,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,SAAS,sBAAsB,KAA8B,cAA8B;AACzF,aAAW,QAAQ,IAAI,cAAc,GAAG;AACtC,QAAI,KAAK,QAAQ,MAAMA,YAAW,mBAAoB;AACtD,UAAM,KAAK;AACX,QAAI,GAAG,QAAQ,MAAM,aAAc;AACnC,UAAM,OAAO,GAAG,eAAe;AAC/B,QAAI,CAAC,KAAM;AACX,UAAM,OAAO,KAAK,QAAQ,EAAE,KAAK;AACjC,QAAK,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,KAAO,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG;AAC5F,aAAO,KAAK,MAAM,GAAG,EAAE;AACzB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,qBAAqB,WAA2B;AAC9D,SAAO,UAAU,QAAQ,YAAY,KAAK,EAAE,YAAY,EAAE,QAAQ,MAAM,EAAE;AAC5E;AAEA,SAAS,iBAAiB,WAAmB,iBAA+C;AAC1F,MAAI,iBAAiB,IAAI,SAAS,EAAG,QAAO,gBAAgB,IAAI,SAAS;AACzE,SAAO,qBAAqB,SAAS;AACvC;AAEA,SAAS,iBACP,iBACA,YACA,mBACS;AACT,MAAI,kBAAmB,QAAO,CAAC,gBAAgB,WAAW,iBAAiB;AAC3E,MAAI,YAAY;AACd,UAAM,YAAY,WAAW,MAAM,SAAS,KAAK,CAAC,GAAG;AACrD,WAAO,YAAY;AAAA,EACrB;AACA,SAAO;AACT;AAEA,SAAS,qBACP,iBACA,iBACA,mBACsB;AACtB,QAAM,OAAO,oBAAI,IAAgC;AAEjD,aAAW,OAAO,iBAAiB;AACjC,UAAM,cAAc,iBAAiB,IAAI,aAAa,eAAe;AACrE,UAAM,cAAc,iBAAiB,IAAI,aAAa,eAAe;AACrE,UAAM,cAAc,iBAAiB,aAAa,IAAI,YAAY,iBAAiB;AAEnF,QAAI;AACJ,QAAI;AACJ,QAAI;AAEJ,YAAQ,IAAI,MAAM;AAAA,MAChB,KAAK;AACH,sBAAc;AAAa,qBAAa;AAAa,sBAAc;AAAO;AAAA,MAC5E,KAAK;AACH,sBAAc;AAAa,qBAAa;AAAa,sBAAc;AAAO;AAAA,MAC5E,KAAK;AACH,sBAAc;AAAa,qBAAa;AAAa,sBAAc;AAAO;AAAA,IAC9E;AAEA,UAAM,YAAY,GAAG,WAAW,IAAI,UAAU,IAAI,IAAI,UAAU;AAChE,QAAI,KAAK,IAAI,SAAS,GAAG;AACvB,YAAM,WAAW,KAAK,IAAI,SAAS;AACnC,UAAI,SAAS,gBAAgB,UAAU,gBAAgB,SAAS,gBAAgB,QAAQ;AACtF,aAAK,IAAI,WAAW;AAAA,UAClB,aAAa;AAAA,UAAa,aAAa;AAAA,UACvC,aAAa;AAAA,UAAY,aAAa,IAAI;AAAA,UAC1C;AAAA,UAAa,eAAe,eAAe,SAAS;AAAA,QACtD,CAAC;AAAA,MACH;AAAA,IACF,OAAO;AACL,WAAK,IAAI,WAAW;AAAA,QAClB,aAAa;AAAA,QAAa,aAAa;AAAA,QACvC,aAAa;AAAA,QAAY,aAAa,IAAI;AAAA,QAC1C;AAAA,QAAa,eAAe;AAAA,MAC9B,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO,MAAM,KAAK,KAAK,OAAO,CAAC;AACjC;AAEO,SAAS,0BAA6C;AAC3D,SAAO;AAAA,IACL,MAAM,UAAU,UAAkB;AAChC,aAAO,qBAAqB,QAAQ;AAAA,IACtC;AAAA,EACF;AACF;;;ACpNA;AAOA,IAAM,kBAAkB,oBAAI,IAAI,CAAC,UAAU,CAAC;AAI5C,SAAS,UAAU,UAA+B;AAChD,SAAO,GAAG,SAAS,MAAM,IAAI,SAAS,IAAI;AAC5C;AAEA,SAAS,oBAAoB,OAAuB;AAClD,QAAM,WAAW,MAAM,SAAS,IAAI,IAAI,MAAM,MAAM,GAAG,EAAE,IAAI;AAC7D,SAAO,SAAS,QAAQ,YAAY,KAAK,EAAE,YAAY,EAAE,QAAQ,MAAM,EAAE;AAC3E;AAEA,SAAS,qBAAqB,cAA2B,cAA+B;AACtF,QAAM,WAAW,aAAa,KAAK,MAAM,GAAG,EAAE,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,WAAW,GAAG,CAAC;AACnF,MAAI,SAAS,WAAW,EAAG,QAAO;AAElC,QAAM,cAAc,SAAS,SAAS,SAAS,CAAC,EAAE,YAAY;AAC9D,MAAI,YAAY,SAAS,YAAY,EAAG,QAAO;AAE/C,QAAM,QAAQ,YAAY,MAAM,GAAG;AACnC,MAAI,MAAM,KAAK,CAAC,MAAM,MAAM,gBAAgB,EAAE,WAAW,YAAY,CAAC,EAAG,QAAO;AAEhF,MAAI,aAAa,UAAU,GAAG;AAC5B,UAAM,eAAe,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE;AACnD,QAAI,aAAa,WAAW,YAAY,EAAG,QAAO;AAAA,EACpD;AACA,SAAO;AACT;AAMO,SAAS,kBAAkB,WAA2C;AAC3E,QAAM,eAAgC,CAAC;AACvC,QAAM,gBAAgB,UAAU,OAAO,CAAC,OAAO,GAAG,WAAW,MAAM;AAEnE,aAAW,YAAY,WAAW;AAChC,UAAM,iBAAiB,SAAS,WAAW,OAAO,CAAC,MAAM,CAAC,gBAAgB,IAAI,CAAC,CAAC;AAChF,QAAI,eAAe,WAAW,EAAG;AAEjC,eAAW,SAAS,gBAAgB;AAClC,UAAI,UAAU,MAAM;AAClB,cAAMC,YAAW,SAAS,KAAK,QAAQ,iBAAiB,EAAE;AAC1D,cAAMC,YAAW,cAAc,KAAK,CAAC,OAAO,GAAG,SAASD,SAAQ;AAChE,YAAIC,aAAY,UAAUA,SAAQ,MAAM,UAAU,QAAQ,GAAG;AAC3D,uBAAa,KAAK,EAAE,MAAM,UAAU,IAAIA,WAAU,cAAc,EAAE,CAAC,IAAI,KAAK,EAAE,GAAG,mBAAmB,EAAE,CAAC;AAAA,QACzG;AACA;AAAA,MACF;AAEA,YAAM,eAAe,oBAAoB,KAAK;AAC9C,UAAI,CAAC,aAAc;AAEnB,YAAM,WAAW,cAAc,KAAK,CAAC,OAAO,qBAAqB,IAAI,YAAY,CAAC;AAClF,UAAI,YAAY,UAAU,QAAQ,MAAM,UAAU,QAAQ,GAAG;AAC3D,qBAAa,KAAK,EAAE,MAAM,UAAU,IAAI,UAAU,cAAc,EAAE,CAAC,IAAI,KAAK,EAAE,GAAG,mBAAmB,EAAE,CAAC;AAAA,MACzG;AAAA,IACF;AAAA,EACF;AACA,SAAO,wBAAwB,YAAY;AAC7C;AAEA,SAAS,wBAAwB,MAAwC;AACvE,QAAM,MAAM,oBAAI,IAA2B;AAC3C,aAAW,OAAO,MAAM;AACtB,UAAM,MAAM,GAAG,UAAU,IAAI,IAAI,CAAC,SAAI,UAAU,IAAI,EAAE,CAAC;AACvD,QAAI,IAAI,IAAI,GAAG,GAAG;AAChB,aAAO,OAAO,IAAI,IAAI,GAAG,EAAG,cAAc,IAAI,YAAY;AAAA,IAC5D,OAAO;AACL,UAAI,IAAI,KAAK,EAAE,GAAG,KAAK,cAAc,EAAE,GAAG,IAAI,aAAa,EAAE,CAAC;AAAA,IAChE;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI,OAAO,CAAC;AAChC;AAKO,SAAS,WACd,WACA,cACsB;AACtB,QAAM,UAAU,oBAAI,IAAY;AAChC,aAAW,MAAM,UAAW,SAAQ,IAAI,UAAU,EAAE,CAAC;AAErD,QAAM,QAA6D,CAAC;AACpE,aAAW,OAAO,cAAc;AAC9B,UAAM,KAAK;AAAA,MACT,MAAM,UAAU,IAAI,IAAI;AAAA,MACxB,IAAI,UAAU,IAAI,EAAE;AAAA,MACpB,OAAO,OAAO,KAAK,IAAI,YAAY,EAAE,KAAK,IAAI,KAAK;AAAA,IACrD,CAAC;AAAA,EACH;AACA,SAAO,EAAE,OAAO,MAAM,KAAK,OAAO,GAAG,MAAM;AAC7C;AAKO,SAAS,aAAa,KAAqC;AAChE,QAAM,YAAY,oBAAI,IAAsB;AAC5C,aAAW,QAAQ,IAAI,MAAO,WAAU,IAAI,MAAM,CAAC,CAAC;AACpD,aAAW,QAAQ,IAAI,MAAO,WAAU,IAAI,KAAK,IAAI,GAAG,KAAK,KAAK,EAAE;AAEpE,QAAM,QAAQ,oBAAI,IAAmB;AACrC,aAAW,QAAQ,IAAI,MAAO,OAAM,IAAI,MAAM,aAAW;AAEzD,QAAM,WAAqB,CAAC;AAC5B,QAAMC,SAAiB,CAAC;AAExB,WAAS,IAAI,MAAoB;AAC/B,UAAM,IAAI,MAAM,YAAU;AAC1B,IAAAA,OAAK,KAAK,IAAI;AACd,eAAW,YAAY,UAAU,IAAI,IAAI,KAAK,CAAC,GAAG;AAChD,YAAM,KAAK,MAAM,IAAI,QAAQ;AAC7B,UAAI,OAAO,cAAY;AACrB,cAAM,aAAaA,OAAK,QAAQ,QAAQ;AACxC,iBAAS,KAAK,mBAAmBA,OAAK,MAAM,UAAU,EAAE,OAAO,QAAQ,EAAE,KAAK,UAAK,CAAC,EAAE;AAAA,MACxF,WAAW,OAAO,eAAa;AAC7B,YAAI,QAAQ;AAAA,MACd;AAAA,IACF;AACA,IAAAA,OAAK,IAAI;AACT,UAAM,IAAI,MAAM,aAAW;AAAA,EAC7B;AAEA,aAAW,QAAQ,IAAI,OAAO;AAC5B,QAAI,MAAM,IAAI,IAAI,MAAM,cAAa,KAAI,IAAI;AAAA,EAC/C;AACA,SAAO;AACT;AAKO,SAAS,gBAAgB,KAAqC;AACnE,QAAM,WAAW,oBAAI,IAAoB;AACzC,QAAM,YAAY,oBAAI,IAAsB;AAE5C,aAAW,QAAQ,IAAI,OAAO;AAAE,aAAS,IAAI,MAAM,CAAC;AAAG,cAAU,IAAI,MAAM,CAAC,CAAC;AAAA,EAAG;AAChF,aAAW,QAAQ,IAAI,OAAO;AAC5B,cAAU,IAAI,KAAK,IAAI,GAAG,KAAK,KAAK,EAAE;AACtC,aAAS,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,EAAE,KAAK,KAAK,CAAC;AAAA,EACxD;AAEA,QAAM,QAAkB,CAAC;AACzB,aAAW,CAAC,MAAM,MAAM,KAAK,UAAU;AACrC,QAAI,WAAW,EAAG,OAAM,KAAK,IAAI;AAAA,EACnC;AAEA,QAAM,SAAmB,CAAC;AAC1B,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,OAAO,MAAM,MAAM;AACzB,WAAO,KAAK,IAAI;AAChB,eAAW,YAAY,UAAU,IAAI,IAAI,KAAK,CAAC,GAAG;AAChD,YAAM,MAAM,SAAS,IAAI,QAAQ,KAAK,KAAK;AAC3C,eAAS,IAAI,UAAU,EAAE;AACzB,UAAI,OAAO,EAAG,OAAM,KAAK,QAAQ;AAAA,IACnC;AAAA,EACF;AACA,SAAO;AACT;AASO,SAAS,yBAA2C;AACzD,SAAO;AAAA,IACL,QAAQ,WAAkD;AACxD,YAAM,eAAe,kBAAkB,SAAS;AAChD,YAAM,MAAM,WAAW,WAAW,YAAY;AAC9C,YAAM,gBAAgB,aAAa,GAAG;AAEtC,aAAO;AAAA,QACL,YAAY;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,QACA,WAAW,cAAc,SAAS;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACpMA;AASA,SAAS,cAAc,WAA2B;AAChD,QAAM,QAAQ,UAAU,YAAY;AACpC,MAAI,MAAM,WAAW,QAAQ,EAAG,QAAO;AACvC,MAAI,UAAU,YAAY,UAAU,UAAW,QAAO;AACtD,MAAI,UAAU,UAAW,QAAO;AAChC,MAAI,MAAM,WAAW,MAAM,KAAK,UAAU,MAAO,QAAO;AACxD,MAAI,UAAU,UAAU,UAAU,QAAS,QAAO;AAClD,MAAI,UAAU,OAAQ,QAAO;AAC7B,MAAI,UAAU,WAAW,UAAU,YAAY,UAAU,UAAW,QAAO;AAC3E,MAAI,UAAU,OAAQ,QAAO;AAC7B,MAAI,MAAM,WAAW,MAAM,EAAG,QAAO;AACrC,SAAO;AACT;AAKA,SAAS,mBAAmB,MAAsB;AAChD,SAAO,KAAK,QAAQ,kBAAkB,GAAG;AAC3C;AAKA,SAAS,kBAAkB,QAAuB,WAAyC;AACzF,QAAM,QAAkB,CAAC,WAAW;AAGpC,aAAW,SAAS,QAAQ;AAC1B,UAAM,aAAa,mBAAmB,MAAM,SAAS;AACrD,UAAM,KAAK,KAAK,UAAU,IAAI;AAC9B,eAAW,SAAS,MAAM,QAAQ;AAChC,YAAM,QAAQ,cAAc,MAAM,IAAI;AACtC,YAAM,KAAK,MAAM,aAAa,OAAO;AACrC,YAAM,UAAU,MAAM,UAAU,KAAK,MAAM,OAAO,MAAM;AACxD,YAAM,KAAK,OAAO,KAAK,IAAI,MAAM,IAAI,GAAG,KAAK,MAAM,KAAK,EAAE,GAAG,OAAO,EAAE;AAAA,IACxE;AACA,UAAM,KAAK,KAAK;AAAA,EAClB;AAGA,QAAM,aAAa,IAAI,IAAI,OAAO,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC;AACzD,aAAW,OAAO,WAAW;AAC3B,QAAI,CAAC,WAAW,IAAI,IAAI,WAAW,KAAK,CAAC,WAAW,IAAI,IAAI,WAAW,EAAG;AAE1E,UAAM,MAAM,mBAAmB,IAAI,WAAW;AAC9C,UAAM,MAAM,mBAAmB,IAAI,WAAW;AAC9C,UAAM,YAAY,IAAI,gBAAgB,OAAO;AAE7C,QAAI;AACJ,YAAQ,IAAI,aAAa;AAAA,MACvB,KAAK;AAAO,sBAAc,KAAK,SAAS;AAAM;AAAA,MAC9C,KAAK;AAAO,sBAAc,KAAK,SAAS;AAAM;AAAA,MAC9C,KAAK;AAAO,sBAAc,KAAK,SAAS;AAAM;AAAA,MAC9C;AAAS,sBAAc,KAAK,SAAS;AAAA,IACvC;AAEA,UAAM,KAAK,KAAK,GAAG,IAAI,WAAW,IAAI,GAAG,OAAO,IAAI,WAAW,GAAG;AAAA,EACpE;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,2BAA+C;AAC7D,SAAO;AAAA,IACL,SAAS,QAAuB,WAAkD;AAChF,YAAM,cAAc,kBAAkB,QAAQ,SAAS;AACvD,aAAO,EAAE,QAAQ,WAAW,YAAY;AAAA,IAC1C;AAAA,EACF;AACF;;;AC/EA;AASA,SAAS,iBAAiB,OAAe,KAAuB;AAE9D,MAAI,IAAI,SAAS,KAAK,EAAG,QAAO,eAAe,KAAK;AAEpD,QAAM,WAAW,MAAM,SAAS,IAAI,IAAI,MAAM,MAAM,GAAG,EAAE,IAAI;AAC7D,MAAI,IAAI,SAAS,QAAQ,EAAG,QAAO,eAAe,QAAQ;AAE1D,MAAI,UAAU,KAAM,QAAO;AAC3B,SAAO,eAAe,KAAK;AAC7B;AAKA,SAAS,aAAa,MAAwB;AAC5C,QAAM,aAAa,KAAK,SAAS;AACjC,MAAI,WAAW,WAAW,EAAG,QAAO,gBAAgB,KAAK,SAAS,IAAI;AAEtE,MAAI,cAAc,KAAK,SAAS;AAChC,QAAM,eAAyB,CAAC;AAChC,aAAW,SAAS,YAAY;AAC9B,kBAAc,YAAY,QAAQ,IAAI,KAAK,IAAI,MAAM,iBAAiB,OAAO,UAAU,CAAC,GAAG;AAC3F,iBAAa,KAAK,KAAK;AAAA,EACzB;AACA,SAAO,iBAAiB,WAAW;AACrC;AAKA,SAAS,mBAAmB,MAA0B;AACpD,QAAM,QAAkB,CAAC;AACzB,MAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,eAAW,aAAa,KAAK,YAAY;AACvC,YAAM,KAAK,cAAc,SAAS,iBAAiB;AAAA,IACrD;AAAA,EACF,OAAO;AAEL,QAAI,KAAK,SAAS,WAAW,QAAQ;AACnC,YAAM,KAAK,kDAAkD;AAC7D,YAAM,KAAK,yCAAyC;AACpD,YAAM,KAAK,yDAAyD;AAAA,IACtE,WAAW,KAAK,SAAS,WAAW,OAAO;AACzC,YAAM,KAAK,yCAAyC;AAAA,IACtD,WAAW,KAAK,SAAS,WAAW,UAAU;AAC5C,YAAM,KAAK,kDAAkD;AAAA,IAC/D,OAAO;AACL,YAAM,KAAK,kDAAkD;AAAA,IAC/D;AAAA,EACF;AACA,SAAO;AACT;AAKA,SAAS,iBAAiB,OAA0B;AAClD,QAAM,QAAkB,CAAC;AAEzB,QAAM,KAAK,kDAAkD;AAC7D,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,kBAAkB,MAAM,IAAI,YAAY;AACnD,QAAM,KAAK,kDAAkD;AAC7D,QAAM,KAAK,EAAE;AAEb,aAAW,QAAQ,MAAM,OAAO;AAC9B,UAAM,KAAK,gBAAgB,KAAK,KAAK,KAAK,KAAK,WAAW,6BAA6B;AACvF,UAAM,KAAK,UAAU,KAAK,MAAM,KAAK,KAAK,SAAS,MAAM,IAAI,KAAK,SAAS,IAAI,EAAE;AACjF,UAAM,KAAK,OAAO,aAAa,IAAI,CAAC,EAAE;AACtC,UAAM,KAAK,EAAE;AAEb,QAAI,KAAK,SAAS,WAAW,OAAO;AAClC,YAAM,KAAK,8CAA8C;AAAA,IAC3D,WAAW,KAAK,SAAS,WAAW,QAAQ;AAC1C,YAAM,KAAK,6DAA6D;AAAA,IAC1E,WAAW,KAAK,SAAS,WAAW,OAAO;AACzC,YAAM,KAAK,4DAA4D;AAAA,IACzE,WAAW,KAAK,SAAS,WAAW,UAAU;AAC5C,YAAM,KAAK,iDAAiD;AAAA,IAC9D,WAAW,KAAK,SAAS,WAAW,SAAS;AAC3C,YAAM,KAAK,8DAA8D;AAAA,IAC3E;AAEA,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,GAAG,mBAAmB,IAAI,CAAC;AACtC,UAAM,KAAK,OAAO;AAClB,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,KAAK,KAAK;AAChB,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,0BAA6C;AAC3D,SAAO;AAAA,IACL,SAAS,QAA0C;AACjD,aAAO,OAAO,IAAI,CAAC,WAAW;AAAA,QAC5B,UAAU,GAAG,MAAM,MAAM,IAAI,MAAM,KAAK,QAAQ,QAAQ,GAAG,EAAE,YAAY,CAAC;AAAA,QAC1E,SAAS,iBAAiB,KAAK;AAAA,QAC/B,QAAQ,MAAM;AAAA,QACd,OAAO,MAAM;AAAA,MACf,EAAE;AAAA,IACJ;AAAA,EACF;AACF;;;ACjHA;;;ACAA;AAWA,IAAM,qBAAqB,CAAC,OAAO,QAAQ,OAAO,UAAU,OAAO;AAE5D,SAAS,eAAe,QAAwC;AACrE,QAAM,SAAwC,CAAC;AAC/C,QAAM,WAA4C,CAAC;AAEnD,MAAI,WAAW,QAAQ,WAAW,UAAa,OAAO,WAAW,UAAU;AACzE,WAAO,KAAK,EAAE,OAAO,UAAU,MAAM,gBAAgB,MAAM,IAAI,SAAS,mCAAmC,CAAC;AAC5G,WAAO,EAAE,QAAQ,OAAO,OAAO,UAAU,QAAQ,SAAS;AAAA,EAC5D;AAEA,QAAM,MAAM;AAGZ,QAAM,WAAkD;AAAA,IACtD,EAAE,MAAM,cAAc,MAAM,SAAS;AAAA,IACrC,EAAE,MAAM,WAAW,MAAM,SAAS;AAAA,IAClC,EAAE,MAAM,eAAe,MAAM,SAAS;AAAA,IACtC,EAAE,MAAM,iBAAiB,MAAM,SAAS;AAAA,IACxC,EAAE,MAAM,iBAAiB,MAAM,SAAS;AAAA,IACxC,EAAE,MAAM,aAAa,MAAM,QAAQ;AAAA,IACnC,EAAE,MAAM,QAAQ,MAAM,QAAQ;AAAA,EAChC;AAEA,aAAW,KAAK,UAAU;AACxB,QAAI,IAAI,EAAE,IAAI,MAAM,UAAa,IAAI,EAAE,IAAI,MAAM,MAAM;AACrD,aAAO,KAAK;AAAA,QACV,OAAO;AAAA,QAAU,MAAM;AAAA,QAAiB,MAAM,EAAE;AAAA,QAChD,SAAS,mBAAmB,EAAE,IAAI;AAAA,QAClC,YAAY,QAAQ,EAAE,IAAI,mBAAmB,EAAE,IAAI;AAAA,MACrD,CAAC;AAAA,IACH;AAAA,EACF;AAGA,qBAAmB,KAAK,MAAM;AAG9B,MAAI,IAAI,iBAAiB,OAAO,IAAI,kBAAkB,YAAY,CAAC,MAAM,QAAQ,IAAI,aAAa,GAAG;AACnG,0BAAsB,IAAI,eAA0C,QAAQ,QAAQ;AAAA,EACtF;AAGA,MAAI,IAAI,iBAAiB,OAAO,IAAI,kBAAkB,YAAY,CAAC,MAAM,QAAQ,IAAI,aAAa,GAAG;AACnG,0BAAsB,IAAI,eAA0C,QAAQ,QAAQ;AAAA,EACtF;AAGA,MAAI,MAAM,QAAQ,IAAI,SAAS,GAAG;AAChC,sBAAkB,IAAI,WAAW,MAAM;AAAA,EACzC;AAGA,MAAI,MAAM,QAAQ,IAAI,IAAI,GAAG;AAC3B,sBAAkB,IAAI,MAAM,QAAQ,QAAQ;AAAA,EAC9C;AAGA,MAAI,OAAO,IAAI,YAAY,YAAY,CAAC,qBAAqB,KAAK,IAAI,OAAO,GAAG;AAC9E,aAAS,KAAK,EAAE,OAAO,UAAU,MAAM,WAAW,SAAS,YAAY,IAAI,OAAO,kCAAkC,CAAC;AAAA,EACvH;AAEA,SAAO,EAAE,QAAQ,OAAO,WAAW,GAAG,OAAO,UAAU,QAAQ,SAAS;AAC1E;AAEA,SAAS,mBAAmB,KAA8B,QAA6C;AACrG,MAAI,IAAI,eAAe,UAAa,OAAO,IAAI,eAAe,UAAU;AACtE,WAAO,KAAK,EAAE,OAAO,UAAU,MAAM,gBAAgB,MAAM,cAAc,SAAS,gCAAgC,CAAC;AAAA,EACrH,WAAW,OAAO,IAAI,eAAe,YAAY,IAAI,WAAW,KAAK,MAAM,IAAI;AAC7E,WAAO,KAAK,EAAE,OAAO,UAAU,MAAM,kBAAkB,MAAM,cAAc,SAAS,iCAAiC,CAAC;AAAA,EACxH;AAEA,MAAI,IAAI,kBAAkB,WAAc,OAAO,IAAI,kBAAkB,YAAY,MAAM,QAAQ,IAAI,aAAa,IAAI;AAClH,WAAO,KAAK,EAAE,OAAO,UAAU,MAAM,gBAAgB,MAAM,iBAAiB,SAAS,yCAAyC,CAAC;AAAA,EACjI;AACA,MAAI,IAAI,kBAAkB,WAAc,OAAO,IAAI,kBAAkB,YAAY,MAAM,QAAQ,IAAI,aAAa,IAAI;AAClH,WAAO,KAAK,EAAE,OAAO,UAAU,MAAM,gBAAgB,MAAM,iBAAiB,SAAS,yCAAyC,CAAC;AAAA,EACjI;AACA,MAAI,IAAI,cAAc,UAAa,CAAC,MAAM,QAAQ,IAAI,SAAS,GAAG;AAChE,WAAO,KAAK,EAAE,OAAO,UAAU,MAAM,gBAAgB,MAAM,aAAa,SAAS,+BAA+B,CAAC;AAAA,EACnH;AACA,MAAI,IAAI,SAAS,UAAa,CAAC,MAAM,QAAQ,IAAI,IAAI,GAAG;AACtD,WAAO,KAAK,EAAE,OAAO,UAAU,MAAM,gBAAgB,MAAM,QAAQ,SAAS,0BAA0B,CAAC;AAAA,EACzG;AACF;AAEA,SAAS,sBACP,WACA,QACA,UACM;AACN,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,SAAS,GAAG;AACpD,UAAM,IAAI,iBAAiB,GAAG;AAC9B,QAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GAAG;AACvE,aAAO,KAAK,EAAE,OAAO,UAAU,MAAM,gBAAgB,MAAM,GAAG,SAAS,kBAAkB,GAAG,2BAA2B,CAAC;AACxH;AAAA,IACF;AACA,QAAI,CAAC,oCAAoC,KAAK,GAAG,GAAG;AAClD,eAAS,KAAK,EAAE,OAAO,UAAU,MAAM,GAAG,SAAS,sBAAsB,GAAG,wCAAwC,CAAC;AAAA,IACvH;AACA,QAAI,OAAO,KAAK,KAAK,EAAE,WAAW,GAAG;AACnC,eAAS,KAAK,EAAE,OAAO,UAAU,MAAM,GAAG,SAAS,kBAAkB,GAAG,aAAa,CAAC;AAAA,IACxF;AAAA,EACF;AACF;AAEA,SAAS,sBACP,UACA,QACA,WACM;AACN,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACnD,UAAM,IAAI,iBAAiB,GAAG;AAC9B,QAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GAAG;AACvE,aAAO,KAAK,EAAE,OAAO,UAAU,MAAM,gBAAgB,MAAM,GAAG,SAAS,kBAAkB,GAAG,2BAA2B,CAAC;AACxH;AAAA,IACF;AACA,eAAW,CAAC,WAAW,UAAU,KAAK,OAAO,QAAQ,KAAgC,GAAG;AACtF,UAAI,OAAO,eAAe,UAAU;AAClC,eAAO,KAAK,EAAE,OAAO,UAAU,MAAM,gBAAgB,MAAM,GAAG,CAAC,IAAI,SAAS,IAAI,SAAS,4BAA4B,SAAS,qBAAqB,CAAC;AAAA,MACtJ;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,kBAAkB,SAAoB,QAA6C;AAC1F,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,QAAQ,QAAQ,CAAC;AACvB,UAAM,IAAI,aAAa,CAAC;AACxB,QAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,aAAO,KAAK,EAAE,OAAO,UAAU,MAAM,gBAAgB,MAAM,GAAG,SAAS,oBAAoB,CAAC,qBAAqB,CAAC;AAClH;AAAA,IACF;AACA,QAAI,OAAO,MAAM,gBAAgB,UAAU;AACzC,aAAO,KAAK,EAAE,OAAO,UAAU,MAAM,iBAAiB,MAAM,GAAG,CAAC,gBAAgB,SAAS,oBAAoB,CAAC,oCAAoC,CAAC;AAAA,IACrJ;AACA,QAAI,OAAO,MAAM,UAAU,UAAU;AACnC,aAAO,KAAK,EAAE,OAAO,UAAU,MAAM,iBAAiB,MAAM,GAAG,CAAC,UAAU,SAAS,oBAAoB,CAAC,8BAA8B,CAAC;AAAA,IACzI;AAAA,EACF;AACF;AAEA,SAAS,kBACP,MACA,QACA,UACM;AACN,MAAI,KAAK,WAAW,GAAG;AACrB,aAAS,KAAK,EAAE,OAAO,UAAU,MAAM,QAAQ,SAAS,uDAAuD,CAAC;AAChH;AAAA,EACF;AAEA,QAAM,eAAe,oBAAI,IAAY;AACrC,QAAM,cAAc,oBAAI,IAAY;AAEpC,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,OAAO,KAAK,CAAC;AACnB,UAAM,IAAI,QAAQ,CAAC;AACnB,QAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC7C,aAAO,KAAK,EAAE,OAAO,UAAU,MAAM,gBAAgB,MAAM,GAAG,SAAS,sBAAsB,CAAC,qBAAqB,CAAC;AACpH;AAAA,IACF;AAGA,QAAI,KAAK,SAAS,QAAW;AAC3B,aAAO,KAAK,EAAE,OAAO,UAAU,MAAM,iBAAiB,MAAM,GAAG,CAAC,SAAS,SAAS,sBAAsB,CAAC,4BAA4B,CAAC;AAAA,IACxI,WAAW,OAAO,KAAK,SAAS,YAAY,CAAC,OAAO,UAAU,KAAK,IAAI,GAAG;AACxE,aAAO,KAAK,EAAE,OAAO,UAAU,MAAM,gBAAgB,MAAM,GAAG,CAAC,SAAS,SAAS,4BAA4B,CAAC;AAAA,IAChH,OAAO;AACL,UAAI,YAAY,IAAI,KAAK,IAAI,GAAG;AAC9B,eAAO,KAAK,EAAE,OAAO,UAAU,MAAM,kBAAkB,MAAM,GAAG,CAAC,SAAS,SAAS,yBAAyB,KAAK,IAAI,GAAG,CAAC;AAAA,MAC3H;AACA,kBAAY,IAAI,KAAK,IAAI;AAAA,IAC3B;AAGA,QAAI,KAAK,WAAW,QAAW;AAC7B,aAAO,KAAK,EAAE,OAAO,UAAU,MAAM,iBAAiB,MAAM,GAAG,CAAC,WAAW,SAAS,sBAAsB,CAAC,uBAAuB,CAAC;AAAA,IACrI,WAAW,OAAO,KAAK,WAAW,YAAY,CAAE,mBAAyC,SAAS,KAAK,MAAM,GAAG;AAC9G,aAAO,KAAK,EAAE,OAAO,UAAU,MAAM,kBAAkB,MAAM,GAAG,CAAC,WAAW,SAAS,2BAA2B,mBAAmB,KAAK,IAAI,CAAC,GAAG,CAAC;AAAA,IACnJ;AAGA,QAAI,KAAK,SAAS,QAAW;AAC3B,aAAO,KAAK,EAAE,OAAO,UAAU,MAAM,iBAAiB,MAAM,GAAG,CAAC,SAAS,SAAS,sBAAsB,CAAC,qBAAqB,CAAC;AAAA,IACjI,WAAW,OAAO,KAAK,SAAS,YAAY,CAAE,KAAK,KAAgB,WAAW,GAAG,GAAG;AAClF,aAAO,KAAK,EAAE,OAAO,UAAU,MAAM,kBAAkB,MAAM,GAAG,CAAC,SAAS,SAAS,6BAA6B,CAAC;AAAA,IACnH;AAGA,QAAI,KAAK,aAAa,QAAW;AAC/B,aAAO,KAAK,EAAE,OAAO,UAAU,MAAM,iBAAiB,MAAM,GAAG,CAAC,aAAa,SAAS,sBAAsB,CAAC,yBAAyB,CAAC;AAAA,IACzI;AAGA,QAAI,KAAK,SAAS,WAAc,OAAO,KAAK,SAAS,YAAY,KAAK,SAAS,QAAQ,MAAM,QAAQ,KAAK,IAAI,IAAI;AAChH,aAAO,KAAK,EAAE,OAAO,UAAU,MAAM,gBAAgB,MAAM,GAAG,CAAC,SAAS,SAAS,gCAAgC,CAAC;AAAA,IACpH,WAAW,KAAK,SAAS,UAAa,OAAO,KAAK,WAAW,YAAY,CAAC,QAAQ,OAAO,OAAO,EAAE,SAAS,KAAK,MAAM,GAAG;AACvH,eAAS,KAAK,EAAE,OAAO,UAAU,MAAM,GAAG,CAAC,SAAS,SAAS,GAAG,KAAK,MAAM,kBAAkB,CAAC,wBAAwB,CAAC;AAAA,IACzH;AAGA,QAAI,OAAO,KAAK,cAAc,UAAU;AACtC,UAAI,aAAa,IAAI,KAAK,SAAS,GAAG;AACpC,eAAO,KAAK,EAAE,OAAO,UAAU,MAAM,kBAAkB,MAAM,GAAG,CAAC,cAAc,SAAS,iCAAiC,KAAK,SAAS,IAAI,CAAC;AAAA,MAC9I;AACA,mBAAa,IAAI,KAAK,SAAS;AAAA,IACjC;AAGA,QAAI,MAAM,QAAQ,KAAK,SAAS,GAAG;AACjC,iBAAW,OAAO,KAAK,WAAW;AAChC,YAAI,OAAO,QAAQ,YAAY,CAAC,aAAa,IAAI,GAAG,GAAG;AACrD,iBAAO,KAAK;AAAA,YACV,OAAO;AAAA,YAAU,MAAM;AAAA,YAAsB,MAAM,GAAG,CAAC;AAAA,YACvD,SAAS,aAAa,KAAK,QAAQ,CAAC,gBAAgB,GAAG;AAAA,YACvD,YAAY,2CAA2C,GAAG;AAAA,UAC5D,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACzOA;AAgBO,SAAS,iBACd,QACA,SACuB;AACvB,QAAM,SAAwC,CAAC;AAC/C,QAAM,WAA4C,CAAC;AAEnD,gCAA8B,QAAQ,SAAS,QAAQ,QAAQ;AAC/D,gCAA8B,QAAQ,SAAS,QAAQ,QAAQ;AAC/D,4BAA0B,QAAQ,SAAS,QAAQ;AACnD,6BAA2B,QAAQ,SAAS,MAAM;AAClD,mCAAiC,QAAQ,QAAQ,QAAQ;AAEzD,SAAO,EAAE,QAAQ,OAAO,WAAW,GAAG,OAAO,YAAY,QAAQ,SAAS;AAC5E;AAMA,SAAS,cAAc,GAAmB;AACxC,SAAO,EAAE,QAAQ,QAAQ,EAAE,EAAE,QAAQ,QAAQ,GAAG;AAClD;AAEA,SAASC,mBAAkB,WAA6B;AACtD,QAAM,SAAmB,CAAC;AAC1B,QAAM,QAAQ;AACd,MAAI;AACJ,UAAQ,QAAQ,MAAM,KAAK,SAAS,OAAO,KAAM,QAAO,KAAK,MAAM,CAAC,CAAC;AACrE,SAAO;AACT;AAEA,SAAS,qBACP,QAAgB,YAAoB,WACX;AACzB,QAAM,aAAa,cAAc,UAAU;AAC3C,SAAO,UAAU,KAAK,CAAC,OAAO;AAC5B,QAAI,GAAG,WAAW,OAAO,YAAY,EAAG,QAAO;AAC/C,UAAM,SAAS,cAAc,GAAG,IAAI;AACpC,QAAI,WAAW,WAAY,QAAO;AAClC,UAAM,QAAQ,WAAW,MAAM,GAAG;AAClC,UAAM,QAAQ,OAAO,MAAM,GAAG;AAC9B,QAAI,MAAM,WAAW,MAAM,OAAQ,QAAO;AAC1C,WAAO,MAAM,MAAM,CAAC,KAAK,QAAQ,QAAQ,MAAM,GAAG,KAAK,IAAI,WAAW,GAAG,KAAK,MAAM,GAAG,EAAE,WAAW,GAAG,CAAC;AAAA,EAC1G,CAAC;AACH;AAEA,SAAS,gBAAgB,QAAgB,MAAsC;AAC7E,MAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,MAAI,CAAC,MAAM,EAAE,SAAS,MAAM,EAAG,QAAO,KAAK,KAAK,CAAC,MAAM,uBAAuB,KAAK,EAAE,IAAI,CAAC;AAC1F,MAAI,CAAC,OAAO,OAAO,EAAE,SAAS,MAAM,EAAG,QAAO,KAAK,KAAK,CAAC,MAAM,SAAS,KAAK,EAAE,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,MAAM,eAAe,KAAK,EAAE,IAAI,CAAC;AACrI,MAAI,CAAC,KAAK,EAAE,SAAS,MAAM,EAAG,QAAO,KAAK,KAAK,CAAC,MAAM,oBAAoB,KAAK,EAAE,IAAI,CAAC;AACtF,SAAO;AACT;AAMA,SAAS,8BACP,QACA,KACA,QACA,UACM;AACN,aAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,OAAO,aAAa,GAAG;AAC9D,UAAM,IAAI,iBAAiB,GAAG;AAC9B,UAAM,WAAW,IAAI,QAAQ,GAAG;AAChC,QAAI,aAAa,GAAI;AAErB,UAAM,SAAS,IAAI,UAAU,GAAG,QAAQ,EAAE,YAAY;AACtD,UAAM,YAAY,IAAI,UAAU,WAAW,CAAC;AAE5C,UAAM,WAAW,qBAAqB,QAAQ,WAAW,IAAI,SAAS;AACtE,QAAI,CAAC,UAAU;AACb,aAAO,KAAK;AAAA,QACV,OAAO;AAAA,QAAY,MAAM;AAAA,QAAuB,MAAM;AAAA,QACtD,SAAS,UAAU,MAAM,IAAI,SAAS;AAAA,QACtC,YAAY,qCAAqC,MAAM,IAAI,SAAS;AAAA,MACtE,CAAC;AACD;AAAA,IACF;AAEA,UAAM,aAAa,OAAO,KAAK,IAAI;AACnC,QAAI,WAAW,WAAW,EAAG;AAE7B,UAAM,MAAM,gBAAgB,QAAQ,IAAI,IAAI;AAC5C,QAAI,CAAC,KAAK;AACR,eAAS,KAAK,EAAE,OAAO,YAAY,MAAM,GAAG,SAAS,8BAA8B,MAAM,IAAI,SAAS,sCAAsC,CAAC;AAC7I;AAAA,IACF;AAEA,UAAM,gBAAgB,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAC3D,eAAW,aAAa,YAAY;AAClC,UAAI,CAAC,cAAc,IAAI,SAAS,GAAG;AACjC,iBAAS,KAAK,EAAE,OAAO,YAAY,MAAM,GAAG,CAAC,IAAI,SAAS,IAAI,SAAS,UAAU,SAAS,wCAAwC,IAAI,IAAI,IAAI,CAAC;AAAA,MACjJ;AAAA,IACF;AAEA,UAAM,eAAe,IAAI,IAAI,UAAU;AACvC,eAAW,SAAS,IAAI,QAAQ;AAC9B,UAAI,MAAM,YAAY,CAAC,MAAM,iBAAiB,CAAC,aAAa,IAAI,MAAM,IAAI,GAAG;AAC3E,iBAAS,KAAK,EAAE,OAAO,YAAY,MAAM,GAAG,SAAS,uBAAuB,MAAM,IAAI,WAAW,IAAI,IAAI,iCAAiC,CAAC;AAAA,MAC7I;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,8BACP,QACA,KACA,QACA,UACM;AACN,aAAW,CAAC,KAAK,OAAO,KAAK,OAAO,QAAQ,OAAO,aAAa,GAAG;AACjE,UAAM,IAAI,iBAAiB,GAAG;AAC9B,UAAM,WAAW,IAAI,QAAQ,GAAG;AAChC,QAAI,aAAa,GAAI;AAErB,UAAM,SAAS,IAAI,UAAU,GAAG,QAAQ,EAAE,YAAY;AACtD,UAAM,YAAY,IAAI,UAAU,WAAW,CAAC;AAE5C,UAAM,WAAW,qBAAqB,QAAQ,WAAW,IAAI,SAAS;AACtE,QAAI,CAAC,UAAU;AACb,aAAO,KAAK,EAAE,OAAO,YAAY,MAAM,yBAAyB,MAAM,GAAG,SAAS,UAAU,MAAM,IAAI,SAAS,4DAA4D,CAAC;AAC5K;AAAA,IACF;AAEA,UAAM,eAAe,IAAI,IAAIA,mBAAkB,SAAS,IAAI,CAAC;AAC7D,eAAW,aAAa,OAAO,KAAK,OAAO,GAAG;AAC5C,UAAI,CAAC,aAAa,IAAI,SAAS,GAAG;AAChC,iBAAS,KAAK,EAAE,OAAO,YAAY,MAAM,GAAG,CAAC,IAAI,SAAS,IAAI,SAAS,UAAU,SAAS,sDAAsD,CAAC,GAAG,YAAY,EAAE,KAAK,IAAI,CAAC,IAAI,CAAC;AAAA,MACnL;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,0BACP,QACA,KACA,UACM;AACN,WAAS,IAAI,GAAG,IAAI,OAAO,UAAU,QAAQ,KAAK;AAChD,UAAM,QAAQ,OAAO,UAAU,CAAC;AAChC,UAAM,UAAU,IAAI,UAAU,KAAK,CAAC,OAAO;AACzC,UAAI;AAAE,eAAO,IAAI,OAAO,MAAM,WAAW,EAAE,KAAK,GAAG,IAAI;AAAA,MAAG,QAAQ;AAAE,eAAO,GAAG,KAAK,SAAS,MAAM,WAAW;AAAA,MAAG;AAAA,IAClH,CAAC;AACD,QAAI,CAAC,SAAS;AACZ,eAAS,KAAK,EAAE,OAAO,YAAY,MAAM,aAAa,CAAC,iBAAiB,SAAS,wBAAwB,MAAM,WAAW,uCAAuC,CAAC;AAAA,IACpK;AAAA,EACF;AACF;AAEA,SAAS,2BACP,QACA,KACA,QACM;AACN,WAAS,IAAI,GAAG,IAAI,OAAO,KAAK,QAAQ,KAAK;AAC3C,UAAM,OAAO,OAAO,KAAK,CAAC;AAC1B,UAAM,WAAW,qBAAqB,KAAK,QAAQ,KAAK,MAAM,IAAI,SAAS;AAC3E,QAAI,CAAC,UAAU;AACb,aAAO,KAAK;AAAA,QACV,OAAO;AAAA,QAAY,MAAM;AAAA,QAAuB,MAAM,QAAQ,CAAC;AAAA,QAC/D,SAAS,aAAa,KAAK,IAAI,YAAY,KAAK,MAAM,IAAI,KAAK,IAAI;AAAA,QACnE,YAAY,gBAAgB,KAAK,MAAM,IAAI,KAAK,IAAI;AAAA,MACtD,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,SAAS,iCACP,QACA,QACA,UACM;AACN,MAAI,OAAO,KAAK,WAAW,EAAG;AAE9B,QAAM,cAAc,oBAAI,IAAY;AACpC,QAAM,kBAAkB;AAExB,WAAS,IAAI,GAAG,IAAI,OAAO,KAAK,QAAQ,KAAK;AAC3C,UAAM,OAAO,OAAO,KAAK,CAAC;AAG1B,QAAI,KAAK,MAAM;AACb,YAAM,UAAU,KAAK,UAAU,KAAK,IAAI;AACxC,sBAAgB,YAAY;AAC5B,UAAI;AACJ,cAAQ,QAAQ,gBAAgB,KAAK,OAAO,OAAO,MAAM;AACvD,cAAM,UAAU,MAAM,CAAC,KAAK,MAAM,CAAC;AACnC,YAAI,CAAC,YAAY,IAAI,OAAO,GAAG;AAC7B,mBAAS,KAAK,EAAE,OAAO,YAAY,MAAM,QAAQ,CAAC,UAAU,SAAS,6BAA6B,OAAO,uDAAuD,CAAC;AAAA,QACnK;AAAA,MACF;AAAA,IACF;AAGA,QAAI,KAAK,MAAM;AACb,sBAAgB,YAAY;AAC5B,UAAI;AACJ,cAAQ,QAAQ,gBAAgB,KAAK,KAAK,IAAI,OAAO,MAAM;AACzD,cAAM,UAAU,MAAM,CAAC,KAAK,MAAM,CAAC;AACnC,YAAI,CAAC,YAAY,IAAI,OAAO,GAAG;AAC7B,mBAAS,KAAK,EAAE,OAAO,YAAY,MAAM,QAAQ,CAAC,UAAU,SAAS,6BAA6B,OAAO,uDAAuD,CAAC;AAAA,QACnK;AAAA,MACF;AAAA,IACF;AAEA,QAAI,KAAK,UAAW,aAAY,IAAI,KAAK,SAAS;AAAA,EACpD;AAGA,wBAAsB,OAAO,MAAM,MAAM;AAC3C;AAEA,SAAS,sBAAsB,MAAkB,QAA6C;AAC5F,QAAM,QAAQ,oBAAI,IAAsB;AACxC,aAAW,QAAQ,MAAM;AACvB,QAAI,KAAK,WAAW;AAClB,YAAM,IAAI,KAAK,WAAW,KAAK,aAAa,CAAC,CAAC;AAAA,IAChD;AAAA,EACF;AAEA,QAAM,UAAU,oBAAI,IAAY;AAChC,QAAM,UAAU,oBAAI,IAAY;AAEhC,WAAS,IAAI,MAAuB;AAClC,QAAI,QAAQ,IAAI,IAAI,EAAG,QAAO;AAC9B,QAAI,QAAQ,IAAI,IAAI,EAAG,QAAO;AAC9B,YAAQ,IAAI,IAAI;AAChB,YAAQ,IAAI,IAAI;AAChB,eAAW,YAAY,MAAM,IAAI,IAAI,KAAK,CAAC,GAAG;AAC5C,UAAI,IAAI,QAAQ,GAAG;AACjB,eAAO,KAAK,EAAE,OAAO,YAAY,MAAM,oBAAoB,MAAM,QAAQ,SAAS,2CAA2C,IAAI,aAAQ,QAAQ,IAAI,CAAC;AACtJ,eAAO;AAAA,MACT;AAAA,IACF;AACA,YAAQ,OAAO,IAAI;AACnB,WAAO;AAAA,EACT;AAEA,aAAW,QAAQ,MAAM,KAAK,GAAG;AAC/B,QAAI,CAAC,QAAQ,IAAI,IAAI,EAAG,KAAI,IAAI;AAAA,EAClC;AACF;;;ACrQA;AAKA,SAAS,WAAAC,UAAS,0BAA0B;AASrC,SAAS,eACd,QACA,UACuB;AACvB,QAAM,SAAwC,CAAC;AAC/C,QAAM,WAA4C,CAAC;AAEnD,QAAM,UAAU,IAAIA,SAAQ;AAAA,IAC1B,iBAAiB;AAAA,MACf,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,QAAQ;AAAA;AAAA,MACR,QAAQ;AAAA;AAAA,MACR,iBAAiB;AAAA,MACjB,cAAc;AAAA,IAChB;AAAA,IACA,uBAAuB;AAAA,EACzB,CAAC;AAGD,UAAQ;AAAA,IACN;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWF;AAGA,QAAM,WAAW,6BAA6B,MAAM;AACpD,MAAI,UAAU;AACZ,UAAM,WAAW,QAAQ,iBAAiB,yBAAyB,QAAQ;AAC3E,eAAW,QAAQ,SAAS,sBAAsB,GAAG;AACnD,YAAM,MAAM,KAAK,eAAe;AAChC,YAAM,SAAS,OAAO,QAAQ,WAAW,MAAM,IAAI,eAAe;AAClE,YAAM,OAAO,KAAK,cAAc;AAChC,YAAM,WAAW,OAAO,uBAAuB,IAAI,MAAM;AAEzD,UAAI,KAAK,YAAY,MAAM,mBAAmB,OAAO;AACnD,eAAO,KAAK;AAAA,UACV,OAAO;AAAA,UAAU,MAAM;AAAA,UAAiB,MAAM;AAAA,UAC9C,SAAS,6BAA6B,MAAM;AAAA,UAC5C,YAAY;AAAA,QACd,CAAC;AAAA,MACH,WAAW,KAAK,YAAY,MAAM,mBAAmB,SAAS;AAC5D,iBAAS,KAAK,EAAE,OAAO,UAAU,MAAM,UAAU,SAAS,uBAAuB,MAAM,GAAG,CAAC;AAAA,MAC7F;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW,qBAAqB,MAAM;AAC5C,MAAI,UAAU;AACZ,UAAM,WAAW,QAAQ,iBAAiB,yBAAyB,QAAQ;AAC3E,eAAW,QAAQ,SAAS,sBAAsB,GAAG;AACnD,YAAM,MAAM,KAAK,eAAe;AAChC,YAAM,SAAS,OAAO,QAAQ,WAAW,MAAM,IAAI,eAAe;AAClE,YAAM,OAAO,KAAK,cAAc;AAChC,YAAM,WAAW,OAAO,cAAc,IAAI,MAAM;AAEhD,UAAI,KAAK,YAAY,MAAM,mBAAmB,OAAO;AACnD,eAAO,KAAK;AAAA,UACV,OAAO;AAAA,UAAU,MAAM;AAAA,UAAiB,MAAM;AAAA,UAC9C,SAAS,6BAA6B,MAAM;AAAA,UAC5C,YAAY;AAAA,QACd,CAAC;AAAA,MACH,WAAW,KAAK,YAAY,MAAM,mBAAmB,SAAS;AAC5D,iBAAS,KAAK,EAAE,OAAO,UAAU,MAAM,UAAU,SAAS,uBAAuB,MAAM,GAAG,CAAC;AAAA,MAC7F;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,QAAQ,OAAO,WAAW,GAAG,OAAO,UAAU,QAAQ,SAAS;AAC1E;AAEA,SAAS,6BAA6B,QAAyC;AAC7E,MAAI,CAAC,OAAO,iBAAiB,OAAO,KAAK,OAAO,aAAa,EAAE,WAAW,EAAG,QAAO;AAEpF,QAAM,QAAQ,CAAC,sCAAsC;AACrD,MAAI,MAAM;AACV,aAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,OAAO,aAAa,GAAG;AAC9D,UAAM,WAAW,IAAI,QAAQ,GAAG;AAChC,QAAI,aAAa,GAAI;AACrB,UAAM,SAAS,IAAI,UAAU,GAAG,QAAQ;AACxC,UAAM,YAAY,IAAI,UAAU,WAAW,CAAC;AAE5C,UAAM,KAAK,gBAAgB,GAAG,MAAM,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC,GAAG;AACpE,UAAM,KAAK,kBAAkB,GAAG,wBAAwB,MAAM,OAAO,SAAS,WAAW,GAAG,IAAI;AAChG,UAAM,KAAK,gBAAgB,GAAG,6BAA6B,GAAG,oBAAoB;AAClF,UAAM,KAAK,sDAAsD,GAAG,WAAW;AAC/E,UAAM,KAAK,KAAK;AAChB;AAAA,EACF;AACA,QAAM,KAAK,GAAG;AACd,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,qBAAqB,QAAyC;AACrE,MAAI,CAAC,OAAO,QAAQ,OAAO,KAAK,WAAW,EAAG,QAAO;AAErD,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,aAAW,QAAQ,OAAO,MAAM;AAC9B,QAAI,KAAK,MAAM;AACb,YAAM,KAAK,oBAAoB,KAAK,IAAI,MAAM,KAAK,UAAU,KAAK,MAAM,MAAM,CAAC,CAAC,GAAG;AACnF,YAAM,KAAK,sBAAsB,KAAK,IAAI,wBAAwB,KAAK,MAAM,OAAO,KAAK,IAAI,eAAe,KAAK,IAAI,IAAI;AAAA,IAC3H,OAAO;AACL,YAAM,KAAK,sBAAsB,KAAK,IAAI,wBAAwB,KAAK,MAAM,OAAO,KAAK,IAAI,KAAK;AAAA,IACpG;AAEA,QAAI,KAAK,WAAW;AAClB,YAAM,KAAK,eAAe,KAAK,SAAS,6BAA6B,KAAK,IAAI,IAAI;AAAA,IACpF;AAEA,QAAI,KAAK,UAAU;AACjB,YAAM,KAAK,oBAAoB,KAAK,IAAI,mBAAmB;AAC3D,YAAM,KAAK,wBAAwB,KAAK,kBAAkB,iBAAiB,KAAK,IAAI,SAAS,KAAK;AAClG,YAAM,KAAK,KAAK;AAAA,IAClB;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,KAAK,GAAG;AACd,SAAO,MAAM,KAAK,IAAI;AACxB;;;AHzIA,IAAM,kBAAkB,CAAC,aAAa;AAEtC,IAAM,iBAAiB,CAAC,aAAa,WAAW,UAAU,SAAS;AACnE,IAAM,cAAc,CAAC,QAAQ,cAAc,aAAa,QAAQ,WAAW,UAAU;AACrF,IAAM,sBAAsB,CAAC,UAAU,SAAS,UAAU,QAAQ;AAClE,IAAM,uBAAuB,CAAC,QAAQ,QAAQ,UAAU;AACxD,IAAM,mBAAmB,CAAC,eAAe,mBAAmB;AAMrD,SAAS,eAAe,QAAoD;AACjF,QAAM,SAA4B,CAAC;AAGnC,aAAW,SAAS,iBAAiB;AACnC,QAAI,CAAC,OAAO,KAAK,GAAG;AAClB,aAAO,KAAK;AAAA,QACV,QAAQ;AAAA,QACR;AAAA,QACA,SAAS,2BAA2B,KAAK;AAAA,QACzC,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MAAI,OAAO,eAAe,OAAO,OAAO,gBAAgB,UAAU;AAChE,WAAO,KAAK;AAAA,MACV,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,SAAS;AAAA,MACT,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAGA,MAAI,OAAO,WAAW,OAAO,OAAO,YAAY,UAAU;AACxD,QAAI,CAAC,eAAe,SAAS,OAAO,OAAO,GAAG;AAC5C,aAAO,KAAK;AAAA,QACV,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,SAAS,oBAAoB,OAAO,OAAO,qBAAqB,eAAe,KAAK,IAAI,CAAC;AAAA,QACzF,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MAAI,OAAO,SAAS,MAAM,QAAQ,OAAO,KAAK,GAAG;AAC/C,eAAW,QAAQ,OAAO,OAAO;AAC/B,UAAI,CAAC,YAAY,SAAS,IAAc,GAAG;AACzC,eAAO,KAAK;AAAA,UACV,QAAQ;AAAA,UACR,OAAO;AAAA,UACP,SAAS,0BAA0B,IAAI,qBAAqB,YAAY,KAAK,IAAI,CAAC;AAAA,UAClF,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAGA,MAAI,OAAO,OAAO,OAAO,OAAO,QAAQ,UAAU;AAChD,UAAM,MAAM,OAAO;AACnB,QAAI,IAAI,YAAY,CAAC,oBAAoB,SAAS,IAAI,QAAkB,GAAG;AACzE,aAAO,KAAK;AAAA,QACV,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,SAAS,yBAAyB,IAAI,QAAQ,qBAAqB,oBAAoB,KAAK,IAAI,CAAC;AAAA,QACjG,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AACA,QAAI,IAAI,YAAY,IAAI,aAAa,YAAY,CAAC,IAAI,QAAQ;AAC5D,aAAO,KAAK;AAAA,QACV,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,SAAS;AAAA,QACT,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MAAI,OAAO,UAAU,OAAO,OAAO,WAAW,UAAU;AACtD,UAAM,SAAS,OAAO;AACtB,QAAI,OAAO,UAAU,MAAM,QAAQ,OAAO,MAAM,GAAG;AACjD,iBAAW,OAAO,OAAO,QAAQ;AAC/B,YAAI,CAAC,qBAAqB,SAAS,GAAa,GAAG;AACjD,iBAAO,KAAK;AAAA,YACV,QAAQ;AAAA,YACR,OAAO;AAAA,YACP,SAAS,0BAA0B,GAAG,qBAAqB,qBAAqB,KAAK,IAAI,CAAC;AAAA,YAC1F,UAAU;AAAA,UACZ,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,OAAO,eAAe,OAAO,OAAO,gBAAgB,UAAU;AAChE,UAAM,KAAK,OAAO;AAClB,QAAI,GAAG,QAAQ,CAAC,iBAAiB,SAAS,GAAG,IAAc,GAAG;AAC5D,aAAO,KAAK;AAAA,QACV,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,SAAS,8BAA8B,GAAG,IAAI,qBAAqB,iBAAiB,KAAK,IAAI,CAAC;AAAA,QAC9F,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AACA,QAAI,GAAG,kBAAkB,OAAO,GAAG,kBAAkB,YAAY,GAAG,gBAAgB,IAAI;AACtF,aAAO,KAAK;AAAA,QACV,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,SAAS;AAAA,QACT,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MAAI,OAAO,aAAa,OAAO,OAAO,cAAc,UAAU;AAC5D,UAAM,YAAY,OAAO;AACzB,UAAM,aAAa,CAAC,aAAa,YAAY,cAAc;AAE3D,eAAW,aAAa,YAAY;AAClC,YAAM,OAAO,UAAU,SAAS;AAChC,UAAI,SAAS,OAAW;AAExB,UAAI,OAAO,SAAS,SAAU;AAE9B,UAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC7C,eAAO,KAAK;AAAA,UACV,QAAQ;AAAA,UACR,OAAO,aAAa,SAAS;AAAA,UAC7B,SAAS,GAAG,SAAS;AAAA,UACrB,UAAU;AAAA,QACZ,CAAC;AACD;AAAA,MACF;AAEA,YAAM,UAAU;AAChB,UAAI,OAAO,QAAQ,YAAY,YAAY,QAAQ,QAAQ,KAAK,MAAM,IAAI;AACxE,eAAO,KAAK;AAAA,UACV,QAAQ;AAAA,UACR,OAAO,aAAa,SAAS;AAAA,UAC7B,SAAS;AAAA,UACT,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAEA,UAAI,QAAQ,SAAS,WAAc,CAAC,MAAM,QAAQ,QAAQ,IAAI,KAAK,QAAQ,KAAK,KAAK,CAAC,MAAM,OAAO,MAAM,QAAQ,IAAI;AACnH,eAAO,KAAK;AAAA,UACV,QAAQ;AAAA,UACR,OAAO,aAAa,SAAS;AAAA,UAC7B,SAAS;AAAA,UACT,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAEA,UAAI,QAAQ,QAAQ,UAAa,OAAO,QAAQ,QAAQ,UAAU;AAChE,eAAO,KAAK;AAAA,UACV,QAAQ;AAAA,UACR,OAAO,aAAa,SAAS;AAAA,UAC7B,SAAS;AAAA,UACT,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAWO,SAAS,qBACd,QACA,SACA,SAC8B;AAC9B,QAAM,gBAAgB,SAAS,iBAAiB;AAChD,QAAM,aAAa,IAAI,IAAI,SAAS,cAAc,CAAC,CAAC;AAEpD,QAAM,YAA2C,CAAC;AAClD,QAAM,cAA+C,CAAC;AACtD,QAAM,SAAuC;AAAA,IAC3C,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AAEA,MAAI,CAAC,WAAW,IAAI,QAAQ,GAAG;AAC7B,UAAM,eAAe,eAAe,MAAM;AAC1C,WAAO,eAAe;AACtB,cAAU,KAAK,GAAG,aAAa,MAAM;AACrC,gBAAY,KAAK,GAAG,aAAa,QAAQ;AAEzC,QAAI,CAAC,aAAa,QAAQ;AACxB,aAAO,gBAAgB;AACvB,UAAI,cAAe,QAAO;AAAA,IAC5B,OAAO;AACL,aAAO,kBAAkB;AAAA,IAC3B;AAAA,EACF;AAEA,QAAM,cAAc;AAEpB,MAAI,CAAC,WAAW,IAAI,UAAU,GAAG;AAC/B,QAAI,CAAC,SAAS;AACZ,kBAAY,KAAK,EAAE,OAAO,YAAY,MAAM,IAAI,SAAS,+DAA+D,CAAC;AAAA,IAC3H,OAAO;AACL,YAAM,iBAAiB,iBAAiB,aAAa,OAAO;AAC5D,aAAO,iBAAiB;AACxB,gBAAU,KAAK,GAAG,eAAe,MAAM;AACvC,kBAAY,KAAK,GAAG,eAAe,QAAQ;AAE3C,UAAI,CAAC,eAAe,QAAQ;AAC1B,eAAO,gBAAgB,OAAO,iBAAiB;AAC/C,YAAI,cAAe,QAAO;AAAA,MAC5B,OAAO;AACL,eAAO,kBAAkB;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,WAAW,IAAI,QAAQ,GAAG;AAC7B,QAAI,CAAC,SAAS;AACZ,kBAAY,KAAK,EAAE,OAAO,UAAU,MAAM,IAAI,SAAS,8DAA8D,CAAC;AAAA,IACxH,OAAO;AACL,YAAM,eAAe,eAAe,aAAa,OAAO;AACxD,aAAO,eAAe;AACtB,gBAAU,KAAK,GAAG,aAAa,MAAM;AACrC,kBAAY,KAAK,GAAG,aAAa,QAAQ;AAEzC,UAAI,CAAC,aAAa,QAAQ;AACxB,eAAO,gBAAgB,OAAO,iBAAiB;AAAA,MACjD,OAAO;AACL,eAAO,kBAAkB;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAEA,SAAO,SAAS,UAAU,WAAW;AACrC,SAAO;AACT;AAEO,SAAS,uBAAuB,QAA8C;AACnF,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,OAAO,SAAS,6BAA6B,0BAA0B;AAClF,MAAI,OAAO,cAAe,OAAM,KAAK,uBAAuB,OAAO,aAAa,EAAE;AAClF,MAAI,OAAO,gBAAiB,OAAM,KAAK,yBAAyB,OAAO,eAAe,EAAE;AAExF,MAAI,OAAO,OAAO,SAAS,GAAG;AAC5B,UAAM,KAAK,IAAI,WAAW,OAAO,OAAO,MAAM,IAAI;AAClD,eAAW,OAAO,OAAO,QAAQ;AAC/B,YAAM,KAAK,MAAM,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,IAAI,OAAO,EAAE;AACzD,UAAI,IAAI,WAAY,OAAM,KAAK,sBAAyB,IAAI,UAAU,EAAE;AAAA,IAC1E;AAAA,EACF;AAEA,MAAI,OAAO,SAAS,SAAS,GAAG;AAC9B,UAAM,KAAK,IAAI,aAAa,OAAO,SAAS,MAAM,IAAI;AACtD,eAAW,QAAQ,OAAO,UAAU;AAClC,YAAM,KAAK,MAAM,KAAK,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,OAAO,EAAE;AAAA,IAC9D;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;;;AN7QA,IAAM,YAA4B,CAAC,QAAQ,cAAc,aAAa,QAAQ,WAAW,UAAU;AAE5F,SAAS,eAAe,QAAkC;AAC/D,SAAO;AAAA,IACL,MAAM,IAAI,OAAO;AACf,YAAM,YAAY,KAAK,IAAI;AAC3B,YAAM,cAAc,SAAS,OAAO,SAAS;AAE7C,YAAM,SAA4B;AAAA,QAChC,SAAS,CAAC;AAAA,QACV,YAAY,oBAAI,IAAI;AAAA,QACpB,YAAY,oBAAI,IAAI;AAAA,QACpB,gBAAgB,CAAC;AAAA,QACjB,kBAAkB,CAAC;AAAA,QACnB,UAAU;AAAA,MACZ;AAEA,YAAM,cAAmB,cAAQ,OAAO,WAAW;AAGnD,YAAM,UAAU,CAAC,SAAgC;AAC/C,cAAM,aAAa;AAAA,UACZ,WAAK,aAAa,IAAI;AAAA;AAAA,UACtB,WAAK,aAAa,OAAO,IAAI;AAAA;AAAA,UAC7B,WAAK,aAAa,WAAW,OAAO,IAAI;AAAA;AAAA,UACxC,WAAK,aAAa,WAAW,IAAI;AAAA;AAAA,UACjC,WAAK,aAAa,UAAU,OAAO,IAAI;AAAA;AAAA,UACvC,WAAK,aAAa,OAAO,IAAI;AAAA;AAAA,QACpC;AACA,mBAAW,KAAK,YAAY;AAC1B,cAAO,eAAW,CAAC,EAAG,QAAO;AAAA,QAC/B;AACA,eAAO;AAAA,MACT;AAEA,YAAM,aAAa,QAAQ,QAAQ;AACnC,YAAM,kBAAkB,QAAQ,aAAa;AAG7C,UAAI,YAAY,SAAS,MAAM,GAAG;AAChC,YAAI,YAAY;AAEd,gBAAM,OAAU,gBAAY,YAAY,EAAE,eAAe,KAAK,CAAC,EAC5D,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,EAC7B,IAAI,CAAC,MAAM,EAAE,IAAI;AAEpB,gBAAM,eAAe,OAAO;AAC5B,qBAAW,OAAO,MAAM;AACtB,gBAAI,gBAAgB,CAAC,aAAa,SAAS,GAAG,EAAG;AACjD,mBAAO,QAAQ,KAAK,GAAG;AAAA,UACzB;AAGA,cAAI,OAAO,QAAQ,WAAW,GAAG;AAC/B,mBAAO,QAAQ,KAAK,SAAS;AAAA,UAC/B,OAAO;AAEL,kBAAM,YAAe,gBAAY,UAAU,EACxC,OAAO,CAAC,MAAM,EAAE,SAAS,KAAK,KAAK,CAAC,EAAE,SAAS,UAAU,KAAK,MAAM,UAAU;AACjF,gBAAI,UAAU,SAAS,GAAG;AACxB,qBAAO,QAAQ,QAAQ,SAAS;AAAA,YAClC;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,YAAM,kBAAkB,CAAC,cAAsB,QAC7C,QAAQ,YACH,cAAmB,WAAK,aAAa,QAAQ,IACzC,WAAK,cAAmB,WAAK,aAAa,QAAQ,GAAG,GAAG;AAGnE,YAAM,uBAAuB,CAAC,cAAsB,QAClD,QAAQ,YACH,mBAAwB,WAAK,aAAa,aAAa,IACnD,WAAK,mBAAwB,WAAK,aAAa,aAAa,GAAG,GAAG;AAG7E,UAAI,YAAY,SAAS,YAAY,GAAG;AACtC,cAAM,QAAQ,yBAAyB;AACvC,cAAMC,eAAmB,cAAQ,OAAO,WAAW;AAEnD,mBAAW,OAAO,OAAO,SAAS;AAChC,gBAAM,WAAW,gBAAgBA,cAAa,GAAG;AAGjD,gBAAM,SAAY,eAAW,QAAQ,IAAI,kBAAkB,QAAQ,IAAI,CAAC;AACxE,gBAAM,YAAwD,CAAC;AAG/D,gBAAM,YAAiB,WAAK,UAAU,iBAAiB;AACvD,cAAO,eAAW,SAAS,GAAG;AAC5B,sBAAU,KAAK,GAAG,qBAAqB,SAAS,CAAC;AAAA,UACnD;AAGA,cAAO,eAAW,QAAQ,GAAG;AAC3B,kBAAM,aAAgB,gBAAY,QAAQ,EACvC,OAAO,CAAC,MAAM,EAAE,SAAS,KAAK,KAAK,CAAC,EAAE,SAAS,UAAU,KAAK,MAAM,cAAc,MAAM,iBAAiB;AAC5G,uBAAW,QAAQ,YAAY;AAC7B,kBAAI;AACF,sBAAM,WAAW,qBAA0B,WAAK,UAAU,IAAI,CAAC;AAC/D,0BAAU,KAAK,GAAG,QAAQ;AAAA,cAC5B,QAAQ;AAAA,cAER;AAAA,YACF;AAAA,UACF;AAEA,gBAAM,WAA4B,MAAM,SAAS,QAAQ,SAAS;AAClE,iBAAO,WAAW,IAAI,KAAK,QAAQ;AAAA,QACrC;AAAA,MACF;AAGA,UAAI,YAAY,SAAS,WAAW,GAAG;AACrC,cAAM,gBAAgB,uBAAuB;AAC7C,cAAMA,eAAmB,cAAQ,OAAO,WAAW;AAEnD,mBAAW,OAAO,OAAO,SAAS;AAChC,gBAAM,gBAAgB,qBAAqBA,cAAa,GAAG;AAC3D,gBAAM,YAAe,eAAW,aAAa,IACzC,yBAAyB,aAAa,IACtC,CAAC;AAEL,gBAAM,WAAW,cAAc,QAAQ,SAAS;AAChD,mBAAS,aAAa;AAEtB,cAAI,SAAS,WAAW;AACtB,uBAAW,WAAW,SAAS,eAAe;AAC5C,qBAAO,iBAAiB,KAAK;AAAA,gBAC3B,QAAQ;AAAA,gBACR,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,UAAU;AAAA,cACZ,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,UAAI,YAAY,SAAS,MAAM,GAAG;AAChC,cAAMA,eAAmB,cAAQ,OAAO,WAAW;AACnD,cAAM,gBAAgB,uBAAuB;AAE7C,mBAAW,OAAO,OAAO,SAAS;AAChC,gBAAM,gBAAgB,qBAAqBA,cAAa,GAAG;AAC3D,gBAAM,YAAe,eAAW,aAAa,IACzC,yBAAyB,aAAa,IACtC,CAAC;AAEL,gBAAM,WAAW,cAAc,QAAQ,SAAS;AAChD,gBAAM,YAAY,gBAAgB,SAAS,GAAG;AAG9C,gBAAM,SAAS,kBAAkB,KAAK,WAAW,SAAS;AAC1D,iBAAO,WAAW,IAAI,KAAK,MAAM;AAAA,QACnC;AAAA,MACF;AAGA,UAAI,YAAY,SAAS,SAAS,GAAG;AACnC,cAAM,UAAU,wBAAwB;AACxC,cAAM,SAAS,OAAO,UAAU;AAEhC,mBAAW,CAAC,MAAM,IAAI,KAAK,OAAO,YAAY;AAC5C,gBAAM,QAAQ,QAAQ,SAAS,KAAK,MAAM;AAC1C,qBAAW,QAAQ,OAAO;AACxB,iBAAK,WAAgB,WAAK,QAAQ,KAAK,QAAQ;AAAA,UACjD;AACA,iBAAO,eAAe,KAAK,GAAG,KAAK;AAAA,QACrC;AAAA,MACF;AAGA,UAAI,YAAY,SAAS,UAAU,GAAG;AACpC,cAAM,eAAe,eAAe,MAA4C;AAChF,eAAO,iBAAiB,KAAK,GAAG,YAAY;AAAA,MAC9C;AAEA,aAAO,WAAW,KAAK,IAAI,IAAI;AAC/B,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAKA,SAAS,kBACP,YACA,WACA,YACiB;AAEjB,QAAM,SAAS,oBAAI,IAAiD;AAEpE,aAAW,MAAM,WAAW;AAC1B,UAAM,WAAW,GAAG,KAAK,MAAM,GAAG,EAAE,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,WAAW,GAAG,CAAC;AACzE,UAAM,WAAW,SAAS,SAAS,SAAS,CAAC,KAAK;AAClD,QAAI,CAAC,OAAO,IAAI,QAAQ,EAAG,QAAO,IAAI,UAAU,CAAC,CAAC;AAClD,WAAO,IAAI,QAAQ,EAAG,KAAK,EAAE;AAAA,EAC/B;AAEA,QAAM,SAA4C,CAAC;AACnD,MAAI,aAAa;AAEjB,aAAW,CAAC,UAAU,GAAG,KAAK,QAAQ;AACpC,UAAM,QAA0C,IAAI,IAAI,CAAC,IAAI,OAAO;AAAA,MAClE,OAAO,IAAI;AAAA,MACX,QAAQ,GAAG;AAAA,MACX,UAAU;AAAA,MACV,aAAa,GAAG,eAAe,GAAG,GAAG,MAAM,IAAI,GAAG,IAAI;AAAA,MACtD,YAAY,CAAC;AAAA,IACf,EAAE;AAEF,WAAO,KAAK,EAAE,MAAM,GAAG,QAAQ,eAAe,QAAQ,YAAY,MAAM,CAAC;AACzE,kBAAc,MAAM;AAAA,EACtB;AAEA,SAAO,EAAE,QAAQ,WAAW;AAC9B;;;APxKA;;;AiB5EA;AAQA,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AACtB;AAAA,EACE,WAAAC;AAAA,EACA,cAAAC;AAAA,OAMK;AAOP,IAAM,gBAAgB,oBAAI,IAAI;AAAA,EAC5B;AAAA,EAAM;AAAA,EAAa;AAAA,EACnB;AAAA,EAAc;AAAA,EAAa;AAAA,EAAc;AAAA,EACzC;AAAA,EAAc;AAAA,EAAa;AAAA,EAAc;AAC3C,CAAC;AAYM,SAAS,UACd,WACA,SACW;AACX,QAAM,WAAW,SAAS,mBAAmB;AAAA,IAC3C;AAAA,IAAS;AAAA,IAAW;AAAA,IAAY;AAAA,IAAgB;AAAA,IAAW;AAAA,EAC7D;AAEA,QAAM,UAAqB,CAAC;AAC5B,QAAM,UAAU,IAAID,SAAQ,EAAE,iBAAiB,EAAE,QAAQ,MAAM,EAAE,CAAC;AAElE,aAAW,YAAY,WAAW;AAChC,UAAM,eAAoB,cAAQ,QAAQ;AAC1C,QAAI,CAAI,eAAW,YAAY,EAAG;AAElC,QAAI;AACF,YAAM,aAAa,QAAQ,oBAAoB,YAAY;AAC3D,YAAM,aAAa,WAAW,cAAc;AAE5C,iBAAW,SAAS,YAAY;AAC9B,cAAM,OAAO,MAAM,QAAQ;AAC3B,cAAM,iBAAiB,SAAS,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC;AACxD,YAAI,CAAC,eAAgB;AAErB,cAAM,MAAM,oBAAoB,OAAO,YAAY;AACnD,YAAI,IAAK,SAAQ,KAAK,GAAG;AAAA,MAC3B;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,KAAK,gCAAgC,QAAQ,KAAM,IAAc,OAAO;AAAA,IAClF;AAAA,EACF;AAEA,SAAO,gBAAgB,OAAO;AAChC;AAUO,SAAS,oBACd,iBAC8B;AAC9B,QAAM,SAAS,oBAAI,IAA6B;AAChD,QAAM,UAAU,IAAIA,SAAQ,EAAE,iBAAiB,EAAE,QAAQ,MAAM,EAAE,CAAC;AAElE,aAAW,YAAY,iBAAiB;AACtC,UAAM,eAAoB,cAAQ,QAAQ;AAC1C,QAAI,CAAI,eAAW,YAAY,EAAG;AAElC,QAAI;AACF,YAAM,aAAa,QAAQ,oBAAoB,YAAY;AAC3D,YAAM,aAAa,gCAAgC,UAAU;AAE7D,iBAAW,CAAC,UAAU,KAAK,KAAK,YAAY;AAC1C,eAAO,IAAI,UAAU,KAAK;AAAA,MAC5B;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,KAAK,8CAA8C,QAAQ,KAAM,IAAc,OAAO;AAAA,IAChG;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,mBACd,YACA,cACA,iBACA,UACgB;AAChB,QAAM,eAAe,CAAC,GAAG,YAAY;AAErC,MAAI,UAAU;AACZ,UAAM,mBAAwB,cAAQ,QAAQ;AAC9C,QAAO,eAAW,gBAAgB,GAAG;AACnC,YAAM,aACH,gBAAY,gBAAgB,EAC5B;AAAA,QAAO,CAAC,MACP,EAAE,SAAS,KAAK,KAAK,CAAC,EAAE,SAAS,UAAU,KAAK,MAAM,cAAc,MAAM;AAAA,MAC5E,EACC,IAAI,CAAC,MAAW,WAAK,kBAAkB,CAAC,CAAC;AAC5C,mBAAa,KAAK,GAAG,UAAU;AAAA,IACjC;AAAA,EACF;AAEA,QAAM,OAAO,UAAU,YAAY;AACnC,QAAM,iBAAiB,oBAAoB,eAAe;AAE1D,SAAO,EAAE,YAAY,MAAM,gBAAgB,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE;AACjF;AAMA,SAAS,oBAAoB,OAA6B,YAAoC;AAC5F,QAAM,SAAyB,CAAC;AAEhC,QAAM,gBAAgB,MAAM,WAAW;AACvC,QAAM,cAAc,cAAc,SAAS,IAAI,cAAc,CAAC,EAAE,QAAQ,IAAI;AAE5E,aAAW,QAAQ,MAAM,cAAc,GAAG;AACxC,UAAM,QAAQ,qBAAqB,IAAI;AACvC,QAAI,MAAO,QAAO,KAAK,KAAK;AAAA,EAC9B;AAEA,MAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,SAAO,EAAE,MAAM,MAAM,QAAQ,GAAG,YAAY,QAAQ,SAAS,YAAY;AAC3E;AAEA,SAAS,qBAAqB,MAA8C;AAC1E,QAAM,OAAO,KAAK,QAAQ;AAC1B,QAAM,WAAW,KAAK,YAAY;AAClC,MAAI,CAAC,SAAU,QAAO;AAEtB,QAAM,EAAE,UAAU,WAAW,IAAI,YAAY,SAAS,QAAQ,EAAE,KAAK,CAAC;AAEtE,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,UAAU,CAAC,KAAK,iBAAiB;AAAA,IACjC,YAAY,WAAW,SAAS,IAAI,aAAa;AAAA,IACjD,eAAe,cAAc,IAAI,IAAI;AAAA,EACvC;AACF;AAEA,SAAS,YAAY,UAA8D;AACjF,QAAM,UAAU,SAAS,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,MAAM,UAAU,MAAM,WAAW;AAGxG,QAAM,iBAAiB,QAAQ,OAAO,CAAC,MAAM,eAAe,KAAK,CAAC,CAAC;AACnE,MAAI,eAAe,SAAS,KAAK,eAAe,WAAW,QAAQ,QAAQ;AACzE,WAAO,EAAE,UAAU,UAAU,YAAY,eAAe,IAAI,CAAC,MAAM,EAAE,QAAQ,gBAAgB,EAAE,CAAC,EAAE;AAAA,EACpG;AAGA,QAAM,iBAAiB,QAAQ,OAAO,CAAC,MAAM,QAAQ,KAAK,CAAC,CAAC;AAC5D,MAAI,eAAe,SAAS,KAAK,eAAe,WAAW,QAAQ,QAAQ;AACzE,WAAO,EAAE,UAAU,UAAU,YAAY,eAAe;AAAA,EAC1D;AAEA,MAAI,QAAQ,WAAW,EAAG,QAAO,EAAE,UAAU,QAAQ,CAAC,GAAG,YAAY,CAAC,EAAE;AACxE,SAAO,EAAE,UAAU,QAAQ,CAAC,KAAK,UAAU,YAAY,CAAC,EAAE;AAC5D;AAMA,SAAS,gCAAgC,YAAsD;AAC7F,QAAM,SAAS,oBAAI,IAA6B;AAChD,QAAME,gBAAe,oBAAI,IAAI,CAAC,OAAO,QAAQ,OAAO,UAAU,OAAO,CAAC;AACtE,QAAMC,cAAqC,EAAE,KAAK,OAAO,MAAM,QAAQ,KAAK,OAAO,QAAQ,UAAU,OAAO,QAAQ;AAEpH,QAAM,kBAAkB,WAAW,qBAAqBF,YAAW,cAAc;AAEjF,aAAW,QAAQ,iBAAiB;AAClC,UAAM,OAAO,KAAK,cAAc;AAChC,QAAI,KAAK,QAAQ,MAAMA,YAAW,yBAA0B;AAE5D,UAAM,aAAa;AACnB,UAAM,aAAa,WAAW,QAAQ,EAAE,YAAY;AACpD,QAAI,CAACC,cAAa,IAAI,UAAU,EAAG;AAEnC,UAAM,aAAa,WAAW,cAAc,EAAE,QAAQ,EAAE,KAAK;AAC7D,QAAI,eAAe,YAAY,eAAe,cAAe;AAE7D,UAAM,OAAO,KAAK,aAAa;AAC/B,QAAI,KAAK,SAAS,EAAG;AAErB,UAAM,YAAY,eAAe,KAAK,CAAC,CAAC;AACxC,QAAI,CAAC,UAAW;AAEhB,UAAM,iBAAkC,CAAC;AACzC,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,MAAM,KAAK,CAAC;AAClB,UAAI,IAAI,QAAQ,MAAMD,YAAW,wBAAwB;AACvD,cAAM,WAAW,IAAI,cAAcA,YAAW,sBAAsB,EAAE,YAAY;AAClF,mBAAW,WAAW,UAAU;AAC9B,gBAAM,OAAO,oBAAoB,OAAO;AACxC,cAAI,KAAM,gBAAe,KAAK,IAAI;AAAA,QACpC;AAAA,MACF;AAAA,IACF;AAEA,QAAI,eAAe,SAAS,GAAG;AAC7B,aAAO,IAAI,GAAGE,YAAW,UAAU,CAAC,IAAI,SAAS,IAAI,cAAc;AAAA,IACrE;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,oBAAoB,MAAkC;AAC7D,QAAM,OAAO,KAAK,QAAQ,EAAE,KAAK;AAEjC,QAAM,cAAc,KAAK,MAAM,4CAA4C;AAC3E,MAAI,CAAC,YAAa,QAAO;AAEzB,QAAM,SAAS,YAAY,CAAC;AAC5B,QAAM,QAAQ,YAAY,CAAC;AAC3B,QAAM,QAAkB,CAAC;AAEzB,QAAM,aAAa;AACnB,MAAI;AACJ,UAAQ,QAAQ,WAAW,KAAK,IAAI,OAAO,MAAM;AAC/C,UAAM,SAAS,MAAM,CAAC;AACtB,UAAM,OAAO,MAAM,CAAC,EAAE,KAAK;AAC3B,QAAI,WAAW,iBAAiB,WAAW,OAAQ;AAEnD,QAAI,WAAW,QAAQ;AACrB,YAAM,cAAc,KAAK,MAAM,cAAc;AAC7C,UAAI,aAAa;AACf,cAAM,SAAS,YAAY,CAAC,EAAE,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,gBAAgB,EAAE,CAAC;AACxF,cAAM,KAAK,QAAQ,OAAO,KAAK,GAAG,CAAC,GAAG;AAAA,MACxC;AAAA,IACF,WAAW,WAAW,YAAY;AAChC,YAAM,KAAK,UAAU;AAAA,IACvB,OAAO;AACL,YAAM,KAAK,MAAM;AAAA,IACnB;AAAA,EACF;AAEA,SAAO,EAAE,OAAO,QAAQ,MAAM;AAChC;AAEA,SAAS,eAAe,MAA2B;AACjD,QAAM,OAAO,KAAK,QAAQ,EAAE,KAAK;AAEjC,MAAK,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,KAAO,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,GAAI;AAChG,WAAO,KAAK,MAAM,GAAG,EAAE;AAAA,EACzB;AAEA,MAAI,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,GAAG;AAC9C,WAAO,KAAK,MAAM,GAAG,EAAE,EAAE,QAAQ,gBAAgB,CAAC,MAAM,CAAC;AAAA,EAC3D;AAEA,SAAO;AACT;AAMA,SAAS,gBAAgB,MAA4B;AACnD,QAAM,OAAO,oBAAI,IAAqB;AACtC,aAAW,OAAO,MAAM;AACtB,QAAI,CAAC,KAAK,IAAI,IAAI,IAAI,EAAG,MAAK,IAAI,IAAI,MAAM,GAAG;AAAA,EACjD;AACA,SAAO,MAAM,KAAK,KAAK,OAAO,CAAC;AACjC;;;AC3SA;AAOA,SAAS,UAAU,KAAa,KAAqB;AACnD,SAAO,KAAK,MAAM,KAAK,OAAO,KAAK,MAAM,MAAM,EAAE,IAAI;AACvD;AAEA,SAAS,aAAa,QAAgB,WAA2B;AAC/D,QAAM,KAAK,KAAK,IAAI,EAAE,SAAS,EAAE;AACjC,QAAM,OAAO,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC;AAClD,SAAO,GAAG,MAAM,GAAG,SAAS,IAAI,EAAE,IAAI,IAAI;AAC5C;AAEA,SAAS,eAAuB;AAC9B,QAAM,MAAM,MAAM,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC;AACvD,SAAO,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,MAAM,CAAC,CAAC,KAAK,IAAI,UAAU,GAAG,CAAC,GAAG,SAAS,EAAE,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;AACrI;AAKA,SAAS,mBACP,WACA,WACA,cACA,aACS;AACT,QAAM,QAAQ,UAAU,YAAY;AAEpC,MAAI,gBAAgB,aAAa;AAC/B,WAAO,qBAAqB,WAAW;AAAA,EACzC;AAEA,MAAI,MAAM,WAAW,QAAQ,KAAK,UAAU,OAAQ,QAAO,aAAa,SAAS,SAAS;AAC1F,MAAI,UAAU,YAAY,UAAU,UAAW,QAAO,UAAU,GAAG,MAAM;AACzE,MAAI,UAAU,UAAW,QAAO;AAChC,MAAI,MAAM,WAAW,MAAM,KAAK,UAAU,MAAO,SAAO,oBAAI,KAAK,GAAE,YAAY;AAC/E,MAAI,UAAU,OAAQ,QAAO,aAAa;AAC1C,MAAI,MAAM,WAAW,MAAM,EAAG,QAAO;AACrC,MAAI,UAAU,UAAU,UAAU,QAAS,QAAO,CAAC;AACnD,MAAI,UAAU,WAAW,UAAU,YAAY,UAAU,UAAW,QAAO,KAAK,MAAM,KAAK,OAAO,IAAI,GAAK,IAAI;AAE/G,SAAO,aAAa,QAAQ,SAAS;AACvC;AAEO,SAAS,0BAA6C;AAC3D,SAAO;AAAA,IACL,iBAAiB,QAA8C;AAC7D,YAAM,SAAkC,CAAC;AACzC,YAAM,KAAK,KAAK,IAAI,EAAE,SAAS,EAAE;AACjC,YAAM,OAAO,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC;AAElD,iBAAW,SAAS,OAAO,QAAQ;AAEjC,YAAI,MAAM,WAAY;AAEtB,YAAI,MAAM,iBAAiB,OAAW;AAGtC,cAAM,eAAe,MAAM,KAAK,SAAS,KAAK,KAAK,CAAC,MAAM;AAC1D,cAAM,cAAc,eAChB,MAAM,KAAK,QAAQ,QAAQ,EAAE,IAC7B;AAEJ,YAAI,QAAQ,mBAAmB,MAAM,MAAM,MAAM,MAAM,cAAc,WAAW;AAGhF,YAAI,MAAM,UAAU,OAAO,UAAU,UAAU;AAC7C,kBAAQ,GAAG,KAAK,cAAc,EAAE,IAAI,IAAI;AAAA,QAC1C;AAEA,eAAO,MAAM,IAAI,IAAI;AAAA,MACvB;AACA,aAAO;AAAA,IACT;AAAA,IAEA,kBAAkB,SAAgE;AAChF,YAAM,SAAS,oBAAI,IAAuC;AAC1D,iBAAW,UAAU,SAAS;AAC5B,cAAM,SAAS,KAAK,iBAAiB,MAAM;AAC3C,eAAO,IAAI,OAAO,WAAW,CAAC,MAAM,CAAC;AAAA,MACvC;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;ACzFA;AASA,IAAM,gBAAgB;AAMtB,SAAS,4BAA4B,gBAAkC;AACrE,QAAM,WAAW,eAAe,MAAM,QAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAC9D,SAAO,SAAS,OAAO,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC,EAAE,SAAS,GAAG,KAAK,EAAE,SAAS,GAAG,CAAC;AACvF;AAKA,SAAS,oBAAoB,WAA2D;AACtF,QAAM,MAAM,oBAAI,IAAyB;AACzC,aAAW,OAAO,WAAW;AAC3B,QAAI,CAAC,IAAI,IAAI,IAAI,WAAW,EAAG,KAAI,IAAI,IAAI,aAAa,oBAAI,IAAI,CAAC;AACjE,QAAI,CAAC,IAAI,IAAI,IAAI,WAAW,EAAG,KAAI,IAAI,IAAI,aAAa,oBAAI,IAAI,CAAC;AACjE,QAAI,IAAI,IAAI,WAAW,EAAG,IAAI,IAAI,WAAW;AAC7C,QAAI,IAAI,IAAI,WAAW,EAAG,IAAI,IAAI,WAAW;AAAA,EAC/C;AACA,SAAO;AACT;AAKA,SAAS,aACP,YACA,WACA,WAAmB,eACT;AACV,QAAM,UAAU,oBAAI,IAAY;AAChC,QAAM,QAAiD,CAAC;AAExD,aAAW,KAAK,YAAY;AAC1B,QAAI,UAAU,IAAI,CAAC,GAAG;AACpB,YAAM,KAAK,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;AACjC,cAAQ,IAAI,CAAC;AAAA,IACf;AAAA,EACF;AAEA,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,EAAE,OAAO,MAAM,IAAI,MAAM,MAAM;AACrC,QAAI,SAAS,SAAU;AAEvB,eAAW,YAAY,UAAU,IAAI,KAAK,KAAK,CAAC,GAAG;AACjD,UAAI,CAAC,QAAQ,IAAI,QAAQ,GAAG;AAC1B,gBAAQ,IAAI,QAAQ;AACpB,cAAM,KAAK,EAAE,OAAO,UAAU,OAAO,QAAQ,EAAE,CAAC;AAAA,MAClD;AAAA,IACF;AAAA,EACF;AACA,SAAO,MAAM,KAAK,OAAO;AAC3B;AAKA,SAAS,sBACP,QACA,iBACe;AACf,QAAM,WAAW,IAAI,IAAI,MAAM;AAC/B,QAAM,WAA0B,CAAC;AAEjC,aAAW,UAAU,iBAAiB;AACpC,eAAW,MAAM,OAAO,WAAW;AACjC,UAAI,GAAG,cAAc,KAAK,CAAC,MAAM,SAAS,IAAI,CAAC,CAAC,GAAG;AACjD,iBAAS,KAAK,EAAE;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAKA,SAAS,uBACP,YACA,gBACA,WACQ;AACR,QAAM,iBAAiB,oBAAI,IAAI,CAAC,GAAG,YAAY,GAAG,cAAc,CAAC;AACjE,QAAM,QAAkB,CAAC,cAAc;AAEvC,QAAM,UAAU,IAAI,IAAI,UAAU;AAClC,aAAW,KAAK,gBAAgB;AAC9B,UAAM,QAAQ,QAAQ,IAAI,CAAC,IAAI,GAAG,CAAC,aAAa;AAChD,UAAM,KAAK,KAAK,WAAW,CAAC,CAAC,KAAK,KAAK,IAAI;AAAA,EAC7C;AAEA,aAAW,OAAO,WAAW;AAC3B,QAAI,eAAe,IAAI,IAAI,WAAW,KAAK,eAAe,IAAI,IAAI,WAAW,GAAG;AAC9E,YAAM,QAAQ,IAAI,gBAAgB,SAAS;AAC3C,YAAM,KAAK,KAAK,WAAW,IAAI,WAAW,CAAC,IAAI,KAAK,IAAI,IAAI,WAAW,KAAK,WAAW,IAAI,WAAW,CAAC,EAAE;AAAA,IAC3G;AAAA,EACF;AAEA,QAAM,KAAK,yDAAyD;AACpE,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,WAAW,MAAsB;AACxC,SAAO,KAAK,QAAQ,kBAAkB,GAAG;AAC3C;AAUO,SAAS,uBAAuC;AACrD,SAAO;AAAA,IACL,QACE,UACA,YACA,iBACc;AAEd,YAAM,eAAqC,CAAC;AAC5C,iBAAW,MAAM,WAAW,OAAO,GAAG;AACpC,qBAAa,KAAK,GAAG,GAAG,SAAS;AAAA,MACnC;AAGA,YAAM,aAAuB,CAAC;AAC9B,iBAAW,WAAW,UAAU;AAC9B,YAAI,QAAQ,gBAAgB;AAC1B,qBAAW,KAAK,GAAG,4BAA4B,QAAQ,cAAc,CAAC;AAAA,QACxE;AAAA,MACF;AAGA,YAAM,YAAY,oBAAoB,YAAY;AAClD,YAAM,iBAAiB,aAAa,YAAY,SAAS;AAGzD,YAAM,oBAAoB,sBAAsB,gBAAgB,eAAe;AAG/E,YAAM,kBAAkB,CAAC,GAAG,IAAI,IAAI,gBACjC,OAAO,CAAC,MAAM,EAAE,UAAU,KAAK,CAAC,OAAO,kBAAkB,SAAS,EAAE,CAAC,CAAC,EACtE,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAG5B,YAAM,iBAAiB,SAAS,IAAI,CAAC,MAAM,EAAE,KAAK;AAGlD,YAAM,cAAc,uBAAuB,YAAY,gBAAgB,YAAY;AAGnF,YAAM,QAAQ,kBAAkB;AAChC,YAAM,WAAW,QAAQ,KAAK,aAAa,QAAQ,IAAI,SAAS,QAAQ,IAAI,WAAW;AAEvF,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACnLA;AAwBA,IAAM,aAAa;AACnB,IAAM,aAAa;AACnB,IAAM,kBAAkB;AACxB,IAAM,yBAAyB;AAM/B,SAAS,YAAY,IAAyB;AAC5C,SAAO,GAAG,GAAG,MAAM,IAAI,GAAG,IAAI;AAChC;AAEA,SAAS,SAAS,IAAyB;AACzC,SAAO,GAAG,KAAK,QAAQ,aAAa,EAAE;AACxC;AAEA,SAAS,gBAAgB,WAAsD;AAC7E,QAAM,SAAS,oBAAI,IAA2B;AAC9C,aAAW,MAAM,WAAW;AAC1B,UAAM,OAAO,SAAS,EAAE;AACxB,QAAI,CAAC,OAAO,IAAI,IAAI,EAAG,QAAO,IAAI,MAAM,CAAC,CAAC;AAC1C,WAAO,IAAI,IAAI,EAAG,KAAK,EAAE;AAAA,EAC3B;AACA,SAAO;AACT;AAEA,SAAS,eAAe,IAA0B;AAChD,MAAI,GAAG,WAAW,MAAO,QAAO;AAChC,QAAM,UAAU,GAAG,cAAc,CAAC,GAAG,OAAO,CAAC,MAAM,MAAM,UAAU;AACnE,SAAO,OAAO,WAAW;AAC3B;AAEA,SAAS,iBAAiB,IAA0B;AAClD,MAAI,GAAG,WAAW,MAAO,QAAO;AAChC,QAAM,UAAU,GAAG,cAAc,CAAC,GAAG,OAAO,CAAC,MAAM,MAAM,UAAU;AACnE,SAAO,OAAO,SAAS;AACzB;AAEA,SAAS,YAAY,IAAyB;AAC5C,UAAQ,GAAG,QAAQ;AAAA,IACjB,KAAK;AAAQ,aAAO;AAAA,IACpB,KAAK;AAAO,aAAO;AAAA,IACnB,KAAK;AAAA,IACL,KAAK;AAAS,aAAO;AAAA,IACrB,KAAK;AAAU,aAAO;AAAA,IACtB;AAAS,aAAO;AAAA,EAClB;AACF;AAEA,SAAS,iBAAiB,IAAiB,QAAgB,WAA4B;AACrF,QAAM,QAAQ,CAAC,GAAG,MAAM,IAAI,GAAG,MAAM,IAAI,GAAG,IAAI,EAAE;AAClD,MAAI,UAAW,OAAM,KAAK,eAAe,SAAS,GAAG;AACrD,aAAW,SAAS,GAAG,cAAc,CAAC,GAAG;AACvC,QAAI,UAAU,WAAY,OAAM,KAAK,GAAG,KAAK,mBAAmB;AAAA,EAClE;AACA,SAAO,MAAM,KAAK,GAAG;AACvB;AAEA,SAAS,gBAAgB,IAAiB,QAA0B;AAClE,UAAQ,QAAQ;AAAA,IACd,KAAK;AAAU,aAAO,CAAC,0CAAiB,mCAAe;AAAA,IACvD,KAAK;AACH,aAAO,eAAe,EAAE,IACpB,CAAC,sCAAa,sCAAa,IAC3B,CAAC,sCAAa,iEAAoB;AAAA,IACxC,KAAK;AAAU,aAAO,CAAC,sCAAa,kDAAU;AAAA,IAC9C,KAAK;AAAU,aAAO,CAAC,0CAAiB,gDAAkB;AAAA,IAC1D,KAAK;AAAU,aAAO,CAAC,4CAAS;AAAA,IAChC;AAAS,aAAO,CAAC,oCAAW;AAAA,EAC9B;AACF;AAEA,SAAS,WAAW,OAAe,IAAiB,QAAgB,WAA8B;AAChG,SAAO;AAAA,IACL;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA,aAAa,iBAAiB,IAAI,QAAQ,SAAS;AAAA,IACnD,YAAY,gBAAgB,IAAI,MAAM;AAAA,EACxC;AACF;AAcA,SAAS,cAAc,GAA6B;AAClD,SAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,EAAE,QAAQ,OAAO,EAAE,MAAM;AAC1D;AAYA,SAAS,wBAAuC;AAC9C,SAAO;AAAA,IACL,SAAS;AAAA,IACT,UAAU;AAAA,IACV,SAAS,MAAM,YAAY,QAAQ;AACjC,UAAI,OAAsB,CAAC;AAC3B,iBAAW,SAAS,OAAO,OAAO,GAAG;AACnC,YAAI,MAAM,SAAS,KAAK,OAAQ,QAAO;AAAA,MACzC;AACA,UAAI,KAAK,WAAW,EAAG,QAAO;AAE9B,YAAM,OAAO,KAAK,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM;AACjD,YAAM,OAAO,KAAK,KAAK,gBAAgB;AACvC,YAAM,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE,WAAW,OAAO;AACvE,YAAM,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE,WAAW,QAAQ;AAClD,UAAI,CAAC,KAAM,QAAO;AAElB,YAAM,QAAoB,CAAC;AAC3B,YAAM,KAAK;AACX,YAAM,KAAK,WAAW,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC;AACvD,UAAI,KAAM,OAAM,KAAK,WAAW,MAAM,SAAS,GAAG,MAAM,QAAQ,EAAE,CAAC;AACnE,UAAI,IAAK,OAAM,KAAK,WAAW,MAAM,SAAS,GAAG,KAAK,UAAU,EAAE,CAAC;AACnE,UAAI,KAAM,OAAM,KAAK,WAAW,MAAM,SAAS,GAAG,MAAM,UAAU,EAAE,CAAC;AACrE,UAAI,IAAK,OAAM,KAAK,WAAW,MAAM,SAAS,GAAG,KAAK,UAAU,EAAE,CAAC;AAEnE,aAAO;AAAA,QACL,MAAM,GAAG,IAAI;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV;AAAA,QACA,cAAc,CAAC,GAAG,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,qBAAoC;AAC3C,SAAO;AAAA,IACL,SAAS;AAAA,IACT,UAAU;AAAA,IACV,SAAS,MAAM,WAAW;AACxB,YAAM,QAAQ,UAAU,OAAO,cAAc;AAC7C,UAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,YAAM,QAAQ,MAAM,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,MAAM,WAAW,IAAI,GAAG,IAAI,MAAM,CAAC;AAC5E,aAAO;AAAA,QACL,MAAM,GAAG,IAAI;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV;AAAA,QACA,cAAc,CAAC,GAAG,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,yBAAwC;AAC/C,SAAO;AAAA,IACL,SAAS;AAAA,IACT,UAAU;AAAA,IACV,SAAS,MAAM,YAAY,QAAQ;AACjC,YAAM,UAAU,MAAM,KAAK,OAAO,QAAQ,CAAC;AAC3C,UAAI,QAAQ,SAAS,EAAG,QAAO;AAC/B,cAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE,MAAM;AAEtE,YAAM,aAAa,QAAQ,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM;AAChE,YAAM,YAAY,QAAQ,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM;AAC/D,YAAM,WAAW,QAAQ,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,MAAM,iBAAiB,CAAC,KAAK,eAAe,CAAC,CAAC;AACnF,YAAM,WAAW,QAAQ,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,QAAQ;AAChE,YAAM,YAAY,QAAQ,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,QAAQ;AACjE,UAAI,CAAC,cAAc,CAAC,UAAW,QAAO;AAEtC,YAAM,QAAoB,CAAC;AAC3B,YAAM,KAAK,WAAW,MAAM,SAAS,GAAG,YAAY,OAAO,CAAC;AAC5D,YAAM,KAAK,WAAW,MAAM,SAAS,GAAG,WAAW,UAAU,QAAQ,CAAC;AACtE,UAAI,SAAU,OAAM,KAAK,WAAW,MAAM,SAAS,GAAG,UAAU,QAAQ,QAAQ,CAAC;AACjF,UAAI,SAAU,OAAM,KAAK,WAAW,MAAM,SAAS,GAAG,UAAU,WAAW,QAAQ,CAAC;AACpF,UAAI,UAAW,OAAM,KAAK,WAAW,MAAM,SAAS,GAAG,WAAW,WAAW,QAAQ,CAAC;AAEtF,aAAO;AAAA,QACL,MAAM,GAAG,IAAI;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV;AAAA,QACA,cAAc,CAAC,GAAG,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,yBAAwC;AAC/C,SAAO;AAAA,IACL,SAAS;AAAA,IACT,UAAU;AAAA,IACV,SAAS,MAAM,WAAW;AACxB,YAAM,QAAQ,UAAU;AAAA,QAAO,CAAC,OAC9B,GAAG,KAAK,YAAY,EAAE,SAAS,OAAO,KAAK,GAAG,KAAK,YAAY,EAAE,SAAS,MAAM;AAAA,MAClF;AACA,UAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,YAAM,QAAQ,MAAM,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,MAAM,WAAW,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC,CAAC;AACrF,aAAO;AAAA,QACL,MAAM,GAAG,IAAI;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV;AAAA,QACA,cAAc,CAAC,GAAG,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,wBAAuC;AAC9C,SAAO;AAAA,IACL,SAAS;AAAA,IACT,UAAU;AAAA,IACV,SAAS,MAAM,WAAW;AACxB,YAAM,OAAO,UAAU,KAAK,CAAC,OAAO,GAAG,WAAW,MAAM;AACxD,UAAI,CAAC,KAAM,QAAO;AAClB,aAAO;AAAA,QACL,MAAM,GAAG,IAAI;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,OAAO,CAAC;AAAA,UACN,OAAO;AAAA,UACP,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,aAAa,UAAU,KAAK,MAAM,IAAI,KAAK,IAAI;AAAA,UAC/C,YAAY,CAAC,sCAAa,kDAAU;AAAA,QACtC,CAAC;AAAA,QACD,cAAc,CAAC,YAAY,IAAI,CAAC;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,oBAAmC;AAC1C,SAAO;AAAA,IACL,SAAS;AAAA,IACT,UAAU;AAAA,IACV,SAAS,MAAM,WAAW,SAAS,MAAM;AACvC,UAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,YAAM,QAAQ,IAAI,IAAI,UAAU,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC;AAClE,YAAM,QAAoB,CAAC;AAC3B,iBAAW,OAAO,KAAK,MAAM,GAAG,CAAC,GAAG;AAClC,cAAM,KAAK,MAAM,IAAI,GAAG;AACxB,YAAI,GAAI,OAAM,KAAK,WAAW,MAAM,SAAS,GAAG,IAAI,YAAY,EAAE,CAAC,CAAC;AAAA,MACtE;AACA,UAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,aAAO;AAAA,QACL,MAAM,GAAG,IAAI;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV;AAAA,QACA,cAAc,CAAC,GAAG,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AACF;AAMA,SAAS,mBACP,YACA,SACA,aACA,gBACiB;AACjB,QAAM,WAA4B,CAAC;AACnC,QAAM,UAAU,oBAAI,IAAY;AAChC,QAAM,YAAY,CAAC,GAAG,UAAU;AAEhC,QAAM,SAAiC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,EAAE;AAC7D,YAAU,KAAK,CAAC,GAAG,MAAM,OAAO,EAAE,QAAQ,IAAI,OAAO,EAAE,QAAQ,KAAK,EAAE,aAAa,SAAS,EAAE,aAAa,MAAM;AAEjH,SAAO,SAAS,SAAS,eAAe,UAAU,SAAS,GAAG;AAC5D,QAAI,UAAU,IAAI,YAAY;AAC9B,aAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,YAAM,UAAU,UAAU,CAAC,EAAE,aAAa,OAAO,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;AACvE,YAAM,QAAQ,UAAU,CAAC,EAAE,aAAa,OAAO,QAAQ,SAAS,MAAM,QAAQ;AAC9E,UAAI,QAAQ,WAAW;AAAE,oBAAY;AAAO,kBAAU;AAAA,MAAG;AAAA,IAC3D;AACA,QAAI,YAAY,MAAM,aAAa,EAAG;AAEtC,UAAM,SAAS,UAAU,OAAO,SAAS,CAAC,EAAE,CAAC;AAC7C,aAAS,KAAK,MAAM;AACpB,WAAO,aAAa,QAAQ,CAAC,MAAM,QAAQ,IAAI,CAAC,CAAC;AAEjD,QAAI,QAAQ,OAAO,KAAK,QAAQ,OAAO,QAAQ,QAAQ,kBAAkB,SAAS,UAAU,WAAY;AAAA,EAC1G;AACA,SAAO;AACT;AAMA,SAAS,mBAAmB,QAAyB,YAAqC;AACxF,QAAM,aAAa,oBAAI,IAAgD;AACvE,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,MAAM,WAAW,EAAG;AAC9B,UAAM,QAAQ,MAAM,MAAM,CAAC;AAC3B,QAAI,MAAM,WAAW,YAAY,MAAM,WAAW,SAAS;AACzD,YAAM,MAAM,YAAY,MAAM,QAAQ;AACtC,YAAM,IAAI,WAAW,IAAI,GAAG;AAC5B,UAAI,EAAG,GAAE;AAAA,UACJ,YAAW,IAAI,KAAK,EAAE,IAAI,MAAM,UAAU,OAAO,EAAE,CAAC;AAAA,IAC3D;AAAA,EACF;AAEA,QAAM,SAA0B,CAAC;AACjC,aAAW,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,KAAK,YAAY;AAC7C,QAAI,SAAS,GAAG;AACd,YAAM,YAAY,GAAG,UAAU,iBAAiB,OAAO,SAAS,CAAC;AACjE,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,OAAO,CAAC,WAAW,GAAG,IAAI,OAAO,CAAC;AAAA,QAClC,cAAc,CAAC,GAAG;AAAA,MACpB,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AACT;AAUO,SAAS,qBAAmC;AACjD,SAAO;AAAA,IACL,cAAc,YAAY,UAAU;AAClC,YAAM,EAAE,WAAW,IAAI,IAAI;AAG3B,UAAI,UAAU,SAAS,wBAAwB;AAC7C,YAAI,UAAU,WAAW,GAAG;AAC1B,iBAAO,EAAE,QAAQ,CAAC,GAAG,YAAY,EAAE;AAAA,QACrC;AACA,cAAM,QAAQ,UAAU,IAAI,CAAC,IAAI,MAAM,WAAW,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC,CAAC;AAC7E,eAAO;AAAA,UACL,QAAQ,CAAC,EAAE,MAAM,GAAG,UAAU,eAAe,QAAQ,YAAY,MAAM,CAAC;AAAA,UACxE,YAAY,MAAM;AAAA,QACpB;AAAA,MACF;AAGA,YAAM,YAAY,gBAAgB,GAAG;AACrC,YAAM,SAAS,gBAAgB,SAAS;AAGxC,YAAM,YAA6B;AAAA,QACjC,sBAAsB;AAAA,QACtB,mBAAmB;AAAA,QACnB,uBAAuB;AAAA,QACvB,uBAAuB;AAAA,QACvB,sBAAsB;AAAA,QACtB,kBAAkB;AAAA,MACpB;AAEA,YAAM,aAA8B,CAAC;AACrC,iBAAW,KAAK,WAAW;AACzB,cAAM,QAAQ,EAAE,SAAS,YAAY,WAAW,QAAQ,SAAS;AACjE,YAAI,SAAS,MAAM,MAAM,SAAS,EAAG,YAAW,KAAK,KAAK;AAAA,MAC5D;AAGA,YAAM,aAAa,oBAAI,IAAY;AACnC,iBAAW,KAAK,WAAY,GAAE,aAAa,QAAQ,CAAC,MAAM,WAAW,IAAI,CAAC,CAAC;AAC3E,YAAM,YAAY,UAAU,OAAO,CAAC,OAAO,CAAC,WAAW,IAAI,YAAY,EAAE,CAAC,CAAC;AAC3E,UAAI,UAAU,SAAS,GAAG;AACxB,cAAM,QAAQ,UAAU,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,MAAM,WAAW,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC,CAAC;AACzF,mBAAW,KAAK;AAAA,UACd,MAAM,GAAG,UAAU;AAAA,UACnB,QAAQ;AAAA,UACR,UAAU;AAAA,UACV;AAAA,UACA,cAAc,CAAC,GAAG,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;AAAA,QACtE,CAAC;AAAA,MACH;AAGA,YAAM,UAAU,IAAI,IAAI,UAAU,IAAI,WAAW,CAAC;AAClD,YAAM,cAAc,KAAK,IAAI,YAAY,KAAK,IAAI,YAAY,WAAW,MAAM,CAAC;AAChF,YAAM,WAAW,mBAAmB,YAAY,SAAS,aAAa,eAAe;AAGrF,yBAAmB,UAAU,UAAU;AAEvC,YAAM,aAAa,SAAS,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,MAAM,QAAQ,CAAC;AACtE,aAAO,EAAE,QAAQ,SAAS,IAAI,aAAa,GAAG,WAAW;AAAA,IAC3D;AAAA,EACF;AACF;AAsBO,SAAS,wBAAyC;AACvD,QAAM,cAAc,mBAAmB;AAEvC,SAAO;AAAA,IACL,eAAe,YAAY;AAAA,IAE3B,MAAM,qBAAqB,YAAY,UAAU,aAAa;AAE5D,YAAM,WAAW,YAAY,cAAc,YAAY,QAAQ;AAG/D,YAAM,kBAAkB,SAAS,UAC9B,IAAI,CAAC,MAAM,GAAG,EAAE,MAAM,IAAI,EAAE,IAAI,EAAE,EAClC,KAAK,IAAI;AAEZ,YAAM,eAAe,SAAS,OAC3B,IAAI,CAAC,MAAM,KAAK,EAAE,IAAI,KAAK,EAAE,MAAM,MAAM,QAAQ,EACjD,KAAK,IAAI;AAEZ,YAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASf,YAAM,OAAO,WAAW,UAAU;AAAA;AAAA;AAAA,EAGtC,eAAe;AAAA;AAAA;AAAA,EAGf,YAAY;AAAA;AAAA,YAEF,SAAS,UAAU;AAAA,mBACZ,SAAS,SAAS;AAAA;AAAA;AAI/B,UAAI;AACF,cAAM,MAAM,MAAM,YAAY,KAAK;AAAA,UACjC,EAAE,MAAM,UAAU,SAAS,OAAO;AAAA,UAClC,EAAE,MAAM,QAAQ,SAAS,KAAK;AAAA,QAChC,CAAC;AAED,cAAM,YAAY,IAAI,MAAM,aAAa;AACzC,YAAI,CAAC,UAAW,QAAO;AAEvB,cAAM,cAAc,KAAK,MAAM,UAAU,CAAC,CAAC;AAM3C,YAAI,MAAM,QAAQ,YAAY,gBAAgB,GAAG;AAC/C,gBAAM,UAAU,oBAAI,IAAY;AAChC,qBAAW,KAAK,SAAS,QAAQ;AAC/B,uBAAW,KAAK,EAAE,MAAO,SAAQ,IAAI,YAAY,EAAE,QAAQ,CAAC;AAAA,UAC9D;AAEA,qBAAW,cAAc,YAAY,kBAAkB;AACrD,gBAAI,CAAC,WAAW,gBAAgB,CAAC,MAAM,QAAQ,WAAW,YAAY,EAAG;AAEzE,kBAAM,UAAU,WAAW,aAAa,OAAO,CAAC,MAAc,CAAC,QAAQ,IAAI,CAAC,CAAC;AAC7E,gBAAI,QAAQ,WAAW,EAAG;AAE1B,kBAAM,QAAoB,CAAC;AAC3B,uBAAW,OAAO,SAAS;AACzB,oBAAM,KAAK,SAAS,UAAU,KAAK,CAAC,MAAM,GAAG,EAAE,MAAM,IAAI,EAAE,IAAI,OAAO,GAAG;AACzE,kBAAI,IAAI;AACN,sBAAM,KAAK,WAAW,MAAM,SAAS,GAAG,IAAI,YAAY,EAAE,CAAC,CAAC;AAC5D,wBAAQ,IAAI,GAAG;AAAA,cACjB;AAAA,YACF;AAEA,gBAAI,MAAM,SAAS,GAAG;AACpB,uBAAS,OAAO,KAAK;AAAA,gBACnB,MAAM,WAAW,QAAQ,GAAG,UAAU;AAAA,gBACtC,QAAQ;AAAA,gBACR;AAAA,cACF,CAAC;AACD,uBAAS,cAAc,MAAM;AAAA,YAC/B;AAAA,UACF;AAAA,QACF;AAEA,eAAO;AAAA,MACT,QAAQ;AAEN,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;;;ACpiBA;AA6CO,SAAS,YAAY,MAAsB;AAEhD,MAAI;AAAE,SAAK,MAAM,KAAK,KAAK,CAAC;AAAG,WAAO,KAAK,KAAK;AAAA,EAAG,QAAQ;AAAA,EAA6B;AAGxF,QAAM,YAAY,KAAK,MAAM,qDAAqD;AAClF,MAAI,WAAW;AACb,QAAI;AAAE,WAAK,MAAM,UAAU,CAAC,EAAE,KAAK,CAAC;AAAG,aAAO,UAAU,CAAC,EAAE,KAAK;AAAA,IAAG,QAAQ;AAAA,IAA6B;AAAA,EAC1G;AAGA,QAAM,aAAa,KAAK,QAAQ,GAAG;AACnC,QAAM,WAAW,KAAK,YAAY,GAAG;AACrC,QAAM,eAAe,KAAK,QAAQ,GAAG;AACrC,QAAM,aAAa,KAAK,YAAY,GAAG;AAEvC,QAAM,WAAW,CAAC,OAAe,QAA+B;AAC9D,QAAI,UAAU,MAAM,OAAO,MAAO,QAAO;AACzC,QAAI,YAAY,KAAK,MAAM,OAAO,MAAM,CAAC;AACzC,gBAAY,UAAU,QAAQ,gBAAgB,IAAI;AAClD,QAAI;AAAE,WAAK,MAAM,SAAS;AAAG,aAAO;AAAA,IAAW,QAAQ;AAAE,aAAO;AAAA,IAAM;AAAA,EACxE;AAGA,MAAI,iBAAiB,OAAO,eAAe,MAAM,eAAe,aAAa;AAC3E,UAAM,IAAI,SAAS,cAAc,UAAU,KAAK,SAAS,YAAY,QAAQ;AAC7E,QAAI,EAAG,QAAO;AAAA,EAChB,OAAO;AACL,UAAM,IAAI,SAAS,YAAY,QAAQ,KAAK,SAAS,cAAc,UAAU;AAC7E,QAAI,EAAG,QAAO;AAAA,EAChB;AAGA,QAAM,UAAU,KAAK,KAAK,EACvB,QAAQ,sCAAsC,EAAE,EAChD,QAAQ,kBAAkB,EAAE,EAC5B,KAAK,EACL,QAAQ,gBAAgB,IAAI,EAC5B,QAAQ,uBAAuB,CAAC,IAAI,QAAQ,QAAQ,GAAG,MAAM,IAAI,GAAG,IAAI,EACxE,QAAQ,MAAM,GAAG;AAEpB,MAAI;AAAE,SAAK,MAAM,OAAO;AAAG,WAAO;AAAA,EAAS,QAAQ;AAAA,EAA6B;AAEhF,QAAM,IAAI,MAAM,qEAAqE;AACvF;AAMA,eAAe,QAAQ,KAAkB,QAAgB,MAA+B;AACtF,SAAO,IAAI,KAAK;AAAA,IACd,EAAE,MAAM,UAAU,SAAS,OAAO;AAAA,IAClC,EAAE,MAAM,QAAQ,SAAS,KAAK;AAAA,EAChC,CAAC;AACH;AAEA,eAAe,sBACb,YACA,WACA,KACkD;AAClD,QAAM,iBAAiB,UACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,OAAO,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,EACzD,IAAI,CAAC,MAAM,GAAG,EAAE,MAAM,IAAI,EAAE,IAAI,GAAG,EAAE,YAAY,SAAS,YAAO,EAAE,WAAW,KAAK,IAAI,CAAC,MAAM,EAAE,EAAE,EAClG,KAAK,IAAI;AAEZ,MAAI,CAAC,eAAgB,QAAO,CAAC;AAE7B,QAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUf,QAAM,OAAO,WAAW,UAAU;AAAA;AAAA;AAAA,EAAyB,cAAc;AAAA;AAAA;AAEzE,MAAI;AACF,UAAM,MAAM,MAAM,QAAQ,KAAK,QAAQ,IAAI;AAC3C,WAAO,KAAK,MAAM,YAAY,GAAG,CAAC;AAAA,EACpC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAe,sBACb,YACA,WACA,KACiD;AACjD,QAAM,iBAAiB,UACpB,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,WAAW,SAAS,CAAC,EACrD,IAAI,CAAC,MAAM,GAAG,EAAE,MAAM,IAAI,EAAE,IAAI,oBAAe,EAAE,WAAY,KAAK,IAAI,CAAC,GAAG,EAC1E,KAAK,IAAI;AAEZ,MAAI,CAAC,eAAgB,QAAO,CAAC;AAE7B,QAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQf,QAAM,OAAO,WAAW,UAAU;AAAA;AAAA;AAAA,EAAoC,cAAc;AAAA;AAAA;AAEpF,MAAI;AACF,UAAM,MAAM,MAAM,QAAQ,KAAK,QAAQ,IAAI;AAC3C,WAAO,KAAK,MAAM,YAAY,GAAG,CAAC;AAAA,EACpC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAe,mBACb,YACA,WACA,eACA,KACqB;AACrB,QAAM,eAAe,UAAU,IAAI,CAAC,MAAM,GAAG,EAAE,MAAM,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,IAAI;AAE5E,QAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYf,QAAM,OAAO,WAAW,UAAU;AAAA;AAAA;AAAA,EAAuB,YAAY;AAAA;AAAA;AAAA,EAAwB,KAAK,UAAU,eAAe,MAAM,CAAC,CAAC;AAAA;AAAA;AAEnI,MAAI;AACF,UAAM,MAAM,MAAM,QAAQ,KAAK,QAAQ,IAAI;AAC3C,UAAM,SAAS,KAAK,MAAM,YAAY,GAAG,CAAC;AAC1C,WAAO,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC;AAAA,EAC3C,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAYA,SAAS,iBAAiB,QAAoD;AAC5E,QAAM,SAAS,qBAAqB,QAAQ,QAAW,EAAE,YAAY,CAAC,YAAY,QAAQ,EAAE,CAAC;AAC7F,SAAO;AAAA,IACL,OAAO,OAAO;AAAA,IACd,QAAQ,OAAO,OAAO,IAAI,CAAC,MAAM,IAAI,EAAE,IAAI,KAAK,EAAE,OAAO,EAAE;AAAA,IAC3D,UAAU,OAAO,SAAS,IAAI,CAAC,MAAM,IAAI,EAAE,IAAI,KAAK,EAAE,OAAO,EAAE;AAAA,EACjE;AACF;AAEA,eAAe,gBACb,QACA,YACA,KAC2B;AAC3B,MAAI,WAAW,MAAO,QAAO;AAE7B,QAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAMf,QAAM,OAAO;AAAA,EAAqB,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA,EAAgB,WAAW,OAAO,KAAK,IAAI,CAAC;AAAA;AAAA;AAE7G,MAAI;AACF,UAAM,MAAM,MAAM,QAAQ,KAAK,QAAQ,IAAI;AAC3C,WAAO,KAAK,MAAM,YAAY,GAAG,CAAC;AAAA,EACpC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AASA,eAAsB,qBACpB,SAC+B;AAC/B,QAAM,EAAE,YAAY,WAAW,aAAa,aAAa,EAAE,IAAI;AAC/D,MAAI,UAAU;AAEd,UAAQ,IAAI,gDAAgD,UAAU,MAAM;AAE5E,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO,EAAE,SAAS,OAAO,OAAO,kCAAkC,UAAU,IAAI,SAAS,EAAE;AAAA,EAC7F;AAGA,QAAM,gBAAgB,MAAM,sBAAsB,YAAY,WAAW,WAAW;AACpF,QAAM,gBAAgB,MAAM,sBAAsB,YAAY,WAAW,WAAW;AACpF,QAAM,OAAO,MAAM,mBAAmB,YAAY,WAAW,eAAe,WAAW;AAEvF,MAAI,SAA2B;AAAA,IAC7B;AAAA,IACA,SAAS;AAAA,IACT,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AAAA,IACA;AAAA,IACA,WAAW,CAAC;AAAA,IACZ,aAAa,CAAC;AAAA,IACd;AAAA,EACF;AAGA,SAAO,UAAU,YAAY;AAC3B,UAAM,aAAa,iBAAiB,MAAM;AAC1C,QAAI,WAAW,OAAO;AACpB,cAAQ,IAAI,+CAA0C;AACtD,aAAO,EAAE,SAAS,MAAM,QAAQ,QAAQ;AAAA,IAC1C;AAEA,YAAQ,KAAK,oDAAoD,UAAU,CAAC,cAAc;AAC1F,aAAS,MAAM,gBAAgB,QAAQ,YAAY,WAAW;AAC9D;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,OAAO,kCAAkC,UAAU;AAAA,IACnD;AAAA,EACF;AACF;AAKA,eAAsB,yBACpB,aACA,WACA,aACA,SAC4C;AAC5C,QAAM,UAAU,oBAAI,IAAkC;AAEtD,aAAW,cAAc,aAAa;AACpC,UAAM,MAAM,UAAU,IAAI,UAAU,KAAK,CAAC;AAC1C,UAAM,SAAS,MAAM,qBAAqB;AAAA,MACxC;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA,GAAG;AAAA,IACL,CAAC;AACD,YAAQ,IAAI,YAAY,MAAM;AAAA,EAChC;AAEA,QAAM,eAAe,MAAM,KAAK,QAAQ,OAAO,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AAC3E,UAAQ,IAAI,kCAAkC,YAAY,IAAI,YAAY,MAAM,YAAY;AAE5F,SAAO;AACT;;;AC/TA;AA2DA,eAAe,gBACb,KACA,cACA,YACA,MACuD;AACvD,QAAM,WAA4B,CAAC;AACnC,MAAI,YAAY;AAChB,MAAI,oBAAoB;AAExB,WAAS,IAAI,GAAG,IAAI,KAAK,YAAY,KAAK;AACxC,UAAM,YAAY,KAAK,IAAI;AAC3B,QAAI;AACF,YAAM,MAAM,MAAM,QAAQ,KAAK;AAAA,QAC7B,IAAI,KAAK;AAAA,UACP,EAAE,MAAM,UAAU,SAAS,aAAa;AAAA,UACxC,EAAE,MAAM,QAAQ,SAAS,kBAAkB;AAAA,QAC7C,CAAC;AAAA,QACD,IAAI;AAAA,UAAe,CAAC,GAAG,WACrB,WAAW,MAAM,OAAO,IAAI,MAAM,oBAAoB,CAAC,GAAG,KAAK,OAAO;AAAA,QACxE;AAAA,MACF,CAAC;AAED,YAAM,UAAU,YAAY,GAAG;AAC/B,YAAM,SAAS,KAAK,MAAM,OAAO;AAEjC,eAAS,KAAK;AAAA,QACZ,SAAS,IAAI;AAAA,QACb,OAAO,KAAK;AAAA,QACZ,aAAa,IAAI,UAAU,GAAG,GAAG;AAAA,QACjC,YAAY;AAAA,QACZ,YAAY,KAAK,IAAI,IAAI;AAAA,MAC3B,CAAC;AAED,aAAO,EAAE,MAAM,QAAQ,SAAS;AAAA,IAClC,SAAS,KAAc;AACrB,kBAAa,IAAc,WAAW,OAAO,GAAG;AAChD,eAAS,KAAK;AAAA,QACZ,SAAS,IAAI;AAAA,QACb,OAAO,KAAK;AAAA,QACZ,OAAO;AAAA,QACP,YAAY,KAAK,IAAI,IAAI;AAAA,MAC3B,CAAC;AAED,UAAI,IAAI,KAAK,aAAa,GAAG;AAC3B,6BAAqB;AAAA;AAAA,SAAc,IAAI,CAAC,2BAA2B,SAAS;AAAA,MAC9E;AAAA,IACF;AAAA,EACF;AAEA,QAAM,OAAO;AAAA,IACX,IAAI,MAAM,wBAAwB,KAAK,UAAU,aAAa,SAAS,EAAE;AAAA,IACzE,EAAE,SAAS;AAAA,EACb;AACF;AAMA,SAAS,wBACP,SACA,eACkC;AAClC,QAAM,EAAE,YAAY,WAAW,KAAK,IAAI;AAExC,QAAM,cAAc,QAAQ,CAAC,GAC1B,IAAI,CAAC,QAAQ;AACZ,UAAM,SAAS,IAAI,OAChB,OAAO,CAAC,MAAM,CAAC,EAAE,aAAa,EAC9B,IAAI,CAAC,MAAM;AACV,UAAI,OAAO,OAAO,EAAE,IAAI,KAAK,EAAE,IAAI;AACnC,UAAI,EAAE,SAAU,SAAQ;AACxB,UAAI,EAAE,YAAY,OAAQ,SAAQ,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;AAC9D,aAAO;AAAA,IACT,CAAC,EACA,KAAK,IAAI;AACZ,WAAO,GAAG,IAAI,IAAI,GAAG,IAAI,UAAU,YAAY,IAAI,OAAO,KAAK,EAAE;AAAA,EAAM,MAAM;AAAA,EAC/E,CAAC,EACA,KAAK,MAAM;AAEd,QAAM,iBAAiB,UACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,OAAO,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,EACzD,IAAI,CAAC,MAAM,GAAG,EAAE,MAAM,IAAI,EAAE,IAAI,GAAG,EAAE,YAAY,SAAS,kBAAa,EAAE,WAAW,KAAK,IAAI,CAAC,MAAM,EAAE,EAAE,EACxG,KAAK,IAAI;AAEZ,QAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaf,MAAI,OAAO,WAAW,UAAU;AAAA;AAAA;AAAA,EAGhC,kBAAkB,QAAQ;AAAA;AAAA;AAAA,EAG1B,cAAc,iBAAiB;AAE/B,MAAI,QAAQ,eAAe,eAAe;AACxC,YAAQ;AAAA;AAAA;AAAA,EAAmC,KAAK,UAAU,QAAQ,cAAc,eAAe,MAAM,CAAC,CAAC;AAAA,EACzG;AAEA,MAAI,eAAe;AACjB,YAAQ;AAAA;AAAA;AAAA,EAAwC,aAAa;AAAA;AAAA,EAC/D;AAEA,UAAQ;AAER,SAAO,EAAE,QAAQ,KAAK;AACxB;AAEA,SAAS,wBACP,SACkC;AAClC,QAAM,EAAE,YAAY,UAAU,IAAI;AAElC,QAAM,iBAAiB,UACpB,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,WAAW,SAAS,CAAC,EACrD,IAAI,CAAC,MAAM,GAAG,EAAE,MAAM,IAAI,EAAE,IAAI,oBAAe,EAAE,WAAY,KAAK,IAAI,CAAC,GAAG,EAC1E,KAAK,IAAI;AAEZ,QAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQf,QAAM,OAAO,WAAW,UAAU;AAAA;AAAA;AAAA,EAAoC,kBAAkB,QAAQ;AAAA;AAAA;AAEhG,SAAO,EAAE,QAAQ,KAAK;AACxB;AAEA,SAAS,gBACP,SACA,eACkC;AAClC,QAAM,EAAE,YAAY,WAAW,KAAK,IAAI;AAExC,QAAM,eAAe,UAAU,IAAI,CAAC,MAAM,GAAG,EAAE,MAAM,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,IAAI;AAE5E,QAAM,cAAc,QAAQ,CAAC,GAC1B,IAAI,CAAC,QAAQ;AACZ,UAAM,SAAS,IAAI,OAChB,OAAO,CAAC,MAAM,CAAC,EAAE,aAAa,EAC9B,IAAI,CAAC,MAAM,GAAG,EAAE,IAAI,IAAI,EAAE,IAAI,GAAG,EAAE,WAAW,cAAc,EAAE,GAAG,EACjE,KAAK,IAAI;AACZ,WAAO,GAAG,IAAI,IAAI,MAAM,MAAM;AAAA,EAChC,CAAC,EACA,KAAK,IAAI;AAEZ,QAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcf,MAAI,OAAO,WAAW,UAAU;AAAA;AAAA;AAAA,EAGhC,YAAY;AAAA;AAAA;AAAA,EAGZ,cAAc,WAAW;AAAA;AAAA;AAAA,EAGzB,KAAK,UAAU,eAAe,MAAM,CAAC,CAAC;AAEtC,UAAQ;AAER,SAAO,EAAE,QAAQ,KAAK;AACxB;AAMA,SAAS,gBACP,eAC+C;AAC/C,QAAM,UAAyD,CAAC;AAChE,QAAM,OAAO,oBAAI,IAAY;AAE7B,aAAW,CAAC,KAAK,OAAO,KAAK,OAAO,QAAQ,aAAa,GAAG;AAC1D,UAAM,WAAW,IAAI,QAAQ,GAAG;AAChC,QAAI,aAAa,GAAI;AACrB,UAAM,YAAY,IAAI,UAAU,WAAW,CAAC;AAE5C,eAAW,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AACpD,UAAI,UAAU,QAAQ,CAAC,KAAK,IAAI,KAAK,GAAG;AACtC,cAAM,WAAW,UAAU,MAAM,GAAG;AACpC,cAAM,QAAQ,SAAS,UAAU,CAAC,MAAM,MAAM,IAAI,KAAK,EAAE;AACzD,YAAI,QAAQ,GAAG;AACb,kBAAQ,KAAK,EAAE,aAAa,SAAS,QAAQ,CAAC,GAAG,MAAM,CAAC;AACxD,eAAK,IAAI,KAAK;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AASA,eAAsB,uBACpB,SACiC;AACjC,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb,UAAU;AAAA,EACZ,IAAI;AAEJ,QAAM,cAA+B,CAAC;AAEtC,UAAQ,IAAI,+CAA+C,UAAU,MAAM;AAC3E,UAAQ,IAAI,wBAAwB,QAAQ,MAAM,UAAU,CAAC,UAAU,QAAQ,UAAU,MAAM,YAAY;AAE3G,MAAI;AAEF,UAAM,aAAa,wBAAwB,OAAO;AAClD,UAAM,aAAa,MAAM,gBAAgB,aAAa,WAAW,QAAQ,WAAW,MAAM;AAAA,MACxF;AAAA,MAAY;AAAA,MAAS,OAAO;AAAA,IAC9B,CAAC;AACD,gBAAY,KAAK,GAAG,WAAW,QAAQ;AACvC,UAAM,gBACJ,OAAO,WAAW,SAAS,YAAY,CAAC,MAAM,QAAQ,WAAW,IAAI,IACjE,WAAW,OACX,CAAC;AAGP,UAAM,cAAc,wBAAwB,OAAO;AACnD,UAAM,cAAc,MAAM,gBAAgB,aAAa,YAAY,QAAQ,YAAY,MAAM;AAAA,MAC3F;AAAA,MAAY;AAAA,MAAS,OAAO;AAAA,IAC9B,CAAC;AACD,gBAAY,KAAK,GAAG,YAAY,QAAQ;AACxC,UAAM,gBACJ,OAAO,YAAY,SAAS,YAAY,CAAC,MAAM,QAAQ,YAAY,IAAI,IACnE,YAAY,OACZ,CAAC;AAGP,UAAM,aAAa,gBAAgB,SAAS,aAAa;AACzD,UAAM,aAAa,MAAM,gBAAgB,aAAa,WAAW,QAAQ,WAAW,MAAM;AAAA,MACxF;AAAA,MAAY;AAAA,MAAS,OAAO;AAAA,IAC9B,CAAC;AACD,gBAAY,KAAK,GAAG,WAAW,QAAQ;AACvC,UAAM,OAAmB,MAAM,QAAQ,WAAW,IAAI,IAAI,WAAW,OAAqB,CAAC;AAE3F,UAAM,YAAY,gBAAgB,aAAa;AAE/C,UAAM,SAA2B;AAAA,MAC/B;AAAA,MACA,SAAS;AAAA,MACT,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,CAAC;AAAA,MACd;AAAA,IACF;AAEA,WAAO,EAAE,SAAS,MAAM,QAAQ,UAAU,YAAY;AAAA,EACxD,SAAS,KAAc;AACrB,UAAM,gBAAiB,IAAuC,YAAY,CAAC;AAC3E,gBAAY,KAAK,GAAG,aAAa;AAEjC,WAAO;AAAA,MACL,SAAS;AAAA,MACT,UAAU;AAAA,MACV,OAAQ,IAAc,WAAW,OAAO,GAAG;AAAA,IAC7C;AAAA,EACF;AACF;;;ACrWA;AAsCA,SAAS,UAAa,KAAW;AAC/B,SAAO,KAAK,MAAM,KAAK,UAAU,GAAG,CAAC;AACvC;AAEA,SAAS,eAAe,GAAW,GAAmB;AACpD,QAAM,OAAO,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO;AACxC,QAAM,OAAO,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO;AACxC,MAAI,UAAU;AACd,QAAM,SAAS,KAAK,IAAI,KAAK,QAAQ,KAAK,MAAM;AAChD,MAAI,WAAW,EAAG,QAAO;AACzB,WAAS,IAAI,GAAG,IAAI,KAAK,IAAI,KAAK,QAAQ,KAAK,MAAM,GAAG,KAAK;AAC3D,QAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAG;AAAA,aAChB,KAAK,CAAC,EAAE,WAAW,GAAG,KAAK,KAAK,CAAC,EAAE,WAAW,GAAG,EAAG,YAAW;AAAA,EAC1E;AACA,SAAO,UAAU;AACnB;AAEA,SAAS,wBAAwB,QAAgB,YAAoB,WAAmD;AACtH,QAAM,aAAa,UAAU,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AAC9D,MAAI,YAAY;AAChB,MAAI;AACJ,aAAW,MAAM,YAAY;AAC3B,UAAM,QAAQ,eAAe,YAAY,GAAG,IAAI;AAChD,QAAI,QAAQ,WAAW;AAAE,kBAAY;AAAO,kBAAY;AAAA,IAAI;AAAA,EAC9D;AACA,SAAO,aAAa,MAAM,YAAY;AACxC;AAEA,SAAS,gBAAgB,SAAyB;AAChD,QAAM,QAAQ,QAAQ,QAAQ,UAAU,EAAE;AAC1C,QAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,MAAI,MAAM,WAAW,EAAG,QAAO,MAAM,CAAC,EAAE,QAAQ,MAAM,EAAE,IAAI;AAC5D,SAAO,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI;AAC3C;AAEA,SAAS,qBAAqB,OAA8B;AAC1D,MAAI,MAAM,YAAY,OAAQ,QAAO,MAAM,WAAW,CAAC;AACvD,UAAQ,MAAM,KAAK,YAAY,GAAG;AAAA,IAChC,KAAK;AAAU,aAAO,SAAS,MAAM,IAAI,IAAI,KAAK,IAAI,CAAC;AAAA,IACvD,KAAK;AAAU,aAAO;AAAA,IACtB,KAAK;AAAW,aAAO;AAAA,IACvB,KAAK;AAAQ,cAAO,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC3C;AACE,UAAI,MAAM,KAAK,SAAS,IAAI,KAAK,MAAM,KAAK,SAAS,OAAO,EAAG,QAAO,CAAC;AACvE,aAAO,SAAS,MAAM,IAAI;AAAA,EAC9B;AACF;AAEA,SAAS,kBAAkB,QAA0B,OAAmC;AACtF,QAAM,OAAiB,CAAC;AACxB,QAAM,IAAI;AACV,QAAM,IAAI;AACV,QAAM,UAAU,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,CAAC,GAAG,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC;AAC9D,aAAW,OAAO,SAAS;AACzB,QAAI,KAAK,UAAU,EAAE,GAAG,CAAC,MAAM,KAAK,UAAU,EAAE,GAAG,CAAC,GAAG;AACrD,WAAK,KAAK,GAAG;AAAA,IACf;AAAA,EACF;AACA,SAAO;AACT;AAMA,IAAM,6BAA0C;AAAA,EAC9C,MAAM;AAAA,EACN,UAAU;AAAA,EACV,SAAS,CAAC,UAAU,MAAM,SAAS,yBAAyB,MAAM,SAAS;AAAA,EAC3E,KAAK,CAAC,QAAQ,OAAO,YAAY;AAC/B,UAAM,QAAQ,UAAU,MAAM;AAC9B,UAAM,QAAQ,MAAM,QAAQ,MAAM,kDAAkD;AACpF,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,CAAC,EAAE,QAAQ,UAAU,IAAI;AAC/B,UAAM,YAAY,wBAAwB,QAAQ,YAAY,QAAQ,SAAS;AAC/E,QAAI,CAAC,UAAW,QAAO;AAEvB,UAAM,SAAS,GAAG,MAAM,IAAI,UAAU;AACtC,UAAM,SAAS,GAAG,MAAM,IAAI,UAAU,IAAI;AAE1C,QAAI,MAAM,KAAK,WAAW,eAAe,KAAK,MAAM,cAAc,MAAM,GAAG;AACzE,YAAM,cAAc,MAAM,IAAI,MAAM,cAAc,MAAM;AACxD,aAAO,MAAM,cAAc,MAAM;AAAA,IACnC;AACA,QAAI,MAAM,KAAK,WAAW,eAAe,KAAK,MAAM,cAAc,MAAM,GAAG;AACzE,YAAM,cAAc,MAAM,IAAI,MAAM,cAAc,MAAM;AACxD,aAAO,MAAM,cAAc,MAAM;AAAA,IACnC;AACA,QAAI,MAAM,KAAK,WAAW,MAAM,GAAG;AACjC,iBAAW,QAAQ,MAAM,MAAM;AAC7B,YAAI,KAAK,WAAW,UAAU,KAAK,SAAS,YAAY;AACtD,eAAK,OAAO,UAAU;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,uBAAoC;AAAA,EACxC,MAAM;AAAA,EACN,UAAU;AAAA,EACV,SAAS,CAAC,UAAU,MAAM,SAAS,mBAAoB,MAAM,SAAS,mBAAmB,MAAM,KAAK,WAAW,eAAe;AAAA,EAC9H,KAAK,CAAC,QAAQ,OAAO,YAAY;AAC/B,UAAM,QAAQ,UAAU,MAAM;AAC9B,UAAM,aAAa,MAAM,QAAQ,MAAM,eAAe;AACtD,QAAI,CAAC,WAAY,QAAO;AACxB,UAAM,eAAe,WAAW,CAAC;AAEjC,UAAM,WAAW,MAAM,QAAQ,MAAM,YAAY;AACjD,UAAM,MAAM,WAAW,QAAQ,KAAK,KAAK,CAAC,MAAM,EAAE,SAAS,SAAS,CAAC,CAAC,IAAI,QAAQ,KAAK,CAAC;AACxF,QAAI,CAAC,IAAK,QAAO;AAEjB,UAAM,WAAW,IAAI,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,YAAY;AAC/D,QAAI,CAAC,SAAU,QAAO;AAEtB,UAAM,eAAe,qBAAqB,QAAQ;AAElD,eAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,MAAM,aAAa,GAAG;AAC7D,YAAM,SAAS,IAAI,MAAM,GAAG,EAAE,CAAC;AAC/B,UAAI,CAAC,QAAQ,OAAO,OAAO,EAAE,SAAS,MAAM,KAAK,EAAE,gBAAgB,OAAO;AACxE,QAAC,KAAiC,YAAY,IAAI;AAAA,MACpD;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAMA,IAAM,2BAAwC;AAAA,EAC5C,MAAM;AAAA,EACN,UAAU;AAAA,EACV,SAAS,CAAC,UAAU,MAAM,SAAS,wBAAwB,MAAM,SAAS,sBAAsB,MAAM,SAAS;AAAA,EAC/G,KAAK,CAAC,WAAW;AACf,UAAM,QAAQ,UAAU,MAAM;AAC9B,QAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,WAAW,EAAG,QAAO;AAEnD,UAAM,SAAS,oBAAoB,MAAM,IAAI;AAC7C,QAAI,OAAQ,OAAM,OAAO;AACzB,WAAO;AAAA,EACT;AACF;AAEA,SAAS,oBAAoB,MAAqC;AAChE,QAAM,gBAAgB,oBAAI,IAAsB;AAChD,aAAW,QAAQ,MAAM;AACvB,QAAI,KAAK,UAAW,eAAc,IAAI,KAAK,WAAW,IAAI;AAAA,EAC5D;AAEA,QAAM,WAAW,oBAAI,IAAoB;AACzC,QAAM,MAAM,oBAAI,IAAsB;AACtC,aAAW,QAAQ,MAAM;AACvB,aAAS,IAAI,KAAK,MAAM,CAAC;AACzB,QAAI,IAAI,KAAK,MAAM,CAAC,CAAC;AAAA,EACvB;AAEA,aAAW,QAAQ,MAAM;AACvB,QAAI,KAAK,WAAW;AAClB,iBAAW,OAAO,KAAK,WAAW;AAChC,cAAM,UAAU,cAAc,IAAI,GAAG;AACrC,YAAI,SAAS;AACX,cAAI,IAAI,QAAQ,IAAI,GAAG,KAAK,KAAK,IAAI;AACrC,mBAAS,IAAI,KAAK,OAAO,SAAS,IAAI,KAAK,IAAI,KAAK,KAAK,CAAC;AAAA,QAC5D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAkB,CAAC;AACzB,aAAW,CAAC,SAAS,MAAM,KAAK,UAAU;AACxC,QAAI,WAAW,EAAG,OAAM,KAAK,OAAO;AAAA,EACtC;AAEA,QAAM,SAAqB,CAAC;AAC5B,QAAM,UAAU,IAAI,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAEpD,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,UAAU,MAAM,MAAM;AAC5B,UAAM,OAAO,QAAQ,IAAI,OAAO;AAChC,QAAI,KAAM,QAAO,KAAK,IAAI;AAC1B,eAAW,QAAQ,IAAI,IAAI,OAAO,KAAK,CAAC,GAAG;AACzC,eAAS,IAAI,OAAO,SAAS,IAAI,IAAI,KAAK,KAAK,CAAC;AAChD,UAAI,SAAS,IAAI,IAAI,MAAM,EAAG,OAAM,KAAK,IAAI;AAAA,IAC/C;AAAA,EACF;AAEA,MAAI,OAAO,WAAW,KAAK,OAAQ,QAAO;AAC1C,SAAO,OAAO,IAAI,CAAC,GAAG,OAAO,EAAE,GAAG,GAAG,MAAM,IAAI,EAAE,EAAE;AACrD;AAMA,IAAM,oBAAiC;AAAA,EACrC,MAAM;AAAA,EACN,UAAU;AAAA,EACV,SAAS,CAAC,UAAU,MAAM,SAAS;AAAA,EACnC,KAAK,CAAC,QAAQ,QAAQ,YAAY;AAChC,UAAM,QAAQ,UAAU,MAAM;AAC9B,UAAM,cAAsD,CAAC;AAE7D,eAAW,MAAM,QAAQ,WAAW;AAClC,UAAI,CAAC,GAAG,cAAc,GAAG,WAAW,WAAW,EAAG;AAClD,YAAM,MAAM,GAAG,GAAG,MAAM,IAAI,GAAG,IAAI;AACnC,YAAM,UAAkC,CAAC;AAEzC,iBAAW,SAAS,GAAG,YAAY;AACjC,YAAI,UAAU,MAAM;AAClB,gBAAM,WAAW,GAAG,KAAK,MAAM,GAAG;AAClC,gBAAM,QAAQ,SAAS,QAAQ,KAAK;AACpC,cAAI,QAAQ,GAAG;AACb,oBAAQ,KAAK,IAAI,gBAAgB,SAAS,QAAQ,CAAC,CAAC;AAAA,UACtD;AAAA,QACF;AAAA,MACF;AACA,UAAI,OAAO,KAAK,OAAO,EAAE,SAAS,EAAG,aAAY,GAAG,IAAI;AAAA,IAC1D;AAEA,UAAM,gBAAgB;AACtB,WAAO;AAAA,EACT;AACF;AAMA,IAAM,iBAAgC;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AASjC,SAAS,QACd,QACA,eACA,SACA,mBACA,cAAc,GACH;AACX,QAAM,UAA6B,CAAC;AACpC,MAAI,gBAAgB,UAAU,MAAM;AACpC,MAAI,gBAAgB,cAAc,OAAO,CAAC,MAAM,EAAE,UAAU,QAAQ;AAEpE,WAAS,UAAU,GAAG,WAAW,aAAa,WAAW;AACvD,QAAI,cAAc,WAAW,EAAG;AAEhC,QAAI,aAAa;AAEjB,eAAW,SAAS,CAAC,GAAG,aAAa,GAAG;AACtC,YAAM,WAAW,eAAe,KAAK,CAAC,MAAM,EAAE,QAAQ,KAAK,CAAC;AAC5D,UAAI,CAAC,SAAU;AAEf,YAAM,SAAS;AACf,sBAAgB,SAAS,IAAI,eAAe,OAAO,OAAO;AAC1D,mBAAa;AAEb,cAAQ,KAAK;AAAA,QACX,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QAClC;AAAA,QACA,WAAW,MAAM;AAAA,QACjB,WAAW,MAAM;AAAA,QACjB,cAAc,MAAM;AAAA,QACpB,WAAW,SAAS;AAAA,QACpB,aAAa,kBAAkB,QAAQ,aAAa;AAAA,QACpD,0BAA0B;AAAA,MAC5B,CAAC;AAAA,IACH;AAEA,QAAI,CAAC,WAAY;AAGjB,UAAM,eAAe;AAAA,MACnB;AAAA,MACA;AAAA,MACA,EAAE,YAAY,CAAC,QAAQ,EAAE;AAAA,IAC3B;AACA,oBAAgB,aAAa;AAE7B,QAAI,QAAQ,SAAS,GAAG;AACtB,cAAQ,QAAQ,SAAS,CAAC,EAAE,2BAA2B,cAAc,WAAW;AAAA,IAClF;AAEA,QAAI,cAAc,WAAW,EAAG;AAAA,EAClC;AAEA,SAAO;AAAA,IACL,SAAS,cAAc,WAAW;AAAA,IAClC,QAAQ;AAAA,IACR,eAAe,QAAQ;AAAA,IACvB;AAAA,IACA,iBAAiB;AAAA,EACnB;AACF;;;AC5VA;AA+EO,SAAS,sBACd,YACA,OACA,SACgB;AAChB,QAAM,QAA0B,CAAC;AAEjC,MAAI,YAAY,UAAU,MAAM,QAAQ,WAAW,MAAM,GAAG;AAC1D,eAAW,SAAS,WAAW,QAAQ;AACrC,mBAAa,OAAO,MAAM,SAAS,IAAI,KAAK;AAAA,IAC9C;AAAA,EACF;AAEA,SAAO,oBAAoB,OAAO,SAAS,KAAK;AAClD;AAEA,SAAS,aAAa,OAAgC,aAAqB,QAAgC;AACzG,QAAM,aAAa,cACf,GAAG,WAAW,MAAO,MAAM,SAAoB,EAAE,KAChD,MAAM,SAAoB;AAE/B,MAAI,MAAM,QAAQ,MAAM,KAAK,GAAG;AAC9B,eAAW,QAAQ,MAAM,OAAO;AAC9B,iBAAW,QAAQ,KAAK,SAAS,CAAC,GAAG;AACnC,mBAAW,cAAc,KAAK,WAAW,CAAC,GAAG;AAC3C,iBAAO,KAAK;AAAA,YACV,OAAO,KAAK,SAAS;AAAA,YACrB,MAAO,MAAM,QAAmB;AAAA,YAChC,OAAO;AAAA,YACP,QAAQ,gBAAgB,WAAW,MAAM;AAAA,YACzC,YAAY,WAAW,YAAY;AAAA,YACnC,OAAO,WAAW,OAAO;AAAA,UAC3B,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,MAAM,QAAQ,MAAM,MAAM,GAAG;AAC/B,eAAW,SAAS,MAAM,QAAQ;AAChC,mBAAa,EAAE,GAAG,OAAO,MAAM,MAAM,QAAQ,MAAM,KAAK,GAAG,YAAY,MAAM;AAAA,IAC/E;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,QAA0C;AACjE,UAAQ,QAAQ;AAAA,IACd,KAAK;AAAA,IAAU,KAAK;AAAY,aAAO;AAAA,IACvC,KAAK;AAAA,IAAU,KAAK;AAAc,aAAO;AAAA,IACzC,KAAK;AAAW,aAAO;AAAA,IACvB,KAAK;AAAY,aAAO;AAAA,IACxB;AAAS,aAAO;AAAA,EAClB;AACF;AAKO,SAAS,oBAAoB,OAAe,SAAmB,OAAyC;AAC7G,QAAM,SAAS,MAAM,OAAO,CAAC,MAAM,EAAE,WAAW,QAAQ,EAAE;AAC1D,QAAM,SAAS,MAAM,OAAO,CAAC,MAAM,EAAE,WAAW,QAAQ,EAAE;AAC1D,QAAM,UAAU,MAAM,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE;AAC5D,QAAM,WAAW,MAAM,OAAO,CAAC,MAAM,EAAE,WAAW,UAAU,EAAE;AAC9D,QAAM,kBAAkB,MAAM,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,YAAY,CAAC;AAElE,SAAO;AAAA,IACL;AAAA,IACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC;AAAA,IACA,OAAO,MAAM;AAAA,IACb;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAS;AAAA,IACzB,UAAU,MAAM,SAAS,IAAI,SAAS,MAAM,SAAS;AAAA,IACrD;AAAA,IACA,eAAe,MAAM,SAAS,IAAI,KAAK,MAAM,kBAAkB,MAAM,MAAM,IAAI;AAAA,IAC/E;AAAA,EACF;AACF;AASO,SAAS,gBAAgB,UAA0B,UAA4C;AACpG,QAAM,cAAc,IAAI,IAAI,SAAS,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AACtE,QAAM,QAAQ,IAAI,IAAI,SAAS,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AAEhE,QAAM,UAAU,oBAAI,IAAI,CAAC,GAAG,YAAY,KAAK,GAAG,GAAG,MAAM,KAAK,CAAC,CAAC;AAChE,QAAM,QAAoB,CAAC;AAE3B,aAAW,OAAO,SAAS;AACzB,UAAM,OAAO,YAAY,IAAI,GAAG,KAAK;AACrC,UAAM,KAAK,MAAM,IAAI,GAAG,KAAK;AAE7B,UAAM,KAAK;AAAA,MACT,OAAO,MAAM,SAAS,IAAI,SAAS;AAAA,MACnC,MAAM,MAAM,QAAQ,IAAI,QAAQ;AAAA,MAChC,QAAQ,eAAe,MAAM,UAAU,MAAM,IAAI,UAAU,IAAI;AAAA,MAC/D,gBAAgB,MAAM,UAAU;AAAA,MAChC,gBAAgB,IAAI,UAAU;AAAA,MAC9B,iBAAiB,IAAI,cAAc,MAAM,MAAM,cAAc;AAAA,MAC7D,OAAO,IAAI;AAAA,IACb,CAAC;AAAA,EACH;AAEA,QAAM,cAAc,MAAM,OAAO,CAAC,MAAM,EAAE,WAAW,YAAY;AACjE,QAAM,eAAe,MAAM,OAAO,CAAC,MAAM,EAAE,WAAW,aAAa;AACnE,QAAM,eAAe,SAAS,WAAW,SAAS;AAClD,QAAM,iBAAiB,SAAS,WAAW,IAAI,SAAS,YAAY,SAAS,WAAW,OAAO;AAC/F,QAAM,wBAAwB,SAAS,kBAAkB,KACnD,SAAS,kBAAkB,SAAS,mBAAmB,SAAS,kBAAmB,MACrF;AAEJ,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAoB,KAAK,IAAI,qBAAqB,KAAK;AAAA,IACvD;AAAA,IACA;AAAA,IACA;AAAA,IACA,qBAAqB,gBAAgB,WAAW;AAAA,EAClD;AACF;AAEA,SAAS,QAAQ,GAA2B;AAC1C,SAAO,GAAG,EAAE,IAAI,KAAK,EAAE,KAAK;AAC9B;AAEA,SAAS,eACP,MACA,IACoB;AACpB,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,CAAC,GAAI,QAAO;AAChB,MAAI,SAAS,GAAI,QAAO;AACxB,MAAI,SAAS,YAAY,OAAO,SAAU,QAAO;AACjD,MAAI,SAAS,YAAY,OAAO,SAAU,QAAO;AACjD,SAAO;AACT;AAMA,SAAS,gBAAgB,aAA+C;AACtE,QAAM,gBAAsC,CAAC;AAC7C,QAAM,SAAS,CAAC,QAAQ,aAAa,SAAS,YAAY;AAC1D,QAAM,SAAS,CAAC,QAAQ,YAAY,cAAc,OAAO,eAAe,OAAO;AAC/E,QAAM,UAAU,CAAC,SAAS,OAAO,aAAa,QAAQ,OAAO,WAAW;AAExE,QAAM,YAAY,YAAY,OAAO,CAAC,MAAM,EAAE,SAAS,OAAO,KAAK,CAAC,MAAM,EAAE,MAAO,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC;AAC7G,QAAM,YAAY,YAAY,OAAO,CAAC,MAAM,EAAE,SAAS,OAAO,KAAK,CAAC,MAAM,EAAE,MAAO,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC;AAC7G,QAAM,aAAa,YAAY,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ,KAAK,CAAC,MAAM,EAAE,MAAO,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC;AAE/G,MAAI,UAAU,SAAS,GAAG;AACxB,kBAAc,KAAK;AAAA,MACjB,UAAU;AAAA,MACV,OAAO,GAAG,UAAU,MAAM;AAAA,MAC1B,YAAY;AAAA,MACZ,cAAc,UAAU,IAAI,CAAC,MAAM,EAAE,KAAK;AAAA,IAC5C,CAAC;AAAA,EACH;AAEA,MAAI,UAAU,SAAS,GAAG;AACxB,kBAAc,KAAK;AAAA,MACjB,UAAU;AAAA,MACV,OAAO,GAAG,UAAU,MAAM;AAAA,MAC1B,YAAY;AAAA,MACZ,cAAc,UAAU,IAAI,CAAC,MAAM,EAAE,KAAK;AAAA,IAC5C,CAAC;AAAA,EACH;AAEA,MAAI,WAAW,SAAS,GAAG;AACzB,kBAAc,KAAK;AAAA,MACjB,UAAU;AAAA,MACV,OAAO,GAAG,WAAW,MAAM;AAAA,MAC3B,YAAY;AAAA,MACZ,cAAc,WAAW,IAAI,CAAC,MAAM,EAAE,KAAK;AAAA,IAC7C,CAAC;AAAA,EACH;AAEA,QAAM,QAAQ,YAAY;AAAA,IACxB,CAAC,MAAM,CAAC,UAAU,SAAS,CAAC,KAAK,CAAC,UAAU,SAAS,CAAC,KAAK,CAAC,WAAW,SAAS,CAAC;AAAA,EACnF;AACA,MAAI,MAAM,SAAS,GAAG;AACpB,kBAAc,KAAK;AAAA,MACjB,UAAU;AAAA,MACV,OAAO,GAAG,MAAM,MAAM;AAAA,MACtB,YAAY;AAAA,MACZ,cAAc,MAAM,IAAI,CAAC,MAAM,EAAE,KAAK;AAAA,IACxC,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AASO,SAAS,uBAAuB,QAAkC;AACvE,QAAM,QAAkB,CAAC;AAEzB,QAAM,KAAK,SAAI,OAAO,EAAE,CAAC;AACzB,QAAM,KAAK,8BAA8B;AACzC,QAAM,KAAK,SAAI,OAAO,EAAE,GAAG,EAAE;AAE7B,QAAM,KAAK,uPAAoD;AAC/D,QAAM,KAAK,oBAAe,OAAO,SAAS,KAAK,OAAO,OAAO,SAAS,WAAW,KAAK,QAAQ,CAAC,CAAC,MAAM,OAAO,SAAS,MAAM,IAAI,OAAO,SAAS,KAAK,GAAG;AACxJ,QAAM,KAAK,qBAAgB,OAAO,SAAS,KAAK,OAAO,OAAO,SAAS,WAAW,KAAK,QAAQ,CAAC,CAAC,MAAM,OAAO,SAAS,MAAM,IAAI,OAAO,SAAS,KAAK,GAAG;AACzJ,QAAM,KAAK,gBAAW,OAAO,gBAAgB,IAAI,MAAM,EAAE,IAAI,OAAO,eAAe,KAAK,QAAQ,CAAC,CAAC,IAAI;AACtG,QAAM,KAAK,wCAA8B,OAAO,iBAAiB,WAAM,QAAG,EAAE;AAC5E,QAAM,KAAK,gTAAsD,EAAE;AAEnE,QAAM,KAAK,4PAAoD;AAC/D,QAAM,KAAK,qBAAgB,OAAO,SAAS,kBAAkB,KAAM,QAAQ,CAAC,CAAC,GAAG;AAChF,QAAM,KAAK,sBAAiB,OAAO,SAAS,kBAAkB,KAAM,QAAQ,CAAC,CAAC,GAAG;AACjF,QAAM,KAAK,kBAAa,OAAO,yBAAyB,IAAI,MAAM,EAAE,GAAG,OAAO,sBAAsB,QAAQ,CAAC,CAAC,GAAG;AACjH,QAAM,KAAK,gCAAwB,OAAO,qBAAqB,WAAM,QAAG,EAAE;AAC1E,QAAM,KAAK,gTAAsD,EAAE;AAEnE,MAAI,OAAO,YAAY,SAAS,GAAG;AACjC,UAAM,KAAK,uBAAkB,OAAO,YAAY,MAAM,IAAI;AAC1D,eAAW,KAAK,OAAO,aAAa;AAClC,YAAM,KAAK,YAAO,EAAE,KAAK,EAAE;AAC3B,UAAI,EAAE,MAAO,OAAM,KAAK,cAAc,EAAE,MAAM,UAAU,GAAG,GAAG,CAAC,EAAE;AAAA,IACnE;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,aAAa,SAAS,GAAG;AAClC,UAAM,KAAK,wBAAmB,OAAO,aAAa,MAAM,IAAI;AAC5D,eAAW,OAAO,OAAO,aAAc,OAAM,KAAK,YAAO,IAAI,KAAK,EAAE;AACpE,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,oBAAoB,SAAS,GAAG;AACzC,UAAM,KAAK,SAAI,OAAO,EAAE,CAAC;AACzB,UAAM,KAAK,mCAAmC;AAC9C,UAAM,KAAK,SAAI,OAAO,EAAE,CAAC;AACzB,eAAW,OAAO,OAAO,qBAAqB;AAC5C,YAAM,KAAK;AAAA,KAAQ,IAAI,QAAQ,KAAK,IAAI,KAAK,EAAE;AAC/C,YAAM,KAAK,iBAAiB,IAAI,UAAU,EAAE;AAC5C,YAAM,KAAK,cAAc,IAAI,aAAa,KAAK,IAAI,CAAC,EAAE;AAAA,IACxD;AAAA,EACF;AAEA,QAAM,KAAK,IAAI,SAAI,OAAO,EAAE,CAAC;AAC7B,SAAO,MAAM,KAAK,IAAI;AACxB;;;AChVA;AASA,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AAkBf,SAAS,kBACd,WACA,SACkB;AAClB,QAAM,aAAa,SAAS,YAAY;AACxC,QAAM,UAAU,oBAAI,IAA8B;AAClD,QAAM,SAAiD,CAAC;AAExD,QAAM,SAAc,cAAQ,SAAS;AACrC,MAAI,CAAI,eAAW,MAAM,GAAG;AAC1B,WAAO,EAAE,SAAS,QAAQ,CAAC,EAAE,MAAM,QAAQ,OAAO,2BAA2B,CAAC,GAAG,aAAa,GAAG,aAAa,EAAE;AAAA,EAClH;AAEA,QAAM,QAAW,gBAAY,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,OAAO,KAAK,CAAC,EAAE,SAAS,cAAc,CAAC;AAErG,aAAW,QAAQ,OAAO;AACxB,UAAM,WAAgB,WAAK,QAAQ,IAAI;AACvC,QAAI;AACF,YAAM,UAAa,iBAAa,UAAU,OAAO;AACjD,YAAM,SAA2B,KAAK,MAAM,OAAO;AAEnD,UAAI,CAAC,OAAO,YAAY;AACtB,eAAO,KAAK,EAAE,MAAM,OAAO,2BAA2B,CAAC;AACvD;AAAA,MACF;AAGA,UAAI,YAAY;AACd,cAAM,SAAS,qBAAqB,QAAQ,QAAW,EAAE,YAAY,CAAC,YAAY,QAAQ,EAAE,CAAC;AAC7F,YAAI,CAAC,OAAO,QAAQ;AAClB,gBAAM,YAAY,OAAO,OAAO,IAAI,CAAC,MAAM,IAAI,EAAE,IAAI,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,IAAI;AAChF,iBAAO,KAAK,EAAE,MAAM,OAAO,6BAA6B,SAAS,GAAG,CAAC;AAAA,QAEvE;AAAA,MACF;AAEA,cAAQ,IAAI,OAAO,YAAY,MAAM;AAAA,IACvC,SAAS,KAAK;AACZ,aAAO,KAAK,EAAE,MAAM,OAAQ,IAAc,QAAQ,CAAC;AAAA,IACrD;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,aAAa,QAAQ;AAAA,IACrB,aAAa,OAAO;AAAA,EACtB;AACF;AAKO,SAAS,gBACd,WACA,YACyB;AACzB,QAAM,WAAgB,cAAQ,WAAW,GAAG,UAAU,OAAO;AAC7D,MAAI,CAAI,eAAW,QAAQ,EAAG,QAAO;AAErC,MAAI;AACF,UAAM,UAAa,iBAAa,UAAU,OAAO;AACjD,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAAS,kBAAkB,WAA6B;AAC7D,QAAM,SAAc,cAAQ,SAAS;AACrC,MAAI,CAAI,eAAW,MAAM,EAAG,QAAO,CAAC;AAEpC,SAAU,gBAAY,MAAM,EACzB,OAAO,CAAC,MAAM,EAAE,SAAS,OAAO,KAAK,CAAC,EAAE,SAAS,cAAc,CAAC,EAChE,IAAI,CAAC,MAAM,EAAE,QAAQ,WAAW,EAAE,CAAC;AACxC;;;AC1GA;;;ACAA;;;ACAA;AAYA,IAAM,iBAAyC;AAAA,EAC7C,QAAQ;AAAA,EACR,OAAO;AACT;AAEA,IAAM,oBAA4C;AAAA,EAChD,QAAQ;AAAA,EACR,OAAO;AACT;AAMO,SAASC,sBAAqB,QAAgC;AACnE,QAAM,WAAW,OAAO,aAAa,UAAU,UAAU;AACzD,QAAM,UAAU,OAAO,WAAW,kBAAkB,QAAQ;AAC5D,QAAM,QAAQ,OAAO,SAAS,eAAe,QAAQ;AACrD,QAAM,YAAY,OAAO,aAAa;AACtC,QAAM,cAAc,OAAO,eAAe;AAE1C,MAAI,CAAC,OAAO,QAAQ;AAClB,UAAM,IAAI;AAAA,MACR,2BAA2B,QAAQ;AAAA,IACrC;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IAEN,MAAM,KAAK,UAAqE;AAC9E,YAAM,MAAM,GAAG,OAAO;AAEtB,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,iBAAiB,UAAU,OAAO,MAAM;AAAA,QAC1C;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB;AAAA,UACA;AAAA,UACA,YAAY;AAAA,UACZ;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,YAAY,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,eAAe;AACnE,cAAM,IAAI,MAAM,kBAAkB,SAAS,MAAM,MAAM,SAAS,EAAE;AAAA,MACpE;AAEA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,YAAM,UAAU,KAAK,UAAU,CAAC,GAAG,SAAS;AAC5C,UAAI,CAAC,SAAS;AACZ,cAAM,IAAI,MAAM,6BAA6B;AAAA,MAC/C;AACA,aAAO;AAAA,IACT;AAAA,IAEA,eAAe,MAAsB;AAEnC,YAAM,YAAY,KAAK,MAAM,+BAA+B,KAAK,CAAC,GAAG;AACrE,YAAM,aAAa,KAAK,SAAS;AACjC,aAAO,KAAK,KAAK,aAAa,IAAI,WAAW,CAAC;AAAA,IAChD;AAAA,EACF;AACF;;;AC/EA;AASO,SAASC,sBAAqB,QAAgC;AACnE,QAAM,UAAU,OAAO,WAAW;AAClC,QAAM,QAAQ,OAAO,SAAS;AAE9B,SAAO;AAAA,IACL,MAAM;AAAA,IAEN,MAAM,KAAK,UAAqE;AAC9E,YAAM,MAAM,GAAG,OAAO;AAEtB,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU;AAAA,UACnB;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,QACV,CAAC;AAAA,MACH,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,YAAY,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,eAAe;AACnE,cAAM,IAAI,MAAM,qBAAqB,SAAS,MAAM,MAAM,SAAS,EAAE;AAAA,MACvE;AAEA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,YAAM,UAAU,KAAK,SAAS;AAC9B,UAAI,CAAC,SAAS;AACZ,cAAM,IAAI,MAAM,gCAAgC;AAAA,MAClD;AACA,aAAO;AAAA,IACT;AAAA,IAEA,eAAe,MAAsB;AAEnC,YAAM,YAAY,KAAK,MAAM,+BAA+B,KAAK,CAAC,GAAG;AACrE,YAAM,aAAa,KAAK,SAAS;AACjC,aAAO,KAAK,KAAK,aAAa,IAAI,WAAW,CAAC;AAAA,IAChD;AAAA,EACF;AACF;;;AFtCO,SAASC,mBAAkB,QAAgC;AAChE,QAAM,WAAsB;AAAA,IAC1B,GAAG;AAAA,IACH,QAAQ,OAAO,UAAU,QAAQ,IAAI;AAAA,EACvC;AAEA,UAAQ,OAAO,UAAU;AAAA,IACvB,KAAK;AAAA,IACL,KAAK;AACH,aAAOC,sBAAqB,QAAQ;AAAA,IACtC,KAAK;AACH,aAAOC,sBAAqB,QAAQ;AAAA,IACtC;AACE,YAAM,IAAI;AAAA,QACR,0BAA0B,OAAO,QAAQ;AAAA,MAC3C;AAAA,EACJ;AACF;AAYO,SAAS,mBAAmB,UAAqC;AACtE,MAAI,QAAQ;AAEZ,SAAO;AAAA,IACL,MAAM,MAAc;AAClB,eAAS,SAAS,eAAe,IAAI;AAAA,IACvC;AAAA,IAEA,UAAU,UAAoD,UAAkB;AAC9E,iBAAW,OAAO,UAAU;AAC1B,iBAAS,SAAS,eAAe,IAAI,OAAO;AAAA,MAC9C;AACA,eAAS,SAAS,eAAe,QAAQ;AAAA,IAC3C;AAAA,IAEA,IAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAAA,IAEA,QAAQ;AACN,cAAQ;AAAA,IACV;AAAA,EACF;AACF;AAKO,IAAM,iBAAiB;AAAA,EAC5B,iBAAiB;AAAA;AAAA;AAAA;AAAA,EAKjB,eAAe;AAAA;AAAA;AAAA;AAIjB;;;AG9EA;AAiCA,IAAM,WAAuC;AAAA,EAC3C,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,gBAAgB;AAClB;AAIO,SAAS,yBAAuC;AACrD,SAAO;AAAA,IACL,MAAM,QAAmC;AACvC,YAAM,WAA8B,CAAC;AAErC,YAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,iBAAW,QAAQ,OAAO;AAGxB,cAAM,YAAY,KAAK,MAAM,qBAAqB;AAClD,YAAI,WAAW;AACb,mBAAS,KAAK;AAAA,YACZ,OAAO,UAAU,CAAC,EAAE,KAAK;AAAA,YACzB,OAAO,UAAU,CAAC,EAAE,KAAK;AAAA,UAC3B,CAAC;AAAA,QACH;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,IACA,WAAW,QAAwB;AAEjC,UAAI,QAAQ;AACZ,YAAM,YAAY,OAAO,MAAM,gBAAgB;AAC/C,YAAM,YAAY,OAAO,MAAM,gBAAgB;AAC/C,UAAI,UAAW,UAAS,SAAS,UAAU,CAAC,GAAG,EAAE;AACjD,UAAI,UAAW,UAAS,SAAS,UAAU,CAAC,GAAG,EAAE;AACjD,aAAO,SAAS;AAAA,IAClB;AAAA,EACF;AACF;AAYA,eAAsB,cAAc,SAAwD;AAC1F,QAAM,MAAM,EAAE,GAAG,UAAU,GAAG,QAAQ,OAAO;AAC7C,QAAM,EAAE,QAAQ,QAAQ,MAAM,IAAI;AAElC,QAAM,UAA6B,CAAC;AACpC,QAAM,eAAe,oBAAI,IAAoB;AAE7C,WAAS,YAAY,GAAG,aAAa,IAAI,gBAAgB,GAAG,aAAa;AACvE,UAAM,YAAY,KAAK,IAAI;AAG3B,UAAM,EAAE,OAAO,IAAI,MAAM,OAAO,IAAI;AAGpC,UAAM,WAAW,OAAO,MAAM,MAAM;AACpC,UAAM,aAAa,OAAO,WAAW,MAAM;AAC3C,UAAM,SAAS,aAAa,SAAS;AAErC,UAAM,aAA8B;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ,SAAS;AAAA,MACjB,aAAa,SAAS,IAAI,OAAK,EAAE,KAAK;AAAA,MACtC,cAAc,CAAC;AAAA,MACf,YAAY;AAAA,IACd;AAGA,QAAI,SAAS,WAAW,GAAG;AACzB,iBAAW,aAAa,KAAK,IAAI,IAAI;AACrC,cAAQ,KAAK,UAAU;AACvB,cAAQ,cAAc,UAAU;AAChC;AAAA,IACF;AAGA,QAAI,YAAY,IAAI,eAAe;AACjC,iBAAW,aAAa,KAAK,IAAI,IAAI;AACrC,cAAQ,KAAK,UAAU;AACvB,cAAQ,cAAc,UAAU;AAChC;AAAA,IACF;AAGA,UAAM,cAAc,SAAS,OAAO,OAAK;AACvC,YAAM,MAAM,GAAG,EAAE,KAAK,KAAK,EAAE,KAAK;AAClC,YAAM,SAAS,aAAa,IAAI,GAAG,KAAK,KAAK;AAC7C,mBAAa,IAAI,KAAK,KAAK;AAC3B,aAAO,SAAS,IAAI;AAAA,IACtB,CAAC;AAED,QAAI,YAAY,WAAW,GAAG;AAC5B,iBAAW,aAAa,KAAK,IAAI,IAAI;AACrC,cAAQ,KAAK,UAAU;AACvB,cAAQ,cAAc,UAAU;AAChC;AAAA,IACF;AAGA,eAAW,WAAW,aAAa;AACjC,YAAM,UAAU,MAAM,MAAM,MAAM,OAAO;AACzC,UAAI,QAAQ,SAAS;AACnB,mBAAW,aAAa,KAAK,QAAQ,KAAK;AAAA,MAC5C;AAAA,IACF;AAEA,eAAW,aAAa,KAAK,IAAI,IAAI;AACrC,YAAQ,KAAK,UAAU;AACvB,YAAQ,cAAc,UAAU;AAGhC,QAAI,WAAW,aAAa,WAAW,KAAK,CAAC,IAAI,gBAAgB;AAC/D;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAQ,QAAQ,QAAQ,SAAS,CAAC;AACxC,QAAM,oBAAoB,QAAQ,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,aAAa,QAAQ,CAAC;AAEnF,SAAO;AAAA,IACL,YAAY;AAAA,IACZ,aAAa,OAAO,UAAU;AAAA,IAC9B,aAAa,OAAO,UAAU;AAAA,IAC9B;AAAA,IACA,UAAU,OAAO,UAAU,OAAO;AAAA,EACpC;AACF;;;AC1KA;AASA,SAAS,cAAAC,aAAY,cAAc,gBAAAC,eAAc,eAAe,WAAW,kBAAkB;AAC7F,SAAS,eAAe;AAiCxB,IAAM,YAAmB;AAAA,EACvB,QAAQD;AAAA,EACR,MAAM,CAAC,MAAMC,cAAa,GAAG,OAAO;AAAA,EACpC,OAAO,CAAC,GAAG,MAAM;AAAE,cAAU,QAAQ,CAAC,GAAG,EAAE,WAAW,KAAK,CAAC;AAAG,kBAAc,GAAG,GAAG,OAAO;AAAA,EAAG;AAAA,EAC7F,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ,CAAC,MAAM,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AACjD;AAcA,eAAsB,mBAAmB,MAA6D;AACpG,QAAMC,OAAK,KAAK,MAAM;AACtB,QAAM,QAAkB,KAAK,SAAS,SAAS;AAC/C,QAAM,SAAS,KAAK,SAAS,UAAU;AACvC,QAAM,SAAS,KAAK,SAAS,UAAU;AACvC,QAAM,aAAa,KAAK;AACxB,QAAM,aAAa,aAAa;AAKhC,MAAI,CAACA,KAAG,OAAO,UAAU,GAAG;AAC1B,WAAO,EAAE,SAAS,OAAO,OAAO,YAAY,CAAC,GAAG,YAAY,OAAO,OAAO,0BAA0B,UAAU,GAAG;AAAA,EACnH;AAEA,QAAM,kBAAkBA,KAAG,KAAK,UAAU;AAG1C,EAAAA,KAAG,MAAM,YAAY,eAAe;AAGpC,QAAM,aAAa,KAAK,UAAU,SAAS,eAAe;AAE1D,MAAI,WAAW,QAAQ;AAErB,YAAQA,MAAI,UAAU;AACtB,WAAO,EAAE,SAAS,MAAM,OAAO,YAAY,CAAC,GAAG,YAAY,MAAM;AAAA,EACnE;AAGA,MAAI;AACJ,MAAI;AACF,gBAAY,KAAK,MAAM,IAAI,iBAAiB,WAAW,MAAM;AAAA,EAC/D,SAAS,KAAK;AACZ,aAASA,MAAI,YAAY,UAAU;AACnC,WAAO,EAAE,SAAS,OAAO,OAAO,YAAY,CAAC,GAAG,YAAY,MAAM,OAAO,cAAc,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG;AAAA,EAC5I;AAEA,MAAI,CAAC,UAAU,SAAS;AACtB,aAASA,MAAI,YAAY,UAAU;AACnC,WAAO,EAAE,SAAS,OAAO,OAAO,YAAY,UAAU,YAAY,YAAY,MAAM,OAAO,qBAAqB,UAAU,gBAAgB,KAAK,IAAI,CAAC,GAAG;AAAA,EACzJ;AAGA,MAAI,QAAQ;AACV,UAAM,gBAAgB,KAAK,UAAU,SAAS,UAAU,YAAY;AACpE,QAAI,CAAC,cAAc,QAAQ;AACzB,eAASA,MAAI,YAAY,UAAU;AACnC,aAAO,EAAE,SAAS,OAAO,OAAO,YAAY,UAAU,YAAY,YAAY,MAAM,OAAO,8BAA8B,cAAc,OAAO,KAAK,IAAI,CAAC,GAAG;AAAA,IAC7J;AAAA,EACF;AAGA,EAAAA,KAAG,MAAM,YAAY,UAAU,YAAY;AAG3C,MAAI,QAAQ;AACV,UAAM,WAAWA,KAAG,KAAK,UAAU;AACnC,UAAM,iBAAiB,KAAK,UAAU,SAAS,QAAQ;AACvD,QAAI,CAAC,eAAe,QAAQ;AAC1B,eAASA,MAAI,YAAY,UAAU;AACnC,aAAO,EAAE,SAAS,OAAO,OAAO,YAAY,UAAU,YAAY,YAAY,MAAM,OAAO,mCAAmC,eAAe,OAAO,KAAK,IAAI,CAAC,GAAG;AAAA,IACnK;AAAA,EACF;AAGA,UAAQA,MAAI,UAAU;AAGtB,MAAI;AACJ,MAAI,UAAU,uBAAuB,KAAK,eAAe,KAAK,aAAa;AACzE,QAAI;AACF,cAAQ,MAAM,KAAK,YAAY,SAAS,KAAK,WAAW;AAAA,IAC1D,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,MAAM,OAAO,YAAY,UAAU,YAAY,YAAY,OAAO,MAAM;AAC5F;AAEA,SAAS,SAASA,MAAW,YAAoB,YAA0B;AACzE,MAAIA,KAAG,OAAO,UAAU,GAAG;AACzB,UAAM,SAASA,KAAG,KAAK,UAAU;AACjC,IAAAA,KAAG,MAAM,YAAY,MAAM;AAC3B,IAAAA,KAAG,OAAO,UAAU;AAAA,EACtB;AACF;AAEA,SAAS,QAAQA,MAAW,YAA0B;AACpD,MAAIA,KAAG,OAAO,UAAU,GAAG;AACzB,IAAAA,KAAG,OAAO,UAAU;AAAA,EACtB;AACF;;;AC7JA;AAsBA,IAAM,kBAA8C;AAAA,EAClD,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,WAAW;AACb;AAIA,eAAsB,cACpB,aACA,KACA,aACA,SAC0B;AAC1B,QAAM,OAAO,EAAE,GAAG,iBAAiB,GAAG,QAAQ;AAC9C,QAAM,MAAK,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,SAAS,GAAG;AACxD,QAAM,SAAS,GAAG,KAAK,YAAY,GAAG,EAAE;AACxC,QAAM,YAAY,gBAAgB,EAAE;AAGpC,QAAM,IAAI,KAAK,OAAO,CAAC,YAAY,MAAM,MAAM,CAAC;AAGhD,QAAM,YAAY,MAAM,QAAQ;AAChC,QAAM,YAAY,MAAM,WAAW,YAAY,cAAc,SAAS;AAGtE,MAAI;AACF,UAAM,IAAI,KAAK,OAAO,CAAC,SAAS,SAAS,CAAC;AAAA,EAC5C,QAAQ;AAAA,EAER;AAGA,QAAM,IAAI,KAAK,OAAO,CAAC,OAAO,GAAG,CAAC;AAClC,QAAM,IAAI,KAAK,OAAO,CAAC,UAAU,MAAM,2BAA2B,YAAY,QAAQ,GAAG,CAAC;AAC1F,QAAM,IAAI,KAAK,OAAO,CAAC,QAAQ,UAAU,MAAM,CAAC;AAGhD,QAAM,SAAS;AAAA,IACb;AAAA,IAAM;AAAA,IAAU;AAAA,IAChB;AAAA,IAAW,YAAY,YAAY,QAAQ;AAAA,IAC3C;AAAA,IAAU,YAAY,WAAW;AAAA,EACnC;AACA,QAAM,EAAE,QAAQ,MAAM,IAAI,MAAM,IAAI,KAAK,MAAM,MAAM;AAGrD,QAAM,IAAI,KAAK,OAAO,CAAC,YAAY,KAAK,UAAU,CAAC;AAEnD,SAAO,EAAE,OAAO,MAAM,KAAK,GAAG,QAAQ,UAAU;AAClD;AAEA,SAAS,YAAY,GAAgC;AACnD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,aAAa,EAAE,QAAQ;AAAA,IACvB,iBAAiB,EAAE,QAAQ,oBAAoB,EAAE,QAAQ,uBAAuB,EAAE,aAAa,KAAK,QAAQ,CAAC,CAAC;AAAA,IAC9G;AAAA,IACA;AAAA,IACA,EAAE;AAAA,IACF;AAAA,IACA;AAAA,IACA,EAAE,cAAc;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;;;ANjEO,SAAS,kBAAkB,cAGhC;AACA,QAAM,MAAM,aAAa,YAAY;AAErC,MAAI,+BAA+B,KAAK,GAAG;AACzC,WAAO,EAAE,UAAU,eAAe,YAAY,IAAI;AACpD,MAAI,uBAAuB,KAAK,GAAG;AACjC,WAAO,EAAE,UAAU,WAAW,YAAY,IAAI;AAChD,MAAI,gBAAgB,KAAK,GAAG;AAC1B,WAAO,EAAE,UAAU,sBAAsB,YAAY,KAAK;AAC5D,MAAI,iCAAiC,KAAK,GAAG;AAC3C,WAAO,EAAE,UAAU,mBAAmB,YAAY,KAAK;AACzD,MAAI,iCAAiC,KAAK,GAAG;AAC3C,WAAO,EAAE,UAAU,WAAW,YAAY,IAAI;AAChD,MAAI,2BAA2B,KAAK,GAAG;AACrC,WAAO,EAAE,UAAU,mBAAmB,YAAY,IAAI;AACxD,MAAI,6BAA6B,KAAK,GAAG;AACvC,WAAO,EAAE,UAAU,eAAe,YAAY,IAAI;AAEpD,SAAO,EAAE,UAAU,WAAW,YAAY,IAAI;AAChD;AAKA,eAAsB,sBACpB,cACA,KAC4F;AAE5F,QAAM,YAAY,kBAAkB,YAAY;AAEhD,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,MACL,WAAW;AAAA,MACX,UAAU,UAAU;AAAA,MACpB,cAAc;AAAA,MACd,YAAY,UAAU;AAAA,IACxB;AAAA,EACF;AAEA,MAAI;AACF,UAAM,WAAW,MAAM,IAAI,KAAK;AAAA,MAC9B,EAAE,MAAM,UAAU,SAAS,eAAe,gBAAgB;AAAA,MAC1D,EAAE,MAAM,QAAQ,SAAS;AAAA;AAAA,EAAiC,YAAY,GAAG;AAAA,IAC3E,CAAC;AAED,UAAM,SAAS,KAAK,MAAM,QAAQ;AAOlC,WAAO;AAAA,MACL,WAAW,OAAO,aAAa;AAAA,MAC/B,UAAU,OAAO,YAAY,UAAU;AAAA,MACvC,cAAc,OAAO,gBAAgB;AAAA,MACrC,YAAY,OAAO,cAAc,UAAU;AAAA,IAC7C;AAAA,EACF,QAAQ;AAEN,WAAO;AAAA,MACL,WAAW;AAAA,MACX,UAAU,UAAU;AAAA,MACpB,cAAc;AAAA,MACd,YAAY,UAAU;AAAA,IACxB;AAAA,EACF;AACF;AAKA,eAAe,iBACb,iBACA,OACA,MACqB;AAGrB,SAAO;AAAA,IACL,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY,CAAC;AAAA,IACb,YAAY;AAAA,EACd;AACF;AAKO,SAAS,sBAAsB,QAA2B,KAAoC;AACnG,SAAO;AAAA,IACL,MAAM,IAAI,gBAAoD;AAC5D,YAAM,gBAAgB,OAAO,iBAAiB;AAC9C,YAAM,OAAO,OAAO,QAAQ;AAC5B,YAAM,QAAkB,CAAC;AACzB,YAAM,YAAsB,CAAC;AAC7B,UAAI,aAAa;AACjB,UAAI,kBAAkB;AAEtB,eAAS,IAAI,GAAG,IAAI,eAAe,KAAK;AACtC,qBAAa,IAAI;AAEjB,cAAM,UAAU,MAAM,iBAAiB,gBAAgB,MAAM,GAAG;AAChE,YAAI,QAAQ,SAAS;AACnB,gBAAM,KAAK,GAAG,QAAQ,UAAU;AAAA,QAClC,OAAO;AACL,oBAAU,KAAK,aAAa,IAAI,CAAC,kBAAkB;AAAA,QACrD;AAGA,YAAI,KAAK;AACP,6BAAmB,IAAI,eAAe,aAAa,IAAI,CAAC,EAAE;AAAA,QAC5D;AAGA,YAAI,QAAQ,WAAW,QAAQ,WAAW,SAAS,EAAG;AAAA,MACxD;AAEA,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AO5JA;AAGA;AAGO,SAASC,0BAAyC;AACvD,SAAO;AAAA,IACL,MAAM;AAAA,IAEN,MAAM,YAAY,KAAqC;AACrD,aAAO,kBAAkB,GAAG;AAAA,IAC9B;AAAA,IAEA,MAAM,kBAAkB,MAA6C;AACnE,aAAO,qBAAqB,IAAI;AAAA,IAClC;AAAA,IAEA,MAAM,iBAAiB,KAAoC;AACzD,YAAM,YAAY,yBAAyB,GAAG;AAC9C,aAAO,UAAU,IAAI,CAAC,QAAQ;AAAA,QAC5B,QAAQ,GAAG;AAAA,QACX,MAAM,GAAG;AAAA,QACT,SAAS;AAAA,QACT,iBAAiB;AAAA,MACnB,EAAE;AAAA,IACJ;AAAA,EACF;AACF;;;AC5BA;AAAA,YAAYC,SAAQ;AACpB,YAAYC,YAAU;AACtB;AAAA,EACE,WAAAC;AAAA,OAGK;AAIP,IAAM,mBAA2C;AAAA,EAC/C,0BAA0B;AAAA,EAC1B,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,iBAAiB;AACnB;AAEA,IAAM,0BAAkD;AAAA,EACtD,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,WAAW;AAAA,EACX,UAAU;AAAA,EACV,SAAS;AAAA,EACT,UAAU;AAAA,EACV,WAAW;AAAA,EACX,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AACV;AAEA,SAAS,kBAAkB,QAAwB;AACjD,QAAM,IAAI,OAAO,YAAY,EAAE,KAAK;AACpC,MAAI,MAAM,SAAU,QAAO;AAC3B,MAAI,MAAM,SAAU,QAAO;AAC3B,MAAI,MAAM,UAAW,QAAO;AAC5B,MAAI,MAAM,OAAQ,QAAO;AACzB,SAAO;AACT;AAEA,SAASC,sBAAqB,MAAsB;AAClD,SAAO,KAAK,QAAQ,YAAY,KAAK,EAAE,YAAY,EAAE,QAAQ,MAAM,EAAE;AACvE;AAEA,SAAS,0BAA0B,eAA2C;AAC5E,QAAM,QAAQ,cAAc,MAAM,4BAA4B;AAC9D,SAAO,QAAQ,CAAC;AAClB;AAEA,SAAS,0BAA0B,eAA+C;AAChF,QAAM,SAAiC,CAAC;AACxC,QAAM,WAAW,cAAc,MAAM,uBAAuB;AAC5D,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,OAAO,SAAS,CAAC;AACvB,QAAM,QAAQ,KAAK,SAAS,+BAA+B;AAC3D,aAAW,QAAQ,OAAO;AACxB,WAAO,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC;AAAA,EAC1B;AAEA,QAAM,YAAY,KAAK,SAAS,2BAA2B;AAC3D,aAAW,QAAQ,WAAW;AAC5B,WAAO,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC;AAAA,EAC1B;AACA,SAAO;AACT;AAEO,SAAS,iBAAiB,UAAsC;AACrE,QAAM,eAAoB,eAAQ,QAAQ;AAC1C,MAAI,CAAI,eAAW,YAAY,EAAG,QAAO;AAEzC,QAAM,UAAU,IAAID,SAAQ,EAAE,iBAAiB,EAAE,QAAQ,MAAM,EAAE,CAAC;AAClE,QAAM,aAAa,QAAQ,oBAAoB,YAAY;AAE3D,QAAM,UAAU,WAAW,WAAW;AACtC,aAAW,OAAO,SAAS;AACzB,UAAM,kBAAkB,IAAI,aAAa,QAAQ;AACjD,QAAI,CAAC,gBAAiB;AAEtB,UAAM,YAAY,0BAA0B,gBAAgB,QAAQ,CAAC,KAChE,0BAA0B,gBAAgB,QAAQ,CAAC,EAAE,QACrDC,sBAAqB,IAAI,QAAQ,KAAK,SAAS;AAEpD,UAAM,SAAS,qBAAqB,GAAG;AACvC,WAAO,EAAE,WAAW,WAAW,IAAI,QAAQ,GAAG,OAAO;AAAA,EACvD;AACA,SAAO;AACT;AAEA,SAAS,qBAAqB,KAAsC;AAClE,QAAM,SAAwB,CAAC;AAE/B,aAAW,QAAQ,IAAI,cAAc,GAAG;AACtC,UAAM,QAAQ,qBAAqB,IAAI;AACvC,QAAI,MAAO,QAAO,KAAK,KAAK;AAAA,EAC9B;AACA,SAAO;AACT;AAEA,SAAS,qBAAqB,MAA+C;AAC3E,QAAM,aAAa,KAAK,cAAc;AACtC,MAAI,WAAW,WAAW,EAAG,QAAO;AAEpC,QAAM,OAAO,KAAK,QAAQ;AAC1B,MAAI,OAAO;AACX,MAAI,aAAa;AACjB,MAAI,YAAY;AAChB,MAAI,SAAS;AAEb,aAAW,OAAO,YAAY;AAC5B,UAAM,UAAU,IAAI,QAAQ;AAC5B,UAAM,UAAU,IAAI,QAAQ;AAE5B,QAAI,YAAY,4BAA4B,YAAY,iBAAiB;AACvE,mBAAa;AACb,aAAO,iBAAiB,OAAO,KAAK;AACpC,kBAAY;AACZ,YAAM,UAAU,0BAA0B,OAAO;AACjD,UAAI,YAAY,OAAQ,QAAO;AAC/B,UAAI,YAAY,YAAa,QAAO;AAAA,IACtC;AAEA,QAAI,YAAY,UAAU;AACxB,YAAM,UAAU,0BAA0B,OAAO;AACjD,UAAI,QAAQ,QAAQ,wBAAwB,QAAQ,IAAI,GAAG;AACzD,eAAO,wBAAwB,QAAQ,IAAI;AAAA,MAC7C,OAAO;AACL,cAAM,aAAa,0BAA0B,OAAO;AACpD,YAAI,cAAc,wBAAwB,UAAU,GAAG;AACrD,iBAAO,wBAAwB,UAAU;AAAA,QAC3C;AAAA,MACF;AACA,UAAI,QAAQ,aAAa,QAAS,aAAY;AAC9C,UAAI,QAAQ,WAAW,OAAQ,UAAS;AAGxC,UAAI,SAAS,UAAU;AACrB,cAAM,SAAS,KAAK,QAAQ,EAAE,QAAQ;AACtC,eAAO,kBAAkB,MAAM;AAAA,MACjC;AAAA,IACF;AAEA,QAAI,WAAW,kBAAkB;AAC/B,aAAO,iBAAiB,OAAO;AAAA,IACjC;AAEA,QAAI,YAAY,sBAAsB,YAAY,sBAAsB,YAAY,oBAAoB;AACtG,kBAAY;AAAA,IACd;AAAA,EACF;AAGA,QAAM,uBAAuB;AAAA,IAAC;AAAA,IAAU;AAAA,IAA0B;AAAA,IAChE;AAAA,IAAoB;AAAA,IAAoB;AAAA,IAAoB;AAAA,IAC5D;AAAA,IAAa;AAAA,IAAa;AAAA,IAAY;AAAA,IAAc;AAAA,IAAc;AAAA,EAAW;AAC/E,QAAM,gBAAgB,WAAW,KAAK,CAAC,MAAM,qBAAqB,SAAS,EAAE,QAAQ,CAAC,CAAC;AACvF,MAAI,CAAC,cAAe,QAAO;AAG3B,QAAM,iBAAiB,WAAW;AAAA,IAAM,CAAC,MACvC,CAAC,aAAa,aAAa,YAAY,cAAc,cAAc,WAAW,EAAE,SAAS,EAAE,QAAQ,CAAC;AAAA,EACtG;AACA,MAAI,eAAgB,QAAO;AAE3B,SAAO,EAAE,MAAM,MAAM,WAAW,YAAY,OAAO;AACrD;AAEO,SAAS,yBAAyB,UAAwC;AAC/E,QAAM,eAAoB,eAAQ,QAAQ;AAC1C,MAAI,CAAI,eAAW,YAAY,EAAG,QAAO,CAAC;AAE1C,QAAM,UAAU,IAAID,SAAQ,EAAE,iBAAiB,EAAE,QAAQ,MAAM,EAAE,CAAC;AAClE,QAAM,aAAa,QAAQ,oBAAoB,YAAY;AAE3D,QAAM,YAAkC,CAAC;AACzC,aAAW,OAAO,WAAW,WAAW,GAAG;AACzC,UAAM,kBAAkB,IAAI,aAAa,QAAQ;AACjD,QAAI,CAAC,gBAAiB;AAEtB,UAAM,cAAc,0BAA0B,gBAAgB,QAAQ,CAAC,KAClEC,sBAAqB,IAAI,QAAQ,KAAK,SAAS;AAEpD,eAAW,QAAQ,IAAI,cAAc,GAAG;AACtC,YAAM,MAAM,4BAA4B,MAAM,WAAW;AACzD,UAAI,IAAK,WAAU,KAAK,GAAG;AAAA,IAC7B;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,4BACP,MACA,aAC2B;AAC3B,QAAM,aAAa,KAAK,cAAc;AAEtC,aAAW,OAAO,YAAY;AAC5B,UAAM,UAAU,IAAI,QAAQ;AAC5B,UAAM,UAAU,IAAI,QAAQ;AAE5B,QAAI,YAAY,aAAa;AAC3B,YAAM,cAAc,sBAAsB,OAAO;AACjD,UAAI,CAAC,YAAa;AAClB,YAAM,cAAcA,sBAAqB,WAAW;AACpD,YAAM,UAAU,oBAAoB,UAAU,KAAK,GAAG,KAAK,QAAQ,CAAC;AACpE,aAAO;AAAA,QACL;AAAA,QAAa,aAAa;AAAA,QAC1B;AAAA,QAAa,aAAa;AAAA,QAC1B,aAAa;AAAA,MACf;AAAA,IACF;AAEA,QAAI,YAAY,aAAa;AAC3B,YAAM,cAAc,sBAAsB,OAAO;AACjD,UAAI,CAAC,YAAa;AAClB,YAAM,cAAcA,sBAAqB,WAAW;AACpD,aAAO;AAAA,QACL;AAAA,QAAa,aAAa;AAAA,QAC1B;AAAA,QAAa,aAAa,GAAGA,sBAAqB,WAAW,CAAC;AAAA,QAC9D,aAAa;AAAA,MACf;AAAA,IACF;AAEA,QAAI,YAAY,YAAY;AAC1B,YAAM,cAAc,sBAAsB,OAAO;AACjD,UAAI,CAAC,YAAa;AAClB,YAAM,cAAcA,sBAAqB,WAAW;AACpD,aAAO;AAAA,QACL;AAAA,QAAa,aAAa;AAAA,QAC1B;AAAA,QAAa,aAAa,GAAGA,sBAAqB,WAAW,CAAC;AAAA,QAC9D,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,sBAAsB,eAAsC;AAEnE,QAAM,QAAQ,cAAc,MAAM,+CAA+C;AACjF,SAAO,QAAQ,CAAC,KAAK;AACvB;AAEA,SAAS,oBAAoB,YAA6E;AACxG,aAAW,OAAO,YAAY;AAC5B,QAAI,IAAI,QAAQ,MAAM,cAAc;AAClC,YAAM,OAAO,0BAA0B,IAAI,QAAQ,CAAC;AACpD,UAAI,KAAK,KAAM,QAAO,KAAK;AAAA,IAC7B;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,sBAAsB,KAA4B;AAChE,QAAM,cAAmB,eAAQ,GAAG;AACpC,MAAI,CAAI,eAAW,WAAW,EAAG,QAAO,CAAC;AAEzC,QAAM,QAAW,gBAAY,WAAW,EAAE;AAAA,IAAO,CAAC,MAChD,EAAE,SAAS,KAAK,KAChB,CAAC,EAAE,SAAS,UAAU,KACtB,CAAC,EAAE,SAAS,UAAU,KACtB,MAAM;AAAA,EACR;AAEA,QAAM,UAAyB,CAAC;AAChC,aAAW,QAAQ,OAAO;AACxB,QAAI;AACF,YAAM,SAAS,iBAAsB,YAAK,aAAa,IAAI,CAAC;AAC5D,UAAI,OAAQ,SAAQ,KAAK,MAAM;AAAA,IACjC,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,gCAAgC,KAAmC;AACjF,QAAM,cAAmB,eAAQ,GAAG;AACpC,MAAI,CAAI,eAAW,WAAW,EAAG,QAAO,CAAC;AAEzC,QAAM,QAAW,gBAAY,WAAW,EAAE;AAAA,IAAO,CAAC,MAChD,EAAE,SAAS,KAAK,KAChB,CAAC,EAAE,SAAS,UAAU,KACtB,CAAC,EAAE,SAAS,UAAU,KACtB,MAAM;AAAA,EACR;AAEA,QAAM,YAAkC,CAAC;AACzC,aAAW,QAAQ,OAAO;AACxB,QAAI;AACF,gBAAU,KAAK,GAAG,yBAA8B,YAAK,aAAa,IAAI,CAAC,CAAC;AAAA,IAC1E,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,uBAAuC;AACrD,SAAO;AAAA,IACL,MAAM;AAAA,IAEN,MAAM,YAAY,KAAqC;AACrD,aAAO,sBAAsB,GAAG;AAAA,IAClC;AAAA,IAEA,MAAM,kBAAkB,MAA6C;AAEnE,YAAM,MAAW,eAAQ,IAAI;AAC7B,aAAO,gCAAgC,GAAG;AAAA,IAC5C;AAAA,IAEA,MAAM,iBAAiB,KAAoC;AAEzD,YAAM,EAAE,0BAAAC,0BAAyB,IAAI,MAAM;AAC3C,YAAM,YAAYA,0BAAyB,GAAG;AAC9C,aAAO,UAAU,IAAI,CAAC,QAAQ;AAAA,QAC5B,QAAQ,GAAG;AAAA,QACX,MAAM,GAAG;AAAA,QACT,SAAS;AAAA,QACT,iBAAiB;AAAA,MACnB,EAAE;AAAA,IACJ;AAAA,EACF;AACF;;;AC3UA;AAAA,YAAYC,SAAQ;AACpB,YAAYC,YAAU;AAItB,IAAM,kBAA0C;AAAA,EAC9C,UAAU;AAAA,EACV,OAAO;AAAA,EACP,UAAU;AAAA,EACV,SAAS;AAAA,EACT,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,SAAS;AACX;AAyBO,SAAS,kBAAkB,SAAgC;AAChE,QAAM,SAAwB,CAAC;AAC/B,QAAM,aAAa;AACnB,MAAI;AAEJ,UAAQ,QAAQ,WAAW,KAAK,OAAO,OAAO,MAAM;AAClD,UAAM,YAAY,MAAM,CAAC;AACzB,UAAM,OAAO,MAAM,CAAC;AACpB,UAAM,SAAS,kBAAkB,IAAI;AACrC,UAAM,eAAe,KAAK,MAAM,2BAA2B;AAC3D,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN;AAAA,MACA,WAAW,eAAe,CAAC;AAAA,IAC7B,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,MAA6B;AACtD,QAAM,SAAwB,CAAC;AAC/B,QAAM,QAAQ,KAAK,MAAM,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,WAAW,IAAI,KAAK,CAAC,EAAE,WAAW,IAAI,CAAC;AAEjH,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,qBAAqB,IAAI;AACvC,QAAI,MAAO,QAAO,KAAK,KAAK;AAAA,EAC9B;AACA,SAAO;AACT;AAEA,SAAS,qBAAqB,MAAkC;AAE9D,QAAM,QAAQ,KAAK,MAAM,0BAA0B;AACnD,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,OAAO,MAAM,CAAC;AACpB,QAAM,UAAU,MAAM,CAAC;AACvB,QAAM,SAAS,CAAC,CAAC,MAAM,CAAC;AACxB,QAAM,aAAa,KAAK,SAAS,GAAG;AAEpC,QAAM,QAAqB;AAAA,IACzB;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA,MAAM,QAAQ,KAAK,IAAI;AAAA,IACvB,UAAU,YAAY,KAAK,IAAI;AAAA,IAC/B,aAAa,eAAe,KAAK,IAAI;AAAA,EACvC;AAGA,QAAM,eAAe,KAAK,MAAM,qBAAqB;AACrD,MAAI,aAAc,OAAM,eAAe,aAAa,CAAC;AAGrD,QAAM,WAAW,KAAK,MAAM,0BAA0B;AACtD,MAAI,SAAU,OAAM,UAAU,SAAS,CAAC;AAGxC,QAAM,cAAc,KAAK,MAAM,0BAA0B;AACzD,MAAI,YAAa,OAAM,aAAa,YAAY,CAAC;AAGjD,QAAM,WAAW,KAAK,MAAM,sBAAsB;AAClD,MAAI,UAAU;AACZ,UAAM,WAAW,uBAAuB,SAAS,CAAC,CAAC;AAAA,EACrD;AAEA,SAAO;AACT;AAEA,SAAS,uBAAuB,SAA0C;AACxE,QAAM,MAA4C,CAAC;AAEnD,QAAM,YAAY,QAAQ,MAAM,+BAA+B;AAC/D,MAAI,UAAW,KAAI,OAAO,UAAU,CAAC;AAErC,QAAM,cAAc,QAAQ,MAAM,wBAAwB;AAC1D,MAAI,aAAa;AACf,QAAI,SAAS,YAAY,CAAC,EAAE,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAAA,EAC5D;AAEA,QAAM,YAAY,QAAQ,MAAM,4BAA4B;AAC5D,MAAI,WAAW;AACb,QAAI,aAAa,UAAU,CAAC,EAAE,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAAA,EAC9D;AAEA,SAAO;AACT;AAEA,SAAS,qBAAqB,MAAsB;AAClD,SAAO,KAAK,QAAQ,YAAY,KAAK,EAAE,YAAY,EAAE,QAAQ,MAAM,EAAE;AACvE;AAEO,SAAS,sBAAsB,QAAsC;AAC1E,SAAO,OAAO,IAAI,CAAC,UAAU;AAC3B,UAAM,YAAY,MAAM,aAAa,qBAAqB,MAAM,IAAI;AACpE,UAAM,SAAwB,CAAC;AAE/B,eAAW,KAAK,MAAM,QAAQ;AAE5B,UAAI,EAAE,OAAQ;AACd,UAAI,CAAC,gBAAgB,EAAE,IAAI,KAAK,CAAC,EAAE,SAAU;AAE7C,UAAI,CAAC,gBAAgB,EAAE,IAAI,KAAK,EAAE,YAAY,CAAC,EAAE,SAAS,OAAQ;AAElE,YAAM,YAAY,gBAAgB,EAAE,IAAI,KAAK;AAC7C,aAAO,KAAK;AAAA,QACV,MAAM,EAAE,WAAW,EAAE;AAAA,QACrB,MAAM;AAAA,QACN,WAAW,EAAE;AAAA,QACb,YAAY,EAAE;AAAA,QACd,QAAQ,EAAE;AAAA,QACV,cAAc,EAAE;AAAA,MAClB,CAAC;AAAA,IACH;AAEA,WAAO,EAAE,WAAW,WAAW,MAAM,MAAM,OAAO;AAAA,EACpD,CAAC;AACH;AAEO,SAAS,wBAAwB,QAA6C;AACnF,QAAM,YAAkC,CAAC;AACzC,QAAM,OAAO,oBAAI,IAAY;AAE7B,aAAW,SAAS,QAAQ;AAC1B,UAAM,cAAc,MAAM,aAAa,qBAAqB,MAAM,IAAI;AAEtE,eAAW,SAAS,MAAM,QAAQ;AAChC,UAAI,CAAC,MAAM,UAAU,UAAU,CAAC,MAAM,UAAU,WAAY;AAE5D,YAAM,cAAc,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,IAAI;AAC5D,YAAM,cAAc,cACf,YAAY,aAAa,qBAAqB,YAAY,IAAI,IAC/D,qBAAqB,MAAM,IAAI;AAEnC,YAAM,cAAc,MAAM,SAAS,OAAO,CAAC;AAC3C,YAAM,cAAc,MAAM,SAAS,WAAW,CAAC;AAE/C,YAAM,MAAM,GAAG,WAAW,IAAI,WAAW,IAAI,WAAW,IAAI,WAAW;AACvE,UAAI,KAAK,IAAI,GAAG,EAAG;AACnB,WAAK,IAAI,GAAG;AAGZ,YAAM,SAAS,MAAM;AACrB,gBAAU,KAAK;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa,SAAS,QAAQ;AAAA,MAChC,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,gBAAgB,UAA+E;AAC7G,QAAM,eAAoB,eAAQ,QAAQ;AAC1C,MAAI,CAAI,eAAW,YAAY,EAAG,QAAO,EAAE,SAAS,CAAC,GAAG,WAAW,CAAC,EAAE;AAEtE,QAAM,UAAa,iBAAa,cAAc,OAAO;AACrD,QAAM,SAAS,kBAAkB,OAAO;AACxC,SAAO;AAAA,IACL,SAAS,sBAAsB,MAAM;AAAA,IACrC,WAAW,wBAAwB,MAAM;AAAA,EAC3C;AACF;AAEA,SAAS,qBAAqB,KAA4B;AAExD,QAAM,aAAa;AAAA,IACZ,YAAK,KAAK,eAAe;AAAA,IACzB,YAAK,KAAK,UAAU,eAAe;AAAA,IACnC,YAAK,KAAK,MAAM,UAAU,eAAe;AAAA,EAChD;AACA,aAAW,KAAK,YAAY;AAC1B,QAAO,eAAW,CAAC,EAAG,QAAO;AAAA,EAC/B;AACA,SAAO;AACT;AAEO,SAAS,sBAAsC;AACpD,SAAO;AAAA,IACL,MAAM;AAAA,IAEN,MAAM,YAAY,KAAqC;AACrD,YAAM,aAAa,qBAAqB,GAAG;AAC3C,UAAI,CAAC,WAAY,QAAO,CAAC;AACzB,YAAM,EAAE,QAAQ,IAAI,gBAAgB,UAAU;AAC9C,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,kBAAkB,MAA6C;AAEnE,YAAM,aAAa,qBAA0B,eAAQ,IAAI,CAAC,KAAK;AAC/D,YAAM,EAAE,UAAU,IAAI,gBAAgB,UAAU;AAChD,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,iBAAiB,KAAoC;AACzD,YAAM,EAAE,0BAAAC,0BAAyB,IAAI,MAAM;AAC3C,YAAM,YAAYA,0BAAyB,GAAG;AAC9C,aAAO,UAAU,IAAI,CAAC,QAAQ;AAAA,QAC5B,QAAQ,GAAG;AAAA,QACX,MAAM,GAAG;AAAA,QACT,SAAS;AAAA,QACT,iBAAiB;AAAA,MACnB,EAAE;AAAA,IACJ;AAAA,EACF;AACF;;;AC3PA;AAAA,YAAYC,UAAQ;AACpB,YAAYC,YAAU;AACtB;AAAA,EACE,WAAAC;AAAA,EACA,cAAAC;AAAA,EACA,QAAAC;AAAA,OAKK;AAIP,IAAM,mBAA2C;AAAA;AAAA,EAE/C,KAAK;AAAA,EACL,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,SAAS;AAAA,EACT,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,WAAW;AAAA;AAAA,EAEX,MAAM;AAAA,EACN,OAAO;AAAA,EACP,iBAAiB;AAAA,EACjB,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA;AAAA,EAET,SAAS;AAAA,EACT,MAAM;AAAA,EACN,UAAU;AAAA,EACV,MAAM;AAAA;AAAA,EAEN,SAAS;AAAA,EACT,MAAM;AAAA;AAAA,EAEN,MAAM;AAAA,EACN,UAAU;AAAA,EACV,WAAW;AAAA,EACX,aAAa;AAAA,EACb,MAAM;AAAA;AAAA,EAEN,MAAM;AAAA,EACN,OAAO;AAAA;AAAA,EAEP,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AACR;AAEA,IAAM,kBAAkB,oBAAI,IAAI,CAAC,WAAW,cAAc,aAAa,CAAC;AAmBxE,SAAS,eAAe,YAAwC;AAC9D,QAAM,SAAyB,CAAC;AAChC,QAAM,WAAW,WAAW,qBAAqBD,YAAW,mBAAmB;AAE/E,aAAW,QAAQ,UAAU;AAC3B,UAAM,OAAO,KAAK,eAAe;AACjC,QAAI,CAAC,QAAQ,KAAK,QAAQ,MAAMA,YAAW,eAAgB;AAE3D,UAAM,OAAO;AACb,UAAM,WAAW,KAAK,cAAc,EAAE,QAAQ,EAAE,KAAK;AACrD,QAAI,CAAC,gBAAgB,IAAI,QAAQ,EAAG;AAEpC,UAAM,OAAO,KAAK,aAAa;AAC/B,QAAI,KAAK,SAAS,EAAG;AAGrB,UAAM,UAAU,KAAK,CAAC;AACtB,QAAI,QAAQ,QAAQ,MAAMA,YAAW,cAAe;AACpD,UAAM,YAAY,QAAQ,QAAQ,EAAE,MAAM,GAAG,EAAE;AAG/C,UAAM,UAAU,KAAK,CAAC;AACtB,QAAI,QAAQ,QAAQ,MAAMA,YAAW,wBAAyB;AAE9D,UAAM,UAAU,kBAAkB,OAAkC;AACpE,WAAO,KAAK,EAAE,SAAS,KAAK,QAAQ,GAAG,WAAW,QAAQ,CAAC;AAAA,EAC7D;AAEA,SAAO;AACT;AAEA,SAAS,kBAAkB,KAA+C;AACxE,QAAM,UAA2B,CAAC;AAClC,aAAW,QAAQ,IAAI,cAAc,GAAG;AACtC,QAAI,CAACC,MAAK,qBAAqB,IAAI,EAAG;AACtC,UAAM,UAAU,KAAK,QAAQ;AAC7B,UAAM,MAAM,KAAK,eAAe;AAChC,QAAI,CAAC,IAAK;AACV,UAAM,MAAM,iBAAiB,KAAK,OAAO;AACzC,QAAI,IAAK,SAAQ,KAAK,GAAG;AAAA,EAC3B;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,MAAY,SAAuC;AAE3E,QAAM,QAA0B,CAAC;AACjC,MAAI,UAAgB;AAEpB,SAAO,QAAQ,QAAQ,MAAMD,YAAW,gBAAgB;AACtD,UAAM,QAAQ,OAAyB;AACvC,UAAM,SAAU,QAA2B,cAAc;AACzD,QAAI,OAAO,QAAQ,MAAMA,YAAW,0BAA0B;AAC5D,gBAAW,OAAoC,cAAc;AAAA,IAC/D,OAAO;AACL;AAAA,IACF;AAAA,EACF;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAG/B,QAAM,OAAO,MAAM,CAAC;AACpB,QAAM,eAAe,KAAK,cAAc,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,EAAE,IAAI,KAAK;AAC/E,QAAM,cAAc,iBAAiB,YAAY;AACjD,MAAI,CAAC,YAAa,QAAO;AAEzB,QAAM,WAAW,KAAK,aAAa;AACnC,QAAM,UACJ,SAAS,SAAS,KAAK,SAAS,CAAC,EAAE,QAAQ,MAAMA,YAAW,gBACxD,SAAS,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,EAAE,IACjC;AAEN,QAAM,MAAqB;AAAA,IACzB;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW;AAAA,IACX,UAAU;AAAA,EACZ;AAGA,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,CAAC;AACpB,UAAM,SAAS,KAAK,cAAc;AAClC,QAAI,OAAO,QAAQ,MAAMA,YAAW,yBAA0B;AAC9D,UAAM,aAAc,OAAoC,QAAQ;AAEhE,YAAQ,YAAY;AAAA,MAClB,KAAK;AACH,YAAI,YAAY;AAChB,YAAI,YAAY;AAChB;AAAA,MACF,KAAK;AACH,YAAI,YAAY;AAChB;AAAA,MACF,KAAK;AACH,YAAI,WAAW;AACf;AAAA,MACF,KAAK;AAAA,MACL,KAAK,cAAc;AACjB,cAAM,OAAO,KAAK,aAAa;AAC/B,YAAI,eAAe,KAAK,SAAS,IAAI,KAAK,CAAC,EAAE,QAAQ,IAAI;AACzD;AAAA,MACF;AAAA,MACA,KAAK,cAAc;AACjB,cAAM,OAAO,KAAK,aAAa;AAC/B,YAAI,KAAK,SAAS,EAAG,KAAI,iBAAiB,KAAK,CAAC,EAAE,QAAQ;AAC1D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,iBAAiB,QAA8C;AACtE,QAAM,YAAkC,CAAC;AACzC,QAAM,iBAAiB,oBAAI,IAAoB;AAC/C,QAAM,iBAAiB,oBAAI,IAAoB;AAE/C,aAAW,KAAK,QAAQ;AACtB,mBAAe,IAAI,EAAE,SAAS,EAAE,SAAS;AACzC,eAAW,KAAK,EAAE,SAAS;AACzB,qBAAe,IAAI,GAAG,EAAE,OAAO,IAAI,EAAE,OAAO,IAAI,EAAE,OAAO;AAAA,IAC3D;AAAA,EACF;AAEA,aAAW,KAAK,QAAQ;AACtB,eAAW,OAAO,EAAE,SAAS;AAC3B,UAAI,CAAC,IAAI,eAAgB;AAEzB,YAAM,aAAa,IAAI,eAAe,MAAM,mBAAmB;AAC/D,UAAI,CAAC,WAAY;AACjB,YAAM,gBAAgB,WAAW,CAAC;AAClC,YAAM,mBAAmB,WAAW,CAAC;AACrC,YAAM,cAAc,eAAe,IAAI,aAAa;AACpD,UAAI,CAAC,YAAa;AAClB,YAAM,YAAY,eAAe,IAAI,GAAG,aAAa,IAAI,gBAAgB,EAAE,KAAK;AAEhF,gBAAU,KAAK;AAAA,QACb,aAAa,EAAE;AAAA,QACf,aAAa,IAAI;AAAA,QACjB;AAAA,QACA,aAAa;AAAA,QACb,aAAa;AAAA,MACf,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,iBAAiB,UAA+E;AAC9G,QAAM,eAAoB,eAAQ,QAAQ;AAC1C,MAAI,CAAI,gBAAW,YAAY,EAAG,QAAO,EAAE,SAAS,CAAC,GAAG,WAAW,CAAC,EAAE;AAEtE,MAAI;AACF,UAAM,UAAU,IAAID,SAAQ,EAAE,iBAAiB,EAAE,QAAQ,MAAM,EAAE,CAAC;AAClE,UAAM,aAAa,QAAQ,oBAAoB,YAAY;AAC3D,UAAM,SAAS,eAAe,UAAU;AAExC,UAAM,UAAyB,OAAO,IAAI,CAAC,OAAO;AAAA,MAChD,WAAW,EAAE;AAAA,MACb,WAAW,EAAE;AAAA,MACb,QAAQ,EAAE,QAAQ,IAAI,CAAC,OAAoB;AAAA,QACzC,MAAM,EAAE;AAAA,QACR,MAAM,EAAE;AAAA,QACR,WAAW,CAAC,EAAE,aAAa,CAAC,EAAE;AAAA,QAC9B,YAAY,EAAE;AAAA,QACd,QAAQ,EAAE;AAAA,QACV,cAAc,EAAE;AAAA,MAClB,EAAE;AAAA,IACJ,EAAE;AAEF,WAAO,EAAE,SAAS,WAAW,iBAAiB,MAAM,EAAE;AAAA,EACxD,QAAQ;AACN,WAAO,EAAE,SAAS,CAAC,GAAG,WAAW,CAAC,EAAE;AAAA,EACtC;AACF;AAEO,SAAS,sBAAsB,SAA8E;AAClH,QAAM,cAAmB,eAAQ,OAAO;AACxC,MAAI,CAAI,gBAAW,WAAW,EAAG,QAAO,EAAE,SAAS,CAAC,GAAG,WAAW,CAAC,EAAE;AAErE,QAAM,QAAW,iBAAY,WAAW,EAAE;AAAA,IACxC,CAAC,MAAM,EAAE,SAAS,KAAK,KAAK,CAAC,EAAE,SAAS,UAAU,KAAK,CAAC,EAAE,SAAS,UAAU,KAAK,MAAM;AAAA,EAC1F;AAEA,QAAM,aAA4B,CAAC;AACnC,QAAM,eAAqC,CAAC;AAC5C,aAAW,QAAQ,OAAO;AACxB,UAAM,SAAS,iBAAsB,YAAK,aAAa,IAAI,CAAC;AAC5D,eAAW,KAAK,GAAG,OAAO,OAAO;AACjC,iBAAa,KAAK,GAAG,OAAO,SAAS;AAAA,EACvC;AACA,SAAO,EAAE,SAAS,YAAY,WAAW,aAAa;AACxD;AAEO,SAAS,uBAAuC;AACrD,SAAO;AAAA,IACL,MAAM;AAAA,IAEN,MAAM,YAAY,KAAqC;AACrD,aAAO,sBAAsB,GAAG,EAAE;AAAA,IACpC;AAAA,IAEA,MAAM,kBAAkB,KAA4C;AAClE,aAAO,sBAAsB,GAAG,EAAE;AAAA,IACpC;AAAA,IAEA,MAAM,iBAAiB,KAAoC;AACzD,YAAM,EAAE,0BAAAG,0BAAyB,IAAI,MAAM;AAC3C,YAAM,YAAYA,0BAAyB,GAAG;AAC9C,aAAO,UAAU,IAAI,CAAC,QAAQ;AAAA,QAC5B,QAAQ,GAAG;AAAA,QACX,MAAM,GAAG;AAAA,QACT,SAAS;AAAA,QACT,iBAAiB;AAAA,MACnB,EAAE;AAAA,IACJ;AAAA,EACF;AACF;;;ACxSA;AAAA,YAAYC,UAAQ;AACpB,YAAYC,YAAU;AAOtB,IAAM,oBAA0D;AAAA,EAC9D,WAAWC;AAAA,EACX,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAAS;AACX;AAKO,SAAS,cAAc,MAA8B;AAC1D,QAAM,UAAU,kBAAkB,IAAI;AACtC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,qBAAqB,IAAI,iBAAiB,OAAO,KAAK,iBAAiB,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,EACvG;AACA,SAAO,QAAQ;AACjB;AAUO,SAAS,cAAc,aAA6B;AACzD,QAAM,OAAY,eAAQ,WAAW;AAGrC,QAAM,kBAAkB;AAAA,IACjB,YAAK,MAAM,UAAU,eAAe;AAAA,IACpC,YAAK,MAAM,eAAe;AAAA,IAC1B,YAAK,MAAM,MAAM,UAAU,eAAe;AAAA,EACjD;AACA,aAAW,OAAO,iBAAiB;AACjC,QAAO,gBAAW,GAAG,EAAG,QAAO;AAAA,EACjC;AAGA,QAAM,YAAiB,YAAK,MAAM,QAAQ;AAC1C,MAAO,gBAAW,SAAS,GAAG;AAC5B,QAAI;AACF,YAAM,QAAW,iBAAY,WAAW,EAAE,WAAW,KAAK,CAAC;AAC3D,iBAAW,QAAQ,OAAO;AACxB,cAAM,WAAgB,YAAK,WAAW,OAAO,IAAI,CAAC;AAClD,YAAI,CAAC,SAAS,SAAS,KAAK,EAAG;AAC/B,YAAI;AACF,gBAAM,UAAa,kBAAa,UAAU,OAAO;AACjD,cAAI,eAAe,KAAK,OAAO,EAAG,QAAO;AACzC,cAAI,0CAA0C,KAAK,OAAO,EAAG,QAAO;AAAA,QACtE,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,SAAO;AACT;AAMO,SAAS,eACd,eACA,aACgB;AAChB,MAAI,OAAO,kBAAkB,YAAY,kBAAkB,MAAM;AAC/D,WAAO;AAAA,EACT;AACA,QAAM,OAAO,kBAAkB,UAAU,CAAC,gBACtC,cAAc,WAAW,IACzB;AACJ,SAAO,cAAc,IAAI;AAC3B;;;ACvFA;AAeO,SAAS,uBAAuC;AACrD,QAAM,UAA4B,CAAC;AAEnC,WAAS,SAAS,QAA8B;AAC9C,QAAI,CAAC,OAAO,MAAM;AAChB,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AACA,QAAI,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO,IAAI,GAAG;AAC/C,YAAM,IAAI,MAAM,WAAW,OAAO,IAAI,yBAAyB;AAAA,IACjE;AACA,YAAQ,KAAK,MAAM;AAAA,EACrB;AAEA,iBAAe,WAAW,MAA6B;AACrD,UAAM,MAAM,QAAQ,UAAU,CAAC,MAAM,EAAE,SAAS,IAAI;AACpD,QAAI,QAAQ,GAAI;AAChB,UAAM,SAAS,QAAQ,GAAG;AAC1B,QAAI,OAAO,UAAU;AACnB,YAAM,OAAO,SAAS;AAAA,IACxB;AACA,YAAQ,OAAO,KAAK,CAAC;AAAA,EACvB;AAEA,WAAS,IAAI,MAA0C;AACrD,WAAO,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAAA,EAC5C;AAEA,WAAS,OAAiB;AACxB,WAAO,QAAQ,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,EAClC;AAEA,iBAAe,OACb,SACG,MACY;AACf,eAAW,UAAU,SAAS;AAC5B,YAAM,KAAK,OAAO,IAAI;AACtB,UAAI,OAAO,OAAO,YAAY;AAC5B,cAAO,GAAoC,MAAM,QAAQ,IAAI;AAAA,MAC/D;AAAA,IACF;AAAA,EACF;AAEA,iBAAe,sBAAsB,QAAiD;AACpF,QAAI,SAAS;AACb,eAAW,UAAU,SAAS;AAC5B,UAAI,OAAO,iBAAiB;AAC1B,iBAAS,MAAM,OAAO,gBAAgB,MAAM;AAAA,MAC9C;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,SAAO,EAAE,UAAU,YAAY,KAAK,MAAM,QAAQ,sBAAsB;AAC1E;AAKO,SAAS,aAAa,QAAwC;AACnE,SAAO;AACT;;;AC5EA;AAqBO,SAAS,8BAA8B,OAA0B,CAAC,GAAW;AAClF,QAAM,eAAe,KAAK,gBAAgB,CAAC,MAAM;AACjD,QAAM,UAAU,KAAK,kBAAkB;AACvC,QAAM,UAAU,KAAK,gBAAgB;AACrC,QAAM,WAAW,KAAK,YAAY;AAClC,QAAM,WAAW,KAAK,WAClB;AAAA;AAAA;AAAA,qDAIA;AAEJ,QAAM,SACJ,aAAa,SAAS,IAClB;AAAA;AAAA;AAAA,yBAGiB,aAAa,KAAK,IAAI,CAAC,MACxC;AAEN,QAAM,YACJ,aAAa,SAAS,IAClB,+BACA,aAAa,CAAC;AAEpB,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAamB,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAMP,SAAS;AAAA;AAAA;AAAA,eAGrB,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qCAMe,OAAO;AAAA;AAAA;AAAA,iCAGX,QAAQ;AAAA,EACvC,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASV;AAEO,SAAS,yBAAyB,OAA0B,CAAC,GAAW;AAC7E,QAAM,UAAU,KAAK,kBAAkB;AACvC,QAAM,UAAU,KAAK,gBAAgB;AACrC,QAAM,WAAW,KAAK,YAAY;AAClC,QAAM,cAAc,KAAK,eAAe,CAAC,KAAK;AAE9C,SAAO;AAAA;AAAA;AAAA,cAGK,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAkBjB,OAAO;AAAA,8BACe,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAU7B,OAAO;AAAA;AAAA;AAAA,0BAGW,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOlC;AAEA,IAAM,YAAiE;AAAA,EACrE,QAAQ;AAAA,EACR,QAAQ;AACV;AAKO,SAAS,kBAA4B;AAC1C,SAAO,OAAO,KAAK,SAAS;AAC9B;AAKO,SAAS,mBACd,UACA,OAA0B,CAAC,GACnB;AACR,QAAM,YAAY,UAAU,QAAQ;AACpC,MAAI,CAAC,WAAW;AACd,UAAM,IAAI;AAAA,MACR,yBAAyB,QAAQ,iBAAiB,OAAO,KAAK,SAAS,EAAE,KAAK,IAAI,CAAC;AAAA,IACrF;AAAA,EACF;AACA,SAAO,UAAU,IAAI;AACvB;;;ACrKA;;;ACAA;AAiBO,SAAS,gBAAgB,OAAiC;AAC/D,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,MAAM,SAAS,eAAe,EAAG,QAAO;AAC5C,MAAI,MAAM,SAAS,aAAa,EAAG,QAAO;AAC1C,MAAI,MAAM,SAAS,kBAAkB,EAAG,QAAO;AAC/C,MAAI,MAAM,SAAS,uBAAuB,EAAG,QAAO;AACpD,MAAI,MAAM,SAAS,0BAA0B,EAAG,QAAO;AACvD,MAAI,qCAAqC,KAAK,KAAK,EAAG,QAAO;AAC7D,SAAO;AACT;AAIO,SAAS,oBAAoB,SAA6C;AAC/E,QAAM,SAAS,QAAQ,OAAO,OAAK,EAAE,WAAW,QAAQ;AACxD,QAAM,OAAO,OAAO,IAAI,OAAK,gBAAgB,EAAE,KAAK,CAAC;AACrD,SAAO;AAAA,IACL,aAAa,OAAO;AAAA,IACpB,YAAY,KAAK,OAAO,OAAK,MAAM,aAAa,EAAE;AAAA,IAClD,UAAU,KAAK,OAAO,OAAK,MAAM,WAAW,EAAE;AAAA,IAC9C,SAAS,KAAK,OAAO,OAAK,MAAM,UAAU,EAAE;AAAA,IAC5C,SAAS,KAAK,OAAO,OAAK,MAAM,UAAU,EAAE;AAAA,IAC5C,YAAY,KAAK,OAAO,OAAK,MAAM,aAAa,EAAE;AAAA,IAClD,cAAc,KAAK,OAAO,OAAK,MAAM,eAAe,EAAE;AAAA,IACtD,OAAO,KAAK,OAAO,OAAK,MAAM,OAAO,EAAE;AAAA,EACzC;AACF;AAIO,SAAS,uBAAuB,SAAmD;AACxF,MAAI,kBAAkB;AACtB,MAAI,YAAY;AAChB,MAAI,SAAS;AACb,MAAI,WAAW;AACf,QAAM,eAAe,oBAAI,IAA6D;AAEtF,aAAW,KAAK,SAAS;AACvB,UAAM,KAAK,EAAE;AACb,QAAI,CAAC,MAAM,GAAG,mBAAmB,EAAG;AAEpC,uBAAmB,GAAG;AACtB,iBAAa,GAAG,UAAU;AAC1B,cAAU,GAAG,OAAO;AACpB,gBAAY,GAAG,SAAS;AAExB,eAAW,QAAQ,GAAG,UAAU;AAC9B,YAAM,MAAM,GAAG,KAAK,MAAM,IAAI,KAAK,IAAI;AACvC,YAAM,WAAW,aAAa,IAAI,GAAG;AACrC,UAAI,SAAU,UAAS,SAAS;AAAA,UAC3B,cAAa,IAAI,KAAK,EAAE,QAAQ,KAAK,QAAQ,MAAM,KAAK,MAAM,OAAO,EAAE,CAAC;AAAA,IAC/E;AAAA,EACF;AAEA,QAAM,eAAe,MAAM,KAAK,aAAa,OAAO,CAAC,EAClD,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAChC,MAAM,GAAG,CAAC,EACV,IAAI,QAAM,EAAE,QAAQ,EAAE,QAAQ,MAAM,EAAE,MAAM,aAAa,EAAE,MAAM,EAAE;AAEtE,QAAM,YAAY,kBAAkB,KAAK,YAAY,UAAU,kBAAkB,MAAM;AACvF,QAAM,gBAAgB,kBAAkB,IAAI,YAAY,kBAAkB,MAAM;AAEhF,SAAO,EAAE,iBAAiB,WAAW,QAAQ,UAAU,WAAW,eAAe,aAAa;AAChG;AAIA,SAAS,YAAY,OAA0B;AAC7C,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,QAAM,UAAU,MAAM,MAAM,sBAAsB;AAClD,SAAO,UAAU,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;AACnD;AAEO,SAAS,eAAe,QAA+B;AAC5D,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,MAAM;AACxB,UAAM,WAAW,EAAE,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AACrD,UAAM,UAAU,SAAS,UAAU,OAAK,MAAM,IAAI;AAClD,QAAI,YAAY,MAAM,UAAU,KAAK,SAAS,OAAQ,QAAO,SAAS,CAAC,KAAK;AAC5E,UAAM,UAAU,SAAS,MAAM,UAAU,CAAC;AAC1C,QAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,UAAM,QAAQ,QAAQ,CAAC;AACvB,QAAI,QAAQ,KAAK,KAAK,KAAK,QAAQ,SAAS,EAAG,QAAO,QAAQ,CAAC;AAC/D,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIO,SAAS,sBAAsB,SAAkD;AACtF,QAAM,YAAY,oBAAI,IAA4D;AAClF,QAAM,SAAS,QAAQ,OAAO,OAAK,EAAE,WAAW,QAAQ;AAExD,aAAW,QAAQ,QAAQ;AACzB,UAAM,MAAM,gBAAgB,KAAK,KAAK;AACtC,QAAI,QAAQ,iBAAiB,QAAQ,YAAa;AAClD,UAAM,OAAO,YAAY,KAAK,KAAK;AACnC,eAAW,OAAO,MAAM;AACtB,YAAM,SAAS,eAAe,GAAG;AACjC,UAAI,CAAC,OAAQ;AACb,YAAM,UAAU,UAAU,IAAI,MAAM,KAAK,EAAE,OAAO,oBAAI,IAAY,GAAG,WAAW,oBAAI,IAAY,EAAE;AAClG,cAAQ,MAAM,IAAI,KAAK,KAAK;AAC5B,cAAQ,UAAU,IAAI,GAAG;AACzB,gBAAU,IAAI,QAAQ,OAAO;AAAA,IAC/B;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,UAAU,QAAQ,CAAC,EAClC,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO;AAAA,IACrB;AAAA,IACA,OAAO,MAAM,KAAK,EAAE,KAAK,EAAE,KAAK;AAAA,IAChC,WAAW,MAAM,KAAK,EAAE,SAAS,EAAE,KAAK;AAAA,EAC1C,EAAE,EACD,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,SAAS,EAAE,MAAM,UAAU,EAAE,OAAO,cAAc,EAAE,MAAM,CAAC;AACvF;AAIO,SAAS,wBACd,OACA,SACA,YACQ;AACR,QAAM,QAAkB;AAAA,IACtB;AAAA,IACA;AAAA,EACF;AAEA,MAAI,YAAY;AACd,UAAM;AAAA,MACJ,qBAAqB,WAAW,UAAU,QAAQ,CAAC,CAAC,iBAAiB,WAAW,eAAe,eAAe,WAAW,SAAS,YAAY,WAAW,MAAM,cAAc,WAAW,QAAQ;AAAA,MAChM,6BAA6B,WAAW,cAAc,QAAQ,CAAC,CAAC;AAAA,IAClE;AAAA,EACF;AACA,QAAM;AAAA,IACJ,kBAAkB,QAAQ,UAAU;AAAA,IACpC,gBAAgB,QAAQ,QAAQ;AAAA,IAChC,eAAe,QAAQ,OAAO;AAAA,IAC9B,eAAe,QAAQ,OAAO;AAAA,IAC9B,kBAAkB,QAAQ,UAAU;AAAA,IACpC,oBAAoB,QAAQ,YAAY;AAAA,IACxC,YAAY,QAAQ,KAAK;AAAA,IACzB;AAAA,EACF;AAEA,MAAI,cAAc,WAAW,aAAa,SAAS,GAAG;AACpD,UAAM,KAAK,4BAA4B,IAAI,uCAAuC,qCAAqC;AACvH,eAAW,aAAa,QAAQ,CAAC,GAAG,MAAM;AACxC,YAAM,KAAK,KAAK,IAAI,CAAC,MAAM,EAAE,MAAM,MAAM,EAAE,IAAI,MAAM,EAAE,WAAW,IAAI;AAAA,IACxE,CAAC;AACD,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,KAAK,mCAAmC;AAC9C,WAAO,MAAM,KAAK,IAAI,IAAI;AAAA,EAC5B;AAEA,aAAW,QAAQ,OAAO;AACxB,UAAM;AAAA,MACJ,MAAM,KAAK,MAAM;AAAA,MACjB;AAAA,MACA,mBAAmB,KAAK,MAAM,MAAM;AAAA,MACpC;AAAA,IACF;AACA,eAAW,KAAK,KAAK,MAAO,OAAM,KAAK,OAAO,CAAC,EAAE;AACjD,UAAM,KAAK,qBAAqB;AAChC,eAAW,KAAK,KAAK,UAAW,OAAM,KAAK,OAAO,CAAC,EAAE;AACrD,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,SAAO,MAAM,KAAK,IAAI,IAAI;AAC5B;;;AC/LA;AAoBA,SAAS,eAAe,MAAyB,WAAwC;AACvF,MAAI,UAAW,QAAO;AACtB,MAAI,KAAK,MAAM,UAAU,EAAG,QAAO;AACnC,MAAI,KAAK,MAAM,WAAW,EAAG,QAAO;AACpC,SAAO;AACT;AAWO,SAAS,gBAAgB,MAA+C;AAC7E,QAAM,EAAE,WAAW,YAAY,mBAAmB,GAAG,IAAI;AACzD,QAAM,SAA0B,CAAC;AACjC,MAAI,MAAM;AAGV,MAAI,cAAc,WAAW,kBAAkB,KAAK,WAAW,YAAY,kBAAkB;AAC3F,UAAM,UAA6B;AAAA,MACjC,QAAQ;AAAA,MACR,OAAO,WAAW,aAAa,IAAI,OAAK,GAAG,EAAE,MAAM,IAAI,EAAE,IAAI,SAAM,EAAE,WAAW,GAAG;AAAA,MACnF,WAAW,WAAW,aAAa,IAAI,OAAK,EAAE,IAAI;AAAA,IACpD;AACA,WAAO,KAAK;AAAA,MACV,OAAO;AAAA,MACP,QAAQ,QAAQ;AAAA,MAChB,UAAU;AAAA,MACV,OAAO,QAAQ;AAAA,MACf,WAAW,QAAQ;AAAA,MACnB,WAAW;AAAA,MACX,oBAAoB;AAAA,QAClB,oCAA+B,gBAAgB;AAAA,QAC/C;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAGA,aAAW,QAAQ,WAAW;AAC5B,UAAM,WAAW,eAAe,MAAM,KAAK;AAC3C,WAAO,KAAK;AAAA,MACV,OAAO;AAAA,MACP,QAAQ,KAAK;AAAA,MACb;AAAA,MACA,OAAO,KAAK;AAAA,MACZ,WAAW,KAAK;AAAA,MAChB,WAAW;AAAA,MACX,oBAAoB;AAAA,QAClB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAIO,SAAS,yBACd,YACA,SACA,YACQ;AACR,QAAM,QAAkB;AAAA,IACtB;AAAA,IACA;AAAA,EACF;AAEA,MAAI,YAAY;AACd,UAAM;AAAA,MACJ,qBAAqB,WAAW,UAAU,QAAQ,CAAC,CAAC;AAAA,MACpD,6BAA6B,WAAW,cAAc,QAAQ,CAAC,CAAC;AAAA,IAClE;AAAA,EACF;AACA,QAAM;AAAA,IACJ,mBAAmB,QAAQ,WAAW;AAAA,IACtC,kBAAkB,QAAQ,UAAU;AAAA,IACpC,gBAAgB,QAAQ,QAAQ;AAAA,IAChC,eAAe,QAAQ,OAAO;AAAA,IAC9B,eAAe,QAAQ,OAAO;AAAA,IAC9B,kBAAkB,QAAQ,UAAU;AAAA,IACpC,oBAAoB,QAAQ,YAAY;AAAA,IACxC,YAAY,QAAQ,KAAK;AAAA,IACzB;AAAA,EACF;AAEA,MAAI,WAAW,WAAW,GAAG;AAC3B,UAAM,KAAK,kCAAkC;AAC7C,WAAO,MAAM,KAAK,IAAI,IAAI;AAAA,EAC5B;AAEA,aAAW,MAAM,YAAY;AAC3B,UAAM;AAAA,MACJ,gBAAgB,GAAG,KAAK,MAAM,GAAG,MAAM;AAAA,MACvC;AAAA,MACA,eAAe,GAAG,QAAQ;AAAA,MAC1B,qBAAqB,GAAG,MAAM,MAAM;AAAA,MACpC;AAAA,IACF;AACA,eAAW,KAAK,GAAG,MAAO,OAAM,KAAK,OAAO,CAAC,EAAE;AAC/C,QAAI,GAAG,UAAU,SAAS,GAAG;AAC3B,YAAM,KAAK,cAAc;AACzB,iBAAW,KAAK,GAAG,UAAW,OAAM,KAAK,OAAO,CAAC,EAAE;AAAA,IACrD;AACA,UAAM,KAAK,gBAAgB,GAAG,SAAS,EAAE;AACzC,UAAM,KAAK,wBAAwB;AACnC,eAAW,KAAK,GAAG,mBAAoB,OAAM,KAAK,OAAO,CAAC,EAAE;AAC5D,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,SAAO,MAAM,KAAK,IAAI,IAAI;AAC5B;;;AC1IA;AAWO,IAAM,eAAN,MAAmB;AAAA,EAChB,UAA6B,CAAC;AAAA,EAC9B,SAAwB;AAAA,EAEhC,UAAU,WAAyB;AACjC,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,OAAO,OAA8B;AACnC,SAAK,QAAQ,KAAK,KAAK;AAAA,EACzB;AAAA,EAEA,QAAc;AACZ,SAAK,UAAU,CAAC;AAAA,EAClB;AAAA,EAEA,aAAgC;AAC9B,UAAM,gBAAgB,KAAK,QAAQ;AACnC,QAAI,oBAAoB;AACxB,QAAI,wBAAwB;AAC5B,QAAI,qBAAqB;AACzB,QAAI,eAAe;AAEnB,UAAM,aAA8C,CAAC;AACrD,UAAM,UAAwC,CAAC;AAE/C,eAAW,KAAK,KAAK,SAAS;AAC5B,2BAAqB,EAAE;AACvB,+BAAyB,EAAE;AAC3B,4BAAsB,EAAE;AACxB,sBAAgB,EAAE;AAGlB,UAAI,CAAC,WAAW,EAAE,QAAQ,GAAG;AAC3B,mBAAW,EAAE,QAAQ,IAAI,EAAE,UAAU,GAAG,cAAc,GAAG,kBAAkB,GAAG,aAAa,GAAG,eAAe,EAAE;AAAA,MACjH;AACA,YAAM,MAAM,WAAW,EAAE,QAAQ;AACjC,UAAI;AACJ,UAAI,gBAAgB,EAAE;AACtB,UAAI,oBAAoB,EAAE;AAC1B,UAAI,eAAe,EAAE,eAAe,EAAE;AACtC,UAAI,iBAAiB,EAAE;AAGvB,UAAI,CAAC,QAAQ,EAAE,KAAK,GAAG;AACrB,gBAAQ,EAAE,KAAK,IAAI,EAAE,UAAU,GAAG,aAAa,GAAG,eAAe,EAAE;AAAA,MACrE;AACA,YAAM,MAAM,QAAQ,EAAE,KAAK;AAC3B,UAAI;AACJ,UAAI,eAAe,EAAE,eAAe,EAAE;AACtC,UAAI,iBAAiB,EAAE;AAAA,IACzB;AAEA,UAAM,cAAc,oBAAoB;AACxC,UAAM,oBAAoB,KAAK,UAAU,KAAK,SAAS,IACnD,KAAK,MAAM,cAAc,KAAK,SAAS,GAAK,IAAI,MAChD;AAEJ,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,cAAc,gBAAgB,IAAI,KAAK,MAAM,eAAe,aAAa,IAAI;AAAA,MAC7E;AAAA,MACA;AAAA,MACA;AAAA,MACA,gBAAgB,sBAAsB,QAAQ,oBAAoB;AAAA,IACpE;AAAA,EACF;AACF;AAIO,SAAS,0BAA0B,SAAoC;AAC5E,QAAM,QAAkB;AAAA,IACtB;AAAA,IACA;AAAA,IACA,qBAAqB,QAAQ,aAAa;AAAA,IAC1C,mBAAmB,QAAQ,YAAY,eAAe,CAAC;AAAA,IACvD,oBAAoB,QAAQ,kBAAkB,eAAe,CAAC;AAAA,IAC9D,wBAAwB,QAAQ,sBAAsB,eAAe,CAAC;AAAA,IACtE,yBAAsB,QAAQ,mBAAmB,QAAQ,CAAC,CAAC;AAAA,IAC3D,sBAAsB,QAAQ,YAAY;AAAA,EAC5C;AAEA,MAAI,QAAQ,sBAAsB,MAAM;AACtC,UAAM,KAAK,kBAAkB,QAAQ,iBAAiB,IAAI,QAAQ,iBAAiB,kBAAkB,EAAE,EAAE;AAAA,EAC3G;AACA,QAAM,KAAK,EAAE;AAGb,QAAM,OAAO,OAAO,QAAQ,QAAQ,UAAU,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,WAAW;AAClG,MAAI,KAAK,SAAS,GAAG;AACnB,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,eAAW,CAAC,KAAK,CAAC,KAAK,MAAM;AAC3B,YAAM,KAAK,KAAK,GAAG,MAAM,EAAE,QAAQ,MAAM,EAAE,aAAa,eAAe,CAAC,MAAM,EAAE,iBAAiB,eAAe,CAAC,MAAM,EAAE,YAAY,eAAe,CAAC,UAAO,EAAE,cAAc,QAAQ,CAAC,CAAC,IAAI;AAAA,IAC5L;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAGA,QAAM,SAAS,OAAO,QAAQ,QAAQ,OAAO;AAC7C,MAAI,OAAO,SAAS,GAAG;AACrB,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,eAAW,CAAC,OAAO,CAAC,KAAK,QAAQ;AAC/B,YAAM,KAAK,KAAK,KAAK,MAAM,EAAE,QAAQ,MAAM,EAAE,YAAY,eAAe,CAAC,UAAO,EAAE,cAAc,QAAQ,CAAC,CAAC,IAAI;AAAA,IAChH;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,SAAO,MAAM,KAAK,IAAI,IAAI;AAC5B;;;AH7GO,SAAS,mBACd,QACA,SACc;AACd,QAAM,eAAe;AAAA,IACnB,SAAS,OAAO;AAAA,IAChB,YAAY,OAAO;AAAA,MACjB,MAAM,KAAK,OAAO,WAAW,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM;AAAA,QACtD;AAAA,QACA,EAAE,QAAQ,EAAE,OAAO,QAAQ,WAAW,EAAE,UAAU,QAAQ,aAAa,EAAE,YAAY;AAAA,MACvF,CAAC;AAAA,IACH;AAAA,IACA,YAAY,OAAO;AAAA,MACjB,MAAM,KAAK,OAAO,WAAW,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM;AAAA,QACtD;AAAA,QACA,EAAE,QAAQ,EAAE,OAAO,QAAQ,YAAY,EAAE,WAAW;AAAA,MACtD,CAAC;AAAA,IACH;AAAA,IACA,gBAAgB,OAAO,eAAe,IAAI,CAAC,OAAO;AAAA,MAChD,UAAU,EAAE;AAAA,MACZ,QAAQ,EAAE;AAAA,MACV,OAAO,EAAE;AAAA,IACX,EAAE;AAAA,IACF,WAAW,UACP;AAAA,MACE,SAAS,QAAQ,WAAW;AAAA,MAC5B,SAAS,QAAQ,WAAW;AAAA,IAC9B,IACA;AAAA,IACJ,kBAAkB,OAAO;AAAA,IACzB,UAAU,OAAO;AAAA,EACnB;AAEA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,SAAS,KAAK,UAAU,cAAc,MAAM,CAAC;AAAA,IAC7C,UAAU;AAAA,EACZ;AACF;AAIO,SAAS,uBACd,QACA,SACc;AACd,QAAM,QAAkB;AAAA,IACtB;AAAA,IACA;AAAA,IACA,iBAAiB,OAAO,QAAQ;AAAA,IAChC,gBAAgB,OAAO,QAAQ,MAAM,KAAK,OAAO,QAAQ,KAAK,IAAI,CAAC;AAAA,IACnE;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,aAAW,CAAC,KAAK,EAAE,KAAK,OAAO,YAAY;AACzC,UAAM,KAAK,OAAO,GAAG,EAAE;AACvB,UAAM,KAAK,aAAa,GAAG,OAAO,MAAM,EAAE;AAC1C,UAAM,KAAK,gBAAgB,GAAG,UAAU,MAAM,EAAE;AAChD,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,KAAK,kBAAkB,EAAE;AAC/B,aAAW,CAAC,KAAK,IAAI,KAAK,OAAO,YAAY;AAC3C,UAAM,KAAK,OAAO,GAAG,EAAE;AACvB,UAAM,KAAK,aAAa,KAAK,OAAO,MAAM,EAAE;AAC5C,UAAM,KAAK,kBAAkB,KAAK,UAAU,EAAE;AAC9C,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,KAAK,uBAAuB,OAAO,eAAe,MAAM,KAAK,EAAE;AACrE,aAAW,KAAK,OAAO,gBAAgB;AACrC,UAAM,KAAK,OAAO,EAAE,QAAQ,OAAO,EAAE,MAAM,MAAM,EAAE,KAAK,GAAG;AAAA,EAC7D;AAEA,MAAI,OAAO,iBAAiB,SAAS,GAAG;AACtC,UAAM,KAAK,IAAI,wBAAwB,EAAE;AACzC,UAAM,SAAS,OAAO,iBAAiB,OAAO,CAAC,MAAM,EAAE,aAAa,OAAO;AAC3E,UAAM,WAAW,OAAO,iBAAiB,OAAO,CAAC,MAAM,EAAE,aAAa,SAAS;AAC/E,QAAI,OAAO,SAAS,GAAG;AACrB,YAAM,KAAK,eAAe,OAAO,MAAM,KAAK,EAAE;AAC9C,iBAAW,KAAK,QAAQ;AACtB,cAAM,KAAK,QAAQ,EAAE,MAAM,OAAO,EAAE,KAAK,KAAK,EAAE,OAAO,EAAE;AAAA,MAC3D;AAAA,IACF;AACA,QAAI,SAAS,SAAS,GAAG;AACvB,YAAM,KAAK,iBAAiB,SAAS,MAAM,KAAK,EAAE;AAClD,iBAAW,KAAK,UAAU;AACxB,cAAM,KAAK,QAAQ,EAAE,MAAM,OAAO,EAAE,KAAK,KAAK,EAAE,OAAO,EAAE;AAAA,MAC3D;AAAA,IACF;AAAA,EACF;AAEA,MAAI,SAAS,WAAW,SAAS,SAAS;AACxC,UAAM,KAAK,IAAI,wBAAwB,EAAE;AACzC,QAAI,QAAQ,SAAS;AACnB,YAAM;AAAA,QACJ,aAAa,QAAQ,QAAQ,MAAM;AAAA,QACnC,aAAa,QAAQ,QAAQ,MAAM;AAAA,QACnC,cAAc,QAAQ,QAAQ,OAAO;AAAA,QACrC,eAAe,QAAQ,QAAQ,QAAQ;AAAA,MACzC;AAAA,IACF;AACA,QAAI,QAAQ,SAAS;AACnB,YAAM;AAAA,QACJ,iBAAiB,QAAQ,QAAQ,KAAK;AAAA,QACtC,iBAAiB,QAAQ,QAAQ,SAAS;AAAA,QAC1C,kBAAkB,QAAQ,QAAQ,YAAY,KAAK,QAAQ,CAAC,CAAC;AAAA,QAC7D,uBAAuB,QAAQ,QAAQ,gBAAgB,KAAK,QAAQ,CAAC,CAAC;AAAA,QACtE,gCAAgC,QAAQ,QAAQ,yBAAyB,KAAK,QAAQ,CAAC,CAAC;AAAA,QACxF,kBAAkB,QAAQ,QAAQ,UAAU;AAAA,QAC5C,qBAAqB,QAAQ,QAAQ,aAAa;AAAA,MACpD;AACA,UAAI,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACtC,cAAM,KAAK,cAAc,QAAQ,QAAQ,QAAQ,KAAK,IAAI,CAAC,EAAE;AAAA,MAC/D;AAAA,IACF;AAAA,EACF;AAEA,QAAM,KAAK,IAAI,OAAO,iEAAiE;AAEvF,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,SAAS,MAAM,KAAK,IAAI;AAAA,IACxB,UAAU;AAAA,EACZ;AACF;AAIA,SAAS,WAAW,GAAmB;AACrC,SAAO,EAAE,QAAQ,MAAM,OAAO,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,QAAQ;AACpG;AAEA,SAAS,cAAc,YAAkD;AACvE,QAAM,OAAiB,CAAC;AACxB,aAAW,CAAC,KAAK,EAAE,KAAK,YAAY;AAClC,SAAK,KAAK,WAAW,WAAW,GAAG,CAAC,YAAY,GAAG,OAAO,MAAM,YAAY,GAAG,UAAU,MAAM,YAAY;AAAA,EAC7G;AACA,SAAO,KAAK,KAAK,IAAI;AACvB;AAEA,SAAS,iBAAiB,YAAkD;AAC1E,QAAM,OAAiB,CAAC;AACxB,aAAW,CAAC,KAAK,IAAI,KAAK,YAAY;AACpC,SAAK,KAAK,WAAW,WAAW,GAAG,CAAC,YAAY,KAAK,OAAO,MAAM,YAAY,KAAK,UAAU,YAAY;AAAA,EAC3G;AACA,SAAO,KAAK,KAAK,IAAI;AACvB;AAEA,SAAS,aAAa,OAAoC;AACxD,SAAO,MACJ,IAAI,CAAC,MAAM,iBAAiB,WAAW,EAAE,QAAQ,CAAC,mBAAmB,WAAW,EAAE,MAAM,CAAC,YAAY,WAAW,EAAE,KAAK,CAAC,YAAY,EACpI,KAAK,IAAI;AACd;AAEA,SAAS,eAAe,QAAmC;AACzD,SAAO,OACJ;AAAA,IACC,CAAC,MACC,cAAc,EAAE,QAAQ,4BAA4B,EAAE,QAAQ,KAAK,EAAE,QAAQ,mBAAmB,WAAW,EAAE,MAAM,CAAC,YAAY,WAAW,EAAE,KAAK,CAAC,YAAY,WAAW,EAAE,OAAO,CAAC;AAAA,EACxL,EACC,KAAK,IAAI;AACd;AAEO,SAAS,mBACd,QACA,SACc;AACd,QAAM,cAAc,MAAM,KAAK,OAAO,WAAW,OAAO,CAAC,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,OAAO,QAAQ,CAAC;AAClG,QAAM,iBAAiB,MAAM,KAAK,OAAO,WAAW,OAAO,CAAC,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,UAAU,QAAQ,CAAC;AACxG,QAAM,cAAc,MAAM,KAAK,OAAO,WAAW,OAAO,CAAC,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,OAAO,QAAQ,CAAC;AAClG,QAAM,aAAa,MAAM,KAAK,OAAO,WAAW,OAAO,CAAC,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,YAAY,CAAC;AAC9F,QAAM,aAAa,OAAO,iBAAiB,OAAO,CAAC,MAAM,EAAE,aAAa,OAAO,EAAE;AACjF,QAAM,YAAY,OAAO,iBAAiB,OAAO,CAAC,MAAM,EAAE,aAAa,SAAS,EAAE;AAElF,QAAM,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mCAmCoB,OAAO,QAAQ,eAAe,OAAO,QAAQ,MAAM;AAAA;AAAA;AAAA,yEAGb,OAAO,QAAQ,MAAM;AAAA,wEACtB,WAAW;AAAA,2EACR,cAAc;AAAA,wEACjB,WAAW;AAAA,uEACZ,UAAU;AAAA,6EACJ,OAAO,eAAe,MAAM;AAAA,sEACnC,aAAa,IAAI,SAAS,EAAE,KAAK,UAAU;AAAA,wEACzC,YAAY,IAAI,YAAY,EAAE,KAAK,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAO3G,cAAc,OAAO,UAAU,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAQhC,iBAAiB,OAAO,UAAU,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,uBAKrB,OAAO,eAAe,MAAM;AAAA;AAAA;AAAA,SAG1C,aAAa,OAAO,cAAc,CAAC;AAAA;AAAA;AAAA;AAAA,EAK1C,SAAS,WAAW,SAAS,UACzB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKJ,QAAQ,UAAU,0BAA0B,QAAQ,QAAQ,MAAM,oCAAoC,QAAQ,QAAQ,MAAM,qCAAqC,QAAQ,QAAQ,OAAO,sCAAsC,QAAQ,QAAQ,QAAQ,eAAe,EAAE;AAAA,EACvQ,QAAQ,UAAU,8BAA8B,WAAW,QAAQ,QAAQ,KAAK,CAAC,wCAAwC,OAAO,QAAQ,QAAQ,SAAS,CAAC,yCAAyC,QAAQ,QAAQ,YAAY,KAAK,QAAQ,CAAC,CAAC,+CAA+C,QAAQ,QAAQ,gBAAgB,KAAK,QAAQ,CAAC,CAAC,wDAAwD,QAAQ,QAAQ,yBAAyB,KAAK,QAAQ,CAAC,CAAC,0CAA0C,WAAW,QAAQ,QAAQ,UAAU,CAAC,4CAA4C,WAAW,QAAQ,QAAQ,aAAa,CAAC,qCAAqC,WAAW,QAAQ,QAAQ,QAAQ,KAAK,IAAI,KAAK,GAAG,CAAC,eAAe,EAAE;AAAA;AAAA;AAAA,cAIxsB,EACN;AAAA;AAAA,EAGE,OAAO,iBAAiB,SAAS,IAC7B;AAAA,yBACmB,OAAO,iBAAiB,MAAM;AAAA;AAAA;AAAA,SAG9C,eAAe,OAAO,gBAAgB,CAAC;AAAA;AAAA,cAG1C,EACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQE,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,EACZ;AACF;AAIA,IAAM,YAA2G;AAAA,EAC/G,MAAM;AAAA,EACN,MAAM;AAAA,EACN,UAAU;AACZ;AAKO,SAAS,gBACd,QACA,UAA4C,CAAC,MAAM,GACnD,SACgB;AAChB,SAAO,QAAQ,IAAI,CAAC,QAAQ;AAC1B,UAAM,MAAM,UAAU,GAAG;AACzB,QAAI,CAAC,IAAK,OAAM,IAAI,MAAM,2BAA2B,GAAG,iBAAiB,OAAO,KAAK,SAAS,EAAE,KAAK,IAAI,CAAC,EAAE;AAC5G,WAAO,IAAI,QAAQ,OAAO;AAAA,EAC5B,CAAC;AACH;;;AI/UA;AAgCA,SAASC,YAAW,GAAmB;AACrC,SAAO,EACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,OAAO;AAC1B;AAEA,SAAS,OAAO,GAAoB;AAClC,SAAO,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,IAAI,IAAI;AAC3D;AAEO,SAAS,+BAA+B,QAA0C;AACvF,QAAM,cAAc,OAAO,QAAQ,IAAI,CAAC,QAAQ;AAC9C,UAAM,KAAK,OAAO,WAAW,IAAI,GAAG;AACpC,UAAM,OAAO,OAAO,WAAW,IAAI,GAAG;AACtC,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,QAAQ,IAAI,OAAO,UAAU;AAAA,MAC7B,WAAW,IAAI,UAAU,UAAU;AAAA,MACnC,QAAQ,MAAM,OAAO,UAAU;AAAA,MAC/B,OAAO,MAAM,cAAc;AAAA,IAC7B;AAAA,EACF,CAAC;AAED,QAAM,SAAS;AAAA,IACb,SAAS,OAAO,QAAQ;AAAA,IACxB,QAAQ,YAAY,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,QAAQ,CAAC;AAAA,IACpD,WAAW,YAAY,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,WAAW,CAAC;AAAA,IAC1D,QAAQ,YAAY,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,QAAQ,CAAC;AAAA,IACpD,OAAO,YAAY,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,OAAO,CAAC;AAAA,IAClD,OAAO,OAAO,eAAe;AAAA,IAC7B,QAAQ,OAAO,iBAAiB,OAAO,CAAC,MAAM,EAAE,aAAa,OAAO,EAAE;AAAA,IACtE,UAAU,OAAO,iBAAiB,OAAO,CAAC,MAAM,EAAE,aAAa,SAAS,EAAE;AAAA,EAC5E;AAEA,SAAO;AAAA,IACL,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,YAAY,OAAO;AAAA,IACnB,SAAS,CAAC,GAAG,OAAO,OAAO;AAAA,IAC3B;AAAA,IACA;AAAA,IACA,OAAO,OAAO,eAAe,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,QAAQ,EAAE,QAAQ,OAAO,EAAE,MAAM,EAAE;AAAA,IACpG,QAAQ,OAAO,iBAAiB,IAAI,CAAC,OAAO;AAAA,MAC1C,UAAU,EAAE;AAAA,MACZ,QAAQ,EAAE;AAAA,MACV,OAAO,EAAE;AAAA,MACT,SAAS,EAAE;AAAA,IACb,EAAE;AAAA,EACJ;AACF;AAEO,SAAS,iCAAiC,OAA+B;AAC9E,QAAM,MAAO,SAAS,CAAC;AACvB,QAAM,UAAU,MAAM,QAAQ,IAAI,OAAO,IAAI,IAAI,QAAQ,IAAI,CAAC,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC;AAClF,QAAM,KAAM,IAAI,cAAc,CAAC;AAC/B,QAAM,QAAS,IAAI,cAAc,CAAC;AAClC,QAAM,QAAQ,MAAM,QAAQ,IAAI,cAAc,IAC1C,IAAI,eAAe,IAAI,CAAC,MAAM;AAC9B,UAAM,MAAM;AACZ,WAAO;AAAA,MACL,UAAU,OAAO,IAAI,YAAY,EAAE;AAAA,MACnC,QAAQ,OAAO,IAAI,UAAU,EAAE;AAAA,MAC/B,OAAO,OAAO,IAAI,SAAS,EAAE;AAAA,IAC/B;AAAA,EACF,CAAC,IACC,CAAC;AAEL,QAAM,YAAY,MAAM,QAAQ,IAAI,gBAAgB,IAAI,IAAI,mBAAmB,CAAC;AAChF,QAAM,SAAS,UAAU,IAAI,CAAC,SAAS;AACrC,UAAM,MAAM;AACZ,WAAO;AAAA,MACL,UAAU,OAAO,IAAI,YAAY,SAAS;AAAA,MAC1C,QAAQ,OAAO,IAAI,UAAU,SAAS;AAAA,MACtC,OAAO,OAAO,IAAI,SAAS,SAAS;AAAA,MACpC,SAAS,OAAO,IAAI,WAAW,EAAE;AAAA,IACnC;AAAA,EACF,CAAC;AAED,QAAM,cAAc,QAAQ,IAAI,CAAC,SAAS;AAAA,IACxC,QAAQ;AAAA,IACR,QAAQ,OAAO,GAAG,GAAG,GAAG,MAAM;AAAA,IAC9B,WAAW,OAAO,GAAG,GAAG,GAAG,SAAS;AAAA,IACpC,QAAQ,OAAO,MAAM,GAAG,GAAG,MAAM;AAAA,IACjC,OAAO,OAAO,MAAM,GAAG,GAAG,UAAU;AAAA,EACtC,EAAE;AAEF,SAAO;AAAA,IACL,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,YAAY,OAAO,IAAI,QAAQ;AAAA,IAC/B;AAAA,IACA,QAAQ;AAAA,MACN,SAAS,QAAQ;AAAA,MACjB,QAAQ,YAAY,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,QAAQ,CAAC;AAAA,MACpD,WAAW,YAAY,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,WAAW,CAAC;AAAA,MAC1D,QAAQ,YAAY,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,QAAQ,CAAC;AAAA,MACpD,OAAO,YAAY,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,OAAO,CAAC;AAAA,MAClD,OAAO,MAAM;AAAA,MACb,QAAQ,OAAO,OAAO,CAAC,MAAM,EAAE,aAAa,OAAO,EAAE;AAAA,MACrD,UAAU,OAAO,OAAO,CAAC,MAAM,EAAE,aAAa,SAAS,EAAE;AAAA,IAC3D;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,4BAA4B,MAA6B;AACvE,QAAM,iBAAiB,KAAK,YACzB;AAAA,IACC,CAAC,MAAM;AAAA,QACLA,YAAW,EAAE,MAAM,CAAC;AAAA,sBACN,EAAE,MAAM,gBAAa,EAAE,SAAS;AAAA;AAAA,kDAEJ,EAAE,MAAM;AAAA,iDACT,EAAE,KAAK;AAAA;AAAA;AAAA,EAGpD,EACC,KAAK,IAAI;AAEZ,QAAM,WAAW,KAAK,MACnB,MAAM,GAAG,EAAE,EACX;AAAA,IACC,CAAC,MAAM,iBAAiBA,YAAW,EAAE,QAAQ,CAAC,mBAAmBA,YAAW,EAAE,MAAM,CAAC,YAAYA,YAAW,EAAE,KAAK,CAAC;AAAA,EACtH,EACC,KAAK,IAAI;AAEZ,QAAM,YAAY,KAAK,OACpB;AAAA,IACC,CAAC,MAAM,cAAcA,YAAW,EAAE,QAAQ,CAAC,SAASA,YAAW,EAAE,QAAQ,CAAC,YAAYA,YAAW,EAAE,MAAM,CAAC,YAAYA,YAAW,EAAE,KAAK,CAAC,YAAYA,YAAW,EAAE,OAAO,CAAC;AAAA,EAC5K,EACC,KAAK,IAAI;AAEZ,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iDA6IwC,KAAK,UAAU,qBAAkBA,YAAW,KAAK,WAAW,CAAC;AAAA;AAAA,8EAEhC,KAAK,OAAO,OAAO;AAAA,6EACpB,KAAK,OAAO,MAAM;AAAA,gFACf,KAAK,OAAO,SAAS;AAAA,6EACxB,KAAK,OAAO,MAAM;AAAA,4EACnB,KAAK,OAAO,KAAK;AAAA,kFACX,KAAK,OAAO,KAAK;AAAA,mFAChB,KAAK,OAAO,MAAM;AAAA,uFACd,KAAK,OAAO,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMnG,kBAAkB,uDAAuD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAOhE,YAAY,kDAAkD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAQ9D,aAAa,oDAAoD;AAAA;AAAA;AAAA;AAAA;AAAA;AAMlF;AAEO,SAAS,wBAAwB,QAA4C;AAClF,QAAM,OAAO,+BAA+B,MAAM;AAClD,SAAO;AAAA,IACL,UAAU;AAAA,IACV,SAAS,4BAA4B,IAAI;AAAA,EAC3C;AACF;;;AChWA;AAiCO,IAAM,WAA+B;AAAA,EAC1C,EAAE,SAAS,iBAAiB,OAAO,sBAAsB,UAAU,WAAW;AAAA,EAC9E,EAAE,SAAS,qBAAqB,OAAO,kBAAkB,UAAU,WAAW;AAAA,EAC9E,EAAE,SAAS,2BAA2B,OAAO,gCAAgC,UAAU,WAAW;AAAA,EAClG,EAAE,SAAS,iBAAiB,OAAO,aAAa,UAAU,WAAW;AAAA,EACrE,EAAE,SAAS,uBAAuB,OAAO,2BAA2B,UAAU,WAAW;AAAA,EACzF,EAAE,SAAS,qBAAqB,OAAO,0BAA0B,UAAU,WAAW;AAAA,EACtF,EAAE,SAAS,iBAAiB,OAAO,sBAAsB,UAAU,WAAW;AAAA,EAC9E,EAAE,SAAS,uBAAuB,OAAO,eAAe,UAAU,WAAW;AAAA,EAC7E,EAAE,SAAS,eAAe,OAAO,wBAAwB,UAAU,WAAW;AAChF;AAIO,SAAS,gBAAgB,SAA+B;AAC7D,SAAO,QAAQ,IAAI,CAAC,SAAS;AAAA,IAC3B,OAAO;AAAA,IACP,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,UAAU;AAAA,MACR,EAAE,OAAO,kBAAkB,SAAS,2BAA2B,QAAQ,OAAO;AAAA,MAC9E,EAAE,OAAO,aAAa,SAAS,uBAAuB,QAAQ,mBAAmB;AAAA,MACjF,EAAE,OAAO,mBAAmB,SAAS,uBAAuB,QAAQ,QAAQ;AAAA,IAC9E;AAAA,EACF,EAAE;AACJ;AAEO,SAAS,gBAAgB,OAMjB;AACb,SAAO;AAAA,IACL,EAAE,OAAO,YAAY,MAAM,OAAO,IAAI,QAAQ,gBAAgB;AAAA,IAC9D,EAAE,OAAO,WAAW,MAAM,MAAM,IAAI,QAAQ,WAAW;AAAA,IACvD,EAAE,OAAO,cAAc,MAAM,SAAS,IAAI,QAAQ,YAAY;AAAA,IAC9D,EAAE,OAAO,cAAc,MAAM,cAAc,UAAU,QAAQ,YAAY;AAAA,IACzE;AAAA,MACE,OAAO,MAAM,SAAS,IAAI,WAAW,MAAM,MAAM,KAAK;AAAA,MACtD,QAAQ,MAAM,SAAS,IAAI,UAAU;AAAA,IACvC;AAAA,EACF;AACF;AAIO,SAAS,4BAAqD;AACnE,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,IACT,WAAW;AAAA,IACX,SAAS;AAAA,IACT,YAAY,EAAE,MAAM,OAAO,KAAK,uCAAuC;AAAA,IACvE,SAAS,EAAE,QAAQ,UAAU;AAAA,IAC7B,YAAY,CAAC,SAAS;AAAA,IACtB,UAAU,CAAC,OAAO,WAAW,cAAc,MAAM,cAAc;AAAA,IAC/D,kBAAkB,CAAC,wCAAwC,sCAAsC;AAAA,IACjG,MAAM;AAAA,IACN,aAAa;AAAA,MACX,UAAU,SAAS,IAAI,CAAC,OAAO;AAAA,QAC7B,SAAS,EAAE;AAAA,QACX,OAAO,EAAE;AAAA,QACT,UAAU,EAAE;AAAA,MACd,EAAE;AAAA,MACF,iBAAiB;AAAA,QACf,aAAa;AAAA,UACX;AAAA,YACE,IAAI;AAAA,YACJ,OAAO;AAAA,YACP,MAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,MACA,OAAO;AAAA,QACL,UAAU;AAAA,UACR,EAAE,IAAI,mBAAmB,MAAM,SAAS;AAAA,UACxC,EAAE,IAAI,oBAAoB,MAAM,UAAU;AAAA,QAC5C;AAAA,MACF;AAAA,MACA,eAAe;AAAA,QACb,OAAO;AAAA,QACP,YAAY;AAAA,UACV,yBAAyB;AAAA,YACvB,MAAM;AAAA,YACN,SAAS;AAAA,YACT,aAAa;AAAA,UACf;AAAA,UACA,yBAAyB;AAAA,YACvB,MAAM;AAAA,YACN,SAAS;AAAA,YACT,MAAM,CAAC,QAAQ,QAAQ,UAAU;AAAA,YACjC,aAAa;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAMO,SAAS,8BAAsC;AACpD,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0DT;;;ACvMA;;;ACAA;AAKO,SAAS,yBAAyB,QAAgC;AACvE,QAAM,KAAK,OAAO,cAAc,CAAC;AACjC,QAAM,KAAK,OAAO,WAAW,CAAC;AAC9B,QAAM,SAAS,OAAO,UAAU;AAEhC,QAAM,UAAU,GAAG,UAAU,IAAI,GAAG,OAAO,MAAM;AACjD,QAAM,UAAU,GAAG,WAAW;AAC9B,QAAM,UAAU,GAAG,WAAY;AAC/B,QAAM,UAAU,GAAG,WAAY;AAC/B,QAAM,gBAAgB,GAAG,iBAAiB;AAC1C,QAAM,oBAAoB,GAAG,qBAAqB;AAClD,QAAM,eAAe,GAAG,MAAM,oBAAoB;AAElD,QAAM,UAAU,CAAC,CAAE,GAAG,MAAM;AAE5B,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,2DAA2D;AACtE,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,+BAA+B;AAC1C,QAAM,KAAK,eAAe,MAAM,IAAI;AACpC,QAAM,KAAK,gDAAgD;AAC3D,QAAM,KAAK,yBAAyB;AACpC,QAAM,KAAK,iCAAiC;AAC5C,QAAM,KAAK,cAAc,YAAY,OAAO,UAAU,wBAAwB,GAAG;AACjF,QAAM,KAAK,cAAc,YAAY,OAAO,UAAU,wBAAwB,GAAG;AACjF,QAAM,KAAK,cAAc,OAAO,GAAG;AACnC,QAAM,KAAK,qCAAqC;AAChD,QAAM,KAAK,2CAA2C;AACtD,QAAM,KAAK,sDAAsD;AACjE,QAAM,KAAK,UAAU;AACrB,QAAM,KAAK,gBAAgB,OAAO,GAAG;AACrC,QAAM,KAAK,iCAAiC;AAC5C,QAAM,KAAK,oCAAoC;AAC/C,QAAM,KAAK,iCAAiC;AAC5C,QAAM,KAAK,sBAAsB,aAAa,GAAG;AACjD,QAAM,KAAK,0BAA0B,iBAAiB,GAAG;AACzD,QAAM,KAAK,MAAM;AAGjB,QAAM,KAAK,eAAe;AAE1B,MAAI,SAAS;AACX,UAAM,KAAK,OAAO;AAClB,UAAM,KAAK,sBAAsB;AACjC,UAAM,KAAK,sCAAsC;AACjD,UAAM,KAAK,8CAA8C;AACzD,UAAM,KAAK,QAAQ;AACnB,UAAM,KAAK,OAAO;AAClB,UAAM,KAAK,yBAAyB;AACpC,UAAM,KAAK,sCAAsC;AACjD,UAAM,KAAK,gCAAgC;AAC3C,UAAM,KAAK,cAAc;AACzB,UAAM,KAAK,uCAAuC;AAClD,UAAM,KAAK,0BAA0B,YAAY,IAAI;AACrD,UAAM,KAAK,UAAU;AACrB,UAAM,KAAK,QAAQ;AACnB,UAAM,KAAK,OAAO;AAClB,UAAM,KAAK,iCAAiC;AAC5C,UAAM,KAAK,2CAA2C;AACtD,UAAM,KAAK,sCAAsC;AACjD,UAAM,KAAK,8CAA8C;AACzD,UAAM,KAAK,QAAQ;AAAA,EACrB,OAAO;AACL,UAAM,KAAK,OAAO;AAClB,UAAM,KAAK,yBAAyB;AACpC,UAAM,KAAK,8CAA8C;AACzD,UAAM,KAAK,QAAQ;AAAA,EACrB;AAGA,MAAI,GAAG,eAAe;AACpB,eAAW,QAAQ,GAAG,eAAe;AACnC,YAAM,KAAK,OAAO;AAClB,YAAM,KAAK,gBAAgB,KAAK,IAAI,IAAI;AACxC,YAAM,KAAK,qBAAqB,KAAK,SAAS,IAAI;AAClD,UAAI,KAAK,cAAc,QAAQ;AAC7B,cAAM,KAAK,wBAAwB,KAAK,aAAa,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC,IAAI;AAAA,MAC1F;AACA,UAAI,KAAK,YAAY,SAAS,SAAS;AACrC,cAAM,KAAK,cAAc;AACzB,cAAM,KAAK,uCAAuC;AAClD,cAAM,KAAK,0BAA0B,YAAY,IAAI;AACrD,cAAM,KAAK,UAAU;AAAA,MACvB,OAAO;AACL,cAAM,KAAK,8CAA8C;AAAA,MAC3D;AACA,YAAM,KAAK,QAAQ;AAAA,IACrB;AAAA,EACF;AAEA,QAAM,KAAK,MAAM;AACjB,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,EAAE;AAEb,SAAO,MAAM,KAAK,IAAI;AACxB;;;ACpGA;AAMO,SAAS,oBAAoB,QAAgC;AAClE,QAAM,KAAK,OAAO,cAAc,CAAC;AACjC,QAAM,KAAK,OAAO,WAAW,CAAC;AAC9B,QAAM,UAAU,GAAG,WAAW;AAE9B,QAAM,kBAAkB,CAAC,CAAC,GAAG,IAAI;AACjC,QAAM,iBAAiB,CAAC,CAAC,GAAG;AAC5B,QAAM,cAAc,CAAC,CAAC,GAAG,IAAI;AAE7B,QAAM,QAAkB,CAAC;AAEzB,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,+CAA0C;AACrD,QAAM,KAAK,wCAAwC;AACnD,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,6CAA6C,WAAW,uBAAuB,IAAI;AAC9F,QAAM,KAAK,EAAE;AAGb,QAAM,KAAK,gCAAgC;AAC3C,QAAM,KAAK,gBAAgB;AAC3B,QAAM,KAAK,yBAAyB;AACpC,QAAM,KAAK,gBAAgB;AAC3B,QAAM,KAAK,+BAA+B;AAC1C,QAAM,KAAK,uCAAuC;AAClD,QAAM,KAAK,WAAW;AACtB,QAAM,KAAK,2FAA2F;AACtG,QAAM,KAAK,iCAAiC;AAC5C,QAAM,KAAK,mHAA8G;AACzH,QAAM,KAAK,8BAA8B;AACzC,QAAM,KAAK,qEAAqE;AAChF,QAAM,KAAK,2GAA2G;AACtH,QAAM,KAAK,OAAO;AAClB,QAAM,KAAK,0FAA0F;AACrG,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,gBAAgB;AAC3B,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,EAAE;AAGb,QAAM,KAAK,oFAAoF;AAC/F,QAAM,KAAK,6BAA6B;AACxC,QAAM,KAAK,4CAA4C;AACvD,QAAM,KAAK,WAAW;AACtB,QAAM,KAAK,+FAA+F;AAC1G,QAAM,KAAK,2BAA2B;AACtC,QAAM,KAAK,eAAe;AAC1B,QAAM,KAAK,wBAAwB;AACnC,QAAM,KAAK,OAAO;AAClB,QAAM,KAAK,qDAAqD;AAChE,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,iEAAiE;AAC5E,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,EAAE;AAGb,QAAM,KAAK,8DAA8D;AACzE,QAAM,KAAK,8CAA8C;AACzD,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,8BAA8B;AACzC,QAAM,KAAK,SAAS;AACpB,QAAM,KAAK,6CAA6C;AACxD,QAAM,KAAK,sDAAsD;AACjE,QAAM,KAAK,0BAA0B;AACrC,QAAM,KAAK,sFAAsF;AACjG,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,EAAE;AAEb,MAAI,iBAAiB;AACnB,UAAM,KAAK,qCAAqC;AAChD,UAAM,KAAK,SAAS;AACpB,UAAM,KAAK,2BAA2B;AACtC,UAAM,KAAK,uBAAuB,GAAG,GAAI,YAAY,KAAK;AAC1D,UAAM,KAAK,wFAAwF;AACnG,UAAM,KAAK,QAAQ;AACnB,UAAM,KAAK,0DAA0D;AACrE,UAAM,KAAK,aAAa;AACxB,UAAM,KAAK,2DAA2D;AACtE,UAAM,KAAK,KAAK;AAChB,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,gBAAgB;AAClB,UAAM,KAAK,sBAAsB;AACjC,UAAM,KAAK,SAAS;AACpB,UAAM,KAAK,0CAA0C,GAAG,WAAW,4BAA4B;AAC/F,UAAM,KAAK,uDAAuD;AAClE,UAAM,KAAK,aAAa;AACxB,UAAM,KAAK,gEAAgE;AAC3E,UAAM,KAAK,KAAK;AAChB,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,aAAa;AACf,UAAM,KAAK,0EAAqE;AAChF,UAAM,KAAK,0DAA0D;AACrE,UAAM,KAAK,8BAA8B,GAAG,GAAI,QAAQ,KAAK;AAC7D,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,KAAK,wCAAwC;AACnD,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,EAAE;AAEb,SAAO,MAAM,KAAK,IAAI;AACxB;;;AChHA;AAMO,SAAS,uBAAuB,QAAgC;AACrE,QAAM,KAAK,OAAO,cAAc,CAAC;AACjC,QAAM,KAAK,OAAO,WAAW,CAAC;AAC9B,QAAM,UAAU,GAAG,WAAW;AAE9B,QAAM,qBAAqB,CAAC,CAAC,GAAG,IAAI;AACpC,QAAM,iBAAiB,CAAC,CAAC,GAAG,IAAI;AAEhC,QAAM,QAAkB,CAAC;AAEzB,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,kDAA6C;AACxD,QAAM,KAAK,gDAAgD;AAC3D,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,6CAA6C,WAAW,uBAAuB,IAAI;AAC9F,QAAM,KAAK,EAAE;AAEb,QAAM,KAAK,iEAAiE;AAC5E,QAAM,KAAK,iDAAiD;AAC5D,QAAM,KAAK,EAAE;AAEb,MAAI,oBAAoB;AACtB,UAAM,KAAK,mCAAmC;AAC9C,UAAM,KAAK,SAAS;AACpB,UAAM,KAAK,iCAAiC,GAAG,GAAI,eAAe,0BAA0B;AAC5F,UAAM,KAAK,gEAAgE;AAC3E,UAAM,KAAK,aAAa;AACxB,UAAM,KAAK,iEAAiE;AAC5E,UAAM,KAAK,KAAK;AAChB,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,gBAAgB;AAClB,UAAM,KAAK,6EAAwE;AACnF,UAAM,KAAK,0DAA0D;AACrE,UAAM,KAAK,8BAA8B,GAAG,GAAI,WAAW,KAAK;AAChE,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,KAAK,2CAA2C;AACtD,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,EAAE;AAEb,SAAO,MAAM,KAAK,IAAI;AACxB;;;ACnDA;AAMO,SAAS,kBAAkB,QAAgC;AAChE,QAAM,KAAK,OAAO,WAAW,CAAC;AAC9B,QAAM,KAAK,OAAO,cAAc,CAAC;AACjC,QAAM,OAAO,GAAG,QAAQ,CAAC;AACzB,QAAM,UAAU,GAAG,WAAW;AAC9B,QAAM,mBAAmB,KAAK,oBAAoB;AAElD,QAAM,QAAkB,CAAC;AAEzB,QAAM,KAAK,2DAA2D;AACtE,QAAM,KAAK,oCAAoC;AAC/C,QAAM,KAAK,+BAA+B;AAC1C,QAAM,KAAK,EAAE;AAEb,QAAM,KAAK,qBAAqB,gBAAgB,IAAI;AACpD,QAAM,KAAK,EAAE;AAEb,MAAI,KAAK,UAAU;AAEjB,UAAM,KAAK,gDAAgD;AAC3D,UAAM,KAAK,qDAAqD,KAAK,QAAQ,IAAI;AACjF,UAAM,KAAK,oDAAoD,KAAK,YAAY,OAAO,IAAI;AAC3F,UAAM,KAAK,oDAAoD,KAAK,YAAY,EAAE,IAAI;AACtF,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,gBAAgB;AAC3B,UAAM,KAAK,mDAAmD;AAC9D,UAAM,KAAK,mCAAmC;AAC9C,UAAM,KAAK,OAAO;AAClB,UAAM,KAAK,uCAAuC;AAClD,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,uCAAuC;AAClD,UAAM,KAAK,uDAAuD;AAClE,UAAM,KAAK,2EAA2E;AACtF,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,uDAAuD;AAClE,UAAM,KAAK,gEAAgE;AAC3E,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,+BAA+B;AAC1C,UAAM,KAAK,8CAA8C,WAAW,uBAAuB,IAAI;AAC/F,UAAM,KAAK,2CAA2C;AACtD,UAAM,KAAK,0BAA0B;AACrC,UAAM,KAAK,kBAAkB;AAC7B,UAAM,KAAK,gBAAgB;AAC3B,UAAM,KAAK,SAAS;AACpB,UAAM,KAAK,iBAAiB;AAC5B,UAAM,KAAK,yBAAyB;AACpC,UAAM,KAAK,4CAA4C;AACvD,UAAM,KAAK,YAAY;AACvB,UAAM,KAAK,UAAU;AACrB,UAAM,KAAK,QAAQ;AACnB,UAAM,KAAK,MAAM;AACjB,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,wEAAwE;AACnF,UAAM,KAAK,0EAAqE;AAChF,UAAM,KAAK,KAAK;AAAA,EAClB,OAAO;AAEL,UAAM,KAAK,gDAAgD;AAC3D,UAAM,KAAK,+CAA+C;AAC1D,UAAM,KAAK,yCAAyC;AACpD,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,2CAA2C;AACtD,UAAM,KAAK,iCAAiC;AAC5C,UAAM,KAAK,mDAAmD;AAC9D,UAAM,KAAK,sDAAsD;AACjE,UAAM,KAAK,+CAA+C;AAC1D,UAAM,KAAK,2CAA2C;AACtD,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,gEAAgE;AAC3E,UAAM,KAAK,mDAAmD;AAC9D,UAAM,KAAK,0EAAqE;AAChF,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,0BAA0B;AACrC,UAAM,KAAK,KAAK;AAAA,EAClB;AAEA,QAAM,KAAK,EAAE;AAEb,SAAO,MAAM,KAAK,IAAI;AACxB;;;ACrFA;AAsCA,IAAM,qBAAqB,oBAAI,IAAI,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG,CAAC;AAEjE,SAAS,YAAY,QAAyB;AAC5C,SAAO,mBAAmB,IAAI,MAAM;AACtC;AAEA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAC7C;AAEA,eAAe,SAAS,MAAkC;AACxD,MAAI;AACF,WAAO,MAAM,KAAK,KAAK;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAQA,eAAsB,eACpB,KACA,UAAiC,CAAC,GACH;AAC/B,QAAM;AAAA,IACJ,SAAS;AAAA,IACT;AAAA,IACA,UAAU,CAAC;AAAA,IACX,aAAa;AAAA,IACb,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,iBAAiB;AAAA,EACnB,IAAI;AAEJ,QAAM,WAA4B,CAAC;AACnC,MAAI,aAAa;AACjB,MAAI,WAAoB;AAExB,QAAM,iBAAyC,EAAE,GAAG,QAAQ;AAC5D,MAAI,QAAQ,OAAO,SAAS,YAAY,CAAC,eAAe,cAAc,GAAG;AACvE,mBAAe,cAAc,IAAI;AAAA,EACnC;AAEA,WAAS,IAAI,GAAG,KAAK,YAAY,KAAK;AACpC,UAAM,QAAQ,KAAK,IAAI;AAEvB,QAAI;AACF,YAAM,OAAO,MAAM,MAAM,KAAK;AAAA,QAC5B;AAAA,QACA,SAAS;AAAA,QACT,MAAM,OAAQ,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,IAAI,IAAK;AAAA,QACxE,QAAQ,YAAY,QAAQ,SAAS;AAAA,MACvC,CAAC;AAED,YAAM,UAAU,KAAK,IAAI,IAAI;AAC7B,mBAAa,KAAK;AAClB,iBAAW,MAAM,SAAS,IAAI;AAE9B,eAAS,KAAK,EAAE,SAAS,IAAI,GAAG,QAAQ,YAAY,KAAK,QAAQ,WAAW,QAAQ,CAAC;AAErF,UAAI,KAAK,IAAI;AACX,eAAO,EAAE,IAAI,MAAM,QAAQ,YAAY,MAAM,UAAU,SAAS;AAAA,MAClE;AAEA,UAAI,YAAY,UAAU,KAAK,IAAI,YAAY;AAC7C,cAAM,QAAQ,cAAc,KAAK,IAAI,GAAG,CAAC;AACzC,cAAM,MAAM,KAAK;AACjB;AAAA,MACF;AAGA;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,UAAU,KAAK,IAAI,IAAI;AAC7B,YAAM,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC9D,eAAS,KAAK,EAAE,SAAS,IAAI,GAAG,QAAQ,GAAG,KAAK,QAAQ,WAAW,SAAS,OAAO,OAAO,CAAC;AAE3F,UAAI,IAAI,YAAY;AAClB,cAAM,QAAQ,cAAc,KAAK,IAAI,GAAG,CAAC;AACzC,cAAM,MAAM,KAAK;AACjB;AAAA,MACF;AACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAA+B,EAAE,IAAI,OAAO,QAAQ,YAAY,MAAM,UAAU,SAAS;AAE/F,MAAI,gBAAgB;AAClB,UAAM,UAAU,SAAS,IAAI,CAAC,MAAM,IAAI,EAAE,OAAO,KAAK,EAAE,UAAU,KAAK,IAAI,EAAE,SAAS,IAAI,EAAE,KAAK,IAAI;AACrG,UAAM,IAAI,MAAM,0BAA0B,MAAM,IAAI,GAAG,KAAK,SAAS,MAAM,eAAe,OAAO,EAAE;AAAA,EACrG;AAEA,SAAO;AACT;AAKA,eAAsB,eACpB,SACA,UAA4E,CAAC,GAC9D;AACf,QAAM,EAAE,YAAY,KAAQ,aAAa,KAAO,aAAa,UAAU,IAAI;AAC3E,QAAM,YAAY,IAAI,IAAI,YAAY,OAAO,EAAE;AAC/C,QAAM,QAAQ,KAAK,IAAI;AAEvB,SAAO,KAAK,IAAI,IAAI,QAAQ,WAAW;AACrC,QAAI;AACF,YAAM,OAAO,MAAM,MAAM,WAAW,EAAE,QAAQ,OAAO,QAAQ,YAAY,QAAQ,GAAK,EAAE,CAAC;AACzF,UAAI,KAAK,GAAI;AAAA,IACf,QAAQ;AAAA,IAER;AACA,UAAM,MAAM,UAAU;AAAA,EACxB;AAEA,QAAM,IAAI,MAAM,sBAAsB,SAAS,oBAAoB,SAAS,IAAI;AAClF;;;AChKA;AAmDO,IAAM,iBAAN,MAAqB;AAAA,EAClB,SAAyB,CAAC;AAAA,EAC1B,UAAuB,CAAC;AAAA,EACxB,gBAAgB,oBAAI,QAAmC;AAAA,EAC9C;AAAA,EACA;AAAA,EAEjB,YAAY,UAAiC,CAAC,GAAG;AAC/C,SAAK,aAAa,QAAQ,cAAc;AACxC,SAAK,mBAAmB,QAAQ,oBAAoB;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,MAA4B;AACjC,SAAK,GAAG,WAAW,CAAC,YAAY;AAC9B,UAAI,QAAQ,IAAI,EAAE,SAAS,KAAK,UAAU,GAAG;AAC3C,aAAK,cAAc,IAAI,SAAS,KAAK,IAAI,CAAC;AAAA,MAC5C;AAAA,IACF,CAAC;AAED,SAAK,GAAG,YAAY,OAAO,aAAa;AACtC,YAAM,UAAU,SAAS,QAAQ;AACjC,YAAM,YAAY,SAAS,IAAI,EAAE,SAAS,KAAK,UAAU;AACzD,YAAM,YAAY,KAAK,cAAc,IAAI,OAAO;AAEhD,UAAI,aAAa,WAAW;AAC1B,aAAK,QAAQ,KAAK;AAAA,UAChB,KAAK,SAAS,IAAI;AAAA,UAClB,QAAQ,SAAS,OAAO;AAAA,UACxB,QAAQ,QAAQ,OAAO;AAAA,UACvB,YAAY,KAAK,IAAI,IAAI;AAAA,UACzB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,UAClC,SAAS,KAAK,IAAI;AAAA,QACpB,CAAC;AAAA,MACH;AAEA,UAAI,SAAS,OAAO,KAAK,KAAK;AAC5B,YAAI,OAAO;AACX,YAAI,KAAK,kBAAkB;AACzB,cAAI;AACF,mBAAO,MAAM,SAAS,KAAK;AAAA,UAC7B,QAAQ;AACN,mBAAO;AAAA,UACT;AAAA,QACF;AAEA,aAAK,OAAO,KAAK;AAAA,UACf,KAAK,SAAS,IAAI;AAAA,UAClB,QAAQ,SAAS,OAAO;AAAA,UACxB,QAAQ,QAAQ,OAAO;AAAA,UACvB,cAAc;AAAA,UACd,gBAAgB,QAAQ,SAAS,KAAK;AAAA,UACtC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,UAClC,SAAS,KAAK,IAAI;AAAA,QACpB,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,aAA0B;AACxB,WAAO,CAAC,GAAG,KAAK,OAAO;AAAA,EACzB;AAAA;AAAA,EAGA,YAA4B;AAC1B,WAAO,CAAC,GAAG,KAAK,MAAM;AAAA,EACxB;AAAA;AAAA,EAGA,gBAAgB,aAAkC;AAChD,WAAO,KAAK,QAAQ,OAAO,CAAC,MAAM,EAAE,cAAc,WAAW;AAAA,EAC/D;AAAA;AAAA,EAGA,eAA+B;AAC7B,WAAO,KAAK,OAAO,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG;AAAA,EAClD;AAAA;AAAA,EAGA,eAA+B;AAC7B,WAAO,KAAK,OAAO,OAAO,CAAC,MAAM,EAAE,UAAU,OAAO,EAAE,SAAS,GAAG;AAAA,EACpE;AAAA;AAAA,EAGA,YAAqB;AACnB,WAAO,KAAK,OAAO,SAAS;AAAA,EAC9B;AAAA;AAAA,EAGA,QAAc;AACZ,SAAK,SAAS,CAAC;AACf,SAAK,UAAU,CAAC;AAChB,SAAK,gBAAgB,oBAAI,QAAQ;AAAA,EACnC;AACF;;;ACrJA;AAqBO,SAAS,kBAAkB,cAAgC;AAChE,UAAQ,aAAa,MAAM,WAAW,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAC1E;AAUO,SAAS,sBACd,cACA,MAC+B;AAC/B,QAAM,gBAAgB,aAAa,MAAM,GAAG;AAC5C,QAAM,YAAY,KAAK,MAAM,GAAG;AAEhC,MAAI,cAAc,SAAS,UAAU,OAAQ,QAAO;AAEpD,QAAM,SAAiC,CAAC;AAExC,WAAS,IAAI,GAAG,IAAI,cAAc,QAAQ,KAAK;AAC7C,QAAI,cAAc,CAAC,EAAE,WAAW,GAAG,KAAK,UAAU,CAAC,GAAG;AACpD,aAAO,cAAc,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,UAAU,CAAC;AAAA,IACrD;AAAA,EACF;AAEA,QAAM,QAAQ,kBAAkB,YAAY;AAC5C,SAAO,MAAM,MAAM,CAAC,MAAM,OAAO,CAAC,CAAC,IAAI,SAAS;AAClD;AASO,SAAS,UAAU,cAAsB,QAAwC;AACtF,MAAI,SAAS;AACb,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,aAAS,OAAO,QAAQ,IAAI,GAAG,IAAI,KAAK;AAAA,EAC1C;AACA,SAAO;AACT;AAMO,SAAS,kBAAkB,MAA6B;AAC7D,QAAM,QAAQ,KAAK,MAAM,yEAAyE;AAClG,SAAO,QAAQ,CAAC,KAAK;AACvB;AASO,SAAS,oBACd,cACA,UACA,UACsB;AACtB,QAAM,MAAM,YAAY,aAAa,QAAQ,OAAO,GAAG,EAAE,QAAQ,MAAM,EAAE;AACzE,QAAM,SAAS,SAAS,GAAG;AAC3B,MAAI,CAAC,OAAQ,QAAO;AAEpB,SAAO;AAAA,IACL,cAAc;AAAA,IACd,cAAc,UAAU,cAAc,MAAM;AAAA,IAC5C;AAAA,IACA,eAAe;AAAA,EACjB;AACF;;;ACpGA;AAkEA,IAAM,kBAAkB;AAAA,EACtB;AAAA,EAAW;AAAA,EAAY;AAAA,EAAc;AAAA,EAAS;AAAA,EAC9C;AAAA,EAAW;AAAA,EAAU;AAAA,EAAc;AAAA,EAAS;AAAA,EAAW;AACzD;AAEA,SAAS,YAAY,KAAqB;AACxC,MAAI;AACF,WAAO,IAAI,IAAI,GAAG,EAAE;AAAA,EACtB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,aAAaC,QAAuB;AAC3C,QAAM,QAAQA,OAAK,YAAY;AAC/B,SAAO,gBAAgB,KAAK,CAAC,OAAO,MAAM,SAAS,EAAE,CAAC;AACxD;AAcO,SAAS,iBAAiB,WAAgC,WAAW,IAA2B;AACrG,QAAM,SAAS,oBAAI,IAAiC;AAEpD,aAAW,QAAQ,WAAW;AAC5B,QAAI,CAAC,KAAK,IAAI,SAAS,OAAO,EAAG;AACjC,UAAMA,SAAO,YAAY,KAAK,GAAG;AACjC,QAAI,aAAaA,MAAI,EAAG;AACxB,UAAM,SAAS,KAAK,OAAO,YAAY;AACvC,QAAI,CAAC,CAAC,OAAO,QAAQ,OAAO,SAAS,QAAQ,EAAE,SAAS,MAAM,EAAG;AAEjE,UAAM,MAAM,KAAK,YAAY,OAAO,KAAK,SAAS,KAAK,MAAM,MAAM,IAAIA,MAAI;AAC3E,QAAI,CAAC,OAAO,IAAI,GAAG,GAAG;AACpB,aAAO,IAAI,KAAK,EAAE,WAAW,KAAK,WAAW,QAAQ,MAAAA,QAAM,KAAK,KAAK,IAAI,CAAC;AAAA,IAC5E;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,OAAO,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ;AACtD;AAKO,SAAS,yBAAyB,MAAkB,WAAW,IAA2B;AAC/F,QAAM,SAAS,oBAAI,IAAiC;AAEpD,aAAW,OAAO,MAAM;AACtB,UAAM,QAAQ,SAAS,KAAK,YAAY;AACxC,QAAI,UAAU,QAAS;AAEvB,UAAM,SAAS,SAAS,KAAK,QAAQ,EAAE,YAAY;AACnD,QAAI,CAAC,CAAC,OAAO,QAAQ,OAAO,SAAS,QAAQ,EAAE,SAAS,MAAM,EAAG;AAEjE,UAAM,UAAU,SAAS,KAAK,SAAS,KAAK,SAAS,KAAK,KAAK;AAC/D,UAAMA,SAAO,YAAY,OAAO;AAChC,QAAI,CAACA,OAAK,SAAS,OAAO,KAAK,aAAaA,MAAI,EAAG;AAEnD,UAAM,YAAY,SAAS,KAAK,WAAW,KAAK;AAChD,UAAM,MAAM,YAAY,OAAO,SAAS,KAAK,MAAM,MAAM,IAAIA,MAAI;AACjE,QAAI,CAAC,OAAO,IAAI,GAAG,GAAG;AACpB,aAAO,IAAI,KAAK,EAAE,WAAW,QAAQ,MAAAA,QAAM,KAAK,QAAQ,CAAC;AAAA,IAC3D;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,OAAO,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ;AACtD;AAKO,SAAS,mBAAmB,QAAwD;AACzF,QAAM,SAAS,oBAAI,IAAiC;AACpD,aAAW,SAAS,QAAQ;AAC1B,eAAW,QAAQ,OAAO;AACxB,YAAM,MAAM,KAAK,YAAY,OAAO,KAAK,SAAS,KAAK,MAAM,KAAK,MAAM,IAAI,KAAK,IAAI;AACrF,UAAI,CAAC,OAAO,IAAI,GAAG,EAAG,QAAO,IAAI,KAAK,IAAI;AAAA,IAC5C;AAAA,EACF;AACA,SAAO,MAAM,KAAK,OAAO,OAAO,CAAC,EAAE,MAAM,GAAG,EAAE;AAChD;AAIA,SAAS,SAAS,KAAe,OAAuB;AACtD,QAAM,SAAU,IAAgC,KAAK;AACrD,MAAI,UAAU,KAAM,QAAO,OAAO,MAAM;AACxC,QAAM,OAAO,IAAI,OAAO,KAAK;AAC7B,MAAI,QAAQ,KAAM,QAAO,OAAO,IAAI;AACpC,SAAO;AACT;AAEA,SAAS,SAAS,SAA8B,MAAwC;AACtF,MAAI,QAAQ,WAAW;AACrB,UAAM,OAAO,KAAK,KAAK,CAAC,MAAM,SAAS,GAAG,WAAW,MAAM,QAAQ,SAAS;AAC5E,QAAI,KAAM,QAAO;AAAA,EACnB;AACA,SAAO,KAAK,KAAK,CAAC,MAAM;AACtB,UAAM,SAAS,SAAS,GAAG,QAAQ,EAAE,YAAY;AACjD,UAAM,UAAU,SAAS,GAAG,SAAS,KAAK,SAAS,GAAG,KAAK;AAC3D,WAAO,WAAW,QAAQ,UAAU,QAAQ,SAAS,QAAQ,IAAI;AAAA,EACnE,CAAC;AACH;AAEA,SAAS,YAAY,KAAmC;AACtD,QAAM,cAAc,SAAS,KAAK,aAAa,EAAE,YAAY;AAC7D,MAAI,gBAAgB,aAAa,gBAAgB,OAAQ,QAAO;AAChE,QAAM,SAAS,OAAO,SAAS,KAAK,QAAQ,CAAC;AAC7C,MAAI,CAAC,OAAO,MAAM,MAAM,KAAK,UAAU,IAAK,QAAO;AACnD,SAAO;AACT;AAIA,SAASC,OAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAC7C;AAkBA,eAAsB,qBACpB,YACA,SAC8B;AAC9B,QAAM;AAAA,IACJ;AAAA,IACA,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf,IAAI;AAEJ,QAAM,UAAU,CAAC,GAAG,UAAU;AAC9B,QAAM,YAAmC,CAAC;AAC1C,QAAM,SAAwC,CAAC;AAC/C,QAAM,YAAY,KAAK,IAAI;AAC3B,MAAI,YAAY;AAEhB,SAAO,QAAQ,SAAS,KAAK,KAAK,IAAI,IAAI,YAAY,WAAW;AAC/D,UAAM,OAAO,MAAM,UAAU;AAC7B;AAEA,aAAS,IAAI,QAAQ,SAAS,GAAG,KAAK,GAAG,KAAK;AAC5C,YAAM,YAAY,QAAQ,CAAC;AAC3B,YAAM,MAAM,SAAS,WAAW,IAAI;AACpC,UAAI,CAAC,IAAK;AAEV,UAAI,YAAY,GAAG,MAAM,QAAQ;AAC/B,eAAO,KAAK,EAAE,SAAS,WAAW,QAAQ,sBAAsB,CAAC;AAAA,MACnE,OAAO;AACL,kBAAU,KAAK,SAAS;AAAA,MAC1B;AACA,cAAQ,OAAO,GAAG,CAAC;AAAA,IACrB;AAEA,QAAI,QAAQ,WAAW,EAAG;AAG1B,UAAM,OAAO;AACb,UAAM,QAAQ,QAAQ,IAAI,iBAAiB,SAAS,IAAI,MAAM,KAAK,IAAI,YAAY,MAAO,MAAM,OAAO,EAAE;AACzG,UAAMA,OAAM,KAAK;AAAA,EACnB;AAEA,SAAO;AAAA,IACL,gBAAgB,WAAW;AAAA,IAC3B;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA,WAAW,KAAK,IAAI,IAAI;AAAA,EAC1B;AACF;;;AClQA;AAkDO,SAAS,kBAAkB,OAA0B;AAC1D,SAAO;AAAA;AAAA,IAEL,WAA8B;AAC5B,aAAO,CAAC,GAAG,KAAK;AAAA,IAClB;AAAA;AAAA,IAGA,gBAAgB,WAAsC;AACpD,aAAO,MAAM,OAAO,CAAC,MAAM,EAAE,cAAc,SAAS;AAAA,IACtD;AAAA;AAAA,IAGA,cAAc,KAAgC;AAC5C,aAAO,MAAM,OAAO,CAAC,MAAM,IAAI,SAAS,EAAE,WAAW,CAAC;AAAA,IACxD;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,SAAS,QAA+C;AACtD,YAAM,aAAiC,CAAC;AACxC,YAAM,gBAAgB,MAAM,OAAO,CAAC,MAAM;AACxC,YAAI,CAAC,OAAO,IAAI,SAAS,EAAE,WAAW,EAAG,QAAO;AAChD,YAAI,EAAE,UAAU,EAAE,OAAO,YAAY,MAAM,OAAO,OAAO,YAAY,EAAG,QAAO;AAC/E,eAAO;AAAA,MACT,CAAC;AAED,iBAAW,QAAQ,eAAe;AAEhC,YAAI,KAAK,WAAW,OAAO,cAAc,KAAK,SAAS;AACrD,qBAAW,KAAK;AAAA,YACd;AAAA,YACA,UAAU;AAAA,YACV,UAAU,OAAO;AAAA,YACjB,SAAS,GAAG,KAAK,IAAI,KAAK,OAAO,UAAU,8BAA8B,KAAK,OAAO;AAAA,UACvF,CAAC;AAAA,QACH,WAES,KAAK,UAAU,OAAO,cAAc,KAAK,QAAQ;AACxD,qBAAW,KAAK;AAAA,YACd;AAAA,YACA,UAAU;AAAA,YACV,UAAU,OAAO;AAAA,YACjB,SAAS,GAAG,KAAK,IAAI,KAAK,OAAO,UAAU,6BAA6B,KAAK,MAAM;AAAA,UACrF,CAAC;AAAA,QACH;AAGA,YAAI,CAAC,KAAK,YAAY;AACpB,gBAAM,OAAO,OAAO;AACpB,cAAI,SAAS,QAAQ,SAAS,UAAa,SAAS,MAAM,SAAS,QAAQ,SAAS,QAAQ,SAAS,QAAQ;AAC3G,uBAAW,KAAK;AAAA,cACd;AAAA,cACA,UAAU;AAAA,cACV,SAAS,GAAG,KAAK,IAAI;AAAA,YACvB,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA;AAAA;AAAA;AAAA,IAKA,YAAY,SAAkD;AAC5D,aAAO,QAAQ,QAAQ,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;AAAA,IAChD;AAAA;AAAA;AAAA;AAAA,IAKA,UAAU,YAAgF;AACxF,aAAO;AAAA,QACL,OAAO,WAAW,OAAO,CAAC,MAAM,EAAE,aAAa,OAAO,EAAE;AAAA,QACxD,MAAM,WAAW,OAAO,CAAC,MAAM,EAAE,aAAa,MAAM,EAAE;AAAA,QACtD,OAAO,WAAW,OAAO,CAAC,MAAM,EAAE,aAAa,OAAO,EAAE;AAAA,MAC1D;AAAA,IACF;AAAA,EACF;AACF;;;ACrIA;AAOA,SAAS,iBAAAC,gBAAe,aAAAC,YAAW,cAAAC,cAAY,eAAAC,qBAAmB;AAClE,SAAS,WAAAC,UAAS,QAAAC,cAAY;AAC9B,SAAS,oBAAoB;AA+D7B,IAAM,aAAmC,CAAC,YAAY,WAAW,WAAW,QAAQ,QAAQ;AAI5F,SAAS,kBAAkB,QAAgB,cAAiC;AAC1E,QAAM,SAASC,OAAK,QAAQ,IAAI,GAAG,MAAM;AACzC,MAAI,CAACC,aAAW,MAAM,EAAG,QAAO,CAAC;AAEjC,QAAM,QAAkB,CAAC;AACzB,QAAM,UAAUC,cAAY,QAAQ,EAAE,eAAe,MAAM,WAAW,KAAK,CAAC;AAC5E,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAM,OAAO,EAAG;AACrB,QAAI,CAAC,MAAM,KAAK,SAAS,UAAU,KAAK,CAAC,MAAM,KAAK,SAAS,UAAU,EAAG;AAC1E,UAAM,WAAWF;AAAA,MACf,MAAM,cAAe,MAAsC,QAAQ;AAAA,MACnE,MAAM;AAAA,IACR;AACA,QAAI,gBAAgB,CAAC,SAAS,SAAS,YAAY,EAAG;AACtD,UAAM,KAAK,QAAQ;AAAA,EACrB;AACA,SAAO;AACT;AAEA,SAAS,sBAAsB,QAAkC;AAC/D,QAAM,UAA4B,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,EAAE;AAGlF,QAAM,cAAc,OAAO,MAAM,gBAAgB;AACjD,QAAM,cAAc,OAAO,MAAM,gBAAgB;AACjD,QAAM,eAAe,OAAO,MAAM,iBAAiB;AACnD,QAAM,gBAAgB,OAAO,MAAM,uBAAuB;AAE1D,MAAI,YAAa,SAAQ,SAAS,SAAS,YAAY,CAAC,GAAG,EAAE;AAC7D,MAAI,YAAa,SAAQ,SAAS,SAAS,YAAY,CAAC,GAAG,EAAE;AAC7D,MAAI,aAAc,SAAQ,UAAU,SAAS,aAAa,CAAC,GAAG,EAAE;AAChE,MAAI,cAAe,SAAQ,WAAW,SAAS,cAAc,CAAC,GAAG,EAAE;AAEnE,SAAO;AACT;AAIO,SAAS,mBAAmB,QAAwB,UAAgC,CAAC,GAAG;AAC7F,QAAM;AAAA,IACJ,SAAS;AAAA,IACT,WAAW;AAAA,IACX,oBAAoB;AAAA,IACpB,gBAAgB,CAAC,QAAQ,MAAM;AAAA,IAC/B,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,eAAe;AAAA,EACjB,IAAI;AAEJ,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,eAA8B,CAAC;AACrC,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,MAAI,aAAa;AAEjB,WAAS,mBAA4B;AACnC,WAAO,cAAc,KAAK,cAAc;AAAA,EAC1C;AAEA,WAAS,UAAU,OAAoC;AACrD,QAAI,UAAU,UAAU,CAAC,SAAU,QAAO;AAC1C,WAAO,OAAO,SAAS,KAAK;AAAA,EAC9B;AAEA,iBAAe,SACb,MACA,IACyB;AACzB,UAAM,QAAQ,KAAK,IAAI;AACvB,QAAI;AACF,YAAM,SAAS,MAAM,GAAG;AACxB,YAAM,SAAyB;AAAA,QAC7B,OAAO;AAAA,QACP,QAAQ;AAAA,QACR;AAAA,QACA,YAAY,KAAK,IAAI,IAAI;AAAA,MAC3B;AACA,mBAAa,KAAK,MAAM;AACxB,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,YAAM,SAAyB;AAAA,QAC7B,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACtD,YAAY,KAAK,IAAI,IAAI;AAAA,MAC3B;AACA,mBAAa,KAAK,MAAM;AACxB,aAAO;AAAA,IACT;AAAA,EACF;AAEA,WAAS,UAAU,MAAc,QAA6B;AAC5D,UAAM,SAAsB;AAAA,MAC1B,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,YAAY;AAAA,IACd;AACA,iBAAa,KAAK,MAAM;AACxB,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,MAAM,MAAqC;AACzC,YAAM,qBAAqB,KAAK,IAAI;AAGpC,UAAI,UAAU,UAAU,GAAG;AACzB,cAAM,YAAY,MAAM,SAAS,YAAY,YAAY;AACvD,cAAI,aAAc,QAAO,UAAU,CAAC,YAAY;AAChD,gBAAM,WAAW,eAAe,MAAM;AACtC,2BAAiB,MAAM,SAAS,IAAI;AAGpC,qBAAW,QAAQ,eAAe,gBAAgB;AAChD,kBAAM,MAAMG,SAAQ,KAAK,QAAQ;AACjC,gBAAI,CAACF,aAAW,GAAG,EAAG,CAAAG,WAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AACxD,YAAAC,eAAc,KAAK,UAAU,KAAK,SAAS,OAAO;AAAA,UACpD;AAEA,iBAAO;AAAA,QACT,CAAC;AAED,YAAI,UAAU,WAAW,WAAW,cAAc;AAChD,iBAAO,aAAa,kBAAkB;AAAA,QACxC;AAAA,MACF;AAGA,UAAI,UAAU,SAAS,GAAG;AACxB,cAAM,YAAY,kBAAkB,QAAQ,YAAY;AAExD,YAAI,UAAU,WAAW,GAAG;AAC1B,oBAAU,WAAW,qBAAqB;AAAA,QAC5C,OAAO;AACL,gBAAM,aAAa,MAAM,SAAS,WAAW,YAAY;AACvD,kBAAM,OAAO,CAAC,QAAQ,GAAG,SAAS;AAClC,gBAAI,CAAC,OAAQ,MAAK,KAAK,iBAAiB;AAAA,gBACnC,MAAK,KAAK,UAAU;AAEzB,kBAAM,SAAS,QAAQ,aAAa,UAAU,YAAY;AAE1D,gBAAI;AACF,2BAAa,QAAQ,CAAC,cAAc,GAAG,IAAI,GAAG;AAAA,gBAC5C,KAAK,QAAQ,IAAI;AAAA,gBACjB,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,gBAChC,SAAS;AAAA,cACX,CAAC;AACD,qBAAO,EAAE,QAAQ,UAAU,QAAQ,QAAQ,GAAG,SAAS,GAAG,UAAU,EAAE;AAAA,YACxE,SAAS,KAAK;AACZ,oBAAM,SAAU,KAA6B,QAAQ,SAAS,KAAK;AACnE,oBAAM,UAAU,sBAAsB,MAAM;AAC5C,kBAAI,QAAQ,WAAW,KAAK,QAAQ,WAAW,GAAG;AAChD,wBAAQ,SAAS,UAAU;AAAA,cAC7B;AACA,iCAAmB;AACnB,kBAAI,QAAQ,SAAS,GAAG;AACtB,sBAAM,IAAI,MAAM,GAAG,QAAQ,MAAM,oBAAoB,QAAQ,MAAM,WAAW,EAAE,OAAO,IAAI,CAAC;AAAA,cAC9F;AACA,qBAAO;AAAA,YACT;AAAA,UACF,CAAC;AAED,cAAI,CAAC,oBAAoB,WAAW,QAAQ;AAC1C,+BAAmB,WAAW;AAAA,UAChC;AAEA,cAAI,WAAW,WAAW,WAAW,cAAc;AACjD,mBAAO,aAAa,kBAAkB;AAAA,UACxC;AAAA,QACF;AAAA,MACF;AAGA,UAAI,UAAU,SAAS,GAAG;AACxB,YAAI,CAAC,kBAAkB,CAAC,oBAAoB,iBAAiB,WAAW,GAAG;AACzE,oBAAU,WAAW,wBAAwB;AAAA,QAC/C,OAAO;AACL,gBAAM,SAAS,WAAW,YAAY;AAEpC,kBAAM,WAAW,eAAe,MAAM;AACtC,kBAAM,mBAAmB,MAAM,SAAS,IAAI,CAAC,UAAU,CAAC;AACxD,mBAAO;AAAA,cACL,kBAAkB,iBAAiB;AAAA,cACnC,iBAAiB,iBAAkB;AAAA,YACrC;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAGA,UAAI,UAAU,MAAM,GAAG;AACrB,YAAI,iBAAiB,GAAG;AACtB,oBAAU,QAAQ,uBAAuB;AAAA,QAC3C,WAAW,CAAC,oBAAoB,iBAAiB,WAAW,GAAG;AAC7D,oBAAU,QAAQ,qBAAqB;AAAA,QACzC,OAAO;AACL,gBAAM,aAAa,MAAM,SAAS,QAAQ,YAAY;AACpD,kBAAM,aAAgC;AAAA,cACpC,SAAS;AAAA,cACT,eAAe;AAAA,cACf,MAAM,OAAO,aAAa,QAAQ;AAAA,YACpC;AAEA,kBAAM,OAAO,sBAAsB,UAAU;AAC7C,kBAAM,SAAS,MAAM,KAAK,IAAI,MAAM;AACpC,0BAAc,OAAO;AACrB,4BAAgB;AAChB,mBAAO;AAAA,UACT,CAAC;AAED,cAAI,WAAW,WAAW,aAAa,iBAAiB,cAAc,UAAU,SAAS,GAAG;AAC1F,uBAAW,SAAS;AACpB,yBAAa,aAAa,SAAS,CAAC,IAAI;AAAA,UAC1C;AAAA,QACF;AAAA,MACF;AAGA,UAAI,UAAU,QAAQ,GAAG;AACvB,YAAI,CAAC,gBAAgB;AACnB,oBAAU,UAAU,+BAA+B;AAAA,QACrD,OAAO;AACL,gBAAM,SAAS,UAAU,YAAY;AACnC,sBAAU,gBAAgB,gBAAiB,aAAa;AAExD,gBAAI,CAACJ,aAAW,MAAM,EAAG,CAAAG,WAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AAC9D,uBAAW,KAAK,SAAS;AACvB,cAAAC,eAAcL,OAAK,QAAQ,EAAE,QAAQ,GAAG,EAAE,SAAS,OAAO;AAAA,YAC5D;AAEA,mBAAO;AAAA,UACT,CAAC;AAAA,QACH;AAAA,MACF;AAEA,aAAO,aAAa,kBAAkB;AAAA,IACxC;AAAA,EACF;AAEA,WAAS,aAAa,WAAyC;AAC7D,UAAM,aAAa,aAAa,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO,EAAE;AACpE,UAAM,aAAa,aAAa,MAAM,CAAC,MAAM,EAAE,WAAW,aAAa,EAAE,WAAW,SAAS;AAE7F,QAAI;AACJ,QAAI,WAAY,iBAAgB;AAAA,aACvB,aAAa,EAAG,iBAAgB;AAAA,QACpC,iBAAgB;AAErB,QAAI;AACJ,QAAI,oBAAoB,iBAAiB,SAAS,KAAK,CAAC,UAAU;AAChE,uBAAiB;AAAA,IACnB,WAAW,iBAAiB,cAAc,UAAU,SAAS,GAAG;AAC9D,uBAAiB,GAAG,cAAc,UAAU,MAAM;AAAA,IACpD;AAEA,WAAO;AAAA,MACL;AAAA,MACA,QAAQ;AAAA,MACR,iBAAiB,KAAK,IAAI,IAAI;AAAA,MAC9B,SAAS,gBAAgB,WAAW,CAAC;AAAA,MACrC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;;;AC1VA;AAKA,SAAS,iBAAAM,gBAAe,aAAAC,YAAW,cAAAC,oBAAkB;AACrD,SAAS,QAAAC,cAAY;AAYd,SAAS,0BACd,SACA,SACQ;AACR,QAAM,EAAE,WAAW,QAAQ,IAAI,IAAI;AACnC,MAAI,CAACD,aAAW,SAAS,EAAG,CAAAD,WAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAEpE,QAAM,aAAY,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,SAAS,GAAG;AAC/D,QAAM,aAAa,OAAO;AAC1B,QAAM,WAAW,iBAAiB,UAAU,IAAI,SAAS;AACzD,QAAM,WAAWE,OAAK,WAAW,QAAQ;AAEzC,QAAM,eAAe;AAAA,IACnB,GAAG;AAAA,IACH,QAAQ,QAAQ,OAAO,IAAI,CAAC,OAAO;AAAA,MACjC,OAAO,EAAE;AAAA,MACT,QAAQ,EAAE;AAAA,MACV,OAAO,EAAE;AAAA,MACT,YAAY,EAAE;AAAA,IAChB,EAAE;AAAA;AAAA,IAEF,SAAS,QAAQ,SAAS,IAAI,CAAC,OAAO;AAAA,MACpC,QAAQ,EAAE;AAAA,MACV,UAAU,EAAE;AAAA,IACd,EAAE;AAAA,EACJ;AAEA,EAAAH,eAAc,UAAU,KAAK,UAAU,cAAc,MAAM,CAAC,GAAG,OAAO;AACtE,SAAO;AACT;AAKA,SAAS,YAAY,GAAwB;AAC3C,QAAM,QAAgC;AAAA,IACpC,SAAS;AAAA,IACT,MAAM;AAAA,IACN,OAAO;AAAA,IACP,SAAS;AAAA,EACX;AACA,QAAM,OAAO,MAAM,EAAE,MAAM,KAAK;AAChC,QAAM,MAAM,EAAE,aAAa,IAAI,KAAK,EAAE,UAAU,QAAQ;AACxD,QAAM,MAAM,EAAE,QAAQ,WAAM,EAAE,KAAK,KAAK;AACxC,SAAO,KAAK,IAAI,IAAI,EAAE,KAAK,GAAG,GAAG,GAAG,GAAG;AACzC;AAKO,SAAS,0BAA0B,SAAyC;AACjF,QAAM,QAAkB,CAAC;AAEzB,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,8OAA2C;AACtD,QAAM,KAAK,yBAAyB;AACpC,QAAM,KAAK,8OAA2C;AACtD,QAAM,KAAK,EAAE;AAEb,aAAW,KAAK,QAAQ,QAAQ;AAC9B,UAAM,KAAK,YAAY,CAAC,CAAC;AAAA,EAC3B;AAEA,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,kBAAkB,QAAQ,aAAa,EAAE;AACpD,QAAM,KAAK,kBAAkB,QAAQ,QAAQ,KAAK,IAAI,KAAK,QAAQ,EAAE;AACrE,QAAM,KAAK,kBAAkB,QAAQ,eAAe,IAAI;AAExD,MAAI,QAAQ,kBAAkB;AAC5B,UAAM,IAAI,QAAQ;AAClB,UAAM,KAAK,kBAAkB,EAAE,MAAM,YAAY,EAAE,MAAM,YAAY,EAAE,OAAO,UAAU;AAAA,EAC1F;AAEA,MAAI,QAAQ,eAAe;AACzB,UAAM,IAAI,QAAQ;AAClB,UAAM,KAAK,kBAAkB,EAAE,MAAM,MAAM,WAAW,EAAE,UAAU,MAAM,eAAe,EAAE,UAAU,cAAc;AAAA,EACnH;AAEA,MAAI,QAAQ,SAAS;AACnB,UAAM,KAAK,kBAAkB,QAAQ,QAAQ,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,EAChF;AAEA,MAAI,QAAQ,gBAAgB;AAC1B,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,YAAO,QAAQ,cAAc,EAAE;AAAA,EAC5C;AAEA,QAAM,KAAK,EAAE;AAEb,SAAO;AACT;","names":["fs","path","Project","SyntaxKind","basePath","fullPath","path","path","fs","path","fs","path","Project","SyntaxKind","fs","path","Project","SyntaxKind","Project","SyntaxKind","basePath","producer","path","extractPathParams","Project","backendRoot","fs","path","Project","SyntaxKind","HTTP_METHODS","METHOD_MAP","fs","path","createOpenAIProvider","createOllamaProvider","createLlmProvider","createOpenAIProvider","createOllamaProvider","existsSync","readFileSync","fs","createSequelizeAdapter","fs","path","Project","classNameToTableName","parseControllerDirectory","fs","path","parseControllerDirectory","fs","path","Project","SyntaxKind","Node","parseControllerDirectory","fs","path","createSequelizeAdapter","escapeHtml","path","sleep","writeFileSync","mkdirSync","existsSync","readdirSync","dirname","join","join","existsSync","readdirSync","dirname","mkdirSync","writeFileSync","writeFileSync","mkdirSync","existsSync","join"]}
|
|
1
|
+
{"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../src/parsers/controller-parser.ts","../src/index.ts","../src/config.ts","../src/adapters/sequelize-adapter.ts","../src/adapters/llm-provider.ts","../src/adapters/llm/openai-provider.ts","../src/adapters/llm/zhipu-provider.ts","../src/adapters/llm/ollama-provider.ts","../src/pipeline/index.ts","../src/parsers/model-parser.ts","../src/parsers/association-parser.ts","../src/analyzers/api-chain-analyzer.ts","../src/generators/er-diagram-generator.ts","../src/generators/test-code-generator.ts","../src/validators/config-validator.ts","../src/validators/schema-validator.ts","../src/validators/semantic-validator.ts","../src/validators/dryrun-validator.ts","../src/parsers/dto-parser.ts","../src/generators/mock-data-generator.ts","../src/analyzers/impact-reporter.ts","../src/planners/chain-planner.ts","../src/tools/ai-config-suggester.ts","../src/tools/enhanced-ai-suggester.ts","../src/tools/auto-fixer.ts","../src/tools/baseline-comparator.ts","../src/tools/preset-loader.ts","../src/self-healing/index.ts","../src/llm/index.ts","../src/llm/openai.ts","../src/llm/ollama.ts","../src/self-healing/dialog-loop-runner.ts","../src/self-healing/controlled-fixer.ts","../src/self-healing/auto-fix-generator.ts","../src/adapters/sequelize.ts","../src/adapters/typeorm.ts","../src/adapters/prisma.ts","../src/adapters/drizzle.ts","../src/adapters/registry.ts","../src/plugins/index.ts","../src/ci/index.ts","../src/reporters/index.ts","../src/reporters/checklist-reporter.ts","../src/reporters/workorder-reporter.ts","../src/reporters/token-reporter.ts","../src/dashboard/index.ts","../src/vscode/index.ts","../src/runtime/index.ts","../src/runtime/playwright-config-generator.ts","../src/runtime/global-setup-generator.ts","../src/runtime/global-teardown-generator.ts","../src/runtime/auth-setup-generator.ts","../src/runtime/resilient-fetch.ts","../src/runtime/network-monitor.ts","../src/runtime/dynamic-route-resolver.ts","../src/runtime/log-completion-waiter.ts","../src/runtime/critical-api-rules.ts","../src/orchestrator/index.ts","../src/orchestrator/reporter.ts","../src/scanner/language-detector.ts","../src/scanner/project-scanner.ts","../src/scanner/github-cloner.ts","../src/graph/index.ts","../src/insight/index.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n type CallExpression,\r\n type SourceFile,\r\n Node,\r\n type PropertyAccessExpression,\r\n type Decorator,\r\n type MethodDeclaration,\r\n type ObjectLiteralExpression,\r\n} from 'ts-morph';\r\nimport type { ApiEndpoint } from '../types.js';\r\n\r\nexport interface ControllerParser {\r\n parseFile(filePath: string): Promise<ApiEndpoint[]>;\r\n parseDirectory(dirPath: string): Promise<ApiEndpoint[]>;\r\n}\r\n\r\nconst HTTP_METHODS = new Set(['get', 'post', 'put', 'delete', 'patch']);\r\n\r\nconst METHOD_MAP: Record<string, string> = {\r\n get: 'GET', post: 'POST', put: 'PUT', delete: 'DELETE', patch: 'PATCH',\r\n};\r\n\r\nconst NEST_HTTP_DECORATORS = new Set(['get', 'post', 'put', 'delete', 'patch']);\r\n\r\n/**\r\n * Parse a single Controller file and extract API endpoints.\r\n */\r\nexport function parseControllerFile(filePath: string): ApiEndpoint[] {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return [];\r\n\r\n try {\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const endpoints: ApiEndpoint[] = [];\r\n endpoints.push(...extractRouterCalls(sourceFile));\r\n endpoints.push(...extractBaseCrudRoutes(sourceFile));\r\n endpoints.push(...extractNestControllerRoutes(sourceFile));\r\n\r\n return deduplicateEndpoints(endpoints);\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\n/**\r\n * Parse all Controller files in a directory.\r\n */\r\nexport function parseControllerDirectory(dirPath: string): ApiEndpoint[] {\r\n const absoluteDir = path.resolve(dirPath);\r\n if (!fs.existsSync(absoluteDir)) return [];\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) =>\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts',\r\n );\r\n\r\n const endpoints: ApiEndpoint[] = [];\r\n for (const file of files) {\r\n endpoints.push(...parseControllerFile(path.join(absoluteDir, file)));\r\n }\r\n return deduplicateEndpoints(endpoints);\r\n}\r\n\r\nfunction extractRouterCalls(sourceFile: SourceFile): ApiEndpoint[] {\r\n const endpoints: ApiEndpoint[] = [];\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\r\n\r\n const propAccess = expr as PropertyAccessExpression;\r\n const methodName = propAccess.getName().toLowerCase();\r\n if (!HTTP_METHODS.has(methodName)) continue;\r\n\r\n const objectText = propAccess.getExpression().getText().trim();\r\n if (!isRouterLike(objectText)) continue;\r\n\r\n const args = call.getArguments();\r\n if (args.length === 0) continue;\r\n\r\n const routePath = resolveRoutePath(args[0], sourceFile);\r\n if (!routePath) continue;\r\n\r\n endpoints.push({\r\n method: METHOD_MAP[methodName],\r\n path: routePath,\r\n pathParams: extractPathParams(routePath),\r\n queryParams: [],\r\n bodyFields: [],\r\n responseFields: [],\r\n relatedTables: [],\r\n description: extractDescription(call),\r\n });\r\n }\r\n return endpoints;\r\n}\r\n\r\nfunction isRouterLike(text: string): boolean {\r\n return text === 'router' || text === 'this.router';\r\n}\r\n\r\nfunction extractBaseCrudRoutes(sourceFile: SourceFile): ApiEndpoint[] {\r\n const endpoints: ApiEndpoint[] = [];\r\n\r\n let isBaseCrud = false;\r\n for (const cls of sourceFile.getClasses()) {\r\n const heritage = cls.getExtends();\r\n if (heritage?.getText().includes('BaseCrudController')) {\r\n isBaseCrud = true;\r\n break;\r\n }\r\n }\r\n if (!isBaseCrud) return endpoints;\r\n\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n let resourcePath: string | null = null;\r\n\r\n for (const call of calls) {\r\n const exprText = call.getExpression().getText();\r\n if (\r\n (exprText === 'super.registerRoutes' || exprText.endsWith('.registerRoutes')) &&\r\n !exprText.includes('Custom')\r\n ) {\r\n const args = call.getArguments();\r\n if (args.length >= 2) resourcePath = extractStringLiteral(args[1]);\r\n }\r\n }\r\n if (!resourcePath) return endpoints;\r\n\r\n const basePath = `/v1/:tenantId/${resourcePath}`;\r\n const crudRoutes: Array<{ method: string; path: string; desc: string }> = [\r\n { method: 'GET', path: basePath, desc: `List ${resourcePath}` },\r\n { method: 'GET', path: `${basePath}/:id`, desc: `Get ${resourcePath} by ID` },\r\n { method: 'POST', path: basePath, desc: `Create ${resourcePath}` },\r\n { method: 'PUT', path: `${basePath}/:id`, desc: `Update ${resourcePath}` },\r\n { method: 'DELETE', path: `${basePath}/:id`, desc: `Delete ${resourcePath}` },\r\n { method: 'POST', path: `${basePath}/batch-delete`, desc: `Batch delete ${resourcePath}` },\r\n ];\r\n\r\n for (const route of crudRoutes) {\r\n endpoints.push({\r\n method: route.method,\r\n path: route.path,\r\n pathParams: extractPathParams(route.path),\r\n queryParams: [],\r\n bodyFields: [],\r\n responseFields: [],\r\n relatedTables: [],\r\n description: route.desc,\r\n });\r\n }\r\n return endpoints;\r\n}\r\n\r\nfunction extractNestControllerRoutes(sourceFile: SourceFile): ApiEndpoint[] {\r\n const endpoints: ApiEndpoint[] = [];\r\n\r\n for (const cls of sourceFile.getClasses()) {\r\n const controllerDecorator = cls.getDecorators().find((d) => d.getName().toLowerCase() === 'controller');\r\n if (!controllerDecorator) continue;\r\n\r\n const controllerBasePath = normalizeRoutePath(extractDecoratorPath(controllerDecorator, sourceFile) ?? '');\r\n\r\n for (const methodDecl of cls.getMethods()) {\r\n const requestMapping = extractRequestMapping(methodDecl, sourceFile);\r\n if (requestMapping) {\r\n const fullPath = joinRoutePath(controllerBasePath, normalizeRoutePath(requestMapping.path));\r\n endpoints.push({\r\n method: requestMapping.method,\r\n path: fullPath,\r\n pathParams: extractPathParams(fullPath),\r\n queryParams: [],\r\n bodyFields: [],\r\n responseFields: [],\r\n relatedTables: [],\r\n description: extractMethodDescription(methodDecl),\r\n });\r\n continue;\r\n }\r\n\r\n const httpDecorator = methodDecl.getDecorators().find((d) => NEST_HTTP_DECORATORS.has(d.getName().toLowerCase()));\r\n if (!httpDecorator) continue;\r\n\r\n const methodName = httpDecorator.getName().toLowerCase();\r\n const method = METHOD_MAP[methodName];\r\n if (!method) continue;\r\n\r\n const methodPath = normalizeRoutePath(extractDecoratorPath(httpDecorator, sourceFile) ?? '');\r\n const fullPath = joinRoutePath(controllerBasePath, methodPath);\r\n\r\n endpoints.push({\r\n method,\r\n path: fullPath,\r\n pathParams: extractPathParams(fullPath),\r\n queryParams: [],\r\n bodyFields: [],\r\n responseFields: [],\r\n relatedTables: [],\r\n description: extractMethodDescription(methodDecl),\r\n });\r\n }\r\n }\r\n\r\n return endpoints;\r\n}\r\n\r\n/**\r\n * Infer related database table names from Service file imports.\r\n */\r\nexport function inferRelatedTables(servicePaths: string[]): string[] {\r\n const tables = new Set<string>();\r\n for (const sp of servicePaths) {\r\n const absolutePath = path.resolve(sp);\r\n if (!fs.existsSync(absolutePath)) continue;\r\n try {\r\n const content = fs.readFileSync(absolutePath, 'utf-8');\r\n const importRegex = /import\\s*\\{([^}]+)\\}\\s*from\\s*['\"][^'\"]*models[^'\"]*['\"]/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = importRegex.exec(content)) !== null) {\r\n const names = match[1].split(',').map((s) => s.trim());\r\n for (const name of names) {\r\n const cleanName = name.replace(/\\s+as\\s+\\w+/, '').trim();\r\n if (cleanName) tables.add(pascalToSnake(cleanName));\r\n }\r\n }\r\n } catch {\r\n // skip\r\n }\r\n }\r\n return Array.from(tables);\r\n}\r\n\r\nfunction resolveRoutePath(node: Node, sourceFile: SourceFile): string | null {\r\n const kind = node.getKind();\r\n if (kind === SyntaxKind.StringLiteral) return node.getText().slice(1, -1);\r\n if (kind === SyntaxKind.TemplateExpression || kind === SyntaxKind.NoSubstitutionTemplateLiteral) {\r\n return resolveTemplateLiteral(node, sourceFile);\r\n }\r\n if (kind === SyntaxKind.Identifier) {\r\n return resolveVariableValue(sourceFile, node.getText().trim());\r\n }\r\n return null;\r\n}\r\n\r\nfunction extractDecoratorPath(decorator: Decorator, sourceFile: SourceFile): string | null {\r\n const args = decorator.getArguments();\r\n if (args.length === 0) return '';\r\n\r\n const firstArg = args[0];\r\n if (firstArg.getKind() === SyntaxKind.ObjectLiteralExpression) {\r\n return extractPathFromObjectLiteral(firstArg as ObjectLiteralExpression, sourceFile);\r\n }\r\n\r\n return resolveRoutePath(firstArg, sourceFile);\r\n}\r\n\r\nfunction extractPathFromObjectLiteral(node: ObjectLiteralExpression, sourceFile: SourceFile): string | null {\r\n const pathProp = node.getProperty('path');\r\n if (!pathProp || !Node.isPropertyAssignment(pathProp)) return null;\r\n const initializer = pathProp.getInitializer();\r\n if (!initializer) return null;\r\n return resolveRoutePath(initializer, sourceFile);\r\n}\r\n\r\nfunction extractRequestMapping(\r\n methodDecl: MethodDeclaration,\r\n sourceFile: SourceFile,\r\n): { method: string; path: string } | null {\r\n const decorator = methodDecl.getDecorators().find((d) => d.getName().toLowerCase() === 'requestmapping');\r\n if (!decorator) return null;\r\n\r\n const args = decorator.getArguments();\r\n if (args.length === 0) return null;\r\n const firstArg = args[0];\r\n if (firstArg.getKind() !== SyntaxKind.ObjectLiteralExpression) return null;\r\n\r\n const obj = firstArg as ObjectLiteralExpression;\r\n const methodProp = obj.getProperty('method');\r\n let method = 'GET';\r\n if (methodProp && Node.isPropertyAssignment(methodProp)) {\r\n const init = methodProp.getInitializer();\r\n const methodText = init?.getText() || '';\r\n const normalized = methodText\r\n .replace(/['\"`]/g, '')\r\n .split('.')\r\n .pop()\r\n ?.toUpperCase();\r\n if (normalized && ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(normalized)) {\r\n method = normalized;\r\n }\r\n }\r\n\r\n const pathValue = extractPathFromObjectLiteral(obj, sourceFile) ?? '';\r\n return { method, path: pathValue };\r\n}\r\n\r\nfunction normalizeRoutePath(routePath: string): string {\r\n const cleaned = routePath.trim();\r\n if (!cleaned || cleaned === '/') return '';\r\n return `/${cleaned.replace(/^\\/+|\\/+$/g, '')}`;\r\n}\r\n\r\nfunction joinRoutePath(basePath: string, childPath: string): string {\r\n const joined = `${basePath}${childPath}`.replace(/\\/+/g, '/');\r\n return joined || '/';\r\n}\r\n\r\nfunction extractMethodDescription(methodDecl: MethodDeclaration): string {\r\n const docs = methodDecl.getJsDocs();\r\n if (docs.length > 0) {\r\n const desc = docs[0].getDescription().trim();\r\n if (desc) return desc;\r\n }\r\n return '';\r\n}\r\n\r\nfunction resolveTemplateLiteral(node: Node, sourceFile: SourceFile): string {\r\n let result = node.getText().slice(1, -1);\r\n result = result.replace(/\\$\\{([^}]+)\\}/g, (_match, expr: string) => {\r\n const resolved = resolveVariableValue(sourceFile, expr.trim());\r\n return resolved || `{${expr.trim()}}`;\r\n });\r\n return result;\r\n}\r\n\r\nfunction resolveVariableValue(sourceFile: SourceFile, varName: string): string | null {\r\n for (const decl of sourceFile.getDescendantsOfKind(SyntaxKind.VariableDeclaration)) {\r\n if (decl.getName() === varName) {\r\n const init = decl.getInitializer();\r\n if (!init) continue;\r\n const t = init.getText().trim();\r\n if ((t.startsWith(\"'\") && t.endsWith(\"'\")) || (t.startsWith('\"') && t.endsWith('\"')))\r\n return t.slice(1, -1);\r\n if (t.startsWith('`') && t.endsWith('`'))\r\n return resolveTemplateLiteral(init, sourceFile);\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction extractPathParams(routePath: string): string[] {\r\n const params: string[] = [];\r\n const regex = /:(\\w+)/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = regex.exec(routePath)) !== null) params.push(match[1]);\r\n return params;\r\n}\r\n\r\nfunction extractDescription(call: CallExpression): string {\r\n let current: Node = call;\r\n while (\r\n current.getParent() &&\r\n current.getParent()!.getKind() !== SyntaxKind.SourceFile &&\r\n current.getParent()!.getKind() !== SyntaxKind.Block\r\n ) {\r\n current = current.getParent()!;\r\n }\r\n const fullText = current.getFullText();\r\n const leadingText = fullText.substring(0, fullText.indexOf(current.getText()));\r\n const jsdocMatch = leadingText.match(/\\/\\*\\*[\\s\\S]*?\\*\\s+(.+?)(?:\\n|\\*\\/)/);\r\n if (jsdocMatch) return jsdocMatch[1].replace(/^\\*\\s*/, '').trim();\r\n const lineMatch = leadingText.match(/\\/\\/\\s*(.+)/);\r\n if (lineMatch) return lineMatch[1].trim();\r\n return '';\r\n}\r\n\r\nfunction extractStringLiteral(node: Node): string | null {\r\n const t = node.getText().trim();\r\n if ((t.startsWith(\"'\") && t.endsWith(\"'\")) || (t.startsWith('\"') && t.endsWith('\"')))\r\n return t.slice(1, -1);\r\n return null;\r\n}\r\n\r\nfunction pascalToSnake(name: string): string {\r\n return name.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\r\n}\r\n\r\nfunction deduplicateEndpoints(endpoints: ApiEndpoint[]): ApiEndpoint[] {\r\n const seen = new Map<string, ApiEndpoint>();\r\n for (const ep of endpoints) {\r\n const key = `${ep.method}:${ep.path}`;\r\n if (!seen.has(key)) {\r\n seen.set(key, ep);\r\n } else {\r\n const existing = seen.get(key)!;\r\n const merged = new Set([...existing.relatedTables, ...ep.relatedTables]);\r\n existing.relatedTables = Array.from(merged);\r\n if (!existing.description && ep.description) existing.description = ep.description;\r\n }\r\n }\r\n return Array.from(seen.values());\r\n}\r\n\r\nexport function createControllerParser(): ControllerParser {\r\n return {\r\n async parseFile(filePath: string) {\r\n return parseControllerFile(filePath);\r\n },\r\n async parseDirectory(dirPath: string) {\r\n return parseControllerDirectory(dirPath);\r\n },\r\n };\r\n}\r\n","// OpenCroc — AI-native E2E Testing & Project Intelligence Platform\r\n// Public API\r\n\r\n// --- Core Types ---\r\nexport type {\r\n OpenCrocConfig,\r\n ResolvedConfig,\r\n ModuleDefinition,\r\n RouteEntry,\r\n FieldSchema,\r\n TableSchema,\r\n IndexSchema,\r\n ForeignKeyRelation,\r\n ApiEndpoint,\r\n ApiDependency,\r\n DirectedAcyclicGraph,\r\n ApiChainAnalysisResult,\r\n TestStep,\r\n TestChain,\r\n ChainPlanResult,\r\n GeneratedTestFile,\r\n PipelineRunResult,\r\n ERDiagramResult,\r\n ChainFailureResult,\r\n ImpactReport,\r\n ValidationError,\r\n SelfHealingResult,\r\n FixOutcome,\r\n RuntimeConfig,\r\n HookConfig,\r\n ExecutionConfig,\r\n FixScope,\r\n DialogLoopConfig,\r\n TestFailureInfo,\r\n IterationResult,\r\n DialogLoopSummary,\r\n ControlledFixOptions,\r\n ControlledFixOutcome,\r\n AIAttributionResult,\r\n AutoFixPROptions,\r\n AutoFixPRResult,\r\n FailureCategory,\r\n TestResultRecord,\r\n LogCompletionRecord,\r\n FailureSummary,\r\n BackendDomainItem,\r\n LogCompletionSummary,\r\n WorkorderItem,\r\n TokenUsageEntry,\r\n TokenUsageSummary,\r\n // Sprint 2-3 types\r\n ModuleTestConfig,\r\n SeedStep,\r\n ModuleConfigErrorType,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n LayerValidationResult,\r\n ModuleConfigValidationResult,\r\n ModuleConfigValidationContext,\r\n DTOInfo,\r\n DTOFieldInfo,\r\n ValidatorRule,\r\n ModuleMetadata,\r\n FixContext,\r\n FixHistoryEntry,\r\n FixResult,\r\n} from './types.js';\r\n\r\n// --- Config ---\r\nexport { defineConfig } from './config.js';\r\n\r\n// --- Pipeline ---\r\nexport { createPipeline } from './pipeline/index.js';\r\n\r\n// --- Parsers ---\r\nexport { createModelParser, parseModelFile, parseModuleModels } from './parsers/model-parser.js';\r\nexport { createControllerParser, parseControllerFile, parseControllerDirectory, inferRelatedTables } from './parsers/controller-parser.js';\r\nexport { createAssociationParser, parseAssociationFile, buildClassToTableMap, classNameToTableName } from './parsers/association-parser.js';\r\nexport { parseDTOs, parseValidatorRules, scanModuleMetadata } from './parsers/dto-parser.js';\r\n\r\n// --- Generators ---\r\nexport { createTestCodeGenerator } from './generators/test-code-generator.js';\r\nexport { createMockDataGenerator } from './generators/mock-data-generator.js';\r\nexport { createERDiagramGenerator } from './generators/er-diagram-generator.js';\r\n\r\n// --- Analyzers ---\r\nexport { createApiChainAnalyzer, inferDependencies, buildGraph, detectCycles, topologicalSort } from './analyzers/api-chain-analyzer.js';\r\nexport { createImpactReporter } from './analyzers/impact-reporter.js';\r\n\r\n// --- Planners ---\r\nexport { createChainPlanner, createLlmChainPlanner } from './planners/chain-planner.js';\r\n\r\n// --- Validators ---\r\nexport { validateConfig, validateModuleConfig, formatValidationResult } from './validators/config-validator.js';\r\nexport { validateSchema } from './validators/schema-validator.js';\r\nexport { validateSemantic } from './validators/semantic-validator.js';\r\nexport { validateDryrun } from './validators/dryrun-validator.js';\r\n\r\n// --- Tools ---\r\nexport { generateModuleConfig, generateAllModuleConfigs, recoverJSON } from './tools/ai-config-suggester.js';\r\nexport { generateEnhancedConfig } from './tools/enhanced-ai-suggester.js';\r\nexport { autoFix } from './tools/auto-fixer.js';\r\nexport { parsePlaywrightReport, buildTestRunSummary, compareTestRuns, formatComparisonReport } from './tools/baseline-comparator.js';\r\nexport { loadModulePresets, getModulePreset, listModulePresets } from './tools/preset-loader.js';\r\n\r\n// --- Self-Healing ---\r\nexport { createSelfHealingLoop, categorizeFailure, analyzeFailureWithLLM } from './self-healing/index.js';\r\nexport { runDialogLoop, createJsonResultParser } from './self-healing/index.js';\r\nexport type { TestRunner, ResultParser, FixApplier, DialogLoopOptions } from './self-healing/index.js';\r\nexport { applyControlledFix } from './self-healing/index.js';\r\nexport type { ConfigValidator, ConfigFixer, PRGenerator, FsOps, ControlledFixerOptions } from './self-healing/index.js';\r\nexport { generateFixPR } from './self-healing/index.js';\r\nexport type { GitExecutor, PatchWriter } from './self-healing/index.js';\r\n\r\n// --- LLM ---\r\nexport { createLlmProvider, createOpenAIProvider, createOllamaProvider, createTokenTracker, SYSTEM_PROMPTS } from './llm/index.js';\r\n\r\n// --- Adapters ---\r\nexport type { BackendAdapter, LlmProvider } from './adapters/types.js';\r\nexport { createSequelizeAdapter } from './adapters/sequelize.js';\r\nexport { createTypeORMAdapter } from './adapters/typeorm.js';\r\nexport { createPrismaAdapter } from './adapters/prisma.js';\r\nexport { createDrizzleAdapter, parseDrizzleFile, parseDrizzleDirectory } from './adapters/drizzle.js';\r\nexport { createAdapter, detectAdapter, resolveAdapter } from './adapters/registry.js';\r\n\r\n// --- Plugins ---\r\nexport type { OpenCrocPlugin, PluginRegistry } from './plugins/types.js';\r\nexport { createPluginRegistry, definePlugin } from './plugins/index.js';\r\n\r\n// --- CI Templates ---\r\nexport { generateCiTemplate, listCiPlatforms, generateGitHubActionsTemplate, generateGitLabCITemplate } from './ci/index.js';\r\n\r\n// --- Reporters ---\r\nexport type { ReportOutput, BuildWorkordersOptions } from './reporters/index.js';\r\nexport { generateReports, generateHtmlReport, generateJsonReport, generateMarkdownReport } from './reporters/index.js';\r\nexport { classifyFailure, buildFailureSummary, aggregateLogCompletion, parseApiDomain, buildBackendChecklist, renderChecklistMarkdown } from './reporters/index.js';\r\nexport { buildWorkorders, renderWorkordersMarkdown } from './reporters/index.js';\r\nexport { TokenTracker, renderTokenReportMarkdown } from './reporters/index.js';\r\n\r\n// --- Visual Dashboard ---\r\nexport type { DashboardData, DashboardOutput } from './dashboard/index.js';\r\nexport {\r\n buildDashboardDataFromPipeline,\r\n buildDashboardDataFromReportJson,\r\n generateVisualDashboardHtml,\r\n generateVisualDashboard,\r\n} from './dashboard/index.js';\r\n\r\n// --- VSCode Extension Scaffold ---\r\nexport { COMMANDS as VSCODE_COMMANDS, generateExtensionManifest, generateExtensionEntrypoint, buildModuleTree, buildStatusTree } from './vscode/index.js';\r\n\r\n// --- Runtime Infrastructure ---\r\nexport { generatePlaywrightConfig, generateGlobalSetup, generateGlobalTeardown, generateAuthSetup } from './runtime/index.js';\r\nexport { resilientFetch, waitForBackend } from './runtime/resilient-fetch.js';\r\nexport { NetworkMonitor } from './runtime/network-monitor.js';\r\nexport { extractParamNames, extractParamsFromHref, buildPath, extractIdFromText, resolveFromSeedData } from './runtime/dynamic-route-resolver.js';\r\nexport type { AttemptRecord, ResilientFetchOptions, ResilientFetchResult } from './runtime/resilient-fetch.js';\r\nexport type { NetworkError, ApiRecord, NetworkMonitorOptions } from './runtime/network-monitor.js';\r\nexport type { ResolvedRoute } from './runtime/dynamic-route-resolver.js';\r\nexport { selectCandidates, selectCandidatesFromLogs, mergeCandidates, waitForLogCompletion } from './runtime/log-completion-waiter.js';\r\nexport { createRulesEngine } from './runtime/critical-api-rules.js';\r\nexport type { CandidateApiRequest, LogCompletionResult, LogEntry, LogPollerOptions } from './runtime/log-completion-waiter.js';\r\nexport type { CriticalApiRule, ApiRuleViolation, ApiRecordForRules } from './runtime/critical-api-rules.js';\r\n\r\n// --- Orchestration ---\r\nexport { createOrchestrator } from './orchestrator/index.js';\r\nexport { writeOrchestrationSummary, printOrchestrationSummary } from './orchestrator/reporter.js';\r\nexport type {\r\n PhaseStatus,\r\n PhaseResult,\r\n OrchestrationOptions,\r\n OrchestrationPhase,\r\n ExecutionMetrics,\r\n OrchestrationSummary,\r\n} from './orchestrator/index.js';\r\nexport type { OrchestrationReportOptions } from './orchestrator/reporter.js';\r\n\r\n// --- Scanner (Universal Project Analysis) ---\r\nexport { detectProject } from './scanner/language-detector.js';\r\nexport type { LanguageDetectionResult } from './scanner/language-detector.js';\r\nexport { scanProject } from './scanner/project-scanner.js';\r\nexport type { ScanOptions } from './scanner/project-scanner.js';\r\nexport { cloneAndScan } from './scanner/github-cloner.js';\r\nexport type { CloneOptions } from './scanner/github-cloner.js';\r\n\r\n// --- Knowledge Graph ---\r\nexport type {\r\n GraphNode,\r\n GraphEdge,\r\n GraphNodeType,\r\n GraphEdgeRelation,\r\n KnowledgeGraph as StudioKnowledgeGraph,\r\n ProjectMetadata,\r\n ProjectStats,\r\n ProjectType,\r\n RiskAnnotation,\r\n RiskCategory,\r\n RiskSeverity,\r\n ImpactAnalysis,\r\n PerspectiveReport,\r\n ReportPerspective,\r\n ReportSection,\r\n SimulationScenario,\r\n SimulationResult,\r\n ScanResult,\r\n FrameworkDetection,\r\n DiscoveredFile,\r\n ExtractedEntity,\r\n ExtractedRelationship,\r\n} from './graph/types.js';\r\nexport {\r\n buildKnowledgeGraph,\r\n queryNodes,\r\n getNeighbors,\r\n bfsTraversal,\r\n findPaths,\r\n toMermaid,\r\n getGraphStats,\r\n} from './graph/index.js';\r\n\r\n// --- Insight (AI Analysis) ---\r\nexport {\r\n analyzeRisks,\r\n analyzeImpact,\r\n generateReport as generateInsightReport,\r\n simulateScenario,\r\n} from './insight/index.js';\r\n","import * as path from 'node:path';\r\nimport type { OpenCrocConfig, ResolvedConfig, BackendAdapter, LlmProvider } from './types.js';\r\nimport { createSequelizeAdapter } from './adapters/sequelize-adapter.js';\r\nimport { createLlmProvider } from './adapters/llm-provider.js';\r\n\r\n/**\r\n * Define an OpenCroc configuration with type checking.\r\n *\r\n * @example\r\n * ```ts\r\n * // opencroc.config.ts\r\n * import { defineConfig } from 'opencroc';\r\n *\r\n * export default defineConfig({\r\n * backendRoot: './backend',\r\n * adapter: 'sequelize',\r\n * llm: {\r\n * provider: 'openai',\r\n * model: 'gpt-4o-mini',\r\n * },\r\n * });\r\n * ```\r\n */\r\nexport function defineConfig(config: OpenCrocConfig): OpenCrocConfig {\r\n return config;\r\n}\r\n\r\n/**\r\n * Load config from opencroc.config.ts using cosmiconfig.\r\n * Falls back to default config if no file found.\r\n */\r\nexport async function loadConfig(searchFrom?: string): Promise<OpenCrocConfig> {\r\n const { cosmiconfig } = await import('cosmiconfig');\r\n const explorer = cosmiconfig('opencroc', {\r\n searchPlaces: [\r\n 'opencroc.config.ts',\r\n 'opencroc.config.js',\r\n 'opencroc.config.mjs',\r\n 'opencroc.config.cjs',\r\n '.opencrocrc.json',\r\n '.opencrocrc.yaml',\r\n '.opencrocrc.yml',\r\n ],\r\n });\r\n\r\n const result = await explorer.search(searchFrom);\r\n if (!result || result.isEmpty) {\r\n return { backendRoot: './backend' };\r\n }\r\n\r\n // cosmiconfig returns the raw export; handle default export\r\n const raw = result.config;\r\n return typeof raw === 'object' && raw !== null && 'default' in raw\r\n ? (raw as { default: OpenCrocConfig }).default\r\n : raw as OpenCrocConfig;\r\n}\r\n\r\n/**\r\n * Resolve a user config into a fully-resolved config with all defaults filled.\r\n */\r\nexport function resolveConfig(config: OpenCrocConfig): ResolvedConfig {\r\n const resolvedAdapter: string | BackendAdapter =\r\n config.adapter ?? createSequelizeAdapter();\r\n\r\n const resolvedLlmProvider: LlmProvider | undefined =\r\n config.llm ? createLlmProvider(config.llm) : undefined;\r\n\r\n return {\r\n _resolved: true,\r\n backendRoot: path.resolve(config.backendRoot),\r\n outDir: config.outDir ?? './opencroc-output',\r\n adapter: typeof resolvedAdapter === 'string' ? resolveAdapterByName(resolvedAdapter) : resolvedAdapter,\r\n llm: config.llm ?? { provider: 'openai' },\r\n playwright: config.playwright ?? {},\r\n modules: config.modules ?? [],\r\n steps: config.steps ?? ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'],\r\n selfHealing: config.selfHealing ?? { enabled: true, maxIterations: 3 },\r\n report: config.report ?? { format: ['html'] },\r\n execution: config.execution ?? {},\r\n runtime: config.runtime ?? {},\r\n _llmProvider: resolvedLlmProvider,\r\n } as ResolvedConfig;\r\n}\r\n\r\nfunction resolveAdapterByName(name: string): BackendAdapter {\r\n switch (name) {\r\n case 'sequelize':\r\n return createSequelizeAdapter();\r\n case 'typeorm':\r\n case 'prisma':\r\n throw new Error(`Adapter \"${name}\" is not yet implemented. Use a custom BackendAdapter instead.`);\r\n default:\r\n throw new Error(`Unknown adapter: \"${name}\". Supported: sequelize, typeorm, prisma.`);\r\n }\r\n}\r\n","/**\r\n * Sequelize Backend Adapter\r\n *\r\n * Implements BackendAdapter for Sequelize ORM projects.\r\n * Uses ts-morph to parse Model.init() calls, association definitions, and controller routes.\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n type CallExpression,\r\n type ObjectLiteralExpression,\r\n type PropertyAssignment,\r\n type Node,\r\n type SourceFile,\r\n type PropertyAccessExpression,\r\n} from 'ts-morph';\r\nimport type {\r\n BackendAdapter,\r\n TableSchema,\r\n FieldSchema,\r\n IndexSchema,\r\n ForeignKeyRelation,\r\n RouteEntry,\r\n} from '../types.js';\r\n\r\n// ============================================================\r\n// Factory\r\n// ============================================================\r\n\r\nexport function createSequelizeAdapter(): BackendAdapter {\r\n return {\r\n name: 'sequelize',\r\n\r\n async parseModels(dir: string): Promise<TableSchema[]> {\r\n return parseModelsFromDir(dir);\r\n },\r\n\r\n async parseAssociations(file: string): Promise<ForeignKeyRelation[]> {\r\n return parseAssociationsFromFile(file);\r\n },\r\n\r\n async parseControllers(dir: string): Promise<RouteEntry[]> {\r\n return parseControllersFromDir(dir);\r\n },\r\n };\r\n}\r\n\r\n// ============================================================\r\n// Model Parsing\r\n// ============================================================\r\n\r\nfunction parseModelsFromDir(modelDir: string): TableSchema[] {\r\n const absoluteDir = path.resolve(modelDir);\r\n if (!fs.existsSync(absoluteDir)) return [];\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) => {\r\n return (\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts' &&\r\n f !== 'associations.ts'\r\n );\r\n });\r\n\r\n const schemas: TableSchema[] = [];\r\n for (const file of files) {\r\n try {\r\n const schema = parseModelFile(path.join(absoluteDir, file));\r\n if (schema) schemas.push(schema);\r\n } catch {\r\n // Skip files that fail to parse\r\n }\r\n }\r\n return schemas;\r\n}\r\n\r\nfunction parseModelFile(filePath: string): TableSchema | null {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return null;\r\n\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const initCall = findInitCall(sourceFile);\r\n if (!initCall) return null;\r\n\r\n const args = initCall.getArguments();\r\n if (args.length < 2) return null;\r\n\r\n const fields = parseFieldDefinitions(args[0]);\r\n const { tableName, indexes } = parseOptions(args[1]);\r\n if (!tableName) return null;\r\n\r\n // Derive className from file name\r\n const className = path.basename(filePath, '.ts');\r\n\r\n return { tableName, className, fields, indexes };\r\n}\r\n\r\nfunction findInitCall(sourceFile: SourceFile): CallExpression | null {\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() === SyntaxKind.PropertyAccessExpression) {\r\n const propAccess = expr.asKindOrThrow(SyntaxKind.PropertyAccessExpression);\r\n if (propAccess.getName() === 'init') return call;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction parseFieldDefinitions(fieldsNode: Node): FieldSchema[] {\r\n const fields: FieldSchema[] = [];\r\n if (fieldsNode.getKind() !== SyntaxKind.ObjectLiteralExpression) return fields;\r\n\r\n const objLiteral = fieldsNode as ObjectLiteralExpression;\r\n for (const prop of objLiteral.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const fieldName = propAssign.getName();\r\n const initializer = propAssign.getInitializer();\r\n if (!initializer || initializer.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\r\n\r\n fields.push(parseFieldObject(fieldName, initializer as ObjectLiteralExpression));\r\n }\r\n return fields;\r\n}\r\n\r\nfunction parseFieldObject(fieldName: string, fieldObj: ObjectLiteralExpression): FieldSchema {\r\n const field: FieldSchema = { name: fieldName, type: 'STRING', allowNull: true, primaryKey: false };\r\n\r\n for (const prop of fieldObj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const key = propAssign.getName();\r\n const init = propAssign.getInitializer();\r\n if (!init) continue;\r\n\r\n switch (key) {\r\n case 'type':\r\n field.type = extractDataType(init);\r\n break;\r\n case 'allowNull':\r\n field.allowNull = extractBooleanValue(init);\r\n break;\r\n case 'primaryKey':\r\n field.primaryKey = extractBooleanValue(init);\r\n break;\r\n case 'defaultValue':\r\n field.defaultValue = extractDefaultValue(init);\r\n break;\r\n case 'unique':\r\n field.unique = extractBooleanValue(init);\r\n break;\r\n case 'comment': {\r\n const text = init.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"'))) {\r\n field.comment = text.slice(1, -1);\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n return field;\r\n}\r\n\r\nfunction extractDataType(node: Node): string {\r\n const text = node.getText().trim();\r\n const callMatch = text.match(/^DataTypes\\.(\\w+)\\((.+)\\)$/);\r\n if (callMatch) return `${callMatch[1]}(${callMatch[2]})`;\r\n const propMatch = text.match(/^DataTypes\\.(\\w+)$/);\r\n if (propMatch) return propMatch[1];\r\n return text;\r\n}\r\n\r\nfunction extractBooleanValue(node: Node): boolean {\r\n return node.getText().trim() === 'true';\r\n}\r\n\r\nfunction extractDefaultValue(node: Node): unknown {\r\n const text = node.getText().trim();\r\n if (text === 'DataTypes.NOW') return 'DataTypes.NOW';\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"'))) {\r\n return text.slice(1, -1);\r\n }\r\n if (/^-?\\d+(\\.\\d+)?$/.test(text)) return Number(text);\r\n if (text === 'true') return true;\r\n if (text === 'false') return false;\r\n if (text === 'null') return null;\r\n return text;\r\n}\r\n\r\nfunction parseOptions(optionsNode: Node): { tableName: string | null; indexes: IndexSchema[] } {\r\n let tableName: string | null = null;\r\n let indexes: IndexSchema[] = [];\r\n\r\n if (optionsNode.getKind() !== SyntaxKind.ObjectLiteralExpression) return { tableName, indexes };\r\n\r\n const objLiteral = optionsNode as ObjectLiteralExpression;\r\n for (const prop of objLiteral.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const key = propAssign.getName();\r\n const init = propAssign.getInitializer();\r\n if (!init) continue;\r\n\r\n if (key === 'tableName') tableName = extractStringValue(init);\r\n else if (key === 'indexes') indexes = parseIndexes(init);\r\n }\r\n return { tableName, indexes };\r\n}\r\n\r\nfunction extractStringValue(node: Node): string | null {\r\n const text = node.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"'))) {\r\n return text.slice(1, -1);\r\n }\r\n return null;\r\n}\r\n\r\nfunction parseIndexes(node: Node): IndexSchema[] {\r\n const indexes: IndexSchema[] = [];\r\n if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return indexes;\r\n\r\n const arr = node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);\r\n for (const el of arr.getElements()) {\r\n if (el.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\r\n const idx = parseIndexObject(el as ObjectLiteralExpression);\r\n if (idx) indexes.push(idx);\r\n }\r\n return indexes;\r\n}\r\n\r\nfunction parseIndexObject(obj: ObjectLiteralExpression): IndexSchema | null {\r\n let name: string | undefined;\r\n let fields: string[] = [];\r\n let unique = false;\r\n\r\n for (const prop of obj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const key = propAssign.getName();\r\n const init = propAssign.getInitializer();\r\n if (!init) continue;\r\n\r\n if (key === 'name') name = extractStringValue(init) ?? undefined;\r\n else if (key === 'fields') fields = extractStringArray(init);\r\n else if (key === 'unique') unique = extractBooleanValue(init);\r\n }\r\n\r\n if (fields.length === 0) return null;\r\n return { name, fields, unique };\r\n}\r\n\r\nfunction extractStringArray(node: Node): string[] {\r\n if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return [];\r\n const arr = node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);\r\n const result: string[] = [];\r\n for (const el of arr.getElements()) {\r\n const text = el.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"'))) {\r\n result.push(text.slice(1, -1));\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n// ============================================================\r\n// Association Parsing\r\n// ============================================================\r\n\r\nfunction parseAssociationsFromFile(filePath: string): ForeignKeyRelation[] {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return [];\r\n\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n\r\n const seen = new Map<string, ForeignKeyRelation>();\r\n\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\r\n\r\n const propAccess = expr as PropertyAccessExpression;\r\n const methodName = propAccess.getName();\r\n if (!['hasMany', 'belongsTo', 'hasOne', 'belongsToMany'].includes(methodName)) continue;\r\n\r\n const sourceClass = propAccess.getExpression().getText().trim();\r\n const args = call.getArguments();\r\n if (args.length < 1) continue;\r\n\r\n const targetClass = args[0].getText().trim();\r\n let foreignKey = '';\r\n\r\n if (args.length >= 2 && args[1].getKind() === SyntaxKind.ObjectLiteralExpression) {\r\n foreignKey = extractObjStringProp(args[1] as ObjectLiteralExpression, 'foreignKey');\r\n }\r\n\r\n const relation: ForeignKeyRelation = {\r\n sourceTable: pascalToSnake(sourceClass),\r\n targetTable: pascalToSnake(targetClass),\r\n sourceField: methodName === 'belongsTo' ? foreignKey || 'id' : 'id',\r\n targetField: methodName === 'belongsTo' ? 'id' : foreignKey || 'id',\r\n cardinality: methodName === 'hasMany' ? '1:N' : methodName === 'belongsTo' ? 'N:1' : '1:1',\r\n };\r\n\r\n const key = `${relation.sourceTable}|${relation.targetTable}|${foreignKey}`;\r\n if (!seen.has(key)) seen.set(key, relation);\r\n }\r\n\r\n return Array.from(seen.values());\r\n}\r\n\r\nfunction extractObjStringProp(obj: ObjectLiteralExpression, propName: string): string {\r\n for (const prop of obj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const pa = prop as PropertyAssignment;\r\n if (pa.getName() !== propName) continue;\r\n const init = pa.getInitializer();\r\n if (!init) continue;\r\n const text = init.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"'))) {\r\n return text.slice(1, -1);\r\n }\r\n return text;\r\n }\r\n return '';\r\n}\r\n\r\nfunction pascalToSnake(name: string): string {\r\n return name.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\r\n}\r\n\r\n// ============================================================\r\n// Controller Parsing\r\n// ============================================================\r\n\r\nconst HTTP_METHODS = new Set(['get', 'post', 'put', 'delete', 'patch']);\r\n\r\nfunction parseControllersFromDir(controllerDir: string): RouteEntry[] {\r\n const absoluteDir = path.resolve(controllerDir);\r\n if (!fs.existsSync(absoluteDir)) return [];\r\n\r\n const stat = fs.statSync(absoluteDir);\r\n const files: string[] = [];\r\n\r\n if (stat.isDirectory()) {\r\n const entries = fs.readdirSync(absoluteDir);\r\n for (const entry of entries) {\r\n if (entry.endsWith('.ts') && !entry.endsWith('.test.ts') && !entry.endsWith('.spec.ts')) {\r\n files.push(path.join(absoluteDir, entry));\r\n }\r\n }\r\n } else if (stat.isFile()) {\r\n files.push(absoluteDir);\r\n }\r\n\r\n const allRoutes: RouteEntry[] = [];\r\n for (const file of files) {\r\n try {\r\n allRoutes.push(...parseControllerFile(file));\r\n } catch {\r\n // Skip files that fail to parse\r\n }\r\n }\r\n\r\n return deduplicateRoutes(allRoutes);\r\n}\r\n\r\nfunction parseControllerFile(filePath: string): RouteEntry[] {\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(filePath);\r\n const routes: RouteEntry[] = [];\r\n\r\n // Extract router.get/post/put/delete calls\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\r\n\r\n const propAccess = expr as PropertyAccessExpression;\r\n const methodName = propAccess.getName().toLowerCase();\r\n if (!HTTP_METHODS.has(methodName)) continue;\r\n\r\n const objectText = propAccess.getExpression().getText().trim();\r\n if (objectText !== 'router' && objectText !== 'this.router') continue;\r\n\r\n const args = call.getArguments();\r\n if (args.length === 0) continue;\r\n\r\n const routePath = resolveStringArg(args[0]);\r\n if (!routePath) continue;\r\n\r\n // Try to extract handler name from second argument\r\n let handler = '';\r\n if (args.length >= 2) {\r\n handler = args[1].getText().trim();\r\n }\r\n\r\n routes.push({\r\n method: methodName.toUpperCase(),\r\n path: routePath,\r\n handler,\r\n controllerClass: path.basename(filePath, '.ts'),\r\n });\r\n }\r\n\r\n // Check for BaseCrudController\r\n routes.push(...extractBaseCrudRoutes(sourceFile, filePath));\r\n\r\n return routes;\r\n}\r\n\r\nfunction extractBaseCrudRoutes(sourceFile: SourceFile, filePath: string): RouteEntry[] {\r\n const routes: RouteEntry[] = [];\r\n const classes = sourceFile.getClasses();\r\n let isBaseCrud = false;\r\n\r\n for (const cls of classes) {\r\n const heritage = cls.getExtends();\r\n if (heritage?.getText().includes('BaseCrudController')) {\r\n isBaseCrud = true;\r\n break;\r\n }\r\n }\r\n if (!isBaseCrud) return routes;\r\n\r\n // Find super.registerRoutes(router, 'resourcePath')\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n let resourcePath: string | null = null;\r\n\r\n for (const call of calls) {\r\n const exprText = call.getExpression().getText();\r\n if (\r\n (exprText === 'super.registerRoutes' || exprText.endsWith('.registerRoutes')) &&\r\n !exprText.includes('Custom')\r\n ) {\r\n const args = call.getArguments();\r\n if (args.length >= 2) resourcePath = resolveStringArg(args[1]);\r\n }\r\n }\r\n\r\n if (!resourcePath) return routes;\r\n const controllerClass = path.basename(filePath, '.ts');\r\n const basePath = `/v1/:tenantId/${resourcePath}`;\r\n\r\n const crudOps = [\r\n { method: 'GET', path: basePath, handler: 'list' },\r\n { method: 'GET', path: `${basePath}/:id`, handler: 'getById' },\r\n { method: 'POST', path: basePath, handler: 'create' },\r\n { method: 'PUT', path: `${basePath}/:id`, handler: 'update' },\r\n { method: 'DELETE', path: `${basePath}/:id`, handler: 'delete' },\r\n { method: 'POST', path: `${basePath}/batch-delete`, handler: 'batchDelete' },\r\n ];\r\n\r\n for (const op of crudOps) {\r\n routes.push({ method: op.method, path: op.path, handler: op.handler, controllerClass });\r\n }\r\n return routes;\r\n}\r\n\r\nfunction resolveStringArg(node: Node): string | null {\r\n const kind = node.getKind();\r\n if (kind === SyntaxKind.StringLiteral) {\r\n const text = node.getText();\r\n return text.slice(1, -1);\r\n }\r\n if (kind === SyntaxKind.NoSubstitutionTemplateLiteral) {\r\n const text = node.getText();\r\n return text.slice(1, -1);\r\n }\r\n if (kind === SyntaxKind.TemplateExpression) {\r\n // Best-effort resolve template literals\r\n const sourceFile = node.getSourceFile();\r\n let result = node.getText().slice(1, -1);\r\n result = result.replace(/\\$\\{([^}]+)\\}/g, (_match, expr: string) => {\r\n const resolved = resolveVariable(sourceFile, expr.trim());\r\n return resolved || `{${expr.trim()}}`;\r\n });\r\n return result;\r\n }\r\n if (kind === SyntaxKind.Identifier) {\r\n return resolveVariable(node.getSourceFile(), node.getText().trim());\r\n }\r\n return null;\r\n}\r\n\r\nfunction resolveVariable(sourceFile: SourceFile, varName: string): string | null {\r\n const varDecls = sourceFile.getDescendantsOfKind(SyntaxKind.VariableDeclaration);\r\n for (const decl of varDecls) {\r\n if (decl.getName() === varName) {\r\n const init = decl.getInitializer();\r\n if (!init) continue;\r\n const text = init.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"'))) {\r\n return text.slice(1, -1);\r\n }\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction deduplicateRoutes(routes: RouteEntry[]): RouteEntry[] {\r\n const seen = new Map<string, RouteEntry>();\r\n for (const r of routes) {\r\n const key = `${r.method}:${r.path}`;\r\n if (!seen.has(key)) seen.set(key, r);\r\n }\r\n return Array.from(seen.values());\r\n}\r\n","/**\r\n * LLM Provider Factory\r\n *\r\n * Creates the appropriate LLM provider based on config.\r\n */\r\n\r\nimport type { LlmProvider, LlmConfig } from '../types.js';\r\nimport { createOpenAIProvider } from './llm/openai-provider.js';\r\nimport { createZhipuProvider } from './llm/zhipu-provider.js';\r\nimport { createOllamaProvider } from './llm/ollama-provider.js';\r\n\r\nexport function createLlmProvider(config: LlmConfig): LlmProvider {\r\n switch (config.provider) {\r\n case 'openai':\r\n return createOpenAIProvider(config);\r\n case 'zhipu':\r\n return createZhipuProvider(config);\r\n case 'ollama':\r\n return createOllamaProvider(config);\r\n case 'custom':\r\n throw new Error('Custom LLM provider must be passed directly as a LlmProvider instance.');\r\n default:\r\n throw new Error(`Unknown LLM provider: ${config.provider}`);\r\n }\r\n}\r\n\r\nexport { createOpenAIProvider } from './llm/openai-provider.js';\r\nexport { createZhipuProvider } from './llm/zhipu-provider.js';\r\nexport { createOllamaProvider } from './llm/ollama-provider.js';\r\n","/**\r\n * OpenAI LLM Provider\r\n */\r\n\r\nimport type { LlmProvider, LlmConfig } from '../../types.js';\r\n\r\nexport function createOpenAIProvider(config: LlmConfig): LlmProvider {\r\n const baseUrl = config.baseUrl || 'https://api.openai.com/v1';\r\n const model = config.model || 'gpt-4o-mini';\r\n\r\n return {\r\n name: 'openai',\r\n\r\n async chat(messages) {\r\n const apiKey = config.apiKey || process.env.OPENCROC_LLM_API_KEY || process.env.OPENAI_API_KEY;\r\n if (!apiKey) throw new Error('OpenAI API key is required. Set llm.apiKey or OPENAI_API_KEY env var.');\r\n\r\n const response = await fetch(`${baseUrl}/chat/completions`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Authorization': `Bearer ${apiKey}`,\r\n },\r\n body: JSON.stringify({\r\n model,\r\n messages,\r\n max_tokens: config.maxTokens || 4096,\r\n temperature: config.temperature ?? 0.1,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const text = await response.text();\r\n throw new Error(`OpenAI API error ${response.status}: ${text}`);\r\n }\r\n\r\n const data = await response.json() as { choices: Array<{ message: { content: string } }> };\r\n return data.choices[0]?.message?.content || '';\r\n },\r\n\r\n estimateTokens(text) {\r\n // Rough approximation: ~4 chars per token for English, ~2 for CJK\r\n return Math.ceil(text.length / 3);\r\n },\r\n };\r\n}\r\n","/**\r\n * Zhipu (智谱) LLM Provider\r\n */\r\n\r\nimport type { LlmProvider, LlmConfig } from '../../types.js';\r\n\r\nexport function createZhipuProvider(config: LlmConfig): LlmProvider {\r\n const baseUrl = config.baseUrl || 'https://open.bigmodel.cn/api/paas/v4';\r\n const model = config.model || 'glm-4-flash';\r\n\r\n return {\r\n name: 'zhipu',\r\n\r\n async chat(messages) {\r\n const apiKey = config.apiKey || process.env.OPENCROC_LLM_API_KEY || process.env.ZHIPU_API_KEY;\r\n if (!apiKey) throw new Error('Zhipu API key is required. Set llm.apiKey or ZHIPU_API_KEY env var.');\r\n\r\n const response = await fetch(`${baseUrl}/chat/completions`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Authorization': `Bearer ${apiKey}`,\r\n },\r\n body: JSON.stringify({\r\n model,\r\n messages,\r\n max_tokens: config.maxTokens || 4096,\r\n temperature: config.temperature ?? 0.1,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const text = await response.text();\r\n throw new Error(`Zhipu API error ${response.status}: ${text}`);\r\n }\r\n\r\n const data = await response.json() as { choices: Array<{ message: { content: string } }> };\r\n return data.choices[0]?.message?.content || '';\r\n },\r\n\r\n estimateTokens(text) {\r\n // CJK-heavy: ~2 chars per token\r\n return Math.ceil(text.length / 2);\r\n },\r\n };\r\n}\r\n","/**\r\n * Ollama (Local) LLM Provider\r\n */\r\n\r\nimport type { LlmProvider, LlmConfig } from '../../types.js';\r\n\r\nexport function createOllamaProvider(config: LlmConfig): LlmProvider {\r\n const baseUrl = config.baseUrl || 'http://localhost:11434';\r\n const model = config.model || 'llama3.1';\r\n\r\n return {\r\n name: 'ollama',\r\n\r\n async chat(messages) {\r\n const response = await fetch(`${baseUrl}/api/chat`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n model,\r\n messages,\r\n stream: false,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const text = await response.text();\r\n throw new Error(`Ollama API error ${response.status}: ${text}`);\r\n }\r\n\r\n const data = await response.json() as { message?: { content: string } };\r\n return data.message?.content || '';\r\n },\r\n\r\n estimateTokens(text) {\r\n return Math.ceil(text.length / 4);\r\n },\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport type {\r\n OpenCrocConfig,\r\n PipelineRunResult,\r\n PipelineStep,\r\n ERDiagramResult,\r\n ChainPlanResult,\r\n} from '../types.js';\r\nimport { parseModuleModels } from '../parsers/model-parser.js';\r\nimport { parseControllerDirectory } from '../parsers/controller-parser.js';\r\nimport { parseAssociationFile } from '../parsers/association-parser.js';\r\nimport { createApiChainAnalyzer, topologicalSort } from '../analyzers/api-chain-analyzer.js';\r\nimport { createERDiagramGenerator } from '../generators/er-diagram-generator.js';\r\nimport { createTestCodeGenerator } from '../generators/test-code-generator.js';\r\nimport { validateConfig } from '../validators/config-validator.js';\r\n\r\nexport interface Pipeline {\r\n run(steps?: PipelineStep[]): Promise<PipelineRunResult>;\r\n}\r\n\r\nconst ALL_STEPS: PipelineStep[] = ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'];\r\n\r\nexport function createPipeline(config: OpenCrocConfig): Pipeline {\r\n return {\r\n async run(steps) {\r\n const startTime = Date.now();\r\n const activeSteps = steps || config.steps || ALL_STEPS;\r\n\r\n const result: PipelineRunResult = {\r\n modules: [],\r\n erDiagrams: new Map(),\r\n chainPlans: new Map(),\r\n generatedFiles: [],\r\n validationErrors: [],\r\n duration: 0,\r\n };\r\n\r\n const backendRoot = path.resolve(config.backendRoot);\r\n\r\n // Smart discovery: find models/ and controllers/ in common locations\r\n const findDir = (name: string): string | null => {\r\n const candidates = [\r\n path.join(backendRoot, name), // ./models\r\n path.join(backendRoot, 'src', name), // ./src/models\r\n path.join(backendRoot, 'backend', 'src', name), // ./backend/src/models\r\n path.join(backendRoot, 'backend', name), // ./backend/models\r\n path.join(backendRoot, 'server', 'src', name), // ./server/src/models\r\n path.join(backendRoot, 'app', name), // ./app/models\r\n ];\r\n for (const c of candidates) {\r\n if (fs.existsSync(c)) return c;\r\n }\r\n return null;\r\n };\r\n\r\n const modelsRoot = findDir('models');\r\n const controllersRoot = findDir('controllers');\r\n\r\n // Step 1: Scan — discover modules\r\n if (activeSteps.includes('scan')) {\r\n if (modelsRoot) {\r\n // Discover modules from subdirectories\r\n const dirs = fs.readdirSync(modelsRoot, { withFileTypes: true })\r\n .filter((d) => d.isDirectory())\r\n .map((d) => d.name);\r\n\r\n const moduleFilter = config.modules;\r\n for (const dir of dirs) {\r\n if (moduleFilter && !moduleFilter.includes(dir)) continue;\r\n result.modules.push(dir);\r\n }\r\n\r\n // If no subdirectories, treat root as single \"default\" module\r\n if (result.modules.length === 0) {\r\n result.modules.push('default');\r\n } else {\r\n // Also include root-level model files as \"default\" module\r\n const rootFiles = fs.readdirSync(modelsRoot)\r\n .filter((f) => f.endsWith('.ts') && !f.endsWith('.test.ts') && f !== 'index.ts');\r\n if (rootFiles.length > 0) {\r\n result.modules.unshift('default');\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Helper: resolve model dir for a module\r\n const resolveModelDir = (_backendRoot: string, mod: string): string =>\r\n mod === 'default'\r\n ? (modelsRoot || path.join(backendRoot, 'models'))\r\n : path.join(modelsRoot || path.join(backendRoot, 'models'), mod);\r\n\r\n // Helper: resolve controller dir for a module\r\n const resolveControllerDir = (_backendRoot: string, mod: string): string =>\r\n mod === 'default'\r\n ? (controllersRoot || path.join(backendRoot, 'controllers'))\r\n : path.join(controllersRoot || path.join(backendRoot, 'controllers'), mod);\r\n\r\n // Step 2: ER Diagram — parse models and generate relationship graphs\r\n if (activeSteps.includes('er-diagram')) {\r\n const erGen = createERDiagramGenerator();\r\n const backendRoot = path.resolve(config.backendRoot);\r\n\r\n for (const mod of result.modules) {\r\n const modelDir = resolveModelDir(backendRoot, mod);\r\n\r\n // For flat layouts, scan all model files for embedded associations\r\n const tables = fs.existsSync(modelDir) ? parseModuleModels(modelDir) : [];\r\n const relations: import('../types.js').ForeignKeyRelation[] = [];\r\n\r\n // Check for dedicated associations.ts first\r\n const assocFile = path.join(modelDir, 'associations.ts');\r\n if (fs.existsSync(assocFile)) {\r\n relations.push(...parseAssociationFile(assocFile));\r\n }\r\n\r\n // Also scan model files for embedded associations (belongsTo/hasMany at end of file)\r\n if (fs.existsSync(modelDir)) {\r\n const modelFiles = fs.readdirSync(modelDir)\r\n .filter((f) => f.endsWith('.ts') && !f.endsWith('.test.ts') && f !== 'index.ts' && f !== 'associations.ts');\r\n for (const file of modelFiles) {\r\n try {\r\n const embedded = parseAssociationFile(path.join(modelDir, file));\r\n relations.push(...embedded);\r\n } catch {\r\n // skip files that fail to parse\r\n }\r\n }\r\n }\r\n\r\n const erResult: ERDiagramResult = erGen.generate(tables, relations);\r\n result.erDiagrams.set(mod, erResult);\r\n }\r\n }\r\n\r\n // Step 3: API Chain — analyze controller routes and build dependency DAG\r\n if (activeSteps.includes('api-chain')) {\r\n const chainAnalyzer = createApiChainAnalyzer();\r\n const backendRoot = path.resolve(config.backendRoot);\r\n\r\n for (const mod of result.modules) {\r\n const controllerDir = resolveControllerDir(backendRoot, mod);\r\n const endpoints = fs.existsSync(controllerDir)\r\n ? parseControllerDirectory(controllerDir)\r\n : [];\r\n\r\n const analysis = chainAnalyzer.analyze(endpoints);\r\n analysis.moduleName = mod;\r\n\r\n if (analysis.hasCycles) {\r\n for (const warning of analysis.cycleWarnings) {\r\n result.validationErrors.push({\r\n module: mod,\r\n field: 'api-chain',\r\n message: warning,\r\n severity: 'warning',\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Step 4: Plan — generate test chains from dependency analysis\r\n if (activeSteps.includes('plan')) {\r\n const backendRoot = path.resolve(config.backendRoot);\r\n const chainAnalyzer = createApiChainAnalyzer();\r\n\r\n for (const mod of result.modules) {\r\n const controllerDir = resolveControllerDir(backendRoot, mod);\r\n const endpoints = fs.existsSync(controllerDir)\r\n ? parseControllerDirectory(controllerDir)\r\n : [];\r\n\r\n const analysis = chainAnalyzer.analyze(endpoints);\r\n const topoOrder = topologicalSort(analysis.dag);\r\n\r\n // Group by resource to create chains\r\n const chains = generateChainPlan(mod, endpoints, topoOrder);\r\n result.chainPlans.set(mod, chains);\r\n }\r\n }\r\n\r\n // Step 5: Codegen — emit Playwright test files from chain plans\r\n if (activeSteps.includes('codegen')) {\r\n const testGen = createTestCodeGenerator();\r\n const outDir = config.outDir || './opencroc-output';\r\n\r\n for (const [_mod, plan] of result.chainPlans) {\r\n const files = testGen.generate(plan.chains);\r\n for (const file of files) {\r\n file.filePath = path.join(outDir, file.filePath);\r\n }\r\n result.generatedFiles.push(...files);\r\n }\r\n }\r\n\r\n // Step 6: Validate — run validation on generated configs\r\n if (activeSteps.includes('validate')) {\r\n const configErrors = validateConfig(config as unknown as Record<string, unknown>);\r\n result.validationErrors.push(...configErrors);\r\n }\r\n\r\n result.duration = Date.now() - startTime;\r\n return result;\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Generate a basic chain plan from endpoints and topological order.\r\n */\r\nfunction generateChainPlan(\r\n moduleName: string,\r\n endpoints: import('../types.js').ApiEndpoint[],\r\n _topoOrder: string[],\r\n): ChainPlanResult {\r\n // Group endpoints by resource (first non-param path segment)\r\n const groups = new Map<string, import('../types.js').ApiEndpoint[]>();\r\n\r\n for (const ep of endpoints) {\r\n const segments = ep.path.split('/').filter((s) => s && !s.startsWith(':'));\r\n const resource = segments[segments.length - 1] || 'default';\r\n if (!groups.has(resource)) groups.set(resource, []);\r\n groups.get(resource)!.push(ep);\r\n }\r\n\r\n const chains: import('../types.js').TestChain[] = [];\r\n let totalSteps = 0;\r\n\r\n for (const [resource, eps] of groups) {\r\n const steps: import('../types.js').TestStep[] = eps.map((ep, i) => ({\r\n order: i + 1,\r\n action: ep.method,\r\n endpoint: ep,\r\n description: ep.description || `${ep.method} ${ep.path}`,\r\n assertions: [],\r\n }));\r\n\r\n chains.push({ name: `${resource} CRUD chain`, module: moduleName, steps });\r\n totalSteps += steps.length;\r\n }\r\n\r\n return { chains, totalSteps };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n type CallExpression,\r\n type ObjectLiteralExpression,\r\n type PropertyAssignment,\r\n type Node,\r\n} from 'ts-morph';\r\nimport type { TableSchema, FieldSchema, IndexSchema } from '../types.js';\r\n\r\nexport interface ModelParser {\r\n parseFile(filePath: string): Promise<TableSchema | null>;\r\n parseDirectory(dirPath: string): Promise<TableSchema[]>;\r\n}\r\n\r\n/**\r\n * Parse a single Sequelize Model file and extract TableSchema.\r\n */\r\nexport function parseModelFile(filePath: string): TableSchema | null {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return null;\r\n\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const initCall = findInitCall(sourceFile);\r\n if (!initCall) return null;\r\n\r\n const args = initCall.getArguments();\r\n if (args.length < 2) return null;\r\n\r\n const fields = parseFieldDefinitions(args[0]);\r\n const { tableName, indexes } = parseOptions(args[1]);\r\n\r\n if (!tableName) return null;\r\n\r\n return { tableName, fields, indexes };\r\n}\r\n\r\n/**\r\n * Batch parse all Model files in a directory.\r\n */\r\nexport function parseModuleModels(modelDir: string): TableSchema[] {\r\n const absoluteDir = path.resolve(modelDir);\r\n if (!fs.existsSync(absoluteDir)) return [];\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) =>\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts' &&\r\n f !== 'associations.ts',\r\n );\r\n\r\n const schemas: TableSchema[] = [];\r\n for (const file of files) {\r\n try {\r\n const schema = parseModelFile(path.join(absoluteDir, file));\r\n if (schema) schemas.push(schema);\r\n } catch {\r\n // skip unparseable files\r\n }\r\n }\r\n return schemas;\r\n}\r\n\r\nfunction findInitCall(sourceFile: Node): CallExpression | null {\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() === SyntaxKind.PropertyAccessExpression) {\r\n const propAccess = expr.asKindOrThrow(SyntaxKind.PropertyAccessExpression);\r\n if (propAccess.getName() === 'init') return call;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction parseFieldDefinitions(fieldsNode: Node): FieldSchema[] {\r\n const fields: FieldSchema[] = [];\r\n if (fieldsNode.getKind() !== SyntaxKind.ObjectLiteralExpression) return fields;\r\n\r\n const objLiteral = fieldsNode as ObjectLiteralExpression;\r\n for (const prop of objLiteral.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const initializer = propAssign.getInitializer();\r\n if (!initializer || initializer.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\r\n fields.push(parseFieldObject(propAssign.getName(), initializer as ObjectLiteralExpression));\r\n }\r\n return fields;\r\n}\r\n\r\nfunction parseFieldObject(fieldName: string, fieldObj: ObjectLiteralExpression): FieldSchema {\r\n const field: FieldSchema = { name: fieldName, type: 'STRING', allowNull: true, primaryKey: false };\r\n\r\n for (const prop of fieldObj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const key = propAssign.getName();\r\n const init = propAssign.getInitializer();\r\n if (!init) continue;\r\n\r\n switch (key) {\r\n case 'type': field.type = extractDataType(init); break;\r\n case 'allowNull': field.allowNull = init.getText().trim() === 'true'; break;\r\n case 'primaryKey': field.primaryKey = init.getText().trim() === 'true'; break;\r\n case 'defaultValue': field.defaultValue = extractDefaultValue(init); break;\r\n }\r\n }\r\n return field;\r\n}\r\n\r\nfunction extractDataType(node: Node): string {\r\n const text = node.getText().trim();\r\n const callMatch = text.match(/^DataTypes\\.(\\w+)\\((.+)\\)$/);\r\n if (callMatch) return `${callMatch[1]}(${callMatch[2]})`;\r\n const propMatch = text.match(/^DataTypes\\.(\\w+)$/);\r\n if (propMatch) return propMatch[1];\r\n return text;\r\n}\r\n\r\nfunction extractDefaultValue(node: Node): unknown {\r\n const text = node.getText().trim();\r\n if (text === 'DataTypes.NOW') return 'DataTypes.NOW';\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\r\n return text.slice(1, -1);\r\n if (/^-?\\d+(\\.\\d+)?$/.test(text)) return Number(text);\r\n if (text === 'true') return true;\r\n if (text === 'false') return false;\r\n if (text === 'null') return null;\r\n return text;\r\n}\r\n\r\nfunction parseOptions(optionsNode: Node): { tableName: string | null; indexes: IndexSchema[] } {\r\n let tableName: string | null = null;\r\n let indexes: IndexSchema[] = [];\r\n\r\n if (optionsNode.getKind() !== SyntaxKind.ObjectLiteralExpression) return { tableName, indexes };\r\n\r\n const objLiteral = optionsNode as ObjectLiteralExpression;\r\n for (const prop of objLiteral.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const key = propAssign.getName();\r\n const init = propAssign.getInitializer();\r\n if (!init) continue;\r\n\r\n if (key === 'tableName') tableName = extractStringValue(init);\r\n if (key === 'indexes') indexes = parseIndexes(init);\r\n }\r\n return { tableName, indexes };\r\n}\r\n\r\nfunction extractStringValue(node: Node): string | null {\r\n const text = node.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\r\n return text.slice(1, -1);\r\n return null;\r\n}\r\n\r\nfunction parseIndexes(node: Node): IndexSchema[] {\r\n if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return [];\r\n const arr = node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);\r\n const indexes: IndexSchema[] = [];\r\n for (const el of arr.getElements()) {\r\n if (el.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\r\n const idx = parseIndexObject(el as ObjectLiteralExpression);\r\n if (idx) indexes.push(idx);\r\n }\r\n return indexes;\r\n}\r\n\r\nfunction parseIndexObject(obj: ObjectLiteralExpression): IndexSchema | null {\r\n let name = '';\r\n let fields: string[] = [];\r\n let unique = false;\r\n\r\n for (const prop of obj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const pa = prop as PropertyAssignment;\r\n const init = pa.getInitializer();\r\n if (!init) continue;\r\n switch (pa.getName()) {\r\n case 'name': name = extractStringValue(init) || ''; break;\r\n case 'fields': fields = extractStringArray(init); break;\r\n case 'unique': unique = init.getText().trim() === 'true'; break;\r\n }\r\n }\r\n if (!name || fields.length === 0) return null;\r\n return { name, fields, unique };\r\n}\r\n\r\nfunction extractStringArray(node: Node): string[] {\r\n if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return [];\r\n const arr = node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);\r\n return arr.getElements()\r\n .map((el) => el.getText().trim())\r\n .filter((t) => (t.startsWith(\"'\") || t.startsWith('\"')))\r\n .map((t) => t.slice(1, -1));\r\n}\r\n\r\nexport function createModelParser(): ModelParser {\r\n return {\r\n async parseFile(filePath: string) {\r\n return parseModelFile(filePath);\r\n },\r\n async parseDirectory(dirPath: string) {\r\n return parseModuleModels(dirPath);\r\n },\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n type ObjectLiteralExpression,\r\n type PropertyAssignment,\r\n type SourceFile,\r\n} from 'ts-morph';\r\nimport type { ForeignKeyRelation } from '../types.js';\r\nimport { parseModelFile } from './model-parser.js';\r\n\r\nexport interface AssociationParser {\r\n parseFile(filePath: string): Promise<ForeignKeyRelation[]>;\r\n}\r\n\r\ninterface RawAssociation {\r\n sourceClass: string;\r\n targetClass: string;\r\n foreignKey: string;\r\n type: 'hasMany' | 'belongsTo' | 'hasOne';\r\n importPath?: string;\r\n}\r\n\r\n/**\r\n * Parse an associations.ts file to extract all foreign key relations.\r\n */\r\nexport function parseAssociationFile(\r\n filePath: string,\r\n classToTableMap?: Map<string, string>,\r\n moduleTablePrefix?: string,\r\n): ForeignKeyRelation[] {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return [];\r\n\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const importPathMap = collectImportPaths(sourceFile);\r\n const rawAssociations = extractAssociationCalls(sourceFile, importPathMap);\r\n if (rawAssociations.length === 0) return [];\r\n\r\n return deduplicateRelations(rawAssociations, classToTableMap, moduleTablePrefix);\r\n}\r\n\r\n/**\r\n * Build className → tableName map from Model files in a directory.\r\n */\r\nexport function buildClassToTableMap(modelDir: string): Map<string, string> {\r\n const map = new Map<string, string>();\r\n const absoluteDir = path.resolve(modelDir);\r\n if (!fs.existsSync(absoluteDir)) return map;\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) =>\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts' &&\r\n f !== 'associations.ts',\r\n );\r\n\r\n for (const file of files) {\r\n try {\r\n const schema = parseModelFile(path.join(absoluteDir, file));\r\n if (schema) {\r\n const className = file.replace('.ts', '');\r\n map.set(className, schema.tableName);\r\n }\r\n } catch {\r\n // skip\r\n }\r\n }\r\n return map;\r\n}\r\n\r\nfunction collectImportPaths(sourceFile: SourceFile): Map<string, string> {\r\n const map = new Map<string, string>();\r\n for (const decl of sourceFile.getImportDeclarations()) {\r\n const moduleSpecifier = decl.getModuleSpecifierValue();\r\n for (const named of decl.getNamedImports()) {\r\n map.set(named.getName(), moduleSpecifier);\r\n }\r\n }\r\n return map;\r\n}\r\n\r\nfunction extractAssociationCalls(\r\n sourceFile: SourceFile,\r\n importPathMap: Map<string, string>,\r\n): RawAssociation[] {\r\n const associations: RawAssociation[] = [];\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\r\n\r\n const propAccess = expr.asKindOrThrow(SyntaxKind.PropertyAccessExpression);\r\n const methodName = propAccess.getName();\r\n if (methodName !== 'hasMany' && methodName !== 'belongsTo' && methodName !== 'hasOne') continue;\r\n\r\n const sourceClass = propAccess.getExpression().getText().trim();\r\n const args = call.getArguments();\r\n if (args.length < 1) continue;\r\n\r\n const targetClass = args[0].getText().trim();\r\n let foreignKey = '';\r\n\r\n if (args.length >= 2 && args[1].getKind() === SyntaxKind.ObjectLiteralExpression) {\r\n foreignKey = extractStringProperty(args[1] as ObjectLiteralExpression, 'foreignKey');\r\n }\r\n\r\n associations.push({\r\n sourceClass,\r\n targetClass,\r\n foreignKey,\r\n type: methodName as RawAssociation['type'],\r\n importPath: importPathMap.get(targetClass),\r\n });\r\n }\r\n return associations;\r\n}\r\n\r\nfunction extractStringProperty(obj: ObjectLiteralExpression, propertyName: string): string {\r\n for (const prop of obj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const pa = prop as PropertyAssignment;\r\n if (pa.getName() !== propertyName) continue;\r\n const init = pa.getInitializer();\r\n if (!init) continue;\r\n const text = init.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\r\n return text.slice(1, -1);\r\n return text;\r\n }\r\n return '';\r\n}\r\n\r\nexport function classNameToTableName(className: string): string {\r\n return className.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\r\n}\r\n\r\nfunction resolveTableName(className: string, classToTableMap?: Map<string, string>): string {\r\n if (classToTableMap?.has(className)) return classToTableMap.get(className)!;\r\n return classNameToTableName(className);\r\n}\r\n\r\nfunction isCrossModuleRef(\r\n targetTableName: string,\r\n importPath: string | undefined,\r\n moduleTablePrefix?: string,\r\n): boolean {\r\n if (moduleTablePrefix) return !targetTableName.startsWith(moduleTablePrefix);\r\n if (importPath) {\r\n const upLevels = (importPath.match(/\\.\\.\\//g) || []).length;\r\n return upLevels >= 2;\r\n }\r\n return false;\r\n}\r\n\r\nfunction deduplicateRelations(\r\n rawAssociations: RawAssociation[],\r\n classToTableMap?: Map<string, string>,\r\n moduleTablePrefix?: string,\r\n): ForeignKeyRelation[] {\r\n const seen = new Map<string, ForeignKeyRelation>();\r\n\r\n for (const raw of rawAssociations) {\r\n const sourceTable = resolveTableName(raw.sourceClass, classToTableMap);\r\n const targetTable = resolveTableName(raw.targetClass, classToTableMap);\r\n const crossModule = isCrossModuleRef(targetTable, raw.importPath, moduleTablePrefix);\r\n\r\n let parentTable: string;\r\n let childTable: string;\r\n let cardinality: ForeignKeyRelation['cardinality'];\r\n\r\n switch (raw.type) {\r\n case 'hasMany':\r\n parentTable = sourceTable; childTable = targetTable; cardinality = '1:N'; break;\r\n case 'belongsTo':\r\n parentTable = targetTable; childTable = sourceTable; cardinality = 'N:1'; break;\r\n case 'hasOne':\r\n parentTable = sourceTable; childTable = targetTable; cardinality = '1:1'; break;\r\n }\r\n\r\n const dedupeKey = `${parentTable}|${childTable}|${raw.foreignKey}`;\r\n if (seen.has(dedupeKey)) {\r\n const existing = seen.get(dedupeKey)!;\r\n if (existing.cardinality === 'N:1' && (cardinality === '1:N' || cardinality === '1:1')) {\r\n seen.set(dedupeKey, {\r\n sourceTable: parentTable, sourceField: 'id',\r\n targetTable: childTable, targetField: raw.foreignKey,\r\n cardinality, isCrossModule: crossModule || existing.isCrossModule,\r\n });\r\n }\r\n } else {\r\n seen.set(dedupeKey, {\r\n sourceTable: parentTable, sourceField: 'id',\r\n targetTable: childTable, targetField: raw.foreignKey,\r\n cardinality, isCrossModule: crossModule,\r\n });\r\n }\r\n }\r\n return Array.from(seen.values());\r\n}\r\n\r\nexport function createAssociationParser(): AssociationParser {\r\n return {\r\n async parseFile(filePath: string) {\r\n return parseAssociationFile(filePath);\r\n },\r\n };\r\n}\r\n","import type {\r\n ApiEndpoint,\r\n ApiDependency,\r\n ApiChainAnalysisResult,\r\n DirectedAcyclicGraph,\r\n} from '../types.js';\r\n\r\nconst EXCLUDED_PARAMS = new Set(['tenantId']);\r\n\r\nconst enum Color { WHITE = 0, GRAY = 1, BLACK = 2 }\r\n\r\nfunction toNodeKey(endpoint: ApiEndpoint): string {\r\n return `${endpoint.method} ${endpoint.path}`;\r\n}\r\n\r\nfunction paramToResourceHint(param: string): string {\r\n const stripped = param.endsWith('Id') ? param.slice(0, -2) : param;\r\n return stripped.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');\r\n}\r\n\r\nfunction postProducesResource(postEndpoint: ApiEndpoint, resourceHint: string): boolean {\r\n const segments = postEndpoint.path.split('/').filter((s) => s && !s.startsWith(':'));\r\n if (segments.length === 0) return false;\r\n\r\n const lastSegment = segments[segments.length - 1].toLowerCase();\r\n if (lastSegment.includes(resourceHint)) return true;\r\n\r\n const parts = lastSegment.split('-');\r\n if (parts.some((p) => p === resourceHint || p.startsWith(resourceHint))) return true;\r\n\r\n if (resourceHint.length <= 4) {\r\n const abbreviation = parts.map((p) => p[0]).join('');\r\n if (abbreviation.startsWith(resourceHint)) return true;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Infer API dependencies via path parameter matching.\r\n * POST endpoints produce IDs; GET/PUT/DELETE endpoints consume them.\r\n */\r\nexport function inferDependencies(endpoints: ApiEndpoint[]): ApiDependency[] {\r\n const dependencies: ApiDependency[] = [];\r\n const postEndpoints = endpoints.filter((ep) => ep.method === 'POST');\r\n\r\n for (const consumer of endpoints) {\r\n const consumedParams = consumer.pathParams.filter((p) => !EXCLUDED_PARAMS.has(p));\r\n if (consumedParams.length === 0) continue;\r\n\r\n for (const param of consumedParams) {\r\n if (param === 'id') {\r\n const basePath = consumer.path.replace(/\\/:id(\\/.*)?$/, '');\r\n const producer = postEndpoints.find((ep) => ep.path === basePath);\r\n if (producer && toNodeKey(producer) !== toNodeKey(consumer)) {\r\n dependencies.push({ from: consumer, to: producer, paramMapping: { [`:${param}`]: 'response.data.id' } });\r\n }\r\n continue;\r\n }\r\n\r\n const resourceHint = paramToResourceHint(param);\r\n if (!resourceHint) continue;\r\n\r\n const producer = postEndpoints.find((ep) => postProducesResource(ep, resourceHint));\r\n if (producer && toNodeKey(producer) !== toNodeKey(consumer)) {\r\n dependencies.push({ from: consumer, to: producer, paramMapping: { [`:${param}`]: 'response.data.id' } });\r\n }\r\n }\r\n }\r\n return deduplicateDependencies(dependencies);\r\n}\r\n\r\nfunction deduplicateDependencies(deps: ApiDependency[]): ApiDependency[] {\r\n const map = new Map<string, ApiDependency>();\r\n for (const dep of deps) {\r\n const key = `${toNodeKey(dep.from)}→${toNodeKey(dep.to)}`;\r\n if (map.has(key)) {\r\n Object.assign(map.get(key)!.paramMapping, dep.paramMapping);\r\n } else {\r\n map.set(key, { ...dep, paramMapping: { ...dep.paramMapping } });\r\n }\r\n }\r\n return Array.from(map.values());\r\n}\r\n\r\n/**\r\n * Build a directed graph from endpoints and their dependencies.\r\n */\r\nexport function buildGraph(\r\n endpoints: ApiEndpoint[],\r\n dependencies: ApiDependency[],\r\n): DirectedAcyclicGraph {\r\n const nodeSet = new Set<string>();\r\n for (const ep of endpoints) nodeSet.add(toNodeKey(ep));\r\n\r\n const edges: Array<{ from: string; to: string; label?: string }> = [];\r\n for (const dep of dependencies) {\r\n edges.push({\r\n from: toNodeKey(dep.from),\r\n to: toNodeKey(dep.to),\r\n label: Object.keys(dep.paramMapping).join(', ') || undefined,\r\n });\r\n }\r\n return { nodes: Array.from(nodeSet), edges };\r\n}\r\n\r\n/**\r\n * Detect cycles in a directed graph using DFS coloring.\r\n */\r\nexport function detectCycles(dag: DirectedAcyclicGraph): string[] {\r\n const adjacency = new Map<string, string[]>();\r\n for (const node of dag.nodes) adjacency.set(node, []);\r\n for (const edge of dag.edges) adjacency.get(edge.from)?.push(edge.to);\r\n\r\n const color = new Map<string, Color>();\r\n for (const node of dag.nodes) color.set(node, Color.WHITE);\r\n\r\n const warnings: string[] = [];\r\n const path: string[] = [];\r\n\r\n function dfs(node: string): void {\r\n color.set(node, Color.GRAY);\r\n path.push(node);\r\n for (const neighbor of adjacency.get(node) || []) {\r\n const nc = color.get(neighbor);\r\n if (nc === Color.GRAY) {\r\n const cycleStart = path.indexOf(neighbor);\r\n warnings.push(`Cycle detected: ${path.slice(cycleStart).concat(neighbor).join(' → ')}`);\r\n } else if (nc === Color.WHITE) {\r\n dfs(neighbor);\r\n }\r\n }\r\n path.pop();\r\n color.set(node, Color.BLACK);\r\n }\r\n\r\n for (const node of dag.nodes) {\r\n if (color.get(node) === Color.WHITE) dfs(node);\r\n }\r\n return warnings;\r\n}\r\n\r\n/**\r\n * Topological sort using Kahn's algorithm.\r\n */\r\nexport function topologicalSort(dag: DirectedAcyclicGraph): string[] {\r\n const inDegree = new Map<string, number>();\r\n const adjacency = new Map<string, string[]>();\r\n\r\n for (const node of dag.nodes) { inDegree.set(node, 0); adjacency.set(node, []); }\r\n for (const edge of dag.edges) {\r\n adjacency.get(edge.from)?.push(edge.to);\r\n inDegree.set(edge.to, (inDegree.get(edge.to) || 0) + 1);\r\n }\r\n\r\n const queue: string[] = [];\r\n for (const [node, degree] of inDegree) {\r\n if (degree === 0) queue.push(node);\r\n }\r\n\r\n const sorted: string[] = [];\r\n while (queue.length > 0) {\r\n const node = queue.shift()!;\r\n sorted.push(node);\r\n for (const neighbor of adjacency.get(node) || []) {\r\n const nd = (inDegree.get(neighbor) || 1) - 1;\r\n inDegree.set(neighbor, nd);\r\n if (nd === 0) queue.push(neighbor);\r\n }\r\n }\r\n return sorted;\r\n}\r\n\r\nexport interface ApiChainAnalyzer {\r\n analyze(endpoints: ApiEndpoint[]): ApiChainAnalysisResult;\r\n}\r\n\r\n/**\r\n * Analyze API endpoints: infer dependencies, build DAG, detect cycles, topological sort.\r\n */\r\nexport function createApiChainAnalyzer(): ApiChainAnalyzer {\r\n return {\r\n analyze(endpoints: ApiEndpoint[]): ApiChainAnalysisResult {\r\n const dependencies = inferDependencies(endpoints);\r\n const dag = buildGraph(endpoints, dependencies);\r\n const cycleWarnings = detectCycles(dag);\r\n\r\n return {\r\n moduleName: '',\r\n endpoints,\r\n dependencies,\r\n dag,\r\n hasCycles: cycleWarnings.length > 0,\r\n cycleWarnings,\r\n };\r\n },\r\n };\r\n}\r\n","import type { ERDiagramResult, TableSchema, ForeignKeyRelation } from '../types.js';\r\n\r\nexport interface ERDiagramGenerator {\r\n generate(tables: TableSchema[], relations: ForeignKeyRelation[]): ERDiagramResult;\r\n}\r\n\r\n/**\r\n * Map field type string to a short Mermaid ER type label.\r\n */\r\nfunction toMermaidType(fieldType: string): string {\r\n const upper = fieldType.toUpperCase();\r\n if (upper.startsWith('STRING')) return 'string';\r\n if (upper === 'BIGINT' || upper === 'INTEGER') return 'bigint';\r\n if (upper === 'BOOLEAN') return 'boolean';\r\n if (upper.startsWith('DATE') || upper === 'NOW') return 'datetime';\r\n if (upper === 'JSON' || upper === 'JSONB') return 'json';\r\n if (upper === 'TEXT') return 'text';\r\n if (upper === 'FLOAT' || upper === 'DOUBLE' || upper === 'DECIMAL') return 'float';\r\n if (upper === 'UUID') return 'uuid';\r\n if (upper.startsWith('ENUM')) return 'enum';\r\n return 'string';\r\n}\r\n\r\n/**\r\n * Mermaid requires entity names without special characters.\r\n */\r\nfunction sanitizeEntityName(name: string): string {\r\n return name.replace(/[^a-zA-Z0-9_]/g, '_');\r\n}\r\n\r\n/**\r\n * Generate Mermaid ER diagram syntax from parsed schemas and relations.\r\n */\r\nfunction generateMermaidER(tables: TableSchema[], relations: ForeignKeyRelation[]): string {\r\n const lines: string[] = ['erDiagram'];\r\n\r\n // Entity blocks\r\n for (const table of tables) {\r\n const entityName = sanitizeEntityName(table.tableName);\r\n lines.push(` ${entityName} {`);\r\n for (const field of table.fields) {\r\n const mType = toMermaidType(field.type);\r\n const pk = field.primaryKey ? 'PK' : '';\r\n const comment = field.comment ? ` \"${field.comment}\"` : '';\r\n lines.push(` ${mType} ${field.name}${pk ? ' ' + pk : ''}${comment}`);\r\n }\r\n lines.push(' }');\r\n }\r\n\r\n // Relationships\r\n const tableNames = new Set(tables.map((t) => t.tableName));\r\n for (const rel of relations) {\r\n if (!tableNames.has(rel.sourceTable) || !tableNames.has(rel.targetTable)) continue;\r\n\r\n const src = sanitizeEntityName(rel.sourceTable);\r\n const tgt = sanitizeEntityName(rel.targetTable);\r\n const linkStyle = rel.isCrossModule ? '..' : '--';\r\n\r\n let cardinality: string;\r\n switch (rel.cardinality) {\r\n case '1:N': cardinality = `||${linkStyle}o{`; break;\r\n case 'N:1': cardinality = `}o${linkStyle}||`; break;\r\n case '1:1': cardinality = `||${linkStyle}||`; break;\r\n default: cardinality = `||${linkStyle}o{`;\r\n }\r\n\r\n lines.push(` ${src} ${cardinality} ${tgt} : \"${rel.targetField}\"`);\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\nexport function createERDiagramGenerator(): ERDiagramGenerator {\r\n return {\r\n generate(tables: TableSchema[], relations: ForeignKeyRelation[]): ERDiagramResult {\r\n const mermaidText = generateMermaidER(tables, relations);\r\n return { tables, relations, mermaidText };\r\n },\r\n };\r\n}\r\n","import type { GeneratedTestFile, TestChain, TestStep } from '../types.js';\r\n\r\nexport interface TestCodeGenerator {\r\n generate(chains: TestChain[]): GeneratedTestFile[];\r\n}\r\n\r\n/**\r\n * Resolve a path parameter from the available createdIds.\r\n */\r\nfunction resolvePathParam(param: string, ids: string[]): string {\r\n // Try direct match (e.g., 'kbId' → look for 'kbId' in ids)\r\n if (ids.includes(param)) return `createdIds['${param}']`;\r\n // Try with 'Id' suffix stripped\r\n const stripped = param.endsWith('Id') ? param.slice(0, -2) : param;\r\n if (ids.includes(stripped)) return `createdIds['${stripped}']`;\r\n // Generic id\r\n if (param === 'id') return `createdIds['id']`;\r\n return `createdIds['${param}'] || '1'`;\r\n}\r\n\r\n/**\r\n * Generate URL building code for a test step.\r\n */\r\nfunction buildUrlCode(step: TestStep): string {\r\n const pathParams = step.endpoint.pathParams;\r\n if (pathParams.length === 0) return `const url = '${step.endpoint.path}';`;\r\n\r\n let urlTemplate = step.endpoint.path;\r\n const replacements: string[] = [];\r\n for (const param of pathParams) {\r\n urlTemplate = urlTemplate.replace(`:${param}`, `\\${${resolvePathParam(param, pathParams)}}`);\r\n replacements.push(param);\r\n }\r\n return `const url = \\`${urlTemplate}\\`;`;\r\n}\r\n\r\n/**\r\n * Generate assertion code for a test step.\r\n */\r\nfunction generateAssertions(step: TestStep): string[] {\r\n const lines: string[] = [];\r\n if (step.assertions.length > 0) {\r\n for (const assertion of step.assertions) {\r\n lines.push(` expect(${assertion}).toBeTruthy();`);\r\n }\r\n } else {\r\n // Default assertions\r\n if (step.endpoint.method === 'POST') {\r\n lines.push(' expect(response.status()).toBeLessThan(400);');\r\n lines.push(' const body = await response.json();');\r\n lines.push(\" if (body.data?.id) createdIds['id'] = body.data.id;\");\r\n } else if (step.endpoint.method === 'GET') {\r\n lines.push(' expect(response.ok()).toBeTruthy();');\r\n } else if (step.endpoint.method === 'DELETE') {\r\n lines.push(' expect(response.status()).toBeLessThan(400);');\r\n } else {\r\n lines.push(' expect(response.status()).toBeLessThan(400);');\r\n }\r\n }\r\n return lines;\r\n}\r\n\r\n/**\r\n * Generate a single Playwright test file from a test chain.\r\n */\r\nfunction generateTestFile(chain: TestChain): string {\r\n const lines: string[] = [];\r\n\r\n lines.push(`import { test, expect } from '@playwright/test';`);\r\n lines.push('');\r\n lines.push(`test.describe('${chain.name}', () => {`);\r\n lines.push(\" const createdIds: Record<string, string> = {};\");\r\n lines.push('');\r\n\r\n for (const step of chain.steps) {\r\n lines.push(` test('Step ${step.order}: ${step.description}', async ({ request }) => {`);\r\n lines.push(` // ${step.action}: ${step.endpoint.method} ${step.endpoint.path}`);\r\n lines.push(` ${buildUrlCode(step)}`);\r\n lines.push('');\r\n\r\n if (step.endpoint.method === 'GET') {\r\n lines.push(' const response = await request.get(url);');\r\n } else if (step.endpoint.method === 'POST') {\r\n lines.push(' const response = await request.post(url, { data: {} });');\r\n } else if (step.endpoint.method === 'PUT') {\r\n lines.push(' const response = await request.put(url, { data: {} });');\r\n } else if (step.endpoint.method === 'DELETE') {\r\n lines.push(' const response = await request.delete(url);');\r\n } else if (step.endpoint.method === 'PATCH') {\r\n lines.push(' const response = await request.patch(url, { data: {} });');\r\n }\r\n\r\n lines.push('');\r\n lines.push(...generateAssertions(step));\r\n lines.push(' });');\r\n lines.push('');\r\n }\r\n\r\n lines.push('});');\r\n return lines.join('\\n');\r\n}\r\n\r\nexport function createTestCodeGenerator(): TestCodeGenerator {\r\n return {\r\n generate(chains: TestChain[]): GeneratedTestFile[] {\r\n return chains.map((chain) => ({\r\n filePath: `${chain.module}/${chain.name.replace(/\\s+/g, '-').toLowerCase()}.spec.ts`,\r\n content: generateTestFile(chain),\r\n module: chain.module,\r\n chain: chain.name,\r\n }));\r\n },\r\n };\r\n}\r\n","import type {\r\n ValidationError,\r\n ModuleTestConfig,\r\n ModuleConfigValidationContext,\r\n ModuleConfigValidationResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n} from '../types.js';\r\nimport { validateSchema } from './schema-validator.js';\r\nimport { validateSemantic } from './semantic-validator.js';\r\nimport { validateDryrun } from './dryrun-validator.js';\r\n\r\nconst REQUIRED_FIELDS = ['backendRoot'];\r\n\r\nconst VALID_ADAPTERS = ['sequelize', 'typeorm', 'prisma', 'drizzle'];\r\nconst VALID_STEPS = ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'];\r\nconst VALID_LLM_PROVIDERS = ['openai', 'zhipu', 'ollama', 'custom'];\r\nconst VALID_REPORT_FORMATS = ['html', 'json', 'markdown'];\r\nconst VALID_HEAL_MODES = ['config-only', 'config-and-source'];\r\n\r\n/**\r\n * Validate an OpenCroc configuration object.\r\n * Returns an array of ValidationErrors (empty = valid).\r\n */\r\nexport function validateConfig(config: Record<string, unknown>): ValidationError[] {\r\n const errors: ValidationError[] = [];\r\n\r\n // Required fields\r\n for (const field of REQUIRED_FIELDS) {\r\n if (!config[field]) {\r\n errors.push({\r\n module: 'config',\r\n field,\r\n message: `Missing required field: ${field}`,\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n\r\n // backendRoot must be a string\r\n if (config.backendRoot && typeof config.backendRoot !== 'string') {\r\n errors.push({\r\n module: 'config',\r\n field: 'backendRoot',\r\n message: 'backendRoot must be a string path',\r\n severity: 'error',\r\n });\r\n }\r\n\r\n // adapter validation\r\n if (config.adapter && typeof config.adapter === 'string') {\r\n if (!VALID_ADAPTERS.includes(config.adapter)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'adapter',\r\n message: `Invalid adapter: ${config.adapter}. Must be one of: ${VALID_ADAPTERS.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n\r\n // steps validation\r\n if (config.steps && Array.isArray(config.steps)) {\r\n for (const step of config.steps) {\r\n if (!VALID_STEPS.includes(step as string)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'steps',\r\n message: `Invalid pipeline step: ${step}. Must be one of: ${VALID_STEPS.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n }\r\n\r\n // LLM config validation\r\n if (config.llm && typeof config.llm === 'object') {\r\n const llm = config.llm as Record<string, unknown>;\r\n if (llm.provider && !VALID_LLM_PROVIDERS.includes(llm.provider as string)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'llm.provider',\r\n message: `Invalid LLM provider: ${llm.provider}. Must be one of: ${VALID_LLM_PROVIDERS.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n if (llm.provider && llm.provider !== 'ollama' && !llm.apiKey) {\r\n errors.push({\r\n module: 'config',\r\n field: 'llm.apiKey',\r\n message: 'LLM apiKey is required for cloud providers',\r\n severity: 'warning',\r\n });\r\n }\r\n }\r\n\r\n // Report config validation\r\n if (config.report && typeof config.report === 'object') {\r\n const report = config.report as Record<string, unknown>;\r\n if (report.format && Array.isArray(report.format)) {\r\n for (const fmt of report.format) {\r\n if (!VALID_REPORT_FORMATS.includes(fmt as string)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'report.format',\r\n message: `Invalid report format: ${fmt}. Must be one of: ${VALID_REPORT_FORMATS.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Self-healing config validation\r\n if (config.selfHealing && typeof config.selfHealing === 'object') {\r\n const sh = config.selfHealing as Record<string, unknown>;\r\n if (sh.mode && !VALID_HEAL_MODES.includes(sh.mode as string)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'selfHealing.mode',\r\n message: `Invalid self-healing mode: ${sh.mode}. Must be one of: ${VALID_HEAL_MODES.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n if (sh.maxIterations && (typeof sh.maxIterations !== 'number' || sh.maxIterations < 1)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'selfHealing.maxIterations',\r\n message: 'maxIterations must be a positive number',\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n\r\n // Execution hooks validation\r\n if (config.execution && typeof config.execution === 'object') {\r\n const execution = config.execution as Record<string, unknown>;\r\n const hookFields = ['setupHook', 'authHook', 'teardownHook'];\r\n\r\n for (const hookField of hookFields) {\r\n const hook = execution[hookField];\r\n if (hook === undefined) continue;\r\n\r\n if (typeof hook === 'string') continue;\r\n\r\n if (typeof hook !== 'object' || hook === null) {\r\n errors.push({\r\n module: 'config',\r\n field: `execution.${hookField}`,\r\n message: `${hookField} must be a string command or an object { command, args?, cwd? }`,\r\n severity: 'error',\r\n });\r\n continue;\r\n }\r\n\r\n const hookObj = hook as Record<string, unknown>;\r\n if (typeof hookObj.command !== 'string' || hookObj.command.trim() === '') {\r\n errors.push({\r\n module: 'config',\r\n field: `execution.${hookField}.command`,\r\n message: 'command is required and must be a non-empty string',\r\n severity: 'error',\r\n });\r\n }\r\n\r\n if (hookObj.args !== undefined && (!Array.isArray(hookObj.args) || hookObj.args.some((a) => typeof a !== 'string'))) {\r\n errors.push({\r\n module: 'config',\r\n field: `execution.${hookField}.args`,\r\n message: 'args must be an array of strings',\r\n severity: 'error',\r\n });\r\n }\r\n\r\n if (hookObj.cwd !== undefined && typeof hookObj.cwd !== 'string') {\r\n errors.push({\r\n module: 'config',\r\n field: `execution.${hookField}.cwd`,\r\n message: 'cwd must be a string path',\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n }\r\n\r\n return errors;\r\n}\r\n\r\n// ============================================================\r\n// Three-Layer Module Config Validator\r\n// ============================================================\r\n\r\nexport interface ValidateModuleConfigOptions {\r\n stopOnFailure?: boolean;\r\n skipLayers?: Array<'schema' | 'semantic' | 'dryrun'>;\r\n}\r\n\r\nexport function validateModuleConfig(\r\n config: unknown,\r\n context?: ModuleConfigValidationContext,\r\n options?: ValidateModuleConfigOptions,\r\n): ModuleConfigValidationResult {\r\n const stopOnFailure = options?.stopOnFailure ?? true;\r\n const skipLayers = new Set(options?.skipLayers ?? []);\r\n\r\n const allErrors: ModuleConfigValidationError[] = [];\r\n const allWarnings: ModuleConfigValidationWarning[] = [];\r\n const result: ModuleConfigValidationResult = {\r\n passed: false,\r\n errors: allErrors,\r\n warnings: allWarnings,\r\n };\r\n\r\n if (!skipLayers.has('schema')) {\r\n const schemaResult = validateSchema(config);\r\n result.schemaResult = schemaResult;\r\n allErrors.push(...schemaResult.errors);\r\n allWarnings.push(...schemaResult.warnings);\r\n\r\n if (!schemaResult.passed) {\r\n result.failedAtLayer = 'schema';\r\n if (stopOnFailure) return result;\r\n } else {\r\n result.lastPassedLayer = 'schema';\r\n }\r\n }\r\n\r\n const validConfig = config as ModuleTestConfig;\r\n\r\n if (!skipLayers.has('semantic')) {\r\n if (!context) {\r\n allWarnings.push({ layer: 'semantic', path: '', message: 'ValidationContext not provided, skipping semantic validation' });\r\n } else {\r\n const semanticResult = validateSemantic(validConfig, context);\r\n result.semanticResult = semanticResult;\r\n allErrors.push(...semanticResult.errors);\r\n allWarnings.push(...semanticResult.warnings);\r\n\r\n if (!semanticResult.passed) {\r\n result.failedAtLayer = result.failedAtLayer || 'semantic';\r\n if (stopOnFailure) return result;\r\n } else {\r\n result.lastPassedLayer = 'semantic';\r\n }\r\n }\r\n }\r\n\r\n if (!skipLayers.has('dryrun')) {\r\n if (!context) {\r\n allWarnings.push({ layer: 'dryrun', path: '', message: 'ValidationContext not provided, skipping dry-run validation' });\r\n } else {\r\n const dryrunResult = validateDryrun(validConfig, context);\r\n result.dryrunResult = dryrunResult;\r\n allErrors.push(...dryrunResult.errors);\r\n allWarnings.push(...dryrunResult.warnings);\r\n\r\n if (!dryrunResult.passed) {\r\n result.failedAtLayer = result.failedAtLayer || 'dryrun';\r\n } else {\r\n result.lastPassedLayer = 'dryrun';\r\n }\r\n }\r\n }\r\n\r\n result.passed = allErrors.length === 0;\r\n return result;\r\n}\r\n\r\nexport function formatValidationResult(result: ModuleConfigValidationResult): string {\r\n const lines: string[] = [];\r\n lines.push(result.passed ? '\\u2705 Validation PASSED' : '\\u274c Validation FAILED');\r\n if (result.failedAtLayer) lines.push(` Failed at layer: ${result.failedAtLayer}`);\r\n if (result.lastPassedLayer) lines.push(` Last passed layer: ${result.lastPassedLayer}`);\r\n\r\n if (result.errors.length > 0) {\r\n lines.push('', `Errors (${result.errors.length}):`);\r\n for (const err of result.errors) {\r\n lines.push(` [${err.layer}] ${err.path}: ${err.message}`);\r\n if (err.suggestion) lines.push(` \\ud83d\\udca1 ${err.suggestion}`);\r\n }\r\n }\r\n\r\n if (result.warnings.length > 0) {\r\n lines.push('', `Warnings (${result.warnings.length}):`);\r\n for (const warn of result.warnings) {\r\n lines.push(` [${warn.layer}] ${warn.path}: ${warn.message}`);\r\n }\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n","/**\r\n * Schema Validator — Layer 1 of three-layer module config validation.\r\n * Checks structural integrity, field types, format conventions.\r\n */\r\n\r\nimport type {\r\n LayerValidationResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n} from '../types.js';\r\n\r\nconst VALID_HTTP_METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'] as const;\r\n\r\nexport function validateSchema(config: unknown): LayerValidationResult {\r\n const errors: ModuleConfigValidationError[] = [];\r\n const warnings: ModuleConfigValidationWarning[] = [];\r\n\r\n if (config === null || config === undefined || typeof config !== 'object') {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: '', message: 'Config must be a non-null object' });\r\n return { passed: false, layer: 'schema', errors, warnings };\r\n }\r\n\r\n const cfg = config as Record<string, unknown>;\r\n\r\n // Required top-level fields\r\n const required: Array<{ name: string; type: string }> = [\r\n { name: 'moduleName', type: 'string' },\r\n { name: 'version', type: 'string' },\r\n { name: 'generatedAt', type: 'string' },\r\n { name: 'bodyTemplates', type: 'object' },\r\n { name: 'paramRewrites', type: 'object' },\r\n { name: 'idAliases', type: 'array' },\r\n { name: 'seed', type: 'array' },\r\n ];\r\n\r\n for (const f of required) {\r\n if (cfg[f.name] === undefined || cfg[f.name] === null) {\r\n errors.push({\r\n layer: 'schema', type: 'missing-field', path: f.name,\r\n message: `Required field '${f.name}' is missing`,\r\n suggestion: `Add '${f.name}' field of type ${f.type}`,\r\n });\r\n }\r\n }\r\n\r\n // Field type checks\r\n validateFieldTypes(cfg, errors);\r\n\r\n // bodyTemplates structure\r\n if (cfg.bodyTemplates && typeof cfg.bodyTemplates === 'object' && !Array.isArray(cfg.bodyTemplates)) {\r\n validateBodyTemplates(cfg.bodyTemplates as Record<string, unknown>, errors, warnings);\r\n }\r\n\r\n // paramRewrites structure\r\n if (cfg.paramRewrites && typeof cfg.paramRewrites === 'object' && !Array.isArray(cfg.paramRewrites)) {\r\n validateParamRewrites(cfg.paramRewrites as Record<string, unknown>, errors, warnings);\r\n }\r\n\r\n // idAliases structure\r\n if (Array.isArray(cfg.idAliases)) {\r\n validateIdAliases(cfg.idAliases, errors);\r\n }\r\n\r\n // seed array\r\n if (Array.isArray(cfg.seed)) {\r\n validateSeedArray(cfg.seed, errors, warnings);\r\n }\r\n\r\n // version format\r\n if (typeof cfg.version === 'string' && !/^\\d+\\.\\d+(\\.\\d+)?$/.test(cfg.version)) {\r\n warnings.push({ layer: 'schema', path: 'version', message: `Version '${cfg.version}' does not follow semver format` });\r\n }\r\n\r\n return { passed: errors.length === 0, layer: 'schema', errors, warnings };\r\n}\r\n\r\nfunction validateFieldTypes(cfg: Record<string, unknown>, errors: ModuleConfigValidationError[]): void {\r\n if (cfg.moduleName !== undefined && typeof cfg.moduleName !== 'string') {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'moduleName', message: `'moduleName' must be a string` });\r\n } else if (typeof cfg.moduleName === 'string' && cfg.moduleName.trim() === '') {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: 'moduleName', message: \"'moduleName' must not be empty\" });\r\n }\r\n\r\n if (cfg.bodyTemplates !== undefined && (typeof cfg.bodyTemplates !== 'object' || Array.isArray(cfg.bodyTemplates))) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'bodyTemplates', message: \"'bodyTemplates' must be a plain object\" });\r\n }\r\n if (cfg.paramRewrites !== undefined && (typeof cfg.paramRewrites !== 'object' || Array.isArray(cfg.paramRewrites))) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'paramRewrites', message: \"'paramRewrites' must be a plain object\" });\r\n }\r\n if (cfg.idAliases !== undefined && !Array.isArray(cfg.idAliases)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'idAliases', message: \"'idAliases' must be an array\" });\r\n }\r\n if (cfg.seed !== undefined && !Array.isArray(cfg.seed)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'seed', message: \"'seed' must be an array\" });\r\n }\r\n}\r\n\r\nfunction validateBodyTemplates(\r\n templates: Record<string, unknown>,\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (const [key, value] of Object.entries(templates)) {\r\n const p = `bodyTemplates.${key}`;\r\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: p, message: `Body template '${key}' must be a plain object` });\r\n continue;\r\n }\r\n if (!/^(GET|POST|PUT|PATCH|DELETE)\\s+\\//.test(key)) {\r\n warnings.push({ layer: 'schema', path: p, message: `Body template key '${key}' should follow format 'METHOD /path'` });\r\n }\r\n if (Object.keys(value).length === 0) {\r\n warnings.push({ layer: 'schema', path: p, message: `Body template '${key}' is empty` });\r\n }\r\n }\r\n}\r\n\r\nfunction validateParamRewrites(\r\n rewrites: Record<string, unknown>,\r\n errors: ModuleConfigValidationError[],\r\n _warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (const [key, value] of Object.entries(rewrites)) {\r\n const p = `paramRewrites.${key}`;\r\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: p, message: `Param rewrite '${key}' must be a plain object` });\r\n continue;\r\n }\r\n for (const [paramName, paramValue] of Object.entries(value as Record<string, unknown>)) {\r\n if (typeof paramValue !== 'string') {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: `${p}.${paramName}`, message: `Param rewrite value for '${paramName}' must be a string` });\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction validateIdAliases(aliases: unknown[], errors: ModuleConfigValidationError[]): void {\r\n for (let i = 0; i < aliases.length; i++) {\r\n const alias = aliases[i] as Record<string, unknown> | null;\r\n const p = `idAliases[${i}]`;\r\n if (typeof alias !== 'object' || alias === null) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: p, message: `idAlias at index ${i} must be an object` });\r\n continue;\r\n }\r\n if (typeof alias.pathPattern !== 'string') {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.pathPattern`, message: `idAlias at index ${i} must have a string 'pathPattern'` });\r\n }\r\n if (typeof alias.alias !== 'string') {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.alias`, message: `idAlias at index ${i} must have a string 'alias'` });\r\n }\r\n }\r\n}\r\n\r\nfunction validateSeedArray(\r\n seed: unknown[],\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n if (seed.length === 0) {\r\n warnings.push({ layer: 'schema', path: 'seed', message: 'Seed array is empty, no setup steps will be executed' });\r\n return;\r\n }\r\n\r\n const capturedVars = new Set<string>();\r\n const stepNumbers = new Set<number>();\r\n\r\n for (let i = 0; i < seed.length; i++) {\r\n const step = seed[i] as Record<string, unknown> | null;\r\n const p = `seed[${i}]`;\r\n if (typeof step !== 'object' || step === null) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: p, message: `Seed step at index ${i} must be an object` });\r\n continue;\r\n }\r\n\r\n // step number\r\n if (step.step === undefined) {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.step`, message: `Seed step at index ${i} is missing 'step' number` });\r\n } else if (typeof step.step !== 'number' || !Number.isInteger(step.step)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: `${p}.step`, message: `'step' must be an integer` });\r\n } else {\r\n if (stepNumbers.has(step.step)) {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: `${p}.step`, message: `Duplicate step number ${step.step}` });\r\n }\r\n stepNumbers.add(step.step);\r\n }\r\n\r\n // method\r\n if (step.method === undefined) {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.method`, message: `Seed step at index ${i} is missing 'method'` });\r\n } else if (typeof step.method !== 'string' || !(VALID_HTTP_METHODS as readonly string[]).includes(step.method)) {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: `${p}.method`, message: `'method' must be one of ${VALID_HTTP_METHODS.join(', ')}` });\r\n }\r\n\r\n // path\r\n if (step.path === undefined) {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.path`, message: `Seed step at index ${i} is missing 'path'` });\r\n } else if (typeof step.path !== 'string' || !(step.path as string).startsWith('/')) {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: `${p}.path`, message: `'path' must start with '/'` });\r\n }\r\n\r\n // required\r\n if (step.required === undefined) {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.required`, message: `Seed step at index ${i} is missing 'required'` });\r\n }\r\n\r\n // body\r\n if (step.body !== undefined && (typeof step.body !== 'object' || step.body === null || Array.isArray(step.body))) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: `${p}.body`, message: `'body' must be a plain object` });\r\n } else if (step.body === undefined && typeof step.method === 'string' && ['POST', 'PUT', 'PATCH'].includes(step.method)) {\r\n warnings.push({ layer: 'schema', path: `${p}.body`, message: `${step.method} step at index ${i} has no body template` });\r\n }\r\n\r\n // captureAs uniqueness\r\n if (typeof step.captureAs === 'string') {\r\n if (capturedVars.has(step.captureAs)) {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: `${p}.captureAs`, message: `Duplicate captureAs variable '${step.captureAs}'` });\r\n }\r\n capturedVars.add(step.captureAs);\r\n }\r\n\r\n // dependsOn reference check\r\n if (Array.isArray(step.dependsOn)) {\r\n for (const dep of step.dependsOn) {\r\n if (typeof dep === 'string' && !capturedVars.has(dep)) {\r\n errors.push({\r\n layer: 'schema', type: 'dependency-missing', path: `${p}.dependsOn`,\r\n message: `Seed step ${step.step ?? i} depends on '${dep}' not captured by any preceding step`,\r\n suggestion: `Ensure a preceding step has captureAs: '${dep}'`,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * Semantic Validator — Layer 2 of three-layer module config validation.\r\n * Checks that config matches actual source code (routes, DTO fields, dependencies).\r\n */\r\n\r\nimport type {\r\n ModuleTestConfig,\r\n SeedStep,\r\n ApiEndpoint,\r\n DTOInfo,\r\n ModuleConfigValidationContext,\r\n LayerValidationResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n} from '../types.js';\r\n\r\nexport function validateSemantic(\r\n config: ModuleTestConfig,\r\n context: ModuleConfigValidationContext,\r\n): LayerValidationResult {\r\n const errors: ModuleConfigValidationError[] = [];\r\n const warnings: ModuleConfigValidationWarning[] = [];\r\n\r\n validateBodyTemplatesSemantic(config, context, errors, warnings);\r\n validateParamRewritesSemantic(config, context, errors, warnings);\r\n validateIdAliasesSemantic(config, context, warnings);\r\n validateSeedRoutesSemantic(config, context, errors);\r\n validateSeedDependenciesSemantic(config, errors, warnings);\r\n\r\n return { passed: errors.length === 0, layer: 'semantic', errors, warnings };\r\n}\r\n\r\n// ============================================================\r\n// Helpers\r\n// ============================================================\r\n\r\nfunction normalizePath(p: string): string {\r\n return p.replace(/\\/+$/, '').replace(/\\/+/g, '/');\r\n}\r\n\r\nfunction extractPathParams(routePath: string): string[] {\r\n const params: string[] = [];\r\n const regex = /:(\\w+)/g;\r\n let match;\r\n while ((match = regex.exec(routePath)) !== null) params.push(match[1]);\r\n return params;\r\n}\r\n\r\nfunction findMatchingEndpoint(\r\n method: string, configPath: string, endpoints: ApiEndpoint[],\r\n): ApiEndpoint | undefined {\r\n const normalized = normalizePath(configPath);\r\n return endpoints.find((ep) => {\r\n if (ep.method !== method.toUpperCase()) return false;\r\n const epNorm = normalizePath(ep.path);\r\n if (epNorm === normalized) return true;\r\n const cSegs = normalized.split('/');\r\n const eSegs = epNorm.split('/');\r\n if (cSegs.length !== eSegs.length) return false;\r\n return cSegs.every((seg, idx) => seg === eSegs[idx] || seg.startsWith(':') || eSegs[idx].startsWith(':'));\r\n });\r\n}\r\n\r\nfunction findMatchingDTO(method: string, dtos: DTOInfo[]): DTOInfo | undefined {\r\n if (dtos.length === 0) return undefined;\r\n if (['POST'].includes(method)) return dtos.find((d) => /Create|Input|Request/.test(d.name));\r\n if (['PUT', 'PATCH'].includes(method)) return dtos.find((d) => /Update/.test(d.name)) || dtos.find((d) => /Create|Input/.test(d.name));\r\n if (['GET'].includes(method)) return dtos.find((d) => /Query|List|Params/.test(d.name));\r\n return undefined;\r\n}\r\n\r\n// ============================================================\r\n// Validators\r\n// ============================================================\r\n\r\nfunction validateBodyTemplatesSemantic(\r\n config: ModuleTestConfig,\r\n ctx: ModuleConfigValidationContext,\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (const [key, body] of Object.entries(config.bodyTemplates)) {\r\n const p = `bodyTemplates.${key}`;\r\n const spaceIdx = key.indexOf(' ');\r\n if (spaceIdx === -1) continue;\r\n\r\n const method = key.substring(0, spaceIdx).toUpperCase();\r\n const routePath = key.substring(spaceIdx + 1);\r\n\r\n const endpoint = findMatchingEndpoint(method, routePath, ctx.endpoints);\r\n if (!endpoint) {\r\n errors.push({\r\n layer: 'semantic', type: 'interface-not-found', path: p,\r\n message: `Route '${method} ${routePath}' in bodyTemplates does not match any parsed API endpoint`,\r\n suggestion: `Check that the controller defines ${method} ${routePath}`,\r\n });\r\n continue;\r\n }\r\n\r\n const bodyFields = Object.keys(body);\r\n if (bodyFields.length === 0) continue;\r\n\r\n const dto = findMatchingDTO(method, ctx.dtos);\r\n if (!dto) {\r\n warnings.push({ layer: 'semantic', path: p, message: `No matching DTO found for '${method} ${routePath}', cannot verify field completeness` });\r\n continue;\r\n }\r\n\r\n const dtoFieldNames = new Set(dto.fields.map((f) => f.name));\r\n for (const fieldName of bodyFields) {\r\n if (!dtoFieldNames.has(fieldName)) {\r\n warnings.push({ layer: 'semantic', path: `${p}.${fieldName}`, message: `Field '${fieldName}' in body template not found in DTO '${dto.name}'` });\r\n }\r\n }\r\n\r\n const bodyFieldSet = new Set(bodyFields);\r\n for (const field of dto.fields) {\r\n if (field.required && !field.isSystemField && !bodyFieldSet.has(field.name)) {\r\n warnings.push({ layer: 'semantic', path: p, message: `Required DTO field '${field.name}' (from ${dto.name}) not present in body template` });\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction validateParamRewritesSemantic(\r\n config: ModuleTestConfig,\r\n ctx: ModuleConfigValidationContext,\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (const [key, mapping] of Object.entries(config.paramRewrites)) {\r\n const p = `paramRewrites.${key}`;\r\n const spaceIdx = key.indexOf(' ');\r\n if (spaceIdx === -1) continue;\r\n\r\n const method = key.substring(0, spaceIdx).toUpperCase();\r\n const routePath = key.substring(spaceIdx + 1);\r\n\r\n const endpoint = findMatchingEndpoint(method, routePath, ctx.endpoints);\r\n if (!endpoint) {\r\n errors.push({ layer: 'semantic', type: 'param-mapping-invalid', path: p, message: `Route '${method} ${routePath}' in paramRewrites does not match any parsed API endpoint` });\r\n continue;\r\n }\r\n\r\n const actualParams = new Set(extractPathParams(endpoint.path));\r\n for (const paramName of Object.keys(mapping)) {\r\n if (!actualParams.has(paramName)) {\r\n warnings.push({ layer: 'semantic', path: `${p}.${paramName}`, message: `Param '${paramName}' in paramRewrites not found in route path params [${[...actualParams].join(', ')}]` });\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction validateIdAliasesSemantic(\r\n config: ModuleTestConfig,\r\n ctx: ModuleConfigValidationContext,\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (let i = 0; i < config.idAliases.length; i++) {\r\n const alias = config.idAliases[i];\r\n const matched = ctx.endpoints.some((ep) => {\r\n try { return new RegExp(alias.pathPattern).test(ep.path); } catch { return ep.path.includes(alias.pathPattern); }\r\n });\r\n if (!matched) {\r\n warnings.push({ layer: 'semantic', path: `idAliases[${i}].pathPattern`, message: `idAlias pathPattern '${alias.pathPattern}' does not match any known API route` });\r\n }\r\n }\r\n}\r\n\r\nfunction validateSeedRoutesSemantic(\r\n config: ModuleTestConfig,\r\n ctx: ModuleConfigValidationContext,\r\n errors: ModuleConfigValidationError[],\r\n): void {\r\n for (let i = 0; i < config.seed.length; i++) {\r\n const step = config.seed[i];\r\n const endpoint = findMatchingEndpoint(step.method, step.path, ctx.endpoints);\r\n if (!endpoint) {\r\n errors.push({\r\n layer: 'semantic', type: 'interface-not-found', path: `seed[${i}].path`,\r\n message: `Seed step ${step.step}: route '${step.method} ${step.path}' does not match any parsed API endpoint`,\r\n suggestion: `Verify that '${step.method} ${step.path}' exists in the module controllers`,\r\n });\r\n }\r\n }\r\n}\r\n\r\nfunction validateSeedDependenciesSemantic(\r\n config: ModuleTestConfig,\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n if (config.seed.length === 0) return;\r\n\r\n const capturedSet = new Set<string>();\r\n const variablePattern = /\\{\\{(\\w+)\\}\\}|\\$\\{(\\w+)\\}/g;\r\n\r\n for (let i = 0; i < config.seed.length; i++) {\r\n const step = config.seed[i];\r\n\r\n // Check body variable references\r\n if (step.body) {\r\n const bodyStr = JSON.stringify(step.body);\r\n variablePattern.lastIndex = 0;\r\n let match;\r\n while ((match = variablePattern.exec(bodyStr)) !== null) {\r\n const varName = match[1] || match[2];\r\n if (!capturedSet.has(varName)) {\r\n warnings.push({ layer: 'semantic', path: `seed[${i}].body`, message: `Body references variable '${varName}' which may not be captured by a preceding seed step` });\r\n }\r\n }\r\n }\r\n\r\n // Check path variable references\r\n if (step.path) {\r\n variablePattern.lastIndex = 0;\r\n let match;\r\n while ((match = variablePattern.exec(step.path)) !== null) {\r\n const varName = match[1] || match[2];\r\n if (!capturedSet.has(varName)) {\r\n warnings.push({ layer: 'semantic', path: `seed[${i}].path`, message: `Path references variable '${varName}' which may not be captured by a preceding seed step` });\r\n }\r\n }\r\n }\r\n\r\n if (step.captureAs) capturedSet.add(step.captureAs);\r\n }\r\n\r\n // Cycle detection via DFS\r\n detectDependencyCycle(config.seed, errors);\r\n}\r\n\r\nfunction detectDependencyCycle(seed: SeedStep[], errors: ModuleConfigValidationError[]): void {\r\n const graph = new Map<string, string[]>();\r\n for (const step of seed) {\r\n if (step.captureAs) {\r\n graph.set(step.captureAs, step.dependsOn || []);\r\n }\r\n }\r\n\r\n const visited = new Set<string>();\r\n const inStack = new Set<string>();\r\n\r\n function dfs(node: string): boolean {\r\n if (inStack.has(node)) return true;\r\n if (visited.has(node)) return false;\r\n visited.add(node);\r\n inStack.add(node);\r\n for (const neighbor of graph.get(node) || []) {\r\n if (dfs(neighbor)) {\r\n errors.push({ layer: 'semantic', type: 'dependency-cycle', path: 'seed', message: `Circular dependency detected involving '${node}' → '${neighbor}'` });\r\n return true;\r\n }\r\n }\r\n inStack.delete(node);\r\n return false;\r\n }\r\n\r\n for (const node of graph.keys()) {\r\n if (!visited.has(node)) dfs(node);\r\n }\r\n}\r\n","/**\r\n * Dry-run Validator — Layer 3 of three-layer module config validation.\r\n * Generates temporary TypeScript code from config and runs ts-morph compile check.\r\n */\r\n\r\nimport { Project, DiagnosticCategory } from 'ts-morph';\r\nimport type {\r\n ModuleTestConfig,\r\n ModuleConfigValidationContext,\r\n LayerValidationResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n} from '../types.js';\r\n\r\nexport function validateDryrun(\r\n config: ModuleTestConfig,\r\n _context: ModuleConfigValidationContext,\r\n): LayerValidationResult {\r\n const errors: ModuleConfigValidationError[] = [];\r\n const warnings: ModuleConfigValidationWarning[] = [];\r\n\r\n const project = new Project({\r\n compilerOptions: {\r\n strict: false,\r\n noEmit: true,\r\n target: 2, // ES2015\r\n module: 1, // CommonJS\r\n esModuleInterop: true,\r\n skipLibCheck: true,\r\n },\r\n useInMemoryFileSystem: true,\r\n });\r\n\r\n // Add helper type declarations\r\n project.createSourceFile(\r\n '__helpers.d.ts',\r\n `\r\ndeclare function apiRequest(\r\n method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH',\r\n path: string,\r\n body?: Record<string, any>,\r\n params?: Record<string, string>\r\n): Promise<{ status: number; data: any }>;\r\ndeclare function captureId(response: { data: any }, field?: string): string;\r\ndeclare const tenantId: string;\r\ndeclare const captured: Record<string, string>;\r\n`,\r\n );\r\n\r\n // Generate and check bodyTemplates test code\r\n const bodyCode = generateBodyTemplateTestCode(config);\r\n if (bodyCode) {\r\n const bodyFile = project.createSourceFile('__dryrun_body_test.ts', bodyCode);\r\n for (const diag of bodyFile.getPreEmitDiagnostics()) {\r\n const msg = diag.getMessageText();\r\n const msgStr = typeof msg === 'string' ? msg : msg.getMessageText();\r\n const line = diag.getLineNumber();\r\n const location = line ? `bodyTemplates (line ${line})` : 'bodyTemplates';\r\n\r\n if (diag.getCategory() === DiagnosticCategory.Error) {\r\n errors.push({\r\n layer: 'dryrun', type: 'compile-error', path: location,\r\n message: `TypeScript compile error: ${msgStr}`,\r\n suggestion: 'Fix the body template that causes this type error',\r\n });\r\n } else if (diag.getCategory() === DiagnosticCategory.Warning) {\r\n warnings.push({ layer: 'dryrun', path: location, message: `TypeScript warning: ${msgStr}` });\r\n }\r\n }\r\n }\r\n\r\n // Generate and check seed test code\r\n const seedCode = generateSeedTestCode(config);\r\n if (seedCode) {\r\n const seedFile = project.createSourceFile('__dryrun_seed_test.ts', seedCode);\r\n for (const diag of seedFile.getPreEmitDiagnostics()) {\r\n const msg = diag.getMessageText();\r\n const msgStr = typeof msg === 'string' ? msg : msg.getMessageText();\r\n const line = diag.getLineNumber();\r\n const location = line ? `seed (line ${line})` : 'seed';\r\n\r\n if (diag.getCategory() === DiagnosticCategory.Error) {\r\n errors.push({\r\n layer: 'dryrun', type: 'compile-error', path: location,\r\n message: `TypeScript compile error: ${msgStr}`,\r\n suggestion: 'Fix the seed step that causes this type error',\r\n });\r\n } else if (diag.getCategory() === DiagnosticCategory.Warning) {\r\n warnings.push({ layer: 'dryrun', path: location, message: `TypeScript warning: ${msgStr}` });\r\n }\r\n }\r\n }\r\n\r\n return { passed: errors.length === 0, layer: 'dryrun', errors, warnings };\r\n}\r\n\r\nfunction generateBodyTemplateTestCode(config: ModuleTestConfig): string | null {\r\n if (!config.bodyTemplates || Object.keys(config.bodyTemplates).length === 0) return null;\r\n\r\n const lines = ['async function testBodyTemplates() {'];\r\n let idx = 0;\r\n for (const [key, body] of Object.entries(config.bodyTemplates)) {\r\n const spaceIdx = key.indexOf(' ');\r\n if (spaceIdx === -1) continue;\r\n const method = key.substring(0, spaceIdx);\r\n const routePath = key.substring(spaceIdx + 1);\r\n\r\n lines.push(` const body_${idx} = ${JSON.stringify(body, null, 2)};`);\r\n lines.push(` const result_${idx} = await apiRequest('${method}', '${routePath}', body_${idx});`);\r\n lines.push(` if (result_${idx}.status !== 200 && result_${idx}.status !== 201) {`);\r\n lines.push(` throw new Error('Unexpected status: ' + result_${idx}.status);`);\r\n lines.push(' }');\r\n idx++;\r\n }\r\n lines.push('}');\r\n return lines.join('\\n');\r\n}\r\n\r\nfunction generateSeedTestCode(config: ModuleTestConfig): string | null {\r\n if (!config.seed || config.seed.length === 0) return null;\r\n\r\n const lines = [\r\n 'async function testSeedSteps() {',\r\n ' const captured: Record<string, string> = {};',\r\n '',\r\n ];\r\n\r\n for (const step of config.seed) {\r\n if (step.body) {\r\n lines.push(` const body_step${step.step} = ${JSON.stringify(step.body, null, 2)};`);\r\n lines.push(` const result_step${step.step} = await apiRequest('${step.method}', '${step.path}', body_step${step.step});`);\r\n } else {\r\n lines.push(` const result_step${step.step} = await apiRequest('${step.method}', '${step.path}');`);\r\n }\r\n\r\n if (step.captureAs) {\r\n lines.push(` captured['${step.captureAs}'] = captureId(result_step${step.step});`);\r\n }\r\n\r\n if (step.required) {\r\n lines.push(` if (result_step${step.step}.status >= 400) {`);\r\n lines.push(` throw new Error('${step.failureMessage || `Required step ${step.step} failed`}');`);\r\n lines.push(' }');\r\n }\r\n lines.push('');\r\n }\r\n\r\n lines.push('}');\r\n return lines.join('\\n');\r\n}\r\n","/**\r\n * DTO / TypeScript Interface Parser\r\n *\r\n * Uses ts-morph to parse TypeScript interfaces from Service and Model files,\r\n * extracting field info (name, type, required, enum values) and\r\n * express-validator rules from Controller files.\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n type InterfaceDeclaration,\r\n type PropertySignature,\r\n type SourceFile,\r\n type Node,\r\n type PropertyAccessExpression,\r\n} from 'ts-morph';\r\nimport type { DTOInfo, DTOFieldInfo, ValidatorRule, ModuleMetadata } from '../types.js';\r\n\r\n// ============================================================\r\n// System fields (auto-generated, not user-editable)\r\n// ============================================================\r\n\r\nconst SYSTEM_FIELDS = new Set([\r\n 'id', 'tenant_id', 'tenantId',\r\n 'created_at', 'createdAt', 'updated_at', 'updatedAt',\r\n 'created_by', 'createdBy', 'updated_by', 'updatedBy',\r\n]);\r\n\r\n// ============================================================\r\n// Core exports\r\n// ============================================================\r\n\r\n/**\r\n * Parse DTOs (TypeScript interfaces) from Service and Model files.\r\n *\r\n * @param filePaths Files to scan (Service / Model .ts files)\r\n * @param options.dtoNamePatterns Regex patterns to match DTO interface names\r\n */\r\nexport function parseDTOs(\r\n filePaths: string[],\r\n options?: { dtoNamePatterns?: RegExp[] },\r\n): DTOInfo[] {\r\n const patterns = options?.dtoNamePatterns ?? [\r\n /DTO$/i, /Query$/i, /Params$/i, /Attributes$/i, /Input$/i, /Request$/i,\r\n ];\r\n\r\n const allDTOs: DTOInfo[] = [];\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n\r\n for (const filePath of filePaths) {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) continue;\r\n\r\n try {\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n const interfaces = sourceFile.getInterfaces();\r\n\r\n for (const iface of interfaces) {\r\n const name = iface.getName();\r\n const matchesPattern = patterns.some((p) => p.test(name));\r\n if (!matchesPattern) continue;\r\n\r\n const dto = parseInterfaceToDTO(iface, absolutePath);\r\n if (dto) allDTOs.push(dto);\r\n }\r\n } catch (err) {\r\n console.warn(`[dto-parser] Failed to parse ${filePath}:`, (err as Error).message);\r\n }\r\n }\r\n\r\n return deduplicateDTOs(allDTOs);\r\n}\r\n\r\n/**\r\n * Parse express-validator rules from Controller files.\r\n *\r\n * Scans router.get/post/put/delete calls for middleware arrays containing\r\n * body('field').notEmpty(), param('field').isInt(), etc.\r\n *\r\n * @returns Map<routeKey, ValidatorRule[]> routeKey = \"METHOD /path\"\r\n */\r\nexport function parseValidatorRules(\r\n controllerPaths: string[],\r\n): Map<string, ValidatorRule[]> {\r\n const result = new Map<string, ValidatorRule[]>();\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n\r\n for (const filePath of controllerPaths) {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) continue;\r\n\r\n try {\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n const routeRules = extractValidatorRulesFromSource(sourceFile);\r\n\r\n for (const [routeKey, rules] of routeRules) {\r\n result.set(routeKey, rules);\r\n }\r\n } catch (err) {\r\n console.warn(`[dto-parser] Failed to parse validators in ${filePath}:`, (err as Error).message);\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Scan a module comprehensively, returning enhanced ModuleMetadata.\r\n */\r\nexport function scanModuleMetadata(\r\n moduleName: string,\r\n servicePaths: string[],\r\n controllerPaths: string[],\r\n modelDir?: string,\r\n): ModuleMetadata {\r\n const allFilePaths = [...servicePaths];\r\n\r\n if (modelDir) {\r\n const absoluteModelDir = path.resolve(modelDir);\r\n if (fs.existsSync(absoluteModelDir)) {\r\n const modelFiles = fs\r\n .readdirSync(absoluteModelDir)\r\n .filter((f) =>\r\n f.endsWith('.ts') && !f.endsWith('.test.ts') && f !== 'index.ts' && f !== 'associations.ts',\r\n )\r\n .map((f) => path.join(absoluteModelDir, f));\r\n allFilePaths.push(...modelFiles);\r\n }\r\n }\r\n\r\n const dtos = parseDTOs(allFilePaths);\r\n const validatorRules = parseValidatorRules(controllerPaths);\r\n\r\n return { moduleName, dtos, validatorRules, timestamp: new Date().toISOString() };\r\n}\r\n\r\n// ============================================================\r\n// Interface parsing internals\r\n// ============================================================\r\n\r\nfunction parseInterfaceToDTO(iface: InterfaceDeclaration, sourcePath: string): DTOInfo | null {\r\n const fields: DTOFieldInfo[] = [];\r\n\r\n const extendsClause = iface.getExtends();\r\n const extendsName = extendsClause.length > 0 ? extendsClause[0].getText() : undefined;\r\n\r\n for (const prop of iface.getProperties()) {\r\n const field = parsePropertyToField(prop);\r\n if (field) fields.push(field);\r\n }\r\n\r\n if (fields.length === 0) return null;\r\n\r\n return { name: iface.getName(), sourcePath, fields, extends: extendsName };\r\n}\r\n\r\nfunction parsePropertyToField(prop: PropertySignature): DTOFieldInfo | null {\r\n const name = prop.getName();\r\n const typeNode = prop.getTypeNode();\r\n if (!typeNode) return null;\r\n\r\n const { baseType, enumValues } = resolveType(typeNode.getText().trim());\r\n\r\n return {\r\n name,\r\n type: baseType,\r\n required: !prop.hasQuestionToken(),\r\n enumValues: enumValues.length > 0 ? enumValues : undefined,\r\n isSystemField: SYSTEM_FIELDS.has(name),\r\n };\r\n}\r\n\r\nfunction resolveType(typeText: string): { baseType: string; enumValues: string[] } {\r\n const cleaned = typeText.split('|').map((t) => t.trim()).filter((t) => t !== 'null' && t !== 'undefined');\r\n\r\n // String literal union: 'TEXT' | 'IMAGE'\r\n const stringLiterals = cleaned.filter((t) => /^['\"].*['\"]$/.test(t));\r\n if (stringLiterals.length > 0 && stringLiterals.length === cleaned.length) {\r\n return { baseType: 'string', enumValues: stringLiterals.map((t) => t.replace(/^['\"]|['\"]$/g, '')) };\r\n }\r\n\r\n // Number literal union: 0 | 1 | 2\r\n const numberLiterals = cleaned.filter((t) => /^\\d+$/.test(t));\r\n if (numberLiterals.length > 0 && numberLiterals.length === cleaned.length) {\r\n return { baseType: 'number', enumValues: numberLiterals };\r\n }\r\n\r\n if (cleaned.length === 1) return { baseType: cleaned[0], enumValues: [] };\r\n return { baseType: cleaned[0] || typeText, enumValues: [] };\r\n}\r\n\r\n// ============================================================\r\n// express-validator rule extraction\r\n// ============================================================\r\n\r\nfunction extractValidatorRulesFromSource(sourceFile: SourceFile): Map<string, ValidatorRule[]> {\r\n const result = new Map<string, ValidatorRule[]>();\r\n const HTTP_METHODS = new Set(['get', 'post', 'put', 'delete', 'patch']);\r\n const METHOD_MAP: Record<string, string> = { get: 'GET', post: 'POST', put: 'PUT', delete: 'DELETE', patch: 'PATCH' };\r\n\r\n const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n\r\n for (const call of callExpressions) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\r\n\r\n const propAccess = expr as PropertyAccessExpression;\r\n const methodName = propAccess.getName().toLowerCase();\r\n if (!HTTP_METHODS.has(methodName)) continue;\r\n\r\n const objectText = propAccess.getExpression().getText().trim();\r\n if (objectText !== 'router' && objectText !== 'this.router') continue;\r\n\r\n const args = call.getArguments();\r\n if (args.length < 2) continue;\r\n\r\n const routePath = resolveArgText(args[0]);\r\n if (!routePath) continue;\r\n\r\n const validatorRules: ValidatorRule[] = [];\r\n for (let i = 1; i < args.length; i++) {\r\n const arg = args[i];\r\n if (arg.getKind() === SyntaxKind.ArrayLiteralExpression) {\r\n const elements = arg.asKindOrThrow(SyntaxKind.ArrayLiteralExpression).getElements();\r\n for (const element of elements) {\r\n const rule = parseValidatorChain(element);\r\n if (rule) validatorRules.push(rule);\r\n }\r\n }\r\n }\r\n\r\n if (validatorRules.length > 0) {\r\n result.set(`${METHOD_MAP[methodName]} ${routePath}`, validatorRules);\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction parseValidatorChain(node: Node): ValidatorRule | null {\r\n const text = node.getText().trim();\r\n\r\n const sourceMatch = text.match(/^(body|param|query)\\(\\s*['\"](\\w+)['\"]\\s*\\)/);\r\n if (!sourceMatch) return null;\r\n\r\n const source = sourceMatch[1] as 'body' | 'param' | 'query';\r\n const field = sourceMatch[2];\r\n const rules: string[] = [];\r\n\r\n const chainRegex = /\\.(\\w+)\\(([^)]*)\\)/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = chainRegex.exec(text)) !== null) {\r\n const method = match[1];\r\n const args = match[2].trim();\r\n if (method === 'withMessage' || method === 'bail') continue;\r\n\r\n if (method === 'isIn') {\r\n const valuesMatch = args.match(/\\[([^\\]]+)\\]/);\r\n if (valuesMatch) {\r\n const values = valuesMatch[1].split(',').map((v) => v.trim().replace(/^['\"]|['\"]$/g, ''));\r\n rules.push(`isIn(${values.join(',')})`);\r\n }\r\n } else if (method === 'optional') {\r\n rules.push('optional');\r\n } else {\r\n rules.push(method);\r\n }\r\n }\r\n\r\n return { field, source, rules };\r\n}\r\n\r\nfunction resolveArgText(node: Node): string | null {\r\n const text = node.getText().trim();\r\n\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"'))) {\r\n return text.slice(1, -1);\r\n }\r\n\r\n if (text.startsWith('`') && text.endsWith('`')) {\r\n return text.slice(1, -1).replace(/\\$\\{[^}]+\\}/g, (m) => m);\r\n }\r\n\r\n return null;\r\n}\r\n\r\n// ============================================================\r\n// Helpers\r\n// ============================================================\r\n\r\nfunction deduplicateDTOs(dtos: DTOInfo[]): DTOInfo[] {\r\n const seen = new Map<string, DTOInfo>();\r\n for (const dto of dtos) {\r\n if (!seen.has(dto.name)) seen.set(dto.name, dto);\r\n }\r\n return Array.from(seen.values());\r\n}\r\n","import type { TableSchema } from '../types.js';\r\n\r\nexport interface MockDataGenerator {\r\n generateForTable(schema: TableSchema): Record<string, unknown>;\r\n generateForTables(schemas: TableSchema[]): Map<string, Record<string, unknown>[]>;\r\n}\r\n\r\nfunction randomInt(min: number, max: number): number {\r\n return Math.floor(Math.random() * (max - min + 1)) + min;\r\n}\r\n\r\nfunction randomString(prefix: string, fieldName: string): string {\r\n const ts = Date.now().toString(36);\r\n const rand = Math.random().toString(36).slice(2, 6);\r\n return `${prefix}${fieldName}_${ts}_${rand}`;\r\n}\r\n\r\nfunction generateUUID(): string {\r\n const hex = () => Math.random().toString(16).slice(2, 6);\r\n return `${hex()}${hex()}-${hex()}-4${hex().slice(1)}-${(8 + randomInt(0, 3)).toString(16)}${hex().slice(1)}-${hex()}${hex()}${hex()}`;\r\n}\r\n\r\n/**\r\n * Generate a mock value based on field type and constraints.\r\n */\r\nfunction generateFieldValue(\r\n fieldName: string,\r\n fieldType: string,\r\n isForeignKey: boolean,\r\n parentTable?: string,\r\n): unknown {\r\n const upper = fieldType.toUpperCase();\r\n\r\n if (isForeignKey && parentTable) {\r\n return `{{parentRecordIds.${parentTable}}}`;\r\n }\r\n\r\n if (upper.startsWith('STRING') || upper === 'TEXT') return randomString('test_', fieldName);\r\n if (upper === 'BIGINT' || upper === 'INTEGER') return randomInt(1, 999999);\r\n if (upper === 'BOOLEAN') return true;\r\n if (upper.startsWith('DATE') || upper === 'NOW') return new Date().toISOString();\r\n if (upper === 'UUID') return generateUUID();\r\n if (upper.startsWith('ENUM')) return 'ACTIVE';\r\n if (upper === 'JSON' || upper === 'JSONB') return {};\r\n if (upper === 'FLOAT' || upper === 'DOUBLE' || upper === 'DECIMAL') return Math.round(Math.random() * 10000) / 100;\r\n\r\n return randomString('val_', fieldName);\r\n}\r\n\r\nexport function createMockDataGenerator(): MockDataGenerator {\r\n return {\r\n generateForTable(schema: TableSchema): Record<string, unknown> {\r\n const record: Record<string, unknown> = {};\r\n const ts = Date.now().toString(36);\r\n const rand = Math.random().toString(36).slice(2, 6);\r\n\r\n for (const field of schema.fields) {\r\n // Skip auto-generated primary keys\r\n if (field.primaryKey) continue;\r\n // Skip fields with default values\r\n if (field.defaultValue !== undefined) continue;\r\n\r\n // Detect foreign key fields (ending with _id)\r\n const isForeignKey = field.name.endsWith('_id') && !field.primaryKey;\r\n const parentTable = isForeignKey\r\n ? field.name.replace(/_id$/, '')\r\n : undefined;\r\n\r\n let value = generateFieldValue(field.name, field.type, isForeignKey, parentTable);\r\n\r\n // Unique constraint: append suffix\r\n if (field.unique && typeof value === 'string') {\r\n value = `${value}__e2e_test_${ts}_${rand}`;\r\n }\r\n\r\n record[field.name] = value;\r\n }\r\n return record;\r\n },\r\n\r\n generateForTables(schemas: TableSchema[]): Map<string, Record<string, unknown>[]> {\r\n const result = new Map<string, Record<string, unknown>[]>();\r\n for (const schema of schemas) {\r\n const record = this.generateForTable(schema);\r\n result.set(schema.tableName, [record]);\r\n }\r\n return result;\r\n },\r\n };\r\n}\r\n","import type {\r\n ChainFailureResult,\r\n ERDiagramResult,\r\n ApiChainAnalysisResult,\r\n ApiEndpoint,\r\n ForeignKeyRelation,\r\n ImpactReport,\r\n} from '../types.js';\r\n\r\nconst MAX_BFS_DEPTH = 5;\r\n\r\n/**\r\n * Extract table names from an error chain path string.\r\n * Path format: \"POST /path → field → table_name → GET /path\"\r\n */\r\nfunction extractTablesFromErrorChain(errorChainPath: string): string[] {\r\n const segments = errorChainPath.split('→').map((s) => s.trim());\r\n return segments.filter((s) => !s.includes('/') && !s.includes(' ') && s.includes('_'));\r\n}\r\n\r\n/**\r\n * Build bidirectional table adjacency from foreign key relations.\r\n */\r\nfunction buildTableAdjacency(relations: ForeignKeyRelation[]): Map<string, Set<string>> {\r\n const adj = new Map<string, Set<string>>();\r\n for (const rel of relations) {\r\n if (!adj.has(rel.sourceTable)) adj.set(rel.sourceTable, new Set());\r\n if (!adj.has(rel.targetTable)) adj.set(rel.targetTable, new Set());\r\n adj.get(rel.sourceTable)!.add(rel.targetTable);\r\n adj.get(rel.targetTable)!.add(rel.sourceTable);\r\n }\r\n return adj;\r\n}\r\n\r\n/**\r\n * BFS traversal from seed tables along foreign key relations.\r\n */\r\nfunction bfsTraversal(\r\n seedTables: string[],\r\n adjacency: Map<string, Set<string>>,\r\n maxDepth: number = MAX_BFS_DEPTH,\r\n): string[] {\r\n const visited = new Set<string>();\r\n const queue: Array<{ table: string; depth: number }> = [];\r\n\r\n for (const t of seedTables) {\r\n if (adjacency.has(t)) {\r\n queue.push({ table: t, depth: 0 });\r\n visited.add(t);\r\n }\r\n }\r\n\r\n while (queue.length > 0) {\r\n const { table, depth } = queue.shift()!;\r\n if (depth >= maxDepth) continue;\r\n\r\n for (const neighbor of adjacency.get(table) || []) {\r\n if (!visited.has(neighbor)) {\r\n visited.add(neighbor);\r\n queue.push({ table: neighbor, depth: depth + 1 });\r\n }\r\n }\r\n }\r\n return Array.from(visited);\r\n}\r\n\r\n/**\r\n * Find API endpoints that reference any of the given tables.\r\n */\r\nfunction findAffectedEndpoints(\r\n tables: string[],\r\n analysisResults: ApiChainAnalysisResult[],\r\n): ApiEndpoint[] {\r\n const tableSet = new Set(tables);\r\n const affected: ApiEndpoint[] = [];\r\n\r\n for (const result of analysisResults) {\r\n for (const ep of result.endpoints) {\r\n if (ep.relatedTables.some((t) => tableSet.has(t))) {\r\n affected.push(ep);\r\n }\r\n }\r\n }\r\n return affected;\r\n}\r\n\r\n/**\r\n * Generate a Mermaid flowchart from impact data.\r\n */\r\nfunction generateMermaidDiagram(\r\n seedTables: string[],\r\n affectedTables: string[],\r\n relations: ForeignKeyRelation[],\r\n): string {\r\n const relevantTables = new Set([...seedTables, ...affectedTables]);\r\n const lines: string[] = ['flowchart TD'];\r\n\r\n const seedSet = new Set(seedTables);\r\n for (const t of relevantTables) {\r\n const label = seedSet.has(t) ? `${t}:::error` : t;\r\n lines.push(` ${sanitizeId(t)}[\"${label}\"]`);\r\n }\r\n\r\n for (const rel of relations) {\r\n if (relevantTables.has(rel.sourceTable) && relevantTables.has(rel.targetTable)) {\r\n const arrow = rel.isCrossModule ? '-.->' : '-->';\r\n lines.push(` ${sanitizeId(rel.sourceTable)} ${arrow}|${rel.targetField}| ${sanitizeId(rel.targetTable)}`);\r\n }\r\n }\r\n\r\n lines.push(' classDef error fill:#f96,stroke:#333,stroke-width:2px');\r\n return lines.join('\\n');\r\n}\r\n\r\nfunction sanitizeId(name: string): string {\r\n return name.replace(/[^a-zA-Z0-9_]/g, '_');\r\n}\r\n\r\nexport interface ImpactReporter {\r\n analyze(\r\n failures: ChainFailureResult[],\r\n erDiagrams: Map<string, ERDiagramResult>,\r\n analysisResults: ApiChainAnalysisResult[],\r\n ): ImpactReport;\r\n}\r\n\r\nexport function createImpactReporter(): ImpactReporter {\r\n return {\r\n analyze(\r\n failures: ChainFailureResult[],\r\n erDiagrams: Map<string, ERDiagramResult>,\r\n analysisResults: ApiChainAnalysisResult[],\r\n ): ImpactReport {\r\n // Collect all relations\r\n const allRelations: ForeignKeyRelation[] = [];\r\n for (const er of erDiagrams.values()) {\r\n allRelations.push(...er.relations);\r\n }\r\n\r\n // Extract seed tables from failure error chain paths\r\n const seedTables: string[] = [];\r\n for (const failure of failures) {\r\n if (failure.errorChainPath) {\r\n seedTables.push(...extractTablesFromErrorChain(failure.errorChainPath));\r\n }\r\n }\r\n\r\n // BFS to find all affected tables\r\n const adjacency = buildTableAdjacency(allRelations);\r\n const affectedTables = bfsTraversal(seedTables, adjacency);\r\n\r\n // Find affected endpoints\r\n const affectedEndpoints = findAffectedEndpoints(affectedTables, analysisResults);\r\n\r\n // Determine affected modules\r\n const affectedModules = [...new Set(analysisResults\r\n .filter((r) => r.endpoints.some((ep) => affectedEndpoints.includes(ep)))\r\n .map((r) => r.moduleName))];\r\n\r\n // Affected chains\r\n const affectedChains = failures.map((f) => f.chain);\r\n\r\n // Generate Mermaid diagram\r\n const mermaidText = generateMermaidDiagram(seedTables, affectedTables, allRelations);\r\n\r\n // Severity based on affected API count\r\n const count = affectedEndpoints.length;\r\n const severity = count > 10 ? 'critical' : count > 5 ? 'high' : count > 2 ? 'medium' : 'low';\r\n\r\n return {\r\n affectedModules,\r\n affectedChains,\r\n affectedEndpoints,\r\n affectedTables,\r\n severity,\r\n mermaidText,\r\n };\r\n },\r\n };\r\n}\r\n","/**\r\n * Chain Planner\r\n *\r\n * Rule-based test chain planning:\r\n * - Groups endpoints by resource path\r\n * - Applies chain templates (CRUD, nested, batch, status, error handling)\r\n * - Uses greedy algorithm for optimal coverage selection\r\n * - Detects shared setup steps\r\n */\r\n\r\nimport type {\r\n ApiEndpoint,\r\n ApiChainAnalysisResult,\r\n TestStep,\r\n TestChain,\r\n ChainPlanResult,\r\n LlmProvider,\r\n} from '../types.js';\r\nimport { topologicalSort } from '../analyzers/api-chain-analyzer.js';\r\n\r\n// ============================================================\r\n// Constants\r\n// ============================================================\r\n\r\nconst MIN_CHAINS = 3;\r\nconst MAX_CHAINS = 10;\r\nconst COVERAGE_TARGET = 0.8;\r\nconst SMALL_MODULE_THRESHOLD = 3;\r\n\r\n// ============================================================\r\n// Helpers\r\n// ============================================================\r\n\r\nfunction endpointKey(ep: ApiEndpoint): string {\r\n return `${ep.method} ${ep.path}`;\r\n}\r\n\r\nfunction basePath(ep: ApiEndpoint): string {\r\n return ep.path.replace(/\\/:[^/]+/g, '');\r\n}\r\n\r\nfunction groupByResource(endpoints: ApiEndpoint[]): Map<string, ApiEndpoint[]> {\r\n const groups = new Map<string, ApiEndpoint[]>();\r\n for (const ep of endpoints) {\r\n const base = basePath(ep);\r\n if (!groups.has(base)) groups.set(base, []);\r\n groups.get(base)!.push(ep);\r\n }\r\n return groups;\r\n}\r\n\r\nfunction isListEndpoint(ep: ApiEndpoint): boolean {\r\n if (ep.method !== 'GET') return false;\r\n const params = (ep.pathParams ?? []).filter((p) => p !== 'tenantId');\r\n return params.length === 0;\r\n}\r\n\r\nfunction isDetailEndpoint(ep: ApiEndpoint): boolean {\r\n if (ep.method !== 'GET') return false;\r\n const params = (ep.pathParams ?? []).filter((p) => p !== 'tenantId');\r\n return params.length > 0;\r\n}\r\n\r\nfunction inferAction(ep: ApiEndpoint): string {\r\n switch (ep.method) {\r\n case 'POST': return 'create';\r\n case 'GET': return 'read';\r\n case 'PUT':\r\n case 'PATCH': return 'update';\r\n case 'DELETE': return 'delete';\r\n default: return 'read';\r\n }\r\n}\r\n\r\nfunction buildDescription(ep: ApiEndpoint, action: string, parentKey?: string): string {\r\n const parts = [`${action} ${ep.method} ${ep.path}`];\r\n if (parentKey) parts.push(`(depends on ${parentKey})`);\r\n for (const param of ep.pathParams ?? []) {\r\n if (param === 'tenantId') parts.push(`${param}: config.tenantId`);\r\n }\r\n return parts.join(' ');\r\n}\r\n\r\nfunction buildAssertions(ep: ApiEndpoint, action: string): string[] {\r\n switch (action) {\r\n case 'create': return ['响应状态码 200/201', '响应 data.id 非空'];\r\n case 'read':\r\n return isListEndpoint(ep)\r\n ? ['响应状态码 200', '响应 data 为数组']\r\n : ['响应状态码 200', '响应 data.id 与请求参数一致'];\r\n case 'update': return ['响应状态码 200', '更新字段值已变更'];\r\n case 'delete': return ['响应状态码 200/204', '再次 GET 返回 404 或空'];\r\n case 'verify': return ['验证数据一致性'];\r\n default: return ['响应状态码 200'];\r\n }\r\n}\r\n\r\nfunction createStep(order: number, ep: ApiEndpoint, action: string, parentKey?: string): TestStep {\r\n return {\r\n order,\r\n endpoint: ep,\r\n action,\r\n description: buildDescription(ep, action, parentKey),\r\n assertions: buildAssertions(ep, action),\r\n };\r\n}\r\n\r\n// ============================================================\r\n// Internal chain type (extends public TestChain with planning fields)\r\n// ============================================================\r\n\r\ninterface InternalChain {\r\n name: string;\r\n module: string;\r\n priority: 'P0' | 'P1' | 'P2';\r\n steps: TestStep[];\r\n coverageApis: string[];\r\n}\r\n\r\nfunction toPublicChain(c: InternalChain): TestChain {\r\n return { name: c.name, module: c.module, steps: c.steps };\r\n}\r\n\r\n// ============================================================\r\n// Chain templates\r\n// ============================================================\r\n\r\ninterface ChainTemplate {\r\n pattern: string;\r\n priority: 'P0' | 'P1' | 'P2';\r\n generate(name: string, endpoints: ApiEndpoint[], groups: Map<string, ApiEndpoint[]>, topo: string[]): InternalChain | null;\r\n}\r\n\r\nfunction crudFullCycleTemplate(): ChainTemplate {\r\n return {\r\n pattern: 'crud-full-cycle',\r\n priority: 'P0',\r\n generate(name, _endpoints, groups) {\r\n let best: ApiEndpoint[] = [];\r\n for (const group of groups.values()) {\r\n if (group.length > best.length) best = group;\r\n }\r\n if (best.length === 0) return null;\r\n\r\n const post = best.find((e) => e.method === 'POST');\r\n const getD = best.find(isDetailEndpoint);\r\n const put = best.find((e) => e.method === 'PUT' || e.method === 'PATCH');\r\n const del = best.find((e) => e.method === 'DELETE');\r\n if (!post) return null;\r\n\r\n const steps: TestStep[] = [];\r\n const pk = 'step_1';\r\n steps.push(createStep(steps.length + 1, post, 'create'));\r\n if (getD) steps.push(createStep(steps.length + 1, getD, 'read', pk));\r\n if (put) steps.push(createStep(steps.length + 1, put, 'update', pk));\r\n if (getD) steps.push(createStep(steps.length + 1, getD, 'verify', pk));\r\n if (del) steps.push(createStep(steps.length + 1, del, 'delete', pk));\r\n\r\n return {\r\n name: `${name}-crud-full-cycle`,\r\n module: name,\r\n priority: 'P0',\r\n steps,\r\n coverageApis: [...new Set(steps.map((s) => endpointKey(s.endpoint)))],\r\n };\r\n },\r\n };\r\n}\r\n\r\nfunction listFilterTemplate(): ChainTemplate {\r\n return {\r\n pattern: 'list-filter',\r\n priority: 'P1',\r\n generate(name, endpoints) {\r\n const lists = endpoints.filter(isListEndpoint);\r\n if (lists.length === 0) return null;\r\n const steps = lists.slice(0, 2).map((ep, i) => createStep(i + 1, ep, 'read'));\r\n return {\r\n name: `${name}-list-filter`,\r\n module: name,\r\n priority: 'P1',\r\n steps,\r\n coverageApis: [...new Set(steps.map((s) => endpointKey(s.endpoint)))],\r\n };\r\n },\r\n };\r\n}\r\n\r\nfunction nestedResourceTemplate(): ChainTemplate {\r\n return {\r\n pattern: 'nested-resource',\r\n priority: 'P0',\r\n generate(name, _endpoints, groups) {\r\n const entries = Array.from(groups.entries());\r\n if (entries.length < 2) return null;\r\n entries.sort((a, b) => a[0].split('/').length - b[0].split('/').length);\r\n\r\n const parentPost = entries[0][1].find((e) => e.method === 'POST');\r\n const childPost = entries[1][1].find((e) => e.method === 'POST');\r\n const childGet = entries[1][1].find((e) => isDetailEndpoint(e) || isListEndpoint(e));\r\n const childDel = entries[1][1].find((e) => e.method === 'DELETE');\r\n const parentDel = entries[0][1].find((e) => e.method === 'DELETE');\r\n if (!parentPost || !childPost) return null;\r\n\r\n const steps: TestStep[] = [];\r\n steps.push(createStep(steps.length + 1, parentPost, 'setup'));\r\n steps.push(createStep(steps.length + 1, childPost, 'create', 'step_1'));\r\n if (childGet) steps.push(createStep(steps.length + 1, childGet, 'read', 'step_2'));\r\n if (childDel) steps.push(createStep(steps.length + 1, childDel, 'cleanup', 'step_2'));\r\n if (parentDel) steps.push(createStep(steps.length + 1, parentDel, 'cleanup', 'step_1'));\r\n\r\n return {\r\n name: `${name}-nested-resource`,\r\n module: name,\r\n priority: 'P0',\r\n steps,\r\n coverageApis: [...new Set(steps.map((s) => endpointKey(s.endpoint)))],\r\n };\r\n },\r\n };\r\n}\r\n\r\nfunction batchOperationTemplate(): ChainTemplate {\r\n return {\r\n pattern: 'batch-operation',\r\n priority: 'P1',\r\n generate(name, endpoints) {\r\n const batch = endpoints.filter((ep) =>\r\n ep.path.toLowerCase().includes('batch') || ep.path.toLowerCase().includes('bulk'),\r\n );\r\n if (batch.length === 0) return null;\r\n const steps = batch.slice(0, 3).map((ep, i) => createStep(i + 1, ep, inferAction(ep)));\r\n return {\r\n name: `${name}-batch-operation`,\r\n module: name,\r\n priority: 'P1',\r\n steps,\r\n coverageApis: [...new Set(steps.map((s) => endpointKey(s.endpoint)))],\r\n };\r\n },\r\n };\r\n}\r\n\r\nfunction errorHandlingTemplate(): ChainTemplate {\r\n return {\r\n pattern: 'error-handling',\r\n priority: 'P2',\r\n generate(name, endpoints) {\r\n const post = endpoints.find((ep) => ep.method === 'POST');\r\n if (!post) return null;\r\n return {\r\n name: `${name}-error-handling`,\r\n module: name,\r\n priority: 'P2',\r\n steps: [{\r\n order: 1,\r\n endpoint: post,\r\n action: 'verify',\r\n description: `verify ${post.method} ${post.path} with invalid data`,\r\n assertions: ['响应状态码 400', '响应包含错误信息'],\r\n }],\r\n coverageApis: [endpointKey(post)],\r\n };\r\n },\r\n };\r\n}\r\n\r\nfunction topoOrderTemplate(): ChainTemplate {\r\n return {\r\n pattern: 'topo-order-walk',\r\n priority: 'P1',\r\n generate(name, endpoints, _groups, topo) {\r\n if (topo.length === 0) return null;\r\n const epMap = new Map(endpoints.map((ep) => [endpointKey(ep), ep]));\r\n const steps: TestStep[] = [];\r\n for (const key of topo.slice(0, 6)) {\r\n const ep = epMap.get(key);\r\n if (ep) steps.push(createStep(steps.length + 1, ep, inferAction(ep)));\r\n }\r\n if (steps.length === 0) return null;\r\n return {\r\n name: `${name}-topo-order-walk`,\r\n module: name,\r\n priority: 'P1',\r\n steps,\r\n coverageApis: [...new Set(steps.map((s) => endpointKey(s.endpoint)))],\r\n };\r\n },\r\n };\r\n}\r\n\r\n// ============================================================\r\n// Greedy coverage selection\r\n// ============================================================\r\n\r\nfunction greedySelectChains(\r\n candidates: InternalChain[],\r\n allKeys: Set<string>,\r\n targetCount: number,\r\n coverageTarget: number,\r\n): InternalChain[] {\r\n const selected: InternalChain[] = [];\r\n const covered = new Set<string>();\r\n const remaining = [...candidates];\r\n\r\n const pOrder: Record<string, number> = { P0: 0, P1: 1, P2: 2 };\r\n remaining.sort((a, b) => pOrder[a.priority] - pOrder[b.priority] || b.coverageApis.length - a.coverageApis.length);\r\n\r\n while (selected.length < targetCount && remaining.length > 0) {\r\n let bestIdx = -1, bestScore = -1;\r\n for (let i = 0; i < remaining.length; i++) {\r\n const newApis = remaining[i].coverageApis.filter((a) => !covered.has(a));\r\n const score = remaining[i].priority === 'P0' ? newApis.length * 1.5 : newApis.length;\r\n if (score > bestScore) { bestScore = score; bestIdx = i; }\r\n }\r\n if (bestIdx === -1 || bestScore <= 0) break;\r\n\r\n const chosen = remaining.splice(bestIdx, 1)[0];\r\n selected.push(chosen);\r\n chosen.coverageApis.forEach((a) => covered.add(a));\r\n\r\n if (allKeys.size > 0 && covered.size / allKeys.size >= coverageTarget && selected.length >= MIN_CHAINS) break;\r\n }\r\n return selected;\r\n}\r\n\r\n// ============================================================\r\n// Shared setup detection\r\n// ============================================================\r\n\r\nfunction detectSharedSetups(chains: InternalChain[], moduleName: string): InternalChain[] {\r\n const firstSteps = new Map<string, { ep: ApiEndpoint; count: number }>();\r\n for (const chain of chains) {\r\n if (chain.steps.length === 0) continue;\r\n const first = chain.steps[0];\r\n if (first.action === 'create' || first.action === 'setup') {\r\n const key = endpointKey(first.endpoint);\r\n const e = firstSteps.get(key);\r\n if (e) e.count++;\r\n else firstSteps.set(key, { ep: first.endpoint, count: 1 });\r\n }\r\n }\r\n\r\n const setups: InternalChain[] = [];\r\n for (const [key, { ep, count }] of firstSteps) {\r\n if (count >= 2) {\r\n const setupName = `${moduleName}-shared-setup-${setups.length + 1}`;\r\n setups.push({\r\n name: setupName,\r\n module: moduleName,\r\n priority: 'P0',\r\n steps: [createStep(1, ep, 'setup')],\r\n coverageApis: [key],\r\n });\r\n }\r\n }\r\n return setups;\r\n}\r\n\r\n// ============================================================\r\n// Public API\r\n// ============================================================\r\n\r\nexport interface ChainPlanner {\r\n planForModule(moduleName: string, analysis: ApiChainAnalysisResult): ChainPlanResult;\r\n}\r\n\r\nexport function createChainPlanner(): ChainPlanner {\r\n return {\r\n planForModule(moduleName, analysis) {\r\n const { endpoints, dag } = analysis;\r\n\r\n // Small module shortcut\r\n if (endpoints.length < SMALL_MODULE_THRESHOLD) {\r\n if (endpoints.length === 0) {\r\n return { chains: [], totalSteps: 0 };\r\n }\r\n const steps = endpoints.map((ep, i) => createStep(i + 1, ep, inferAction(ep)));\r\n return {\r\n chains: [{ name: `${moduleName}-basic-flow`, module: moduleName, steps }],\r\n totalSteps: steps.length,\r\n };\r\n }\r\n\r\n // Full planning\r\n const topoOrder = topologicalSort(dag);\r\n const groups = groupByResource(endpoints);\r\n\r\n // Generate candidates from templates\r\n const templates: ChainTemplate[] = [\r\n crudFullCycleTemplate(),\r\n listFilterTemplate(),\r\n nestedResourceTemplate(),\r\n batchOperationTemplate(),\r\n errorHandlingTemplate(),\r\n topoOrderTemplate(),\r\n ];\r\n\r\n const candidates: InternalChain[] = [];\r\n for (const t of templates) {\r\n const chain = t.generate(moduleName, endpoints, groups, topoOrder);\r\n if (chain && chain.steps.length > 0) candidates.push(chain);\r\n }\r\n\r\n // Supplement uncovered endpoints\r\n const coveredSet = new Set<string>();\r\n for (const c of candidates) c.coverageApis.forEach((a) => coveredSet.add(a));\r\n const uncovered = endpoints.filter((ep) => !coveredSet.has(endpointKey(ep)));\r\n if (uncovered.length > 0) {\r\n const steps = uncovered.slice(0, 5).map((ep, i) => createStep(i + 1, ep, inferAction(ep)));\r\n candidates.push({\r\n name: `${moduleName}-supplement`,\r\n module: moduleName,\r\n priority: 'P2',\r\n steps,\r\n coverageApis: [...new Set(steps.map((s) => endpointKey(s.endpoint)))],\r\n });\r\n }\r\n\r\n // Greedy selection\r\n const allKeys = new Set(endpoints.map(endpointKey));\r\n const targetCount = Math.min(MAX_CHAINS, Math.max(MIN_CHAINS, candidates.length));\r\n const selected = greedySelectChains(candidates, allKeys, targetCount, COVERAGE_TARGET);\r\n\r\n // Shared setups\r\n detectSharedSetups(selected, moduleName);\r\n\r\n const totalSteps = selected.reduce((sum, c) => sum + c.steps.length, 0);\r\n return { chains: selected.map(toPublicChain), totalSteps };\r\n },\r\n };\r\n}\r\n\r\n// ============================================================\r\n// LLM-Enhanced Chain Planner\r\n// ============================================================\r\n\r\nexport interface LlmChainPlanner extends ChainPlanner {\r\n planForModuleWithLLM(\r\n moduleName: string,\r\n analysis: ApiChainAnalysisResult,\r\n llmProvider: LlmProvider,\r\n ): Promise<ChainPlanResult>;\r\n}\r\n\r\n/**\r\n * Create a chain planner with optional LLM constraint reasoning.\r\n *\r\n * The LLM is used to:\r\n * 1. Infer business constraints that rule-based templates cannot detect\r\n * 2. Prioritize chains based on domain understanding\r\n * 3. Suggest additional edge-case chains\r\n */\r\nexport function createLlmChainPlanner(): LlmChainPlanner {\r\n const basePlanner = createChainPlanner();\r\n\r\n return {\r\n planForModule: basePlanner.planForModule,\r\n\r\n async planForModuleWithLLM(moduleName, analysis, llmProvider) {\r\n // Step 1: Get rule-based plan\r\n const basePlan = basePlanner.planForModule(moduleName, analysis);\r\n\r\n // Step 2: Ask LLM to evaluate and enhance\r\n const endpointSummary = analysis.endpoints\r\n .map((e) => `${e.method} ${e.path}`)\r\n .join('\\n');\r\n\r\n const chainSummary = basePlan.chains\r\n .map((c) => `- ${c.name}: ${c.steps.length} steps`)\r\n .join('\\n');\r\n\r\n const system = `You are a test planning expert. Given a module's API endpoints and existing test chains,\r\nsuggest improvements. Output a JSON object with:\r\n{\r\n \"priorityAdjustments\": [{ \"chainName\": \"...\", \"newPriority\": \"P0|P1|P2\", \"reason\": \"...\" }],\r\n \"additionalChains\": [{ \"name\": \"...\", \"description\": \"...\", \"priority\": \"P0|P1|P2\", \"endpointKeys\": [\"GET /path\", ...] }],\r\n \"insights\": \"brief text about business constraints or edge cases\"\r\n}\r\nOnly return JSON. No explanation.`;\r\n\r\n const user = `Module: ${moduleName}\r\n\r\nAPI Endpoints:\r\n${endpointSummary}\r\n\r\nExisting Chains:\r\n${chainSummary}\r\n\r\nCoverage: ${basePlan.totalSteps} total steps\r\nCycles detected: ${analysis.hasCycles}\r\n\r\nSuggest improvements (JSON):`;\r\n\r\n try {\r\n const raw = await llmProvider.chat([\r\n { role: 'system', content: system },\r\n { role: 'user', content: user },\r\n ]);\r\n\r\n const jsonMatch = raw.match(/\\{[\\s\\S]*\\}/);\r\n if (!jsonMatch) return basePlan;\r\n\r\n const suggestions = JSON.parse(jsonMatch[0]);\r\n\r\n // Apply priority adjustments (stored as metadata, not on public type)\r\n // Skip - remote TestChain doesn't have priority field\r\n\r\n // Add suggested chains (if they cover uncovered endpoints)\r\n if (Array.isArray(suggestions.additionalChains)) {\r\n const covered = new Set<string>();\r\n for (const c of basePlan.chains) {\r\n for (const s of c.steps) covered.add(endpointKey(s.endpoint));\r\n }\r\n\r\n for (const suggestion of suggestions.additionalChains) {\r\n if (!suggestion.endpointKeys || !Array.isArray(suggestion.endpointKeys)) continue;\r\n\r\n const newApis = suggestion.endpointKeys.filter((k: string) => !covered.has(k));\r\n if (newApis.length === 0) continue;\r\n\r\n const steps: TestStep[] = [];\r\n for (const key of newApis) {\r\n const ep = analysis.endpoints.find((e) => `${e.method} ${e.path}` === key);\r\n if (ep) {\r\n steps.push(createStep(steps.length + 1, ep, inferAction(ep)));\r\n covered.add(key);\r\n }\r\n }\r\n\r\n if (steps.length > 0) {\r\n basePlan.chains.push({\r\n name: suggestion.name || `${moduleName}-llm-suggested`,\r\n module: moduleName,\r\n steps,\r\n });\r\n basePlan.totalSteps += steps.length;\r\n }\r\n }\r\n }\r\n\r\n return basePlan;\r\n } catch {\r\n // LLM failed, fall back to rule-based plan\r\n return basePlan;\r\n }\r\n },\r\n };\r\n}\r\n","/**\r\n * AI Config Suggester — AI-driven module test config generation.\r\n *\r\n * Uses LlmProvider to analyze parsed API endpoints and generate:\r\n * - bodyTemplates (request body for POST/PUT/PATCH endpoints)\r\n * - paramRewrites (semantic parameter name mapping)\r\n * - seed steps (data setup sequence with dependency ordering)\r\n */\r\n\r\nimport type {\r\n LlmProvider,\r\n ApiEndpoint,\r\n ModuleTestConfig,\r\n SeedStep,\r\n ModuleConfigValidationContext,\r\n} from '../types.js';\r\nimport { validateModuleConfig } from '../validators/config-validator.js';\r\n\r\n// ============================================================\r\n// Types\r\n// ============================================================\r\n\r\nexport interface GenerateConfigOptions {\r\n moduleName: string;\r\n endpoints: ApiEndpoint[];\r\n llmProvider: LlmProvider;\r\n /** Max validation+fix retries (default 3) */\r\n maxRetries?: number;\r\n /** Dry-run: don't write to disk */\r\n dryRun?: boolean;\r\n /** Validation context for semantic checking */\r\n validationContext?: ModuleConfigValidationContext;\r\n}\r\n\r\nexport interface GenerateConfigResult {\r\n success: boolean;\r\n config?: ModuleTestConfig;\r\n error?: string;\r\n retries: number;\r\n}\r\n\r\n// ============================================================\r\n// JSON Recovery\r\n// ============================================================\r\n\r\nexport function recoverJSON(text: string): string {\r\n // Direct parse\r\n try { JSON.parse(text.trim()); return text.trim(); } catch { /* recovery fallthrough */ }\r\n\r\n // Markdown code block\r\n const codeBlock = text.match(/```(?:json|javascript|ts)?\\s*\\n?([\\s\\S]*?)\\n?\\s*```/);\r\n if (codeBlock) {\r\n try { JSON.parse(codeBlock[1].trim()); return codeBlock[1].trim(); } catch { /* recovery fallthrough */ }\r\n }\r\n\r\n // Extract outermost {} or []\r\n const braceStart = text.indexOf('{');\r\n const braceEnd = text.lastIndexOf('}');\r\n const bracketStart = text.indexOf('[');\r\n const bracketEnd = text.lastIndexOf(']');\r\n\r\n const tryParse = (start: number, end: number): string | null => {\r\n if (start === -1 || end <= start) return null;\r\n let candidate = text.slice(start, end + 1);\r\n candidate = candidate.replace(/,\\s*([}\\]])/g, '$1');\r\n try { JSON.parse(candidate); return candidate; } catch { return null; }\r\n };\r\n\r\n // Try [] first if it appears earlier\r\n if (bracketStart !== -1 && (braceStart === -1 || bracketStart < braceStart)) {\r\n const r = tryParse(bracketStart, bracketEnd) ?? tryParse(braceStart, braceEnd);\r\n if (r) return r;\r\n } else {\r\n const r = tryParse(braceStart, braceEnd) ?? tryParse(bracketStart, bracketEnd);\r\n if (r) return r;\r\n }\r\n\r\n // Fix trailing commas + unquoted keys + single quotes\r\n const cleaned = text.trim()\r\n .replace(/^```(?:json|javascript|ts)?\\s*\\n?/m, '')\r\n .replace(/\\n?\\s*```\\s*$/m, '')\r\n .trim()\r\n .replace(/,\\s*([}\\]])/g, '$1')\r\n .replace(/([{,]\\s*)(\\w+)\\s*:/g, (_m, prefix, key) => `${prefix}\"${key}\":`)\r\n .replace(/'/g, '\"');\r\n\r\n try { JSON.parse(cleaned); return cleaned; } catch { /* recovery fallthrough */ }\r\n\r\n throw new Error('JSON recovery failed: unable to extract valid JSON from AI response');\r\n}\r\n\r\n// ============================================================\r\n// LLM Prompt Helpers\r\n// ============================================================\r\n\r\nasync function llmChat(llm: LlmProvider, system: string, user: string): Promise<string> {\r\n return llm.chat([\r\n { role: 'system', content: system },\r\n { role: 'user', content: user },\r\n ]);\r\n}\r\n\r\nasync function generateBodyTemplates(\r\n moduleName: string,\r\n endpoints: ApiEndpoint[],\r\n llm: LlmProvider,\r\n): Promise<Record<string, Record<string, unknown>>> {\r\n const writeEndpoints = endpoints\r\n .filter((e) => ['POST', 'PUT', 'PATCH'].includes(e.method))\r\n .map((e) => `${e.method} ${e.path}${e.bodyFields?.length ? ` → [${e.bodyFields.join(', ')}]` : ''}`)\r\n .join('\\n');\r\n\r\n if (!writeEndpoints) return {};\r\n\r\n const system = `You are a test config expert. Generate test body templates for API endpoints.\r\nRules:\r\n1. String fields: \"__e2e_{fieldName}_{timestamp}\" format\r\n2. Enum fields: choose a reasonable value\r\n3. Number fields: use reasonable defaults\r\n4. Boolean fields: default true\r\n5. Only return valid JSON object. No explanation.\r\n\r\nOutput format: { \"POST /path\": { \"field1\": \"value1\" } }`;\r\n\r\n const user = `Module: ${moduleName}\\n\\nWrite endpoints:\\n${writeEndpoints}\\n\\nGenerate body templates (JSON):`;\r\n\r\n try {\r\n const raw = await llmChat(llm, system, user);\r\n return JSON.parse(recoverJSON(raw));\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nasync function generateParamRewrites(\r\n moduleName: string,\r\n endpoints: ApiEndpoint[],\r\n llm: LlmProvider,\r\n): Promise<Record<string, Record<string, string>>> {\r\n const paramEndpoints = endpoints\r\n .filter((e) => e.pathParams && e.pathParams.length > 0)\r\n .map((e) => `${e.method} ${e.path} → params: [${e.pathParams!.join(', ')}]`)\r\n .join('\\n');\r\n\r\n if (!paramEndpoints) return {};\r\n\r\n const system = `You are an API path analysis expert. Map generic :id parameters to semantic names.\r\nRules:\r\n1. Map generic :id to semantic names based on the preceding path segment\r\n2. /categories/:id → categoryId, /users/:id → userId\r\n3. Only return valid JSON object. No explanation.\r\n\r\nOutput format: { \"GET /path/:id\": { \"id\": \"semanticId\" } }`;\r\n\r\n const user = `Module: ${moduleName}\\n\\nEndpoints with path params:\\n${paramEndpoints}\\n\\nGenerate param rewrites (JSON):`;\r\n\r\n try {\r\n const raw = await llmChat(llm, system, user);\r\n return JSON.parse(recoverJSON(raw));\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nasync function generateSeedConfig(\r\n moduleName: string,\r\n endpoints: ApiEndpoint[],\r\n bodyTemplates: Record<string, Record<string, unknown>>,\r\n llm: LlmProvider,\r\n): Promise<SeedStep[]> {\r\n const allEndpoints = endpoints.map((e) => `${e.method} ${e.path}`).join('\\n');\r\n\r\n const system = `You are a test data dependency analysis expert. Generate beforeAll seed steps.\r\nRules:\r\n1. Use only existing API paths from the endpoint list\r\n2. Main resources must be created before sub-resources\r\n3. Use captureAs to mark IDs to capture (e.g. \"kbId\")\r\n4. dependsOn must reference previously captured variables\r\n5. required: true for essential steps\r\n6. step numbers start from 1\r\n7. Only return valid JSON array. No explanation.\r\n\r\nOutput format: [{ \"step\": 1, \"method\": \"POST\", \"path\": \"/path\", \"body\": {}, \"captureAs\": \"id\", \"required\": true, \"dependsOn\": [] }]`;\r\n\r\n const user = `Module: ${moduleName}\\n\\nAPI endpoints:\\n${allEndpoints}\\n\\nBody templates:\\n${JSON.stringify(bodyTemplates, null, 2)}\\n\\nGenerate seed config (JSON array):`;\r\n\r\n try {\r\n const raw = await llmChat(llm, system, user);\r\n const parsed = JSON.parse(recoverJSON(raw));\r\n return Array.isArray(parsed) ? parsed : [];\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\n// ============================================================\r\n// Config Validation + AI Fix\r\n// ============================================================\r\n\r\ninterface InternalValidationResult {\r\n valid: boolean;\r\n errors: string[];\r\n warnings: string[];\r\n}\r\n\r\nfunction internalValidate(config: ModuleTestConfig): InternalValidationResult {\r\n const result = validateModuleConfig(config, undefined, { skipLayers: ['semantic', 'dryrun'] });\r\n return {\r\n valid: result.passed,\r\n errors: result.errors.map((e) => `[${e.path}] ${e.message}`),\r\n warnings: result.warnings.map((w) => `[${w.path}] ${w.message}`),\r\n };\r\n}\r\n\r\nasync function fixConfigErrors(\r\n config: ModuleTestConfig,\r\n validation: InternalValidationResult,\r\n llm: LlmProvider,\r\n): Promise<ModuleTestConfig> {\r\n if (validation.valid) return config;\r\n\r\n const system = `You are a config repair expert. Fix the validation errors in this config.\r\nRules:\r\n1. Fix all listed errors\r\n2. Keep the overall structure intact\r\n3. Only return the fixed complete config as JSON. No explanation.`;\r\n\r\n const user = `Original config:\\n${JSON.stringify(config, null, 2)}\\n\\nErrors:\\n${validation.errors.join('\\n')}\\n\\nFix and return complete JSON:`;\r\n\r\n try {\r\n const raw = await llmChat(llm, system, user);\r\n return JSON.parse(recoverJSON(raw));\r\n } catch {\r\n return config;\r\n }\r\n}\r\n\r\n// ============================================================\r\n// Main Flow\r\n// ============================================================\r\n\r\n/**\r\n * Generate a module test config using AI analysis of endpoints.\r\n */\r\nexport async function generateModuleConfig(\r\n options: GenerateConfigOptions,\r\n): Promise<GenerateConfigResult> {\r\n const { moduleName, endpoints, llmProvider, maxRetries = 3 } = options;\r\n let retries = 0;\r\n\r\n console.log(`[ai-config-suggester] Generating config for \"${moduleName}\"...`);\r\n\r\n if (endpoints.length === 0) {\r\n return { success: false, error: `No endpoints found for module: ${moduleName}`, retries: 0 };\r\n }\r\n\r\n // AI generation\r\n const bodyTemplates = await generateBodyTemplates(moduleName, endpoints, llmProvider);\r\n const paramRewrites = await generateParamRewrites(moduleName, endpoints, llmProvider);\r\n const seed = await generateSeedConfig(moduleName, endpoints, bodyTemplates, llmProvider);\r\n\r\n let config: ModuleTestConfig = {\r\n moduleName,\r\n version: '1.0.0',\r\n generatedAt: new Date().toISOString(),\r\n bodyTemplates,\r\n paramRewrites,\r\n idAliases: [],\r\n specialUrls: {},\r\n seed,\r\n };\r\n\r\n // Validation + fix loop\r\n while (retries < maxRetries) {\r\n const validation = internalValidate(config);\r\n if (validation.valid) {\r\n console.log(`[ai-config-suggester] ✓ Config validated`);\r\n return { success: true, config, retries };\r\n }\r\n\r\n console.warn(`[ai-config-suggester] Validation failed (attempt ${retries + 1}), fixing...`);\r\n config = await fixConfigErrors(config, validation, llmProvider);\r\n retries++;\r\n }\r\n\r\n return {\r\n success: false,\r\n config,\r\n error: `Config validation failed after ${maxRetries} retries`,\r\n retries,\r\n };\r\n}\r\n\r\n/**\r\n * Batch generate configs for multiple modules.\r\n */\r\nexport async function generateAllModuleConfigs(\r\n moduleNames: string[],\r\n endpoints: Map<string, ApiEndpoint[]>,\r\n llmProvider: LlmProvider,\r\n options?: Partial<GenerateConfigOptions>,\r\n): Promise<Map<string, GenerateConfigResult>> {\r\n const results = new Map<string, GenerateConfigResult>();\r\n\r\n for (const moduleName of moduleNames) {\r\n const eps = endpoints.get(moduleName) || [];\r\n const result = await generateModuleConfig({\r\n moduleName,\r\n endpoints: eps,\r\n llmProvider,\r\n ...options,\r\n });\r\n results.set(moduleName, result);\r\n }\r\n\r\n const successCount = Array.from(results.values()).filter((r) => r.success).length;\r\n console.log(`[ai-config-suggester] Summary: ${successCount}/${moduleNames.length} succeeded`);\r\n\r\n return results;\r\n}\r\n","/**\r\n * Enhanced AI Config Suggester — improved config generation with:\r\n * - Richer prompts using DTO field info and validation rules\r\n * - JSON recovery with fallback strategies\r\n * - Retry with previous failure context\r\n * - Three-layer validation integration\r\n */\r\n\r\nimport type {\r\n LlmProvider,\r\n ApiEndpoint,\r\n ModuleTestConfig,\r\n SeedStep,\r\n DTOInfo,\r\n} from '../types.js';\r\nimport { recoverJSON } from './ai-config-suggester.js';\r\n\r\n// ============================================================\r\n// Types\r\n// ============================================================\r\n\r\nexport interface EnhancedGenerateOptions {\r\n moduleName: string;\r\n endpoints: ApiEndpoint[];\r\n llmProvider: LlmProvider;\r\n /** DTO info for richer prompts */\r\n dtos?: DTOInfo[];\r\n /** Example config for few-shot learning */\r\n exampleConfig?: ModuleTestConfig;\r\n /** Temperature (default 0.1) */\r\n temperature?: number;\r\n /** Max retries per phase (default 3) */\r\n maxRetries?: number;\r\n /** Single call timeout in ms (default 30000) */\r\n timeout?: number;\r\n /** Dry-run: preview only */\r\n dryRun?: boolean;\r\n}\r\n\r\nexport interface EnhancedGenerateResult {\r\n success: boolean;\r\n config?: ModuleTestConfig;\r\n attempts: AttemptRecord[];\r\n error?: string;\r\n}\r\n\r\nexport interface AttemptRecord {\r\n attempt: number;\r\n phase: 'body' | 'param' | 'seed' | 'full';\r\n rawResponse?: string;\r\n parsedJson?: unknown;\r\n error?: string;\r\n durationMs: number;\r\n}\r\n\r\n// ============================================================\r\n// AI Call with Retry\r\n// ============================================================\r\n\r\nasync function callAIWithRetry(\r\n llm: LlmProvider,\r\n systemPrompt: string,\r\n userPrompt: string,\r\n opts: { maxRetries: number; timeout: number; phase: string },\r\n): Promise<{ json: unknown; attempts: AttemptRecord[] }> {\r\n const attempts: AttemptRecord[] = [];\r\n let lastError = '';\r\n let currentUserPrompt = userPrompt;\r\n\r\n for (let i = 0; i < opts.maxRetries; i++) {\r\n const startTime = Date.now();\r\n try {\r\n const raw = await Promise.race([\r\n llm.chat([\r\n { role: 'system', content: systemPrompt },\r\n { role: 'user', content: currentUserPrompt },\r\n ]),\r\n new Promise<never>((_, reject) =>\r\n setTimeout(() => reject(new Error('AI request timeout')), opts.timeout),\r\n ),\r\n ]);\r\n\r\n const jsonStr = recoverJSON(raw);\r\n const parsed = JSON.parse(jsonStr);\r\n\r\n attempts.push({\r\n attempt: i + 1,\r\n phase: opts.phase as AttemptRecord['phase'],\r\n rawResponse: raw.substring(0, 500),\r\n parsedJson: parsed,\r\n durationMs: Date.now() - startTime,\r\n });\r\n\r\n return { json: parsed, attempts };\r\n } catch (err: unknown) {\r\n lastError = (err as Error).message || String(err);\r\n attempts.push({\r\n attempt: i + 1,\r\n phase: opts.phase as AttemptRecord['phase'],\r\n error: lastError,\r\n durationMs: Date.now() - startTime,\r\n });\r\n\r\n if (i < opts.maxRetries - 1) {\r\n currentUserPrompt += `\\n\\n[Retry ${i + 1}] Previous call failed: ${lastError}. Please regenerate.`;\r\n }\r\n }\r\n }\r\n\r\n throw Object.assign(\r\n new Error(`AI call failed after ${opts.maxRetries} retries: ${lastError}`),\r\n { attempts },\r\n );\r\n}\r\n\r\n// ============================================================\r\n// Prompt Builders\r\n// ============================================================\r\n\r\nfunction buildBodyTemplatePrompt(\r\n options: EnhancedGenerateOptions,\r\n previousError?: string,\r\n): { system: string; user: string } {\r\n const { moduleName, endpoints, dtos } = options;\r\n\r\n const dtoSummary = (dtos || [])\r\n .map((dto) => {\r\n const fields = dto.fields\r\n .filter((f) => !f.isSystemField)\r\n .map((f) => {\r\n let desc = ` - ${f.name}: ${f.type}`;\r\n if (f.required) desc += ' (required)';\r\n if (f.enumValues?.length) desc += ` [${f.enumValues.join(', ')}]`;\r\n return desc;\r\n })\r\n .join('\\n');\r\n return `${dto.name}${dto.extends ? ` extends ${dto.extends}` : ''}:\\n${fields}`;\r\n })\r\n .join('\\n\\n');\r\n\r\n const writeEndpoints = endpoints\r\n .filter((e) => ['POST', 'PUT', 'PATCH'].includes(e.method))\r\n .map((e) => `${e.method} ${e.path}${e.bodyFields?.length ? ` → body: [${e.bodyFields.join(', ')}]` : ''}`)\r\n .join('\\n');\r\n\r\n const system = `You are an E2E test config expert. Generate test body templates based on API endpoints and DTO definitions.\r\n\r\nStrict rules:\r\n1. String fields: \"__e2e_{fieldName}_{timestamp}\" format\r\n2. Enum fields: use the first declared value from DTO\r\n3. Number fields: reasonable defaults (1, 10, 100)\r\n4. Boolean fields: true\r\n5. Required fields must not be omitted\r\n6. Do not invent fields not in the DTO\r\n7. Output ONLY strict JSON, no explanation\r\n\r\nOutput format: { \"POST /path\": { \"field1\": \"value1\", \"field2\": 123 } }`;\r\n\r\n let user = `Module: ${moduleName}\r\n\r\n=== Write Endpoints ===\r\n${writeEndpoints || '(none)'}\r\n\r\n=== DTO Definitions ===\r\n${dtoSummary || '(no DTOs found)'}`;\r\n\r\n if (options.exampleConfig?.bodyTemplates) {\r\n user += `\\n\\n=== Example (verified) ===\\n${JSON.stringify(options.exampleConfig.bodyTemplates, null, 2)}`;\r\n }\r\n\r\n if (previousError) {\r\n user += `\\n\\n=== Previous failure reason ===\\n${previousError}\\nPlease fix and regenerate.`;\r\n }\r\n\r\n user += '\\n\\nGenerate body templates (strict JSON):';\r\n\r\n return { system, user };\r\n}\r\n\r\nfunction buildParamRewritePrompt(\r\n options: EnhancedGenerateOptions,\r\n): { system: string; user: string } {\r\n const { moduleName, endpoints } = options;\r\n\r\n const paramEndpoints = endpoints\r\n .filter((e) => e.pathParams && e.pathParams.length > 0)\r\n .map((e) => `${e.method} ${e.path} → params: [${e.pathParams!.join(', ')}]`)\r\n .join('\\n');\r\n\r\n const system = `You are an API path analysis expert. Map generic :id parameters to semantic names.\r\nRules:\r\n1. Map :id to semantic names based on path segment: /categories/:id → categoryId\r\n2. Only process paths with :id or similar generic params\r\n3. Output ONLY strict JSON. No explanation.\r\n\r\nOutput format: { \"GET /path/:id\": { \"id\": \"semanticId\" } }`;\r\n\r\n const user = `Module: ${moduleName}\\n\\nEndpoints with path params:\\n${paramEndpoints || '(none)'}\\n\\nGenerate param rewrites (strict JSON):`;\r\n\r\n return { system, user };\r\n}\r\n\r\nfunction buildSeedPrompt(\r\n options: EnhancedGenerateOptions,\r\n bodyTemplates: Record<string, Record<string, unknown>>,\r\n): { system: string; user: string } {\r\n const { moduleName, endpoints, dtos } = options;\r\n\r\n const allEndpoints = endpoints.map((e) => `${e.method} ${e.path}`).join('\\n');\r\n\r\n const dtoSummary = (dtos || [])\r\n .map((dto) => {\r\n const fields = dto.fields\r\n .filter((f) => !f.isSystemField)\r\n .map((f) => `${f.name}(${f.type}${f.required ? ',required' : ''})`)\r\n .join(', ');\r\n return `${dto.name}: [${fields}]`;\r\n })\r\n .join('\\n');\r\n\r\n const system = `You are a test data dependency analysis expert. Generate beforeAll seed steps.\r\n\r\nStrict rules:\r\n1. Use only existing API paths from the endpoint list\r\n2. Main resources first, then sub-resources\r\n3. Use captureAs to mark IDs to capture\r\n4. dependsOn must reference previously captured variables\r\n5. required: true for essential steps\r\n6. body must match DTO definitions\r\n7. step numbers from 1, consecutive\r\n8. Output ONLY strict JSON array. No explanation.\r\n\r\nOutput format: [{ \"step\": 1, \"method\": \"POST\", \"path\": \"/path\", \"body\": {}, \"captureAs\": \"id\", \"required\": true, \"dependsOn\": [], \"failureMessage\": \"...\" }]`;\r\n\r\n let user = `Module: ${moduleName}\r\n\r\n=== All API Endpoints ===\r\n${allEndpoints}\r\n\r\n=== DTO Definitions ===\r\n${dtoSummary || '(no DTOs)'}\r\n\r\n=== Generated Body Templates ===\r\n${JSON.stringify(bodyTemplates, null, 2)}`;\r\n\r\n user += '\\n\\nGenerate seed config (strict JSON array):';\r\n\r\n return { system, user };\r\n}\r\n\r\n// ============================================================\r\n// ID Alias Derivation\r\n// ============================================================\r\n\r\nfunction deriveIdAliases(\r\n paramRewrites: Record<string, Record<string, string>>,\r\n): Array<{ pathPattern: string; alias: string }> {\r\n const aliases: Array<{ pathPattern: string; alias: string }> = [];\r\n const seen = new Set<string>();\r\n\r\n for (const [key, mapping] of Object.entries(paramRewrites)) {\r\n const spaceIdx = key.indexOf(' ');\r\n if (spaceIdx === -1) continue;\r\n const routePath = key.substring(spaceIdx + 1);\r\n\r\n for (const [param, alias] of Object.entries(mapping)) {\r\n if (param === 'id' && !seen.has(alias)) {\r\n const segments = routePath.split('/');\r\n const idIdx = segments.findIndex((s) => s === `:${param}`);\r\n if (idIdx > 0) {\r\n aliases.push({ pathPattern: segments[idIdx - 1], alias });\r\n seen.add(alias);\r\n }\r\n }\r\n }\r\n }\r\n\r\n return aliases;\r\n}\r\n\r\n// ============================================================\r\n// Main Flow\r\n// ============================================================\r\n\r\n/**\r\n * Generate module test config with enhanced prompts and retry logic.\r\n */\r\nexport async function generateEnhancedConfig(\r\n options: EnhancedGenerateOptions,\r\n): Promise<EnhancedGenerateResult> {\r\n const {\r\n moduleName,\r\n llmProvider,\r\n maxRetries = 3,\r\n timeout = 30000,\r\n } = options;\r\n\r\n const allAttempts: AttemptRecord[] = [];\r\n\r\n console.log(`[enhanced-suggester] Generating config for \"${moduleName}\"...`);\r\n console.log(`[enhanced-suggester] ${options.dtos?.length ?? 0} DTOs, ${options.endpoints.length} endpoints`);\r\n\r\n try {\r\n // Step 1: bodyTemplates\r\n const bodyPrompt = buildBodyTemplatePrompt(options);\r\n const bodyResult = await callAIWithRetry(llmProvider, bodyPrompt.system, bodyPrompt.user, {\r\n maxRetries, timeout, phase: 'body',\r\n });\r\n allAttempts.push(...bodyResult.attempts);\r\n const bodyTemplates: Record<string, Record<string, unknown>> =\r\n typeof bodyResult.json === 'object' && !Array.isArray(bodyResult.json)\r\n ? bodyResult.json as Record<string, Record<string, unknown>>\r\n : {};\r\n\r\n // Step 2: paramRewrites\r\n const paramPrompt = buildParamRewritePrompt(options);\r\n const paramResult = await callAIWithRetry(llmProvider, paramPrompt.system, paramPrompt.user, {\r\n maxRetries, timeout, phase: 'param',\r\n });\r\n allAttempts.push(...paramResult.attempts);\r\n const paramRewrites: Record<string, Record<string, string>> =\r\n typeof paramResult.json === 'object' && !Array.isArray(paramResult.json)\r\n ? paramResult.json as Record<string, Record<string, string>>\r\n : {};\r\n\r\n // Step 3: seed\r\n const seedPrompt = buildSeedPrompt(options, bodyTemplates);\r\n const seedResult = await callAIWithRetry(llmProvider, seedPrompt.system, seedPrompt.user, {\r\n maxRetries, timeout, phase: 'seed',\r\n });\r\n allAttempts.push(...seedResult.attempts);\r\n const seed: SeedStep[] = Array.isArray(seedResult.json) ? seedResult.json as SeedStep[] : [];\r\n\r\n const idAliases = deriveIdAliases(paramRewrites);\r\n\r\n const config: ModuleTestConfig = {\r\n moduleName,\r\n version: '1.0.0',\r\n generatedAt: new Date().toISOString(),\r\n bodyTemplates,\r\n paramRewrites,\r\n idAliases,\r\n specialUrls: {},\r\n seed,\r\n };\r\n\r\n return { success: true, config, attempts: allAttempts };\r\n } catch (err: unknown) {\r\n const errorAttempts = (err as { attempts?: AttemptRecord[] }).attempts || [];\r\n allAttempts.push(...errorAttempts);\r\n\r\n return {\r\n success: false,\r\n attempts: allAttempts,\r\n error: (err as Error).message || String(err),\r\n };\r\n }\r\n}\r\n","/**\r\n * Auto-Fixer — automatic config repair based on validation errors.\r\n *\r\n * Four fix strategies:\r\n * 1. InterfacePathMismatchFixer: find the closest matching real route\r\n * 2. MissingDtoFieldFixer: fill in missing required fields from DTO\r\n * 3. SeedDependencyOrderFixer: topological sort of seed steps\r\n * 4. ParamMappingFixer: regenerate paramRewrites from actual routes\r\n */\r\n\r\nimport type {\r\n ModuleTestConfig,\r\n SeedStep,\r\n ApiEndpoint,\r\n DTOFieldInfo,\r\n FixContext,\r\n FixHistoryEntry,\r\n FixResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationContext,\r\n} from '../types.js';\r\nimport { validateModuleConfig } from '../validators/config-validator.js';\r\n\r\n// ============================================================\r\n// Strategy Interface\r\n// ============================================================\r\n\r\ninterface FixStrategy {\r\n name: string;\r\n applies: (error: ModuleConfigValidationError) => boolean;\r\n fix: (config: ModuleTestConfig, error: ModuleConfigValidationError, context: FixContext) => ModuleTestConfig;\r\n priority: number;\r\n}\r\n\r\n// ============================================================\r\n// Utils\r\n// ============================================================\r\n\r\nfunction deepClone<T>(obj: T): T {\r\n return JSON.parse(JSON.stringify(obj));\r\n}\r\n\r\nfunction pathSimilarity(a: string, b: string): number {\r\n const segA = a.split('/').filter(Boolean);\r\n const segB = b.split('/').filter(Boolean);\r\n let matches = 0;\r\n const maxLen = Math.max(segA.length, segB.length);\r\n if (maxLen === 0) return 1;\r\n for (let i = 0; i < Math.min(segA.length, segB.length); i++) {\r\n if (segA[i] === segB[i]) matches++;\r\n else if (segA[i].startsWith(':') || segB[i].startsWith(':')) matches += 0.5;\r\n }\r\n return matches / maxLen;\r\n}\r\n\r\nfunction findMostSimilarEndpoint(method: string, brokenPath: string, endpoints: ApiEndpoint[]): ApiEndpoint | undefined {\r\n const sameMethod = endpoints.filter((e) => e.method === method);\r\n let bestScore = 0;\r\n let bestMatch: ApiEndpoint | undefined;\r\n for (const ep of sameMethod) {\r\n const score = pathSimilarity(brokenPath, ep.path);\r\n if (score > bestScore) { bestScore = score; bestMatch = ep; }\r\n }\r\n return bestScore >= 0.5 ? bestMatch : undefined;\r\n}\r\n\r\nfunction segmentToIdName(segment: string): string {\r\n const clean = segment.replace(/^aigc-/, '');\r\n const parts = clean.split('-');\r\n if (parts.length === 1) return parts[0].replace(/s$/, '') + 'Id';\r\n return parts.map((p) => p[0]).join('') + 'Id';\r\n}\r\n\r\nfunction generateDefaultValue(field: DTOFieldInfo): unknown {\r\n if (field.enumValues?.length) return field.enumValues[0];\r\n switch (field.type.toLowerCase()) {\r\n case 'string': return `__e2e_${field.name}_${Date.now()}`;\r\n case 'number': return 1;\r\n case 'boolean': return true;\r\n case 'date': return new Date().toISOString();\r\n default:\r\n if (field.type.includes('[]') || field.type.includes('Array')) return [];\r\n return `__e2e_${field.name}`;\r\n }\r\n}\r\n\r\nfunction detectChangedKeys(before: ModuleTestConfig, after: ModuleTestConfig): string[] {\r\n const keys: string[] = [];\r\n const b = before as unknown as Record<string, unknown>;\r\n const a = after as unknown as Record<string, unknown>;\r\n const allKeys = new Set([...Object.keys(b), ...Object.keys(a)]);\r\n for (const key of allKeys) {\r\n if (JSON.stringify(b[key]) !== JSON.stringify(a[key])) {\r\n keys.push(key);\r\n }\r\n }\r\n return keys;\r\n}\r\n\r\n// ============================================================\r\n// Strategy 1: InterfacePathMismatchFixer\r\n// ============================================================\r\n\r\nconst interfacePathMismatchFixer: FixStrategy = {\r\n name: 'InterfacePathMismatchFixer',\r\n priority: 100,\r\n applies: (error) => error.type === 'interface-not-found' || error.type === 'param-mapping-invalid',\r\n fix: (config, error, context) => {\r\n const fixed = deepClone(config);\r\n const match = error.message.match(/['\"]?(GET|POST|PUT|DELETE|PATCH)\\s+([^'\"]+)['\"]?/);\r\n if (!match) return fixed;\r\n\r\n const [, method, brokenPath] = match;\r\n const bestMatch = findMostSimilarEndpoint(method, brokenPath, context.endpoints);\r\n if (!bestMatch) return fixed;\r\n\r\n const oldKey = `${method} ${brokenPath}`;\r\n const newKey = `${method} ${bestMatch.path}`;\r\n\r\n if (error.path.startsWith('bodyTemplates') && fixed.bodyTemplates[oldKey]) {\r\n fixed.bodyTemplates[newKey] = fixed.bodyTemplates[oldKey];\r\n delete fixed.bodyTemplates[oldKey];\r\n }\r\n if (error.path.startsWith('paramRewrites') && fixed.paramRewrites[oldKey]) {\r\n fixed.paramRewrites[newKey] = fixed.paramRewrites[oldKey];\r\n delete fixed.paramRewrites[oldKey];\r\n }\r\n if (error.path.startsWith('seed')) {\r\n for (const step of fixed.seed) {\r\n if (step.method === method && step.path === brokenPath) {\r\n step.path = bestMatch.path;\r\n }\r\n }\r\n }\r\n return fixed;\r\n },\r\n};\r\n\r\n// ============================================================\r\n// Strategy 2: MissingDtoFieldFixer\r\n// ============================================================\r\n\r\nconst missingDtoFieldFixer: FixStrategy = {\r\n name: 'MissingDtoFieldFixer',\r\n priority: 90,\r\n applies: (error) => error.type === 'field-missing' || (error.type === 'missing-field' && error.path.startsWith('bodyTemplates')),\r\n fix: (config, error, context) => {\r\n const fixed = deepClone(config);\r\n const fieldMatch = error.message.match(/field '(\\w+)'/);\r\n if (!fieldMatch) return fixed;\r\n const missingField = fieldMatch[1];\r\n\r\n const dtoMatch = error.message.match(/from (\\w+)/);\r\n const dto = dtoMatch ? context.dtos.find((d) => d.name === dtoMatch[1]) : context.dtos[0];\r\n if (!dto) return fixed;\r\n\r\n const fieldDef = dto.fields.find((f) => f.name === missingField);\r\n if (!fieldDef) return fixed;\r\n\r\n const defaultValue = generateDefaultValue(fieldDef);\r\n\r\n for (const [key, body] of Object.entries(fixed.bodyTemplates)) {\r\n const method = key.split(' ')[0];\r\n if (['POST', 'PUT', 'PATCH'].includes(method) && !(missingField in body)) {\r\n (body as Record<string, unknown>)[missingField] = defaultValue;\r\n }\r\n }\r\n return fixed;\r\n },\r\n};\r\n\r\n// ============================================================\r\n// Strategy 3: SeedDependencyOrderFixer\r\n// ============================================================\r\n\r\nconst seedDependencyOrderFixer: FixStrategy = {\r\n name: 'SeedDependencyOrderFixer',\r\n priority: 80,\r\n applies: (error) => error.type === 'dependency-missing' || error.type === 'dependency-cycle' || error.type === 'seed-order-invalid',\r\n fix: (config) => {\r\n const fixed = deepClone(config);\r\n if (!fixed.seed || fixed.seed.length === 0) return fixed;\r\n\r\n const sorted = topologicalSortSeed(fixed.seed);\r\n if (sorted) fixed.seed = sorted;\r\n return fixed;\r\n },\r\n};\r\n\r\nfunction topologicalSortSeed(seed: SeedStep[]): SeedStep[] | null {\r\n const captureToStep = new Map<string, SeedStep>();\r\n for (const step of seed) {\r\n if (step.captureAs) captureToStep.set(step.captureAs, step);\r\n }\r\n\r\n const inDegree = new Map<number, number>();\r\n const adj = new Map<number, number[]>();\r\n for (const step of seed) {\r\n inDegree.set(step.step, 0);\r\n adj.set(step.step, []);\r\n }\r\n\r\n for (const step of seed) {\r\n if (step.dependsOn) {\r\n for (const dep of step.dependsOn) {\r\n const depStep = captureToStep.get(dep);\r\n if (depStep) {\r\n adj.get(depStep.step)?.push(step.step);\r\n inDegree.set(step.step, (inDegree.get(step.step) || 0) + 1);\r\n }\r\n }\r\n }\r\n }\r\n\r\n const queue: number[] = [];\r\n for (const [stepNum, degree] of inDegree) {\r\n if (degree === 0) queue.push(stepNum);\r\n }\r\n\r\n const sorted: SeedStep[] = [];\r\n const stepMap = new Map(seed.map((s) => [s.step, s]));\r\n\r\n while (queue.length > 0) {\r\n const current = queue.shift()!;\r\n const step = stepMap.get(current);\r\n if (step) sorted.push(step);\r\n for (const next of adj.get(current) || []) {\r\n inDegree.set(next, (inDegree.get(next) || 0) - 1);\r\n if (inDegree.get(next) === 0) queue.push(next);\r\n }\r\n }\r\n\r\n if (sorted.length !== seed.length) return null; // has cycle\r\n return sorted.map((s, i) => ({ ...s, step: i + 1 }));\r\n}\r\n\r\n// ============================================================\r\n// Strategy 4: ParamMappingFixer\r\n// ============================================================\r\n\r\nconst paramMappingFixer: FixStrategy = {\r\n name: 'ParamMappingFixer',\r\n priority: 70,\r\n applies: (error) => error.type === 'param-mapping-invalid',\r\n fix: (config, _error, context) => {\r\n const fixed = deepClone(config);\r\n const newRewrites: Record<string, Record<string, string>> = {};\r\n\r\n for (const ep of context.endpoints) {\r\n if (!ep.pathParams || ep.pathParams.length === 0) continue;\r\n const key = `${ep.method} ${ep.path}`;\r\n const mapping: Record<string, string> = {};\r\n\r\n for (const param of ep.pathParams) {\r\n if (param === 'id') {\r\n const segments = ep.path.split('/');\r\n const idIdx = segments.indexOf(':id');\r\n if (idIdx > 0) {\r\n mapping[param] = segmentToIdName(segments[idIdx - 1]);\r\n }\r\n }\r\n }\r\n if (Object.keys(mapping).length > 0) newRewrites[key] = mapping;\r\n }\r\n\r\n fixed.paramRewrites = newRewrites;\r\n return fixed;\r\n },\r\n};\r\n\r\n// ============================================================\r\n// Strategy Registry (sorted by priority desc)\r\n// ============================================================\r\n\r\nconst ALL_STRATEGIES: FixStrategy[] = [\r\n interfacePathMismatchFixer,\r\n missingDtoFieldFixer,\r\n seedDependencyOrderFixer,\r\n paramMappingFixer,\r\n].sort((a, b) => b.priority - a.priority);\r\n\r\n// ============================================================\r\n// Main Fix Flow\r\n// ============================================================\r\n\r\n/**\r\n * Run automatic fix loop on a module test config.\r\n */\r\nexport function autoFix(\r\n config: ModuleTestConfig,\r\n initialErrors: ModuleConfigValidationError[],\r\n context: FixContext,\r\n validationContext?: ModuleConfigValidationContext,\r\n maxAttempts = 3,\r\n): FixResult {\r\n const history: FixHistoryEntry[] = [];\r\n let currentConfig = deepClone(config);\r\n let currentErrors = initialErrors.filter((e) => e.layer !== 'dryrun');\r\n\r\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\r\n if (currentErrors.length === 0) break;\r\n\r\n let fixApplied = false;\r\n\r\n for (const error of [...currentErrors]) {\r\n const strategy = ALL_STRATEGIES.find((s) => s.applies(error));\r\n if (!strategy) continue;\r\n\r\n const before = currentConfig;\r\n currentConfig = strategy.fix(currentConfig, error, context);\r\n fixApplied = true;\r\n\r\n history.push({\r\n timestamp: new Date().toISOString(),\r\n attempt,\r\n errorType: error.type,\r\n errorPath: error.path,\r\n errorMessage: error.message,\r\n fixerUsed: strategy.name,\r\n changedKeys: detectChangedKeys(before, currentConfig),\r\n validationPassedAfterFix: false,\r\n });\r\n }\r\n\r\n if (!fixApplied) break;\r\n\r\n // Re-validate\r\n const revalidation = validateModuleConfig(\r\n currentConfig,\r\n validationContext,\r\n { skipLayers: ['dryrun'] },\r\n );\r\n currentErrors = revalidation.errors;\r\n\r\n if (history.length > 0) {\r\n history[history.length - 1].validationPassedAfterFix = currentErrors.length === 0;\r\n }\r\n\r\n if (currentErrors.length === 0) break;\r\n }\r\n\r\n return {\r\n success: currentErrors.length === 0,\r\n config: currentConfig,\r\n totalAttempts: history.length,\r\n history,\r\n remainingErrors: currentErrors,\r\n };\r\n}\r\n","/**\r\n * Baseline Comparator — compare AI-generated test runs against hardcoded baselines.\r\n *\r\n * Workflow:\r\n * 1. Parse Playwright JSON reports from both baseline and AI-config runs\r\n * 2. Diff each test case: regression / improvement / unchanged / new / removed\r\n * 3. Generate prompt optimization suggestions from failure patterns\r\n * 4. Output formatted comparison report\r\n */\r\n\r\n\r\n\r\n// ============================================================\r\n// Types\r\n// ============================================================\r\n\r\nexport interface TestCaseResult {\r\n title: string;\r\n file: string;\r\n suite: string;\r\n status: 'passed' | 'failed' | 'skipped' | 'timedOut';\r\n durationMs: number;\r\n error?: string;\r\n}\r\n\r\nexport interface TestRunSummary {\r\n label: string;\r\n timestamp: string;\r\n modules: string[];\r\n total: number;\r\n passed: number;\r\n failed: number;\r\n skipped: number;\r\n timedOut: number;\r\n passRate: number;\r\n totalDurationMs: number;\r\n avgDurationMs: number;\r\n cases: TestCaseResult[];\r\n}\r\n\r\nexport interface CaseDiff {\r\n title: string;\r\n file: string;\r\n change: 'regression' | 'improvement' | 'unchanged' | 'new' | 'removed';\r\n baselineStatus: TestCaseResult['status'] | null;\r\n aiConfigStatus: TestCaseResult['status'] | null;\r\n durationDiffMs: number;\r\n error?: string;\r\n}\r\n\r\nexport interface PromptOptimization {\r\n category: 'seed-config' | 'body-template' | 'param-rewrite' | 'id-alias' | 'general';\r\n issue: string;\r\n suggestion: string;\r\n relatedCases: string[];\r\n}\r\n\r\nexport interface ComparisonReport {\r\n baseline: TestRunSummary;\r\n aiConfig: TestRunSummary;\r\n passRateDiff: number;\r\n /** AI pass rate >= 85% of baseline */\r\n meetsThreshold: boolean;\r\n durationChangePercent: number;\r\n /** Duration change within ±10% */\r\n durationAcceptable: boolean;\r\n diffs: CaseDiff[];\r\n regressions: CaseDiff[];\r\n improvements: CaseDiff[];\r\n promptOptimizations: PromptOptimization[];\r\n}\r\n\r\n// ============================================================\r\n// Playwright JSON Report Parsing\r\n// ============================================================\r\n\r\n/**\r\n * Parse a Playwright `--reporter=json` output into a TestRunSummary.\r\n */\r\nexport function parsePlaywrightReport(\r\n reportJson: Record<string, unknown>,\r\n label: string,\r\n modules: string[],\r\n): TestRunSummary {\r\n const cases: TestCaseResult[] = [];\r\n\r\n if (reportJson?.suites && Array.isArray(reportJson.suites)) {\r\n for (const suite of reportJson.suites) {\r\n extractCases(suite, suite.title || '', cases);\r\n }\r\n }\r\n\r\n return buildTestRunSummary(label, modules, cases);\r\n}\r\n\r\nfunction extractCases(suite: Record<string, unknown>, parentTitle: string, result: TestCaseResult[]): void {\r\n const suiteTitle = parentTitle\r\n ? `${parentTitle} > ${(suite.title as string) || ''}`\r\n : (suite.title as string) || '';\r\n\r\n if (Array.isArray(suite.specs)) {\r\n for (const spec of suite.specs) {\r\n for (const test of spec.tests || []) {\r\n for (const testResult of test.results || []) {\r\n result.push({\r\n title: spec.title || '',\r\n file: (suite.file as string) || '',\r\n suite: suiteTitle,\r\n status: normalizeStatus(testResult.status),\r\n durationMs: testResult.duration || 0,\r\n error: testResult.error?.message,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (Array.isArray(suite.suites)) {\r\n for (const child of suite.suites) {\r\n extractCases({ ...child, file: child.file || suite.file }, suiteTitle, result);\r\n }\r\n }\r\n}\r\n\r\nfunction normalizeStatus(status: string): TestCaseResult['status'] {\r\n switch (status) {\r\n case 'passed': case 'expected': return 'passed';\r\n case 'failed': case 'unexpected': return 'failed';\r\n case 'skipped': return 'skipped';\r\n case 'timedOut': return 'timedOut';\r\n default: return 'failed';\r\n }\r\n}\r\n\r\n/**\r\n * Build a TestRunSummary from raw test case results.\r\n */\r\nexport function buildTestRunSummary(label: string, modules: string[], cases: TestCaseResult[]): TestRunSummary {\r\n const passed = cases.filter((c) => c.status === 'passed').length;\r\n const failed = cases.filter((c) => c.status === 'failed').length;\r\n const skipped = cases.filter((c) => c.status === 'skipped').length;\r\n const timedOut = cases.filter((c) => c.status === 'timedOut').length;\r\n const totalDurationMs = cases.reduce((s, c) => s + c.durationMs, 0);\r\n\r\n return {\r\n label,\r\n timestamp: new Date().toISOString(),\r\n modules,\r\n total: cases.length,\r\n passed, failed, skipped, timedOut,\r\n passRate: cases.length > 0 ? passed / cases.length : 0,\r\n totalDurationMs,\r\n avgDurationMs: cases.length > 0 ? Math.round(totalDurationMs / cases.length) : 0,\r\n cases,\r\n };\r\n}\r\n\r\n// ============================================================\r\n// Comparison\r\n// ============================================================\r\n\r\n/**\r\n * Compare two test runs and produce a detailed comparison report.\r\n */\r\nexport function compareTestRuns(baseline: TestRunSummary, aiConfig: TestRunSummary): ComparisonReport {\r\n const baselineMap = new Map(baseline.cases.map((c) => [caseKey(c), c]));\r\n const aiMap = new Map(aiConfig.cases.map((c) => [caseKey(c), c]));\r\n\r\n const allKeys = new Set([...baselineMap.keys(), ...aiMap.keys()]);\r\n const diffs: CaseDiff[] = [];\r\n\r\n for (const key of allKeys) {\r\n const base = baselineMap.get(key) ?? null;\r\n const ai = aiMap.get(key) ?? null;\r\n\r\n diffs.push({\r\n title: base?.title ?? ai?.title ?? key,\r\n file: base?.file ?? ai?.file ?? '',\r\n change: classifyChange(base?.status ?? null, ai?.status ?? null),\r\n baselineStatus: base?.status ?? null,\r\n aiConfigStatus: ai?.status ?? null,\r\n durationDiffMs: (ai?.durationMs ?? 0) - (base?.durationMs ?? 0),\r\n error: ai?.error,\r\n });\r\n }\r\n\r\n const regressions = diffs.filter((d) => d.change === 'regression');\r\n const improvements = diffs.filter((d) => d.change === 'improvement');\r\n const passRateDiff = aiConfig.passRate - baseline.passRate;\r\n const meetsThreshold = baseline.passRate > 0 ? aiConfig.passRate >= baseline.passRate * 0.85 : true;\r\n const durationChangePercent = baseline.totalDurationMs > 0\r\n ? ((aiConfig.totalDurationMs - baseline.totalDurationMs) / baseline.totalDurationMs) * 100\r\n : 0;\r\n\r\n return {\r\n baseline,\r\n aiConfig,\r\n passRateDiff,\r\n meetsThreshold,\r\n durationChangePercent,\r\n durationAcceptable: Math.abs(durationChangePercent) <= 10,\r\n diffs,\r\n regressions,\r\n improvements,\r\n promptOptimizations: analyzeFailures(regressions),\r\n };\r\n}\r\n\r\nfunction caseKey(c: TestCaseResult): string {\r\n return `${c.file}::${c.title}`;\r\n}\r\n\r\nfunction classifyChange(\r\n base: TestCaseResult['status'] | null,\r\n ai: TestCaseResult['status'] | null,\r\n): CaseDiff['change'] {\r\n if (!base) return 'new';\r\n if (!ai) return 'removed';\r\n if (base === ai) return 'unchanged';\r\n if (base === 'passed' && ai !== 'passed') return 'regression';\r\n if (base !== 'passed' && ai === 'passed') return 'improvement';\r\n return 'unchanged';\r\n}\r\n\r\n// ============================================================\r\n// Failure Analysis → Prompt Optimization\r\n// ============================================================\r\n\r\nfunction analyzeFailures(regressions: CaseDiff[]): PromptOptimization[] {\r\n const optimizations: PromptOptimization[] = [];\r\n const seedKw = ['seed', 'beforeall', 'setup', 'beforeeach'];\r\n const bodyKw = ['body', 'required', 'validation', '400', 'bad request', 'field'];\r\n const paramKw = ['param', ':id', 'undefined', 'null', '404', 'not found'];\r\n\r\n const seedFails = regressions.filter((r) => r.error && seedKw.some((k) => r.error!.toLowerCase().includes(k)));\r\n const bodyFails = regressions.filter((r) => r.error && bodyKw.some((k) => r.error!.toLowerCase().includes(k)));\r\n const paramFails = regressions.filter((r) => r.error && paramKw.some((k) => r.error!.toLowerCase().includes(k)));\r\n\r\n if (seedFails.length > 0) {\r\n optimizations.push({\r\n category: 'seed-config',\r\n issue: `${seedFails.length} test(s) regressed due to seed data preparation failures`,\r\n suggestion: 'Ensure AI-generated seed paths match actual API routes and dependency order is correct.',\r\n relatedCases: seedFails.map((r) => r.title),\r\n });\r\n }\r\n\r\n if (bodyFails.length > 0) {\r\n optimizations.push({\r\n category: 'body-template',\r\n issue: `${bodyFails.length} test(s) regressed due to incomplete body templates`,\r\n suggestion: 'List all required fields in prompts, include DTO enum constraints.',\r\n relatedCases: bodyFails.map((r) => r.title),\r\n });\r\n }\r\n\r\n if (paramFails.length > 0) {\r\n optimizations.push({\r\n category: 'param-rewrite',\r\n issue: `${paramFails.length} test(s) regressed due to parameter mapping errors`,\r\n suggestion: 'Explicitly define :id → semantic name mappings in prompts.',\r\n relatedCases: paramFails.map((r) => r.title),\r\n });\r\n }\r\n\r\n const other = regressions.filter(\r\n (r) => !seedFails.includes(r) && !bodyFails.includes(r) && !paramFails.includes(r),\r\n );\r\n if (other.length > 0) {\r\n optimizations.push({\r\n category: 'general',\r\n issue: `${other.length} test(s) regressed due to other reasons`,\r\n suggestion: 'Inspect individual error messages for business logic or data dependency issues.',\r\n relatedCases: other.map((r) => r.title),\r\n });\r\n }\r\n\r\n return optimizations;\r\n}\r\n\r\n// ============================================================\r\n// Report Formatting\r\n// ============================================================\r\n\r\n/**\r\n * Format a ComparisonReport into human-readable text.\r\n */\r\nexport function formatComparisonReport(report: ComparisonReport): string {\r\n const lines: string[] = [];\r\n\r\n lines.push('═'.repeat(60));\r\n lines.push(' Baseline Comparison Report');\r\n lines.push('═'.repeat(60), '');\r\n\r\n lines.push('┌─ Pass Rate ────────────────────────────────────┐');\r\n lines.push(`│ Baseline (${report.baseline.label}): ${(report.baseline.passRate * 100).toFixed(1)}% (${report.baseline.passed}/${report.baseline.total})`);\r\n lines.push(`│ AI Config (${report.aiConfig.label}): ${(report.aiConfig.passRate * 100).toFixed(1)}% (${report.aiConfig.passed}/${report.aiConfig.total})`);\r\n lines.push(`│ Diff: ${report.passRateDiff >= 0 ? '+' : ''}${(report.passRateDiff * 100).toFixed(1)}pp`);\r\n lines.push(`│ Meets threshold (≥ 85%): ${report.meetsThreshold ? '✓' : '✗'}`);\r\n lines.push('└────────────────────────────────────────────────┘', '');\r\n\r\n lines.push('┌─ Duration ─────────────────────────────────────┐');\r\n lines.push(`│ Baseline: ${(report.baseline.totalDurationMs / 1000).toFixed(2)}s`);\r\n lines.push(`│ AI Config: ${(report.aiConfig.totalDurationMs / 1000).toFixed(2)}s`);\r\n lines.push(`│ Change: ${report.durationChangePercent >= 0 ? '+' : ''}${report.durationChangePercent.toFixed(1)}%`);\r\n lines.push(`│ Acceptable (±10%): ${report.durationAcceptable ? '✓' : '✗'}`);\r\n lines.push('└────────────────────────────────────────────────┘', '');\r\n\r\n if (report.regressions.length > 0) {\r\n lines.push(`⚠ Regressions (${report.regressions.length}):`);\r\n for (const r of report.regressions) {\r\n lines.push(` ✗ ${r.title}`);\r\n if (r.error) lines.push(` Error: ${r.error.substring(0, 100)}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n if (report.improvements.length > 0) {\r\n lines.push(`✓ Improvements (${report.improvements.length}):`);\r\n for (const imp of report.improvements) lines.push(` ✓ ${imp.title}`);\r\n lines.push('');\r\n }\r\n\r\n if (report.promptOptimizations.length > 0) {\r\n lines.push('─'.repeat(60));\r\n lines.push(' Prompt Optimization Suggestions');\r\n lines.push('─'.repeat(60));\r\n for (const opt of report.promptOptimizations) {\r\n lines.push(`\\n [${opt.category}] ${opt.issue}`);\r\n lines.push(` Suggestion: ${opt.suggestion}`);\r\n lines.push(` Related: ${opt.relatedCases.join(', ')}`);\r\n }\r\n }\r\n\r\n lines.push('', '═'.repeat(60));\r\n return lines.join('\\n');\r\n}\r\n","/**\r\n * Module Config Preset Loader\r\n *\r\n * Loads pre-generated module test configs (JSON) from a directory,\r\n * validates them, and provides lookup by module name.\r\n *\r\n * This supports the 70 module configs migrated from dynamic-gen/module-configs/.\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\nimport type { ModuleTestConfig } from '../types.js';\r\nimport { validateModuleConfig } from '../validators/config-validator.js';\r\n\r\nexport interface PresetLoadResult {\r\n configs: Map<string, ModuleTestConfig>;\r\n errors: Array<{ file: string; error: string }>;\r\n totalLoaded: number;\r\n totalFailed: number;\r\n}\r\n\r\n/**\r\n * Load all module config presets from a directory.\r\n *\r\n * @param configDir - Path to directory containing *.json module configs\r\n * @param options.validate - Run schema validation on each config (default: true)\r\n * @returns Loaded configs indexed by moduleName\r\n */\r\nexport function loadModulePresets(\r\n configDir: string,\r\n options?: { validate?: boolean },\r\n): PresetLoadResult {\r\n const doValidate = options?.validate ?? true;\r\n const configs = new Map<string, ModuleTestConfig>();\r\n const errors: Array<{ file: string; error: string }> = [];\r\n\r\n const absDir = path.resolve(configDir);\r\n if (!fs.existsSync(absDir)) {\r\n return { configs, errors: [{ file: absDir, error: 'Directory does not exist' }], totalLoaded: 0, totalFailed: 1 };\r\n }\r\n\r\n const files = fs.readdirSync(absDir).filter((f) => f.endsWith('.json') && !f.includes('.fix-history'));\r\n\r\n for (const file of files) {\r\n const filePath = path.join(absDir, file);\r\n try {\r\n const content = fs.readFileSync(filePath, 'utf-8');\r\n const config: ModuleTestConfig = JSON.parse(content);\r\n\r\n if (!config.moduleName) {\r\n errors.push({ file, error: 'Missing moduleName field' });\r\n continue;\r\n }\r\n\r\n // Optional validation\r\n if (doValidate) {\r\n const result = validateModuleConfig(config, undefined, { skipLayers: ['semantic', 'dryrun'] });\r\n if (!result.passed) {\r\n const errorMsgs = result.errors.map((e) => `[${e.path}] ${e.message}`).join('; ');\r\n errors.push({ file, error: `Schema validation failed: ${errorMsgs}` });\r\n // Still load it — it's usable even with warnings\r\n }\r\n }\r\n\r\n configs.set(config.moduleName, config);\r\n } catch (err) {\r\n errors.push({ file, error: (err as Error).message });\r\n }\r\n }\r\n\r\n return {\r\n configs,\r\n errors,\r\n totalLoaded: configs.size,\r\n totalFailed: errors.length,\r\n };\r\n}\r\n\r\n/**\r\n * Get a single module config by name from a preset directory.\r\n */\r\nexport function getModulePreset(\r\n configDir: string,\r\n moduleName: string,\r\n): ModuleTestConfig | null {\r\n const filePath = path.resolve(configDir, `${moduleName}.json`);\r\n if (!fs.existsSync(filePath)) return null;\r\n\r\n try {\r\n const content = fs.readFileSync(filePath, 'utf-8');\r\n return JSON.parse(content);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * List all available module preset names from a directory.\r\n */\r\nexport function listModulePresets(configDir: string): string[] {\r\n const absDir = path.resolve(configDir);\r\n if (!fs.existsSync(absDir)) return [];\r\n\r\n return fs.readdirSync(absDir)\r\n .filter((f) => f.endsWith('.json') && !f.includes('.fix-history'))\r\n .map((f) => f.replace(/\\.json$/, ''));\r\n}\r\n","import type { SelfHealingConfig, SelfHealingResult, FixOutcome, LlmProvider } from '../types.js';\r\nimport { SYSTEM_PROMPTS } from '../llm/index.js';\r\n\r\nexport type { SelfHealingResult, FixOutcome };\r\n\r\n// Advanced Self-Healing (v1.1)\r\nexport { runDialogLoop, createJsonResultParser } from './dialog-loop-runner.js';\r\nexport type { TestRunner, ResultParser, FixApplier, DialogLoopOptions } from './dialog-loop-runner.js';\r\nexport { applyControlledFix } from './controlled-fixer.js';\r\nexport type { ConfigValidator, ConfigFixer, PRGenerator, FsOps, ControlledFixerOptions } from './controlled-fixer.js';\r\nexport { generateFixPR } from './auto-fix-generator.js';\r\nexport type { GitExecutor, PatchWriter } from './auto-fix-generator.js';\r\n\r\nexport interface SelfHealingLoop {\r\n run(testResultsDir: string): Promise<SelfHealingResult>;\r\n}\r\n\r\nexport interface SelfHealingOptions {\r\n config: SelfHealingConfig;\r\n llm?: LlmProvider;\r\n}\r\n\r\n/**\r\n * Categorize a test failure by heuristic rules.\r\n */\r\nexport function categorizeFailure(errorMessage: string): {\r\n category: string;\r\n confidence: number;\r\n} {\r\n const msg = errorMessage.toLowerCase();\r\n\r\n if (/5\\d{2}|internal server error/.test(msg))\r\n return { category: 'backend-5xx', confidence: 0.9 };\r\n if (/timeout|timed?\\s*out/.test(msg))\r\n return { category: 'timeout', confidence: 0.8 };\r\n if (/404|not found/.test(msg))\r\n return { category: 'endpoint-not-found', confidence: 0.85 };\r\n if (/4[0-2]\\d|validation|constraint/.test(msg))\r\n return { category: 'data-constraint', confidence: 0.75 };\r\n if (/econnrefused|enotfound|network/.test(msg))\r\n return { category: 'network', confidence: 0.9 };\r\n if (/selector|locator|element/.test(msg))\r\n return { category: 'frontend-render', confidence: 0.7 };\r\n if (/storage\\s*state|auth|login/.test(msg))\r\n return { category: 'test-script', confidence: 0.8 };\r\n\r\n return { category: 'unknown', confidence: 0.5 };\r\n}\r\n\r\n/**\r\n * LLM-enhanced failure analysis with heuristic fallback.\r\n */\r\nexport async function analyzeFailureWithLLM(\r\n errorMessage: string,\r\n llm?: LlmProvider,\r\n): Promise<{ rootCause: string; category: string; suggestedFix: string; confidence: number }> {\r\n // Always get heuristic result as fallback\r\n const heuristic = categorizeFailure(errorMessage);\r\n\r\n if (!llm) {\r\n return {\r\n rootCause: errorMessage,\r\n category: heuristic.category,\r\n suggestedFix: '',\r\n confidence: heuristic.confidence,\r\n };\r\n }\r\n\r\n try {\r\n const response = await llm.chat([\r\n { role: 'system', content: SYSTEM_PROMPTS.failureAnalysis },\r\n { role: 'user', content: `Analyze this test failure:\\n\\n${errorMessage}` },\r\n ]);\r\n\r\n const parsed = JSON.parse(response) as {\r\n rootCause?: string;\r\n category?: string;\r\n suggestedFix?: string;\r\n confidence?: number;\r\n };\r\n\r\n return {\r\n rootCause: parsed.rootCause || errorMessage,\r\n category: parsed.category || heuristic.category,\r\n suggestedFix: parsed.suggestedFix || '',\r\n confidence: parsed.confidence || heuristic.confidence,\r\n };\r\n } catch {\r\n // LLM failed — fall back to heuristic\r\n return {\r\n rootCause: errorMessage,\r\n category: heuristic.category,\r\n suggestedFix: '',\r\n confidence: heuristic.confidence,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Attempt a config-only fix: validate and write corrected config JSON.\r\n */\r\nasync function attemptConfigFix(\r\n _testResultsDir: string,\r\n _mode: SelfHealingConfig['mode'],\r\n _llm?: LlmProvider,\r\n): Promise<FixOutcome> {\r\n // TODO: Load module config → run autoFix validation → write corrected JSON\r\n // For now, return a no-op outcome\r\n return {\r\n success: false,\r\n scope: 'config-only',\r\n fixedItems: [],\r\n rolledBack: false,\r\n };\r\n}\r\n\r\n/**\r\n * Create a self-healing loop. Accepts an optional LLM provider for AI-enhanced analysis.\r\n */\r\nexport function createSelfHealingLoop(config: SelfHealingConfig, llm?: LlmProvider): SelfHealingLoop {\r\n return {\r\n async run(testResultsDir: string): Promise<SelfHealingResult> {\r\n const maxIterations = config.maxIterations || 3;\r\n const mode = config.mode || 'config-only';\r\n const fixed: string[] = [];\r\n const remaining: string[] = [];\r\n let iterations = 0;\r\n let totalTokensUsed = 0;\r\n\r\n for (let i = 0; i < maxIterations; i++) {\r\n iterations = i + 1;\r\n\r\n const outcome = await attemptConfigFix(testResultsDir, mode, llm);\r\n if (outcome.success) {\r\n fixed.push(...outcome.fixedItems);\r\n } else {\r\n remaining.push(`iteration-${i + 1}: no fix applied`);\r\n }\r\n\r\n // Track token usage if LLM is available\r\n if (llm) {\r\n totalTokensUsed += llm.estimateTokens(`iteration-${i + 1}`);\r\n }\r\n\r\n // If all fixed, stop early\r\n if (outcome.success && outcome.fixedItems.length > 0) break;\r\n }\r\n\r\n return {\r\n iterations,\r\n fixed,\r\n remaining,\r\n totalTokensUsed,\r\n };\r\n },\r\n };\r\n}\r\n","import type { LlmProvider, LlmConfig } from '../types.js';\r\nimport { createOpenAIProvider } from './openai.js';\r\nimport { createOllamaProvider } from './ollama.js';\r\n\r\nexport { createOpenAIProvider } from './openai.js';\r\nexport { createOllamaProvider } from './ollama.js';\r\n\r\n/**\r\n * Create an LLM provider from config.\r\n * Resolves apiKey from config or OPENCROC_LLM_API_KEY env variable.\r\n */\r\nexport function createLlmProvider(config: LlmConfig): LlmProvider {\r\n const resolved: LlmConfig = {\r\n ...config,\r\n apiKey: config.apiKey || process.env.OPENCROC_LLM_API_KEY,\r\n };\r\n\r\n switch (config.provider) {\r\n case 'openai':\r\n case 'zhipu':\r\n return createOpenAIProvider(resolved);\r\n case 'ollama':\r\n return createOllamaProvider(resolved);\r\n default:\r\n throw new Error(\r\n `Unknown LLM provider: \"${config.provider}\". Available: openai, zhipu, ollama`,\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Token usage tracker — accumulates tokens across multiple LLM calls.\r\n */\r\nexport interface TokenTracker {\r\n track(text: string): void;\r\n trackChat(messages: Array<{ role: string; content: string }>, response: string): void;\r\n total: number;\r\n reset(): void;\r\n}\r\n\r\nexport function createTokenTracker(provider: LlmProvider): TokenTracker {\r\n let total = 0;\r\n\r\n return {\r\n track(text: string) {\r\n total += provider.estimateTokens(text);\r\n },\r\n\r\n trackChat(messages: Array<{ role: string; content: string }>, response: string) {\r\n for (const msg of messages) {\r\n total += provider.estimateTokens(msg.content);\r\n }\r\n total += provider.estimateTokens(response);\r\n },\r\n\r\n get total() {\r\n return total;\r\n },\r\n\r\n reset() {\r\n total = 0;\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * System prompts for different LLM use cases in OpenCroc.\r\n */\r\nexport const SYSTEM_PROMPTS = {\r\n failureAnalysis: `You are an expert test failure analyst for an E2E testing framework.\r\nGiven a test failure error message and its context, analyze the root cause and suggest a fix.\r\nRespond in JSON format: { \"rootCause\": string, \"category\": string, \"suggestedFix\": string, \"confidence\": number }\r\nCategories: backend-5xx, timeout, endpoint-not-found, data-constraint, network, frontend-render, test-script, unknown.`,\r\n\r\n chainPlanning: `You are an API test chain planner.\r\nGiven a list of API endpoints and their dependencies, generate an optimal test execution order.\r\nConsider data dependencies, authentication requirements, and cleanup steps.\r\nRespond in JSON format: { \"chains\": [{ \"name\": string, \"steps\": [{ \"endpoint\": string, \"method\": string, \"description\": string }] }] }`,\r\n} as const;\r\n","import type { LlmProvider, LlmConfig } from '../types.js';\r\n\r\nexport interface ChatMessage {\r\n role: 'system' | 'user' | 'assistant';\r\n content: string;\r\n}\r\n\r\ninterface OpenAIResponse {\r\n choices: Array<{ message: { content: string } }>;\r\n usage?: { total_tokens: number };\r\n}\r\n\r\nconst DEFAULT_MODELS: Record<string, string> = {\r\n openai: 'gpt-4o-mini',\r\n zhipu: 'glm-4',\r\n};\r\n\r\nconst DEFAULT_BASE_URLS: Record<string, string> = {\r\n openai: 'https://api.openai.com/v1',\r\n zhipu: 'https://open.bigmodel.cn/api/paas/v4',\r\n};\r\n\r\n/**\r\n * Create an OpenAI-compatible LLM provider.\r\n * Works with OpenAI, Zhipu (GLM), and any OpenAI-compatible API.\r\n */\r\nexport function createOpenAIProvider(config: LlmConfig): LlmProvider {\r\n const provider = config.provider === 'zhipu' ? 'zhipu' : 'openai';\r\n const baseUrl = config.baseUrl || DEFAULT_BASE_URLS[provider];\r\n const model = config.model || DEFAULT_MODELS[provider];\r\n const maxTokens = config.maxTokens || 2048;\r\n const temperature = config.temperature ?? 0.3;\r\n\r\n if (!config.apiKey) {\r\n throw new Error(\r\n `API key is required for ${provider}. Set it in config or via OPENCROC_LLM_API_KEY env variable.`,\r\n );\r\n }\r\n\r\n return {\r\n name: provider,\r\n\r\n async chat(messages: Array<{ role: string; content: string }>): Promise<string> {\r\n const url = `${baseUrl}/chat/completions`;\r\n\r\n const response = await fetch(url, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Authorization': `Bearer ${config.apiKey}`,\r\n },\r\n body: JSON.stringify({\r\n model,\r\n messages,\r\n max_tokens: maxTokens,\r\n temperature,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => 'unknown error');\r\n throw new Error(`LLM API error (${response.status}): ${errorText}`);\r\n }\r\n\r\n const data = (await response.json()) as OpenAIResponse;\r\n const content = data.choices?.[0]?.message?.content;\r\n if (!content) {\r\n throw new Error('LLM returned empty response');\r\n }\r\n return content;\r\n },\r\n\r\n estimateTokens(text: string): number {\r\n // Rough estimate: ~4 chars per token for English, ~2 for CJK\r\n const cjkChars = (text.match(/[\\u4e00-\\u9fff\\u3000-\\u303f]/g) || []).length;\r\n const otherChars = text.length - cjkChars;\r\n return Math.ceil(otherChars / 4 + cjkChars / 2);\r\n },\r\n };\r\n}\r\n","import type { LlmProvider, LlmConfig } from '../types.js';\r\n\r\ninterface OllamaResponse {\r\n message: { content: string };\r\n}\r\n\r\n/**\r\n * Create an Ollama LLM provider for local model inference.\r\n */\r\nexport function createOllamaProvider(config: LlmConfig): LlmProvider {\r\n const baseUrl = config.baseUrl || 'http://localhost:11434';\r\n const model = config.model || 'llama3';\r\n\r\n return {\r\n name: 'ollama',\r\n\r\n async chat(messages: Array<{ role: string; content: string }>): Promise<string> {\r\n const url = `${baseUrl}/api/chat`;\r\n\r\n const response = await fetch(url, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n model,\r\n messages,\r\n stream: false,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => 'unknown error');\r\n throw new Error(`Ollama API error (${response.status}): ${errorText}`);\r\n }\r\n\r\n const data = (await response.json()) as OllamaResponse;\r\n const content = data.message?.content;\r\n if (!content) {\r\n throw new Error('Ollama returned empty response');\r\n }\r\n return content;\r\n },\r\n\r\n estimateTokens(text: string): number {\r\n // Same rough estimate as OpenAI provider\r\n const cjkChars = (text.match(/[\\u4e00-\\u9fff\\u3000-\\u303f]/g) || []).length;\r\n const otherChars = text.length - cjkChars;\r\n return Math.ceil(otherChars / 4 + cjkChars / 2);\r\n },\r\n };\r\n}\r\n","/**\r\n * Dialog Loop Runner — multi-iteration self-healing loop.\r\n *\r\n * Runs tests, parses results, applies controlled fixes, and reruns\r\n * until all tests pass or the maximum iteration count is reached.\r\n * Tracks error history to avoid infinite loops on recurring failures.\r\n */\r\n\r\nimport type {\r\n DialogLoopConfig,\r\n TestFailureInfo,\r\n IterationResult,\r\n DialogLoopSummary,\r\n ControlledFixOutcome,\r\n} from '../types.js';\r\n\r\n// ===== Abstractions for testability =====\r\n\r\nexport interface TestRunner {\r\n run(): Promise<{ stdout: string; exitCode: number }>;\r\n}\r\n\r\nexport interface ResultParser {\r\n parse(stdout: string): TestFailureInfo[];\r\n countTotal(stdout: string): number;\r\n}\r\n\r\nexport interface FixApplier {\r\n apply(failure: TestFailureInfo): Promise<ControlledFixOutcome>;\r\n}\r\n\r\n// ===== Defaults =====\r\n\r\nconst DEFAULTS: Required<DialogLoopConfig> = {\r\n maxIterations: 3,\r\n pollIntervalMs: 10_000,\r\n sameErrorThreshold: 2,\r\n autoRerunOnFix: true,\r\n};\r\n\r\n// ===== JSON result parser (reads Playwright JSON output) =====\r\n\r\nexport function createJsonResultParser(): ResultParser {\r\n return {\r\n parse(stdout: string): TestFailureInfo[] {\r\n const failures: TestFailureInfo[] = [];\r\n // Match pass/fail summary from Playwright output\r\n const lines = stdout.split('\\n');\r\n for (const line of lines) {\r\n // Playwright format: \" ✘ [chromium] › test.spec.ts:10:5 › suite › title\"\r\n // or stderr lines with \"Error:\" prefix\r\n const failMatch = line.match(/[✘✗×]\\s+.*?›\\s+(.+)/);\r\n if (failMatch) {\r\n failures.push({\r\n title: failMatch[1].trim(),\r\n error: failMatch[1].trim(),\r\n });\r\n }\r\n }\r\n return failures;\r\n },\r\n countTotal(stdout: string): number {\r\n // Match \"X passed\" or \"X failed\" from Playwright summary\r\n let total = 0;\r\n const passMatch = stdout.match(/(\\d+)\\s+passed/);\r\n const failMatch = stdout.match(/(\\d+)\\s+failed/);\r\n if (passMatch) total += parseInt(passMatch[1], 10);\r\n if (failMatch) total += parseInt(failMatch[1], 10);\r\n return total || 1; // at least 1 to avoid division by zero\r\n },\r\n };\r\n}\r\n\r\n// ===== Dialog Loop =====\r\n\r\nexport interface DialogLoopOptions {\r\n runner: TestRunner;\r\n parser: ResultParser;\r\n fixer: FixApplier;\r\n config?: DialogLoopConfig;\r\n onIteration?: (result: IterationResult) => void;\r\n}\r\n\r\nexport async function runDialogLoop(options: DialogLoopOptions): Promise<DialogLoopSummary> {\r\n const cfg = { ...DEFAULTS, ...options.config };\r\n const { runner, parser, fixer } = options;\r\n\r\n const history: IterationResult[] = [];\r\n const errorTracker = new Map<string, number>();\r\n\r\n for (let iteration = 1; iteration <= cfg.maxIterations + 1; iteration++) {\r\n const iterStart = Date.now();\r\n\r\n // Step 1: Run tests\r\n const { stdout } = await runner.run();\r\n\r\n // Step 2: Parse results\r\n const failures = parser.parse(stdout);\r\n const totalTests = parser.countTotal(stdout);\r\n const passed = totalTests - failures.length;\r\n\r\n const iterResult: IterationResult = {\r\n iteration,\r\n totalTests,\r\n passed,\r\n failed: failures.length,\r\n failedTests: failures.map(f => f.title),\r\n fixesApplied: [],\r\n durationMs: 0,\r\n };\r\n\r\n // Step 3: All passed → success\r\n if (failures.length === 0) {\r\n iterResult.durationMs = Date.now() - iterStart;\r\n history.push(iterResult);\r\n options.onIteration?.(iterResult);\r\n break;\r\n }\r\n\r\n // Step 4: Max iterations exceeded\r\n if (iteration > cfg.maxIterations) {\r\n iterResult.durationMs = Date.now() - iterStart;\r\n history.push(iterResult);\r\n options.onIteration?.(iterResult);\r\n break;\r\n }\r\n\r\n // Step 5: Filter out repeated errors beyond threshold\r\n const newFailures = failures.filter(f => {\r\n const key = `${f.title}::${f.error}`;\r\n const count = (errorTracker.get(key) ?? 0) + 1;\r\n errorTracker.set(key, count);\r\n return count <= cfg.sameErrorThreshold;\r\n });\r\n\r\n if (newFailures.length === 0) {\r\n iterResult.durationMs = Date.now() - iterStart;\r\n history.push(iterResult);\r\n options.onIteration?.(iterResult);\r\n break;\r\n }\r\n\r\n // Step 6: Apply controlled fixes\r\n for (const failure of newFailures) {\r\n const outcome = await fixer.apply(failure);\r\n if (outcome.success) {\r\n iterResult.fixesApplied.push(failure.title);\r\n }\r\n }\r\n\r\n iterResult.durationMs = Date.now() - iterStart;\r\n history.push(iterResult);\r\n options.onIteration?.(iterResult);\r\n\r\n // Step 7: If any fixes applied and autoRerun, continue loop\r\n if (iterResult.fixesApplied.length === 0 || !cfg.autoRerunOnFix) {\r\n break;\r\n }\r\n }\r\n\r\n const final = history[history.length - 1];\r\n const totalFixesApplied = history.reduce((sum, h) => sum + h.fixesApplied.length, 0);\r\n\r\n return {\r\n iterations: history,\r\n finalPassed: final?.passed ?? 0,\r\n finalFailed: final?.failed ?? 0,\r\n totalFixesApplied,\r\n success: (final?.failed ?? 1) === 0,\r\n };\r\n}\r\n","/**\r\n * Controlled Fixer — two-phase fix engine with safety guarantees.\r\n *\r\n * Phase A (config-only): backup → validate → fix → dry-run → write → verify → cleanup.\r\n * Phase B (config-and-source): generates a draft PR with the AI-suggested code patch.\r\n *\r\n * All mutations are reversible — failures trigger automatic rollback.\r\n */\r\n\r\nimport { existsSync, copyFileSync, readFileSync, writeFileSync, mkdirSync, unlinkSync } from 'node:fs';\r\nimport { dirname } from 'node:path';\r\nimport type {\r\n FixScope,\r\n ControlledFixOptions,\r\n ControlledFixOutcome,\r\n AIAttributionResult,\r\n} from '../types.js';\r\n\r\n// ===== Abstractions for testability =====\r\n\r\nexport interface ConfigValidator {\r\n validate(configContent: string): { passed: boolean; errors: string[] };\r\n}\r\n\r\nexport interface ConfigFixer {\r\n fix(configContent: string, errors: string[]): { success: boolean; fixedContent: string; fixedItems: string[]; remainingErrors: string[] };\r\n}\r\n\r\nexport interface PRGenerator {\r\n generate(attribution: AIAttributionResult): Promise<string>;\r\n}\r\n\r\n// ===== FS abstraction (injectable for tests) =====\r\n\r\nexport interface FsOps {\r\n exists(path: string): boolean;\r\n read(path: string): string;\r\n write(path: string, content: string): void;\r\n copy(src: string, dest: string): void;\r\n remove(path: string): void;\r\n mkdirp(dir: string): void;\r\n}\r\n\r\nconst defaultFs: FsOps = {\r\n exists: existsSync,\r\n read: (p) => readFileSync(p, 'utf-8'),\r\n write: (p, c) => { mkdirSync(dirname(p), { recursive: true }); writeFileSync(p, c, 'utf-8'); },\r\n copy: copyFileSync,\r\n remove: unlinkSync,\r\n mkdirp: (d) => mkdirSync(d, { recursive: true }),\r\n};\r\n\r\n// ===== Core =====\r\n\r\nexport interface ControlledFixerOptions {\r\n configPath: string;\r\n validator: ConfigValidator;\r\n fixer: ConfigFixer;\r\n prGenerator?: PRGenerator;\r\n attribution?: AIAttributionResult;\r\n fs?: FsOps;\r\n options?: ControlledFixOptions;\r\n}\r\n\r\nexport async function applyControlledFix(opts: ControlledFixerOptions): Promise<ControlledFixOutcome> {\r\n const fs = opts.fs ?? defaultFs;\r\n const scope: FixScope = opts.options?.scope ?? 'config-only';\r\n const dryRun = opts.options?.dryRun ?? true;\r\n const verify = opts.options?.verify ?? true;\r\n const configPath = opts.configPath;\r\n const backupPath = configPath + '.backup';\r\n\r\n // --- Phase A: Config-only fix ---\r\n\r\n // Load config\r\n if (!fs.exists(configPath)) {\r\n return { success: false, scope, fixedItems: [], rolledBack: false, error: `Config file not found: ${configPath}` };\r\n }\r\n\r\n const originalContent = fs.read(configPath);\r\n\r\n // Backup before mutation\r\n fs.write(backupPath, originalContent);\r\n\r\n // Validate current config\r\n const validation = opts.validator.validate(originalContent);\r\n\r\n if (validation.passed) {\r\n // No errors to fix\r\n cleanup(fs, backupPath);\r\n return { success: true, scope, fixedItems: [], rolledBack: false };\r\n }\r\n\r\n // Attempt fix\r\n let fixResult: ReturnType<ConfigFixer['fix']>;\r\n try {\r\n fixResult = opts.fixer.fix(originalContent, validation.errors);\r\n } catch (err) {\r\n rollback(fs, backupPath, configPath);\r\n return { success: false, scope, fixedItems: [], rolledBack: true, error: `Fix threw: ${err instanceof Error ? err.message : String(err)}` };\r\n }\r\n\r\n if (!fixResult.success) {\r\n rollback(fs, backupPath, configPath);\r\n return { success: false, scope, fixedItems: fixResult.fixedItems, rolledBack: true, error: `Remaining errors: ${fixResult.remainingErrors.join('; ')}` };\r\n }\r\n\r\n // Dry-run: validate fixed content before writing\r\n if (dryRun) {\r\n const dryValidation = opts.validator.validate(fixResult.fixedContent);\r\n if (!dryValidation.passed) {\r\n rollback(fs, backupPath, configPath);\r\n return { success: false, scope, fixedItems: fixResult.fixedItems, rolledBack: true, error: `Dry-run validation failed: ${dryValidation.errors.join('; ')}` };\r\n }\r\n }\r\n\r\n // Write fixed content\r\n fs.write(configPath, fixResult.fixedContent);\r\n\r\n // Verify after write\r\n if (verify) {\r\n const reloaded = fs.read(configPath);\r\n const postValidation = opts.validator.validate(reloaded);\r\n if (!postValidation.passed) {\r\n rollback(fs, backupPath, configPath);\r\n return { success: false, scope, fixedItems: fixResult.fixedItems, rolledBack: true, error: `Post-write verification failed: ${postValidation.errors.join('; ')}` };\r\n }\r\n }\r\n\r\n // Phase A success — clean up backup\r\n cleanup(fs, backupPath);\r\n\r\n // --- Phase B: Config-and-source (optional) ---\r\n let prUrl: string | undefined;\r\n if (scope === 'config-and-source' && opts.attribution && opts.prGenerator) {\r\n try {\r\n prUrl = await opts.prGenerator.generate(opts.attribution);\r\n } catch {\r\n // PR generation failure is non-fatal; config fix already succeeded\r\n }\r\n }\r\n\r\n return { success: true, scope, fixedItems: fixResult.fixedItems, rolledBack: false, prUrl };\r\n}\r\n\r\nfunction rollback(fs: FsOps, backupPath: string, configPath: string): void {\r\n if (fs.exists(backupPath)) {\r\n const backup = fs.read(backupPath);\r\n fs.write(configPath, backup);\r\n fs.remove(backupPath);\r\n }\r\n}\r\n\r\nfunction cleanup(fs: FsOps, backupPath: string): void {\r\n if (fs.exists(backupPath)) {\r\n fs.remove(backupPath);\r\n }\r\n}\r\n","/**\r\n * Auto-Fix PR Generator — creates draft PRs from AI attribution results.\r\n *\r\n * Flow: create branch → write patch → git apply → commit → push → gh pr create --draft.\r\n * All PRs are draft-only as a safety invariant.\r\n */\r\n\r\nimport type { AIAttributionResult, AutoFixPROptions, AutoFixPRResult } from '../types.js';\r\n\r\n// ===== Executor abstraction (injectable for tests) =====\r\n\r\nexport interface GitExecutor {\r\n exec(command: string, args: string[]): Promise<{ stdout: string; exitCode: number }>;\r\n}\r\n\r\nexport interface PatchWriter {\r\n write(path: string, content: string): Promise<void>;\r\n mkdir(dir: string): Promise<void>;\r\n}\r\n\r\n// ===== Defaults =====\r\n\r\nconst DEFAULT_OPTIONS: Required<AutoFixPROptions> = {\r\n branchPrefix: 'autofix/',\r\n baseBranch: 'main',\r\n draftOnly: true,\r\n};\r\n\r\n// ===== Core =====\r\n\r\nexport async function generateFixPR(\r\n attribution: AIAttributionResult,\r\n git: GitExecutor,\r\n patchWriter: PatchWriter,\r\n options?: AutoFixPROptions,\r\n): Promise<AutoFixPRResult> {\r\n const opts = { ...DEFAULT_OPTIONS, ...options };\r\n const ts = new Date().toISOString().replace(/[:.]/g, '-');\r\n const branch = `${opts.branchPrefix}${ts}`;\r\n const patchFile = `report/patch-${ts}.patch`;\r\n\r\n // Create branch\r\n await git.exec('git', ['checkout', '-b', branch]);\r\n\r\n // Write patch\r\n await patchWriter.mkdir('report');\r\n await patchWriter.write(patchFile, attribution.fixSuggestion.codePatch);\r\n\r\n // Apply patch (non-fatal if fails)\r\n try {\r\n await git.exec('git', ['apply', patchFile]);\r\n } catch {\r\n // Patch may not apply cleanly — continue anyway\r\n }\r\n\r\n // Stage, commit, push\r\n await git.exec('git', ['add', '.']);\r\n await git.exec('git', ['commit', '-m', `fix: AI auto-patch for \"${attribution.testName}\"`]);\r\n await git.exec('git', ['push', 'origin', branch]);\r\n\r\n // Create draft PR (always draft for safety)\r\n const prArgs = [\r\n 'pr', 'create', '--draft',\r\n '--title', `[AI Fix] ${attribution.testName}`,\r\n '--body', buildPRBody(attribution),\r\n ];\r\n const { stdout: prUrl } = await git.exec('gh', prArgs);\r\n\r\n // Return to base branch\r\n await git.exec('git', ['checkout', opts.baseBranch]);\r\n\r\n return { prUrl: prUrl.trim(), branch, patchFile };\r\n}\r\n\r\nfunction buildPRBody(a: AIAttributionResult): string {\r\n return [\r\n '## AI Auto-Fix PR',\r\n '',\r\n `**Test:** ${a.testName}`,\r\n `**Category:** ${a.category} | **Severity:** ${a.severity} | **Confidence:** ${(a.confidence * 100).toFixed(0)}%`,\r\n '',\r\n '### Root Cause',\r\n a.rootCause,\r\n '',\r\n '### Fix',\r\n a.fixSuggestion.description,\r\n '',\r\n '---',\r\n '> This PR was auto-generated by AI and **must be reviewed before merging**.',\r\n ].join('\\n');\r\n}\r\n","import type { BackendAdapter } from '../types.js';\r\nimport { parseModuleModels } from '../parsers/model-parser.js';\r\nimport { parseAssociationFile } from '../parsers/association-parser.js';\r\nimport { parseControllerDirectory } from '../parsers/controller-parser.js';\r\nimport type { TableSchema, ForeignKeyRelation, RouteEntry } from '../types.js';\r\n\r\nexport function createSequelizeAdapter(): BackendAdapter {\r\n return {\r\n name: 'sequelize',\r\n\r\n async parseModels(dir: string): Promise<TableSchema[]> {\r\n return parseModuleModels(dir);\r\n },\r\n\r\n async parseAssociations(file: string): Promise<ForeignKeyRelation[]> {\r\n return parseAssociationFile(file);\r\n },\r\n\r\n async parseControllers(dir: string): Promise<RouteEntry[]> {\r\n const endpoints = parseControllerDirectory(dir);\r\n return endpoints.map((ep) => ({\r\n method: ep.method,\r\n path: ep.path,\r\n handler: '',\r\n controllerClass: '',\r\n }));\r\n },\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport {\r\n Project,\r\n type ClassDeclaration,\r\n type PropertyDeclaration,\r\n} from 'ts-morph';\r\nimport type { BackendAdapter, TableSchema, FieldSchema, ForeignKeyRelation, RouteEntry } from '../types.js';\r\n\r\n// TypeORM decorator → field type mapping\r\nconst TYPEORM_TYPE_MAP: Record<string, string> = {\r\n 'PrimaryGeneratedColumn': 'BIGINT',\r\n 'PrimaryColumn': 'BIGINT',\r\n 'CreateDateColumn': 'DATE',\r\n 'UpdateDateColumn': 'DATE',\r\n 'DeleteDateColumn': 'DATE',\r\n 'VersionColumn': 'INTEGER',\r\n};\r\n\r\nconst TYPEORM_COLUMN_TYPE_MAP: Record<string, string> = {\r\n 'varchar': 'STRING',\r\n 'text': 'TEXT',\r\n 'int': 'INTEGER',\r\n 'integer': 'INTEGER',\r\n 'bigint': 'BIGINT',\r\n 'float': 'FLOAT',\r\n 'double': 'DOUBLE',\r\n 'decimal': 'DECIMAL',\r\n 'boolean': 'BOOLEAN',\r\n 'bool': 'BOOLEAN',\r\n 'date': 'DATEONLY',\r\n 'datetime': 'DATE',\r\n 'timestamp': 'DATE',\r\n 'json': 'JSON',\r\n 'jsonb': 'JSONB',\r\n 'enum': 'ENUM',\r\n 'uuid': 'UUID',\r\n};\r\n\r\nfunction tsTypeToFieldType(tsType: string): string {\r\n const t = tsType.toLowerCase().trim();\r\n if (t === 'string') return 'STRING';\r\n if (t === 'number') return 'INTEGER';\r\n if (t === 'boolean') return 'BOOLEAN';\r\n if (t === 'date') return 'DATE';\r\n return 'STRING';\r\n}\r\n\r\nfunction classNameToTableName(name: string): string {\r\n return name.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\r\n}\r\n\r\nfunction extractDecoratorStringArg(decoratorText: string): string | undefined {\r\n const match = decoratorText.match(/\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/);\r\n return match?.[1];\r\n}\r\n\r\nfunction extractDecoratorObjectArg(decoratorText: string): Record<string, string> {\r\n const result: Record<string, string> = {};\r\n const objMatch = decoratorText.match(/\\(\\s*\\{([^}]*)\\}\\s*\\)/);\r\n if (!objMatch) return result;\r\n const body = objMatch[1];\r\n const pairs = body.matchAll(/(\\w+)\\s*:\\s*['\"]([^'\"]*)['\"]/g);\r\n for (const pair of pairs) {\r\n result[pair[1]] = pair[2];\r\n }\r\n // Also match non-string values like nullable: true\r\n const boolPairs = body.matchAll(/(\\w+)\\s*:\\s*(true|false)/g);\r\n for (const pair of boolPairs) {\r\n result[pair[1]] = pair[2];\r\n }\r\n return result;\r\n}\r\n\r\nexport function parseTypeORMFile(filePath: string): TableSchema | null {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return null;\r\n\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const classes = sourceFile.getClasses();\r\n for (const cls of classes) {\r\n const entityDecorator = cls.getDecorator('Entity');\r\n if (!entityDecorator) continue;\r\n\r\n const tableName = extractDecoratorStringArg(entityDecorator.getText())\r\n || extractDecoratorObjectArg(entityDecorator.getText()).name\r\n || classNameToTableName(cls.getName() || 'unknown');\r\n\r\n const fields = extractTypeORMFields(cls);\r\n return { tableName, className: cls.getName(), fields };\r\n }\r\n return null;\r\n}\r\n\r\nfunction extractTypeORMFields(cls: ClassDeclaration): FieldSchema[] {\r\n const fields: FieldSchema[] = [];\r\n\r\n for (const prop of cls.getProperties()) {\r\n const field = parseTypeORMProperty(prop);\r\n if (field) fields.push(field);\r\n }\r\n return fields;\r\n}\r\n\r\nfunction parseTypeORMProperty(prop: PropertyDeclaration): FieldSchema | null {\r\n const decorators = prop.getDecorators();\r\n if (decorators.length === 0) return null;\r\n\r\n const name = prop.getName();\r\n let type = 'STRING';\r\n let primaryKey = false;\r\n let allowNull = true;\r\n let unique = false;\r\n\r\n for (const dec of decorators) {\r\n const decName = dec.getName();\r\n const decText = dec.getText();\r\n\r\n if (decName === 'PrimaryGeneratedColumn' || decName === 'PrimaryColumn') {\r\n primaryKey = true;\r\n type = TYPEORM_TYPE_MAP[decName] || 'BIGINT';\r\n allowNull = false;\r\n const argType = extractDecoratorStringArg(decText);\r\n if (argType === 'uuid') type = 'UUID';\r\n if (argType === 'increment') type = 'BIGINT';\r\n }\r\n\r\n if (decName === 'Column') {\r\n const objArgs = extractDecoratorObjectArg(decText);\r\n if (objArgs.type && TYPEORM_COLUMN_TYPE_MAP[objArgs.type]) {\r\n type = TYPEORM_COLUMN_TYPE_MAP[objArgs.type];\r\n } else {\r\n const simpleType = extractDecoratorStringArg(decText);\r\n if (simpleType && TYPEORM_COLUMN_TYPE_MAP[simpleType]) {\r\n type = TYPEORM_COLUMN_TYPE_MAP[simpleType];\r\n }\r\n }\r\n if (objArgs.nullable === 'false') allowNull = false;\r\n if (objArgs.unique === 'true') unique = true;\r\n\r\n // Fall back to TS type annotation\r\n if (type === 'STRING') {\r\n const tsType = prop.getType().getText();\r\n type = tsTypeToFieldType(tsType);\r\n }\r\n }\r\n\r\n if (decName in TYPEORM_TYPE_MAP) {\r\n type = TYPEORM_TYPE_MAP[decName];\r\n }\r\n\r\n if (decName === 'CreateDateColumn' || decName === 'UpdateDateColumn' || decName === 'DeleteDateColumn') {\r\n allowNull = true;\r\n }\r\n }\r\n\r\n // Skip properties without any recognized TypeORM decorator\r\n const recognizedDecorators = ['Column', 'PrimaryGeneratedColumn', 'PrimaryColumn',\r\n 'CreateDateColumn', 'UpdateDateColumn', 'DeleteDateColumn', 'VersionColumn',\r\n 'ManyToOne', 'OneToMany', 'OneToOne', 'ManyToMany', 'JoinColumn', 'JoinTable'];\r\n const hasRecognized = decorators.some((d) => recognizedDecorators.includes(d.getName()));\r\n if (!hasRecognized) return null;\r\n\r\n // Skip relation-only properties (no Column)\r\n const isRelationOnly = decorators.every((d) =>\r\n ['ManyToOne', 'OneToMany', 'OneToOne', 'ManyToMany', 'JoinColumn', 'JoinTable'].includes(d.getName()),\r\n );\r\n if (isRelationOnly) return null;\r\n\r\n return { name, type, allowNull, primaryKey, unique };\r\n}\r\n\r\nexport function parseTypeORMAssociations(filePath: string): ForeignKeyRelation[] {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return [];\r\n\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const relations: ForeignKeyRelation[] = [];\r\n for (const cls of sourceFile.getClasses()) {\r\n const entityDecorator = cls.getDecorator('Entity');\r\n if (!entityDecorator) continue;\r\n\r\n const sourceTable = extractDecoratorStringArg(entityDecorator.getText())\r\n || classNameToTableName(cls.getName() || 'unknown');\r\n\r\n for (const prop of cls.getProperties()) {\r\n const rel = extractRelationFromProperty(prop, sourceTable);\r\n if (rel) relations.push(rel);\r\n }\r\n }\r\n return relations;\r\n}\r\n\r\nfunction extractRelationFromProperty(\r\n prop: PropertyDeclaration,\r\n sourceTable: string,\r\n): ForeignKeyRelation | null {\r\n const decorators = prop.getDecorators();\r\n\r\n for (const dec of decorators) {\r\n const decName = dec.getName();\r\n const decText = dec.getText();\r\n\r\n if (decName === 'ManyToOne') {\r\n const targetClass = extractRelationTarget(decText);\r\n if (!targetClass) continue;\r\n const targetTable = classNameToTableName(targetClass);\r\n const fkField = findJoinColumnField(decorators) || `${prop.getName()}_id`;\r\n return {\r\n sourceTable, sourceField: fkField,\r\n targetTable, targetField: 'id',\r\n cardinality: 'N:1',\r\n };\r\n }\r\n\r\n if (decName === 'OneToMany') {\r\n const targetClass = extractRelationTarget(decText);\r\n if (!targetClass) continue;\r\n const targetTable = classNameToTableName(targetClass);\r\n return {\r\n sourceTable, sourceField: 'id',\r\n targetTable, targetField: `${classNameToTableName(sourceTable)}_id`,\r\n cardinality: '1:N',\r\n };\r\n }\r\n\r\n if (decName === 'OneToOne') {\r\n const targetClass = extractRelationTarget(decText);\r\n if (!targetClass) continue;\r\n const targetTable = classNameToTableName(targetClass);\r\n return {\r\n sourceTable, sourceField: 'id',\r\n targetTable, targetField: `${classNameToTableName(sourceTable)}_id`,\r\n cardinality: '1:1',\r\n };\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction extractRelationTarget(decoratorText: string): string | null {\r\n // @ManyToOne(() => User, ...) or @ManyToOne(type => User, ...)\r\n const match = decoratorText.match(/\\(\\s*(?:\\(\\)\\s*=>|type\\s*=>|\\w+\\s*=>)\\s*(\\w+)/);\r\n return match?.[1] || null;\r\n}\r\n\r\nfunction findJoinColumnField(decorators: ReturnType<PropertyDeclaration['getDecorators']>): string | null {\r\n for (const dec of decorators) {\r\n if (dec.getName() === 'JoinColumn') {\r\n const args = extractDecoratorObjectArg(dec.getText());\r\n if (args.name) return args.name;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nexport function parseTypeORMDirectory(dir: string): TableSchema[] {\r\n const absoluteDir = path.resolve(dir);\r\n if (!fs.existsSync(absoluteDir)) return [];\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) =>\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts',\r\n );\r\n\r\n const schemas: TableSchema[] = [];\r\n for (const file of files) {\r\n try {\r\n const schema = parseTypeORMFile(path.join(absoluteDir, file));\r\n if (schema) schemas.push(schema);\r\n } catch {\r\n // skip\r\n }\r\n }\r\n return schemas;\r\n}\r\n\r\nexport function parseTypeORMAssociationsFromDir(dir: string): ForeignKeyRelation[] {\r\n const absoluteDir = path.resolve(dir);\r\n if (!fs.existsSync(absoluteDir)) return [];\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) =>\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts',\r\n );\r\n\r\n const relations: ForeignKeyRelation[] = [];\r\n for (const file of files) {\r\n try {\r\n relations.push(...parseTypeORMAssociations(path.join(absoluteDir, file)));\r\n } catch {\r\n // skip\r\n }\r\n }\r\n return relations;\r\n}\r\n\r\nexport function createTypeORMAdapter(): BackendAdapter {\r\n return {\r\n name: 'typeorm',\r\n\r\n async parseModels(dir: string): Promise<TableSchema[]> {\r\n return parseTypeORMDirectory(dir);\r\n },\r\n\r\n async parseAssociations(file: string): Promise<ForeignKeyRelation[]> {\r\n // TypeORM embeds relations in entity files, so parse the directory\r\n const dir = path.dirname(file);\r\n return parseTypeORMAssociationsFromDir(dir);\r\n },\r\n\r\n async parseControllers(dir: string): Promise<RouteEntry[]> {\r\n // Controller parsing is framework-agnostic (Express/Koa router patterns)\r\n const { parseControllerDirectory } = await import('../parsers/controller-parser.js');\r\n const endpoints = parseControllerDirectory(dir);\r\n return endpoints.map((ep) => ({\r\n method: ep.method,\r\n path: ep.path,\r\n handler: '',\r\n controllerClass: '',\r\n }));\r\n },\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport type { BackendAdapter, TableSchema, FieldSchema, ForeignKeyRelation, RouteEntry } from '../types.js';\r\n\r\n// Prisma scalar → generic field type mapping\r\nconst PRISMA_TYPE_MAP: Record<string, string> = {\r\n 'String': 'STRING',\r\n 'Int': 'INTEGER',\r\n 'BigInt': 'BIGINT',\r\n 'Float': 'FLOAT',\r\n 'Decimal': 'DECIMAL',\r\n 'Boolean': 'BOOLEAN',\r\n 'DateTime': 'DATE',\r\n 'Json': 'JSON',\r\n 'Bytes': 'BLOB',\r\n};\r\n\r\ninterface PrismaModel {\r\n name: string;\r\n fields: PrismaField[];\r\n tableName?: string;\r\n}\r\n\r\ninterface PrismaField {\r\n name: string;\r\n type: string;\r\n isOptional: boolean;\r\n isList: boolean;\r\n isId: boolean;\r\n isUnique: boolean;\r\n isUpdatedAt: boolean;\r\n defaultValue?: string;\r\n relation?: { name?: string; fields?: string[]; references?: string[] };\r\n nativeType?: string;\r\n mapName?: string;\r\n}\r\n\r\n/**\r\n * Parse a .prisma schema file into models.\r\n */\r\nexport function parsePrismaSchema(content: string): PrismaModel[] {\r\n const models: PrismaModel[] = [];\r\n const modelRegex = /model\\s+(\\w+)\\s*\\{([^}]*)\\}/g;\r\n let match: RegExpExecArray | null;\r\n\r\n while ((match = modelRegex.exec(content)) !== null) {\r\n const modelName = match[1];\r\n const body = match[2];\r\n const fields = parsePrismaFields(body);\r\n const mapDirective = body.match(/@@map\\([\"']([^\"']+)[\"']\\)/);\r\n models.push({\r\n name: modelName,\r\n fields,\r\n tableName: mapDirective?.[1],\r\n });\r\n }\r\n return models;\r\n}\r\n\r\nfunction parsePrismaFields(body: string): PrismaField[] {\r\n const fields: PrismaField[] = [];\r\n const lines = body.split('\\n').map((l) => l.trim()).filter((l) => l && !l.startsWith('//') && !l.startsWith('@@'));\r\n\r\n for (const line of lines) {\r\n const field = parsePrismaFieldLine(line);\r\n if (field) fields.push(field);\r\n }\r\n return fields;\r\n}\r\n\r\nfunction parsePrismaFieldLine(line: string): PrismaField | null {\r\n // field_name Type? @attributes\r\n const match = line.match(/^(\\w+)\\s+(\\w+)(\\[\\])?\\??/);\r\n if (!match) return null;\r\n\r\n const name = match[1];\r\n const rawType = match[2];\r\n const isList = !!match[3];\r\n const isOptional = line.includes('?');\r\n\r\n const field: PrismaField = {\r\n name,\r\n type: rawType,\r\n isOptional,\r\n isList,\r\n isId: /@id\\b/.test(line),\r\n isUnique: /@unique\\b/.test(line),\r\n isUpdatedAt: /@updatedAt\\b/.test(line),\r\n };\r\n\r\n // @default(...)\r\n const defaultMatch = line.match(/@default\\(([^)]+)\\)/);\r\n if (defaultMatch) field.defaultValue = defaultMatch[1];\r\n\r\n // @map(\"...\")\r\n const mapMatch = line.match(/@map\\([\"']([^\"']+)[\"']\\)/);\r\n if (mapMatch) field.mapName = mapMatch[1];\r\n\r\n // @db.VarChar(255) etc.\r\n const nativeMatch = line.match(/@db\\.(\\w+(?:\\([^)]*\\))?)/);\r\n if (nativeMatch) field.nativeType = nativeMatch[1];\r\n\r\n // @relation(...)\r\n const relMatch = line.match(/@relation\\(([^)]*)\\)/);\r\n if (relMatch) {\r\n field.relation = parseRelationDirective(relMatch[1]);\r\n }\r\n\r\n return field;\r\n}\r\n\r\nfunction parseRelationDirective(content: string): PrismaField['relation'] {\r\n const rel: NonNullable<PrismaField['relation']> = {};\r\n\r\n const nameMatch = content.match(/(?:name:\\s*)?[\"']([^\"']+)[\"']/);\r\n if (nameMatch) rel.name = nameMatch[1];\r\n\r\n const fieldsMatch = content.match(/fields:\\s*\\[([^\\]]+)\\]/);\r\n if (fieldsMatch) {\r\n rel.fields = fieldsMatch[1].split(',').map((s) => s.trim());\r\n }\r\n\r\n const refsMatch = content.match(/references:\\s*\\[([^\\]]+)\\]/);\r\n if (refsMatch) {\r\n rel.references = refsMatch[1].split(',').map((s) => s.trim());\r\n }\r\n\r\n return rel;\r\n}\r\n\r\nfunction modelNameToTableName(name: string): string {\r\n return name.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\r\n}\r\n\r\nexport function prismaModelsToSchemas(models: PrismaModel[]): TableSchema[] {\r\n return models.map((model) => {\r\n const tableName = model.tableName || modelNameToTableName(model.name);\r\n const fields: FieldSchema[] = [];\r\n\r\n for (const f of model.fields) {\r\n // Skip relation fields (other model types or lists)\r\n if (f.isList) continue;\r\n if (!PRISMA_TYPE_MAP[f.type] && !f.relation) continue;\r\n // Skip pure relation references (no scalar counterpart)\r\n if (!PRISMA_TYPE_MAP[f.type] && f.relation && !f.relation.fields) continue;\r\n\r\n const fieldType = PRISMA_TYPE_MAP[f.type] || 'STRING';\r\n fields.push({\r\n name: f.mapName || f.name,\r\n type: fieldType,\r\n allowNull: f.isOptional,\r\n primaryKey: f.isId,\r\n unique: f.isUnique,\r\n defaultValue: f.defaultValue,\r\n });\r\n }\r\n\r\n return { tableName, className: model.name, fields };\r\n });\r\n}\r\n\r\nexport function prismaModelsToRelations(models: PrismaModel[]): ForeignKeyRelation[] {\r\n const relations: ForeignKeyRelation[] = [];\r\n const seen = new Set<string>();\r\n\r\n for (const model of models) {\r\n const sourceTable = model.tableName || modelNameToTableName(model.name);\r\n\r\n for (const field of model.fields) {\r\n if (!field.relation?.fields || !field.relation?.references) continue;\r\n\r\n const targetModel = models.find((m) => m.name === field.type);\r\n const targetTable = targetModel\r\n ? (targetModel.tableName || modelNameToTableName(targetModel.name))\r\n : modelNameToTableName(field.type);\r\n\r\n const sourceField = field.relation.fields[0];\r\n const targetField = field.relation.references[0];\r\n\r\n const key = `${sourceTable}|${sourceField}|${targetTable}|${targetField}`;\r\n if (seen.has(key)) continue;\r\n seen.add(key);\r\n\r\n // Determine cardinality: field with @relation + fields is the \"many\" side\r\n const isList = field.isList;\r\n relations.push({\r\n sourceTable,\r\n sourceField,\r\n targetTable,\r\n targetField,\r\n cardinality: isList ? '1:N' : 'N:1',\r\n });\r\n }\r\n }\r\n return relations;\r\n}\r\n\r\nexport function parsePrismaFile(filePath: string): { schemas: TableSchema[]; relations: ForeignKeyRelation[] } {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return { schemas: [], relations: [] };\r\n\r\n const content = fs.readFileSync(absolutePath, 'utf-8');\r\n const models = parsePrismaSchema(content);\r\n return {\r\n schemas: prismaModelsToSchemas(models),\r\n relations: prismaModelsToRelations(models),\r\n };\r\n}\r\n\r\nfunction findPrismaSchemaFile(dir: string): string | null {\r\n // Look for schema.prisma in dir, dir/prisma, or project root/prisma\r\n const candidates = [\r\n path.join(dir, 'schema.prisma'),\r\n path.join(dir, 'prisma', 'schema.prisma'),\r\n path.join(dir, '..', 'prisma', 'schema.prisma'),\r\n ];\r\n for (const c of candidates) {\r\n if (fs.existsSync(c)) return c;\r\n }\r\n return null;\r\n}\r\n\r\nexport function createPrismaAdapter(): BackendAdapter {\r\n return {\r\n name: 'prisma',\r\n\r\n async parseModels(dir: string): Promise<TableSchema[]> {\r\n const schemaFile = findPrismaSchemaFile(dir);\r\n if (!schemaFile) return [];\r\n const { schemas } = parsePrismaFile(schemaFile);\r\n return schemas;\r\n },\r\n\r\n async parseAssociations(file: string): Promise<ForeignKeyRelation[]> {\r\n // For Prisma, associations are in the schema file itself\r\n const schemaFile = findPrismaSchemaFile(path.dirname(file)) || file;\r\n const { relations } = parsePrismaFile(schemaFile);\r\n return relations;\r\n },\r\n\r\n async parseControllers(dir: string): Promise<RouteEntry[]> {\r\n const { parseControllerDirectory } = await import('../parsers/controller-parser.js');\r\n const endpoints = parseControllerDirectory(dir);\r\n return endpoints.map((ep) => ({\r\n method: ep.method,\r\n path: ep.path,\r\n handler: '',\r\n controllerClass: '',\r\n }));\r\n },\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n Node,\r\n type SourceFile,\r\n type CallExpression,\r\n type ObjectLiteralExpression,\r\n type PropertyAccessExpression,\r\n} from 'ts-morph';\r\nimport type { BackendAdapter, TableSchema, FieldSchema, ForeignKeyRelation, RouteEntry } from '../types.js';\r\n\r\n// Drizzle column constructor name → generic field type\r\nconst DRIZZLE_TYPE_MAP: Record<string, string> = {\r\n // integer family\r\n int: 'INTEGER',\r\n integer: 'INTEGER',\r\n serial: 'INTEGER',\r\n smallint: 'INTEGER',\r\n tinyint: 'INTEGER',\r\n mediumint: 'INTEGER',\r\n bigint: 'BIGINT',\r\n bigserial: 'BIGINT',\r\n // float / decimal\r\n real: 'FLOAT',\r\n float: 'FLOAT',\r\n doublePrecision: 'FLOAT',\r\n double: 'FLOAT',\r\n numeric: 'DECIMAL',\r\n decimal: 'DECIMAL',\r\n // string\r\n varchar: 'STRING',\r\n char: 'STRING',\r\n nvarchar: 'STRING',\r\n text: 'TEXT',\r\n // boolean\r\n boolean: 'BOOLEAN',\r\n bool: 'BOOLEAN',\r\n // date / time\r\n date: 'DATE',\r\n datetime: 'DATE',\r\n timestamp: 'DATE',\r\n timestamptz: 'DATE',\r\n time: 'TIME',\r\n // json\r\n json: 'JSON',\r\n jsonb: 'JSON',\r\n // binary / misc\r\n blob: 'BLOB',\r\n bytea: 'BLOB',\r\n uuid: 'STRING',\r\n};\r\n\r\nconst TABLE_FUNCTIONS = new Set(['pgTable', 'mysqlTable', 'sqliteTable']);\r\n\r\ninterface DrizzleColumn {\r\n varName: string;\r\n sqlName: string;\r\n type: string;\r\n isPrimary: boolean;\r\n isNotNull: boolean;\r\n isUnique: boolean;\r\n defaultValue?: string;\r\n referencesExpr?: string;\r\n}\r\n\r\ninterface DrizzleTable {\r\n varName: string;\r\n tableName: string;\r\n columns: DrizzleColumn[];\r\n}\r\n\r\nfunction findTableCalls(sourceFile: SourceFile): DrizzleTable[] {\r\n const tables: DrizzleTable[] = [];\r\n const varDecls = sourceFile.getDescendantsOfKind(SyntaxKind.VariableDeclaration);\r\n\r\n for (const decl of varDecls) {\r\n const init = decl.getInitializer();\r\n if (!init || init.getKind() !== SyntaxKind.CallExpression) continue;\r\n\r\n const call = init as CallExpression;\r\n const funcName = call.getExpression().getText().trim();\r\n if (!TABLE_FUNCTIONS.has(funcName)) continue;\r\n\r\n const args = call.getArguments();\r\n if (args.length < 2) continue;\r\n\r\n // 1st arg: SQL table name\r\n const nameArg = args[0];\r\n if (nameArg.getKind() !== SyntaxKind.StringLiteral) continue;\r\n const tableName = nameArg.getText().slice(1, -1);\r\n\r\n // 2nd arg: column definitions object\r\n const colsArg = args[1];\r\n if (colsArg.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\r\n\r\n const columns = parseColumnObject(colsArg as ObjectLiteralExpression);\r\n tables.push({ varName: decl.getName(), tableName, columns });\r\n }\r\n\r\n return tables;\r\n}\r\n\r\nfunction parseColumnObject(obj: ObjectLiteralExpression): DrizzleColumn[] {\r\n const columns: DrizzleColumn[] = [];\r\n for (const prop of obj.getProperties()) {\r\n if (!Node.isPropertyAssignment(prop)) continue;\r\n const varName = prop.getName();\r\n const val = prop.getInitializer();\r\n if (!val) continue;\r\n const col = parseColumnChain(val, varName);\r\n if (col) columns.push(col);\r\n }\r\n return columns;\r\n}\r\n\r\nfunction parseColumnChain(expr: Node, varName: string): DrizzleColumn | null {\r\n // Flatten method chain from root outward: root call → chained calls\r\n const chain: CallExpression[] = [];\r\n let current: Node = expr;\r\n\r\n while (current.getKind() === SyntaxKind.CallExpression) {\r\n chain.unshift(current as CallExpression);\r\n const callee = (current as CallExpression).getExpression();\r\n if (callee.getKind() === SyntaxKind.PropertyAccessExpression) {\r\n current = (callee as PropertyAccessExpression).getExpression();\r\n } else {\r\n break;\r\n }\r\n }\r\n\r\n if (chain.length === 0) return null;\r\n\r\n // Root call determines the column type: e.g. varchar('col_name', { length: 255 })\r\n const root = chain[0];\r\n const rootFuncName = root.getExpression().getText().trim().split('.').pop() ?? '';\r\n const drizzleType = DRIZZLE_TYPE_MAP[rootFuncName];\r\n if (!drizzleType) return null;\r\n\r\n const rootArgs = root.getArguments();\r\n const sqlName =\r\n rootArgs.length > 0 && rootArgs[0].getKind() === SyntaxKind.StringLiteral\r\n ? rootArgs[0].getText().slice(1, -1)\r\n : varName;\r\n\r\n const col: DrizzleColumn = {\r\n varName,\r\n sqlName,\r\n type: drizzleType,\r\n isPrimary: false,\r\n isNotNull: false,\r\n isUnique: false,\r\n };\r\n\r\n // Walk remaining chain for modifiers\r\n for (let i = 1; i < chain.length; i++) {\r\n const call = chain[i];\r\n const callee = call.getExpression();\r\n if (callee.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\r\n const methodName = (callee as PropertyAccessExpression).getName();\r\n\r\n switch (methodName) {\r\n case 'primaryKey':\r\n col.isPrimary = true;\r\n col.isNotNull = true;\r\n break;\r\n case 'notNull':\r\n col.isNotNull = true;\r\n break;\r\n case 'unique':\r\n col.isUnique = true;\r\n break;\r\n case 'default':\r\n case 'defaultNow': {\r\n const args = call.getArguments();\r\n col.defaultValue = args.length > 0 ? args[0].getText() : 'now()';\r\n break;\r\n }\r\n case 'references': {\r\n const args = call.getArguments();\r\n if (args.length > 0) col.referencesExpr = args[0].getText();\r\n break;\r\n }\r\n }\r\n }\r\n\r\n return col;\r\n}\r\n\r\nfunction resolveRelations(tables: DrizzleTable[]): ForeignKeyRelation[] {\r\n const relations: ForeignKeyRelation[] = [];\r\n const varToTableName = new Map<string, string>();\r\n const varColToSqlCol = new Map<string, string>();\r\n\r\n for (const t of tables) {\r\n varToTableName.set(t.varName, t.tableName);\r\n for (const c of t.columns) {\r\n varColToSqlCol.set(`${t.varName}.${c.varName}`, c.sqlName);\r\n }\r\n }\r\n\r\n for (const t of tables) {\r\n for (const col of t.columns) {\r\n if (!col.referencesExpr) continue;\r\n // Extract target from arrow function: () => targetTable.targetCol\r\n const arrowMatch = col.referencesExpr.match(/=>\\s*(\\w+)\\.(\\w+)/);\r\n if (!arrowMatch) continue;\r\n const targetVarName = arrowMatch[1];\r\n const targetColVarName = arrowMatch[2];\r\n const targetTable = varToTableName.get(targetVarName);\r\n if (!targetTable) continue;\r\n const targetCol = varColToSqlCol.get(`${targetVarName}.${targetColVarName}`) ?? targetColVarName;\r\n\r\n relations.push({\r\n sourceTable: t.tableName,\r\n sourceField: col.sqlName,\r\n targetTable,\r\n targetField: targetCol,\r\n cardinality: 'N:1',\r\n });\r\n }\r\n }\r\n\r\n return relations;\r\n}\r\n\r\nexport function parseDrizzleFile(filePath: string): { schemas: TableSchema[]; relations: ForeignKeyRelation[] } {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return { schemas: [], relations: [] };\r\n\r\n try {\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n const tables = findTableCalls(sourceFile);\r\n\r\n const schemas: TableSchema[] = tables.map((t) => ({\r\n tableName: t.tableName,\r\n className: t.varName,\r\n fields: t.columns.map((c): FieldSchema => ({\r\n name: c.sqlName,\r\n type: c.type,\r\n allowNull: !c.isNotNull && !c.isPrimary,\r\n primaryKey: c.isPrimary,\r\n unique: c.isUnique,\r\n defaultValue: c.defaultValue,\r\n })),\r\n }));\r\n\r\n return { schemas, relations: resolveRelations(tables) };\r\n } catch {\r\n return { schemas: [], relations: [] };\r\n }\r\n}\r\n\r\nexport function parseDrizzleDirectory(dirPath: string): { schemas: TableSchema[]; relations: ForeignKeyRelation[] } {\r\n const absoluteDir = path.resolve(dirPath);\r\n if (!fs.existsSync(absoluteDir)) return { schemas: [], relations: [] };\r\n\r\n const files = fs.readdirSync(absoluteDir).filter(\r\n (f) => f.endsWith('.ts') && !f.endsWith('.test.ts') && !f.endsWith('.spec.ts') && f !== 'index.ts',\r\n );\r\n\r\n const allSchemas: TableSchema[] = [];\r\n const allRelations: ForeignKeyRelation[] = [];\r\n for (const file of files) {\r\n const result = parseDrizzleFile(path.join(absoluteDir, file));\r\n allSchemas.push(...result.schemas);\r\n allRelations.push(...result.relations);\r\n }\r\n return { schemas: allSchemas, relations: allRelations };\r\n}\r\n\r\nexport function createDrizzleAdapter(): BackendAdapter {\r\n return {\r\n name: 'drizzle',\r\n\r\n async parseModels(dir: string): Promise<TableSchema[]> {\r\n return parseDrizzleDirectory(dir).schemas;\r\n },\r\n\r\n async parseAssociations(dir: string): Promise<ForeignKeyRelation[]> {\r\n return parseDrizzleDirectory(dir).relations;\r\n },\r\n\r\n async parseControllers(dir: string): Promise<RouteEntry[]> {\r\n const { parseControllerDirectory } = await import('../parsers/controller-parser.js');\r\n const endpoints = parseControllerDirectory(dir);\r\n return endpoints.map((ep) => ({\r\n method: ep.method,\r\n path: ep.path,\r\n handler: '',\r\n controllerClass: '',\r\n }));\r\n },\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport type { BackendAdapter } from '../types.js';\r\nimport { createSequelizeAdapter } from './sequelize.js';\r\nimport { createTypeORMAdapter } from './typeorm.js';\r\nimport { createPrismaAdapter } from './prisma.js';\r\nimport { createDrizzleAdapter } from './drizzle.js';\r\n\r\nconst ADAPTER_FACTORIES: Record<string, () => BackendAdapter> = {\r\n sequelize: createSequelizeAdapter,\r\n typeorm: createTypeORMAdapter,\r\n prisma: createPrismaAdapter,\r\n drizzle: createDrizzleAdapter,\r\n};\r\n\r\n/**\r\n * Create an adapter by name.\r\n */\r\nexport function createAdapter(name: string): BackendAdapter {\r\n const factory = ADAPTER_FACTORIES[name];\r\n if (!factory) {\r\n throw new Error(`Unknown adapter: \"${name}\". Available: ${Object.keys(ADAPTER_FACTORIES).join(', ')}`);\r\n }\r\n return factory();\r\n}\r\n\r\n/**\r\n * Auto-detect the ORM adapter from project structure.\r\n *\r\n * Detection order:\r\n * 1. Prisma — if `prisma/schema.prisma` exists\r\n * 2. TypeORM — if any .ts file has `@Entity` decorator\r\n * 3. Sequelize — default fallback (`.init()` pattern)\r\n */\r\nexport function detectAdapter(backendRoot: string): string {\r\n const root = path.resolve(backendRoot);\r\n\r\n // Check for Prisma\r\n const prismaLocations = [\r\n path.join(root, 'prisma', 'schema.prisma'),\r\n path.join(root, 'schema.prisma'),\r\n path.join(root, '..', 'prisma', 'schema.prisma'),\r\n ];\r\n for (const loc of prismaLocations) {\r\n if (fs.existsSync(loc)) return 'prisma';\r\n }\r\n\r\n // Check for TypeORM / Drizzle — scan models directory\r\n const modelsDir = path.join(root, 'models');\r\n if (fs.existsSync(modelsDir)) {\r\n try {\r\n const files = fs.readdirSync(modelsDir, { recursive: true });\r\n for (const file of files) {\r\n const filePath = path.join(modelsDir, String(file));\r\n if (!filePath.endsWith('.ts')) continue;\r\n try {\r\n const content = fs.readFileSync(filePath, 'utf-8');\r\n if (/@Entity\\s*\\(/.test(content)) return 'typeorm';\r\n if (/(?:pgTable|mysqlTable|sqliteTable)\\s*\\(/.test(content)) return 'drizzle';\r\n } catch {\r\n // skip\r\n }\r\n }\r\n } catch {\r\n // skip\r\n }\r\n }\r\n\r\n // Default to Sequelize\r\n return 'sequelize';\r\n}\r\n\r\n/**\r\n * Resolve adapter: if a string name is given, create it; if already a BackendAdapter, use it.\r\n * If 'auto', detect from project structure.\r\n */\r\nexport function resolveAdapter(\r\n adapterOrName: string | BackendAdapter | undefined,\r\n backendRoot: string,\r\n): BackendAdapter {\r\n if (typeof adapterOrName === 'object' && adapterOrName !== null) {\r\n return adapterOrName;\r\n }\r\n const name = adapterOrName === 'auto' || !adapterOrName\r\n ? detectAdapter(backendRoot)\r\n : adapterOrName;\r\n return createAdapter(name);\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\nimport type { OpenCrocPlugin, PluginRegistry } from './types.js';\r\n\r\nexport type { OpenCrocPlugin, PluginRegistry } from './types.js';\r\n\r\n/**\r\n * Create a plugin registry.\r\n *\r\n * @example\r\n * ```ts\r\n * const registry = createPluginRegistry();\r\n * registry.register({ name: 'my-plugin', beforePipeline() { console.log('go!'); } });\r\n * await registry.invoke('beforePipeline', config);\r\n * ```\r\n */\r\nexport function createPluginRegistry(): PluginRegistry {\r\n const plugins: OpenCrocPlugin[] = [];\r\n\r\n function register(plugin: OpenCrocPlugin): void {\r\n if (!plugin.name) {\r\n throw new Error('Plugin must have a name');\r\n }\r\n if (plugins.some((p) => p.name === plugin.name)) {\r\n throw new Error(`Plugin \"${plugin.name}\" is already registered`);\r\n }\r\n plugins.push(plugin);\r\n }\r\n\r\n async function unregister(name: string): Promise<void> {\r\n const idx = plugins.findIndex((p) => p.name === name);\r\n if (idx === -1) return;\r\n const plugin = plugins[idx];\r\n if (plugin.teardown) {\r\n await plugin.teardown();\r\n }\r\n plugins.splice(idx, 1);\r\n }\r\n\r\n function get(name: string): OpenCrocPlugin | undefined {\r\n return plugins.find((p) => p.name === name);\r\n }\r\n\r\n function list(): string[] {\r\n return plugins.map((p) => p.name);\r\n }\r\n\r\n async function invoke<K extends keyof OpenCrocPlugin>(\r\n hook: K,\r\n ...args: unknown[]\r\n ): Promise<void> {\r\n for (const plugin of plugins) {\r\n const fn = plugin[hook];\r\n if (typeof fn === 'function') {\r\n await (fn as (...a: unknown[]) => unknown).apply(plugin, args);\r\n }\r\n }\r\n }\r\n\r\n async function applyConfigTransforms(config: OpenCrocConfig): Promise<OpenCrocConfig> {\r\n let result = config;\r\n for (const plugin of plugins) {\r\n if (plugin.transformConfig) {\r\n result = await plugin.transformConfig(result);\r\n }\r\n }\r\n return result;\r\n }\r\n\r\n return { register, unregister, get, list, invoke, applyConfigTransforms };\r\n}\r\n\r\n/**\r\n * Helper to define a plugin with type safety.\r\n */\r\nexport function definePlugin(plugin: OpenCrocPlugin): OpenCrocPlugin {\r\n return plugin;\r\n}\r\n","/**\r\n * CI template generators for popular CI/CD platforms.\r\n *\r\n * Usage:\r\n * npx opencroc ci --platform=github\r\n * npx opencroc ci --platform=gitlab\r\n */\r\n\r\nexport interface CiTemplateOptions {\r\n /** Node.js version(s). Default: ['20.x'] */\r\n nodeVersions?: string[];\r\n /** Install command. Default: 'npm ci' */\r\n installCommand?: string;\r\n /** Whether to run self-healing. Default: false */\r\n selfHeal?: boolean;\r\n /** Custom opencroc generate args */\r\n generateArgs?: string;\r\n /** Custom opencroc test args */\r\n testArgs?: string;\r\n}\r\n\r\nexport function generateGitHubActionsTemplate(opts: CiTemplateOptions = {}): string {\r\n const nodeVersions = opts.nodeVersions ?? ['20.x'];\r\n const install = opts.installCommand ?? 'npm ci';\r\n const genArgs = opts.generateArgs ?? '--all';\r\n const testArgs = opts.testArgs ?? '';\r\n const healStep = opts.selfHeal\r\n ? `\r\n - name: Self-heal failures\r\n if: failure()\r\n run: npx opencroc heal --max-iterations 3`\r\n : '';\r\n\r\n const matrix =\r\n nodeVersions.length > 1\r\n ? `\r\n strategy:\r\n matrix:\r\n node-version: [${nodeVersions.join(', ')}]`\r\n : '';\r\n\r\n const nodeSetup =\r\n nodeVersions.length > 1\r\n ? '${{ matrix.node-version }}'\r\n : nodeVersions[0];\r\n\r\n return `# Generated by OpenCroc — AI-native E2E testing\r\n# https://github.com/opencroc/opencroc\r\n\r\nname: OpenCroc E2E\r\n\r\non:\r\n push:\r\n branches: [main]\r\n pull_request:\r\n branches: [main]\r\n\r\njobs:\r\n e2e:\r\n runs-on: ubuntu-latest${matrix}\r\n steps:\r\n - uses: actions/checkout@v4\r\n\r\n - uses: actions/setup-node@v4\r\n with:\r\n node-version: '${nodeSetup}'\r\n\r\n - name: Install dependencies\r\n run: ${install}\r\n\r\n - name: Install Playwright browsers\r\n run: npx playwright install --with-deps chromium\r\n\r\n - name: Generate E2E tests\r\n run: npx opencroc generate ${genArgs}\r\n\r\n - name: Run E2E tests\r\n run: npx opencroc test ${testArgs}\r\n${healStep}\r\n - name: Upload test report\r\n if: always()\r\n uses: actions/upload-artifact@v4\r\n with:\r\n name: opencroc-report\r\n path: opencroc-output/\r\n retention-days: 14\r\n`;\r\n}\r\n\r\nexport function generateGitLabCITemplate(opts: CiTemplateOptions = {}): string {\r\n const install = opts.installCommand ?? 'npm ci';\r\n const genArgs = opts.generateArgs ?? '--all';\r\n const testArgs = opts.testArgs ?? '';\r\n const nodeVersion = opts.nodeVersions?.[0] ?? '20';\r\n\r\n return `# Generated by OpenCroc — AI-native E2E testing\r\n# https://github.com/opencroc/opencroc\r\n\r\nimage: node:${nodeVersion}\r\n\r\nstages:\r\n - generate\r\n - test\r\n\r\nvariables:\r\n PLAYWRIGHT_BROWSERS_PATH: \\${CI_PROJECT_DIR}/.cache/ms-playwright\r\n\r\ncache:\r\n key: \\${CI_COMMIT_REF_SLUG}\r\n paths:\r\n - node_modules/\r\n - .cache/ms-playwright/\r\n\r\ngenerate:\r\n stage: generate\r\n script:\r\n - ${install}\r\n - npx opencroc generate ${genArgs}\r\n artifacts:\r\n paths:\r\n - opencroc-output/\r\n expire_in: 1 day\r\n\r\ne2e:\r\n stage: test\r\n needs: [generate]\r\n before_script:\r\n - ${install}\r\n - npx playwright install --with-deps chromium\r\n script:\r\n - npx opencroc test ${testArgs}\r\n artifacts:\r\n when: always\r\n paths:\r\n - opencroc-output/\r\n expire_in: 14 days\r\n`;\r\n}\r\n\r\nconst TEMPLATES: Record<string, (opts: CiTemplateOptions) => string> = {\r\n github: generateGitHubActionsTemplate,\r\n gitlab: generateGitLabCITemplate,\r\n};\r\n\r\n/**\r\n * Get available CI platform names.\r\n */\r\nexport function listCiPlatforms(): string[] {\r\n return Object.keys(TEMPLATES);\r\n}\r\n\r\n/**\r\n * Generate a CI template for the given platform.\r\n */\r\nexport function generateCiTemplate(\r\n platform: string,\r\n opts: CiTemplateOptions = {},\r\n): string {\r\n const generator = TEMPLATES[platform];\r\n if (!generator) {\r\n throw new Error(\r\n `Unknown CI platform: \"${platform}\". Available: ${Object.keys(TEMPLATES).join(', ')}`,\r\n );\r\n }\r\n return generator(opts);\r\n}\r\n","import type {\r\n PipelineRunResult,\r\n ERDiagramResult,\r\n ChainPlanResult,\r\n GeneratedTestFile,\r\n ValidationError,\r\n ExecutionMetrics,\n} from '../types.js';\r\nimport type { ExecutionQualityGateResult } from '../execution/types.js';\n\r\n// ===== Reporter Types =====\r\n\r\nexport interface ReportOutput {\r\n format: 'html' | 'json' | 'markdown';\r\n content: string;\r\n filename: string;\r\n}\r\n\nexport interface ReportExecutionContext {\n metrics?: ExecutionMetrics | null;\n quality?: ExecutionQualityGateResult | null;\n}\n\r\n// ===== JSON Reporter =====\r\n\r\nexport function generateJsonReport(\n result: PipelineRunResult,\n context?: ReportExecutionContext,\n): ReportOutput {\n const serializable = {\r\n modules: result.modules,\r\n erDiagrams: Object.fromEntries(\r\n Array.from(result.erDiagrams.entries()).map(([k, v]) => [\r\n k,\r\n { tables: v.tables.length, relations: v.relations.length, mermaidText: v.mermaidText },\r\n ]),\r\n ),\r\n chainPlans: Object.fromEntries(\r\n Array.from(result.chainPlans.entries()).map(([k, v]) => [\r\n k,\r\n { chains: v.chains.length, totalSteps: v.totalSteps },\r\n ]),\r\n ),\r\n generatedFiles: result.generatedFiles.map((f) => ({\r\n filePath: f.filePath,\r\n module: f.module,\r\n chain: f.chain,\r\n })),\r\n execution: context\n ? {\n metrics: context.metrics ?? null,\n quality: context.quality ?? null,\n }\n : undefined,\n validationErrors: result.validationErrors,\r\n duration: result.duration,\r\n };\r\n\r\n return {\r\n format: 'json',\r\n content: JSON.stringify(serializable, null, 2),\r\n filename: 'opencroc-report.json',\r\n };\r\n}\r\n\r\n// ===== Markdown Reporter =====\r\n\r\nexport function generateMarkdownReport(\n result: PipelineRunResult,\n context?: ReportExecutionContext,\n): ReportOutput {\n const lines: string[] = [\r\n '# OpenCroc Report',\r\n '',\r\n `**Duration**: ${result.duration}ms`,\r\n `**Modules**: ${result.modules.length} (${result.modules.join(', ')})`,\r\n '',\r\n '## ER Diagrams',\r\n '',\r\n ];\r\n\r\n for (const [mod, er] of result.erDiagrams) {\r\n lines.push(`### ${mod}`);\r\n lines.push(`- Tables: ${er.tables.length}`);\r\n lines.push(`- Relations: ${er.relations.length}`);\r\n lines.push('');\r\n }\r\n\r\n lines.push('## Chain Plans', '');\r\n for (const [mod, plan] of result.chainPlans) {\r\n lines.push(`### ${mod}`);\r\n lines.push(`- Chains: ${plan.chains.length}`);\r\n lines.push(`- Total Steps: ${plan.totalSteps}`);\r\n lines.push('');\r\n }\r\n\r\n lines.push(`## Generated Files (${result.generatedFiles.length})`, '');\r\n for (const f of result.generatedFiles) {\r\n lines.push(`- \\`${f.filePath}\\` (${f.module} / ${f.chain})`);\r\n }\r\n\r\n if (result.validationErrors.length > 0) {\r\n lines.push('', '## Validation Issues', '');\r\n const errors = result.validationErrors.filter((e) => e.severity === 'error');\r\n const warnings = result.validationErrors.filter((e) => e.severity === 'warning');\r\n if (errors.length > 0) {\r\n lines.push(`### Errors (${errors.length})`, '');\r\n for (const e of errors) {\r\n lines.push(`- **[${e.module}]** ${e.field}: ${e.message}`);\r\n }\r\n }\r\n if (warnings.length > 0) {\r\n lines.push(`### Warnings (${warnings.length})`, '');\r\n for (const w of warnings) {\r\n lines.push(`- **[${w.module}]** ${w.field}: ${w.message}`);\r\n }\r\n }\r\n }\r\n\n if (context?.metrics || context?.quality) {\n lines.push('', '## Execution Quality', '');\n if (context.metrics) {\n lines.push(\n `- Passed: ${context.metrics.passed}`,\n `- Failed: ${context.metrics.failed}`,\n `- Skipped: ${context.metrics.skipped}`,\n `- TimedOut: ${context.metrics.timedOut}`,\n );\n }\n if (context.quality) {\n lines.push(\n `- Gate Level: ${context.quality.level}`,\n `- Setup Fail: ${context.quality.setupFail}`,\n `- Skip Ratio: ${(context.quality.skipRatio * 100).toFixed(2)}%`,\n `- Auth Fail Ratio: ${(context.quality.authFailRatio * 100).toFixed(2)}%`,\n `- Effective Execution Rate: ${(context.quality.effectiveExecutionRate * 100).toFixed(2)}%`,\n `- Auth Status: ${context.quality.authStatus}`,\n `- Backend Status: ${context.quality.backendStatus}`,\n );\n if (context.quality.reasons.length > 0) {\n lines.push(`- Reasons: ${context.quality.reasons.join(', ')}`);\n }\n }\n }\n\r\n lines.push('', '---', '*Generated by [OpenCroc](https://github.com/opencroc/opencroc)*');\r\n\r\n return {\r\n format: 'markdown',\r\n content: lines.join('\\n'),\r\n filename: 'opencroc-report.md',\r\n };\r\n}\r\n\r\n// ===== HTML Reporter =====\r\n\r\nfunction escapeHtml(s: string): string {\r\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\r\n}\r\n\r\nfunction erSummaryRows(erDiagrams: Map<string, ERDiagramResult>): string {\r\n const rows: string[] = [];\r\n for (const [mod, er] of erDiagrams) {\r\n rows.push(`<tr><td>${escapeHtml(mod)}</td><td>${er.tables.length}</td><td>${er.relations.length}</td></tr>`);\r\n }\r\n return rows.join('\\n');\r\n}\r\n\r\nfunction chainSummaryRows(chainPlans: Map<string, ChainPlanResult>): string {\r\n const rows: string[] = [];\r\n for (const [mod, plan] of chainPlans) {\r\n rows.push(`<tr><td>${escapeHtml(mod)}</td><td>${plan.chains.length}</td><td>${plan.totalSteps}</td></tr>`);\r\n }\r\n return rows.join('\\n');\r\n}\r\n\r\nfunction fileListRows(files: GeneratedTestFile[]): string {\r\n return files\r\n .map((f) => `<tr><td><code>${escapeHtml(f.filePath)}</code></td><td>${escapeHtml(f.module)}</td><td>${escapeHtml(f.chain)}</td></tr>`)\r\n .join('\\n');\r\n}\r\n\r\nfunction validationRows(errors: ValidationError[]): string {\r\n return errors\r\n .map(\r\n (e) =>\r\n `<tr class=\"${e.severity}\"><td><span class=\"badge ${e.severity}\">${e.severity}</span></td><td>${escapeHtml(e.module)}</td><td>${escapeHtml(e.field)}</td><td>${escapeHtml(e.message)}</td></tr>`,\r\n )\r\n .join('\\n');\r\n}\r\n\r\nexport function generateHtmlReport(\n result: PipelineRunResult,\n context?: ReportExecutionContext,\n): ReportOutput {\n const totalTables = Array.from(result.erDiagrams.values()).reduce((s, e) => s + e.tables.length, 0);\r\n const totalRelations = Array.from(result.erDiagrams.values()).reduce((s, e) => s + e.relations.length, 0);\r\n const totalChains = Array.from(result.chainPlans.values()).reduce((s, p) => s + p.chains.length, 0);\r\n const totalSteps = Array.from(result.chainPlans.values()).reduce((s, p) => s + p.totalSteps, 0);\r\n const errorCount = result.validationErrors.filter((e) => e.severity === 'error').length;\r\n const warnCount = result.validationErrors.filter((e) => e.severity === 'warning').length;\r\n\r\n const html = `<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n<meta charset=\"utf-8\" />\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\r\n<title>OpenCroc Report</title>\r\n<style>\r\n :root { --bg: #0d1117; --fg: #c9d1d9; --card: #161b22; --border: #30363d; --accent: #58a6ff; --green: #3fb950; --yellow: #d29922; --red: #f85149; }\r\n * { box-sizing: border-box; margin: 0; padding: 0; }\r\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; background: var(--bg); color: var(--fg); padding: 2rem; }\r\n h1 { color: var(--accent); margin-bottom: 0.25rem; }\r\n .subtitle { color: #8b949e; margin-bottom: 2rem; }\r\n .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin-bottom: 2rem; }\r\n .card { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 1.25rem; }\r\n .card .label { font-size: 0.85rem; color: #8b949e; }\r\n .card .value { font-size: 2rem; font-weight: 700; color: var(--accent); }\r\n .card .value.green { color: var(--green); }\r\n .card .value.yellow { color: var(--yellow); }\r\n .card .value.red { color: var(--red); }\r\n section { margin-bottom: 2rem; }\r\n h2 { color: var(--fg); border-bottom: 1px solid var(--border); padding-bottom: 0.5rem; margin-bottom: 1rem; }\r\n table { width: 100%; border-collapse: collapse; background: var(--card); border-radius: 8px; overflow: hidden; }\r\n th, td { text-align: left; padding: 0.6rem 1rem; border-bottom: 1px solid var(--border); }\r\n th { background: #21262d; color: #8b949e; font-weight: 600; font-size: 0.85rem; text-transform: uppercase; }\r\n tr:last-child td { border-bottom: none; }\r\n code { background: #21262d; padding: 0.15rem 0.4rem; border-radius: 4px; font-size: 0.85rem; }\r\n .badge { display: inline-block; padding: 0.15rem 0.5rem; border-radius: 12px; font-size: 0.75rem; font-weight: 600; text-transform: uppercase; }\r\n .badge.error { background: rgba(248,81,73,0.15); color: var(--red); }\r\n .badge.warning { background: rgba(210,153,34,0.15); color: var(--yellow); }\r\n footer { margin-top: 3rem; text-align: center; color: #484f58; font-size: 0.85rem; }\r\n footer a { color: var(--accent); text-decoration: none; }\r\n</style>\r\n</head>\r\n<body>\r\n<h1>OpenCroc Report</h1>\r\n<p class=\"subtitle\">Generated in ${result.duration}ms · ${result.modules.length} module(s)</p>\r\n\r\n<div class=\"grid\">\r\n <div class=\"card\"><div class=\"label\">Modules</div><div class=\"value\">${result.modules.length}</div></div>\r\n <div class=\"card\"><div class=\"label\">Tables</div><div class=\"value\">${totalTables}</div></div>\r\n <div class=\"card\"><div class=\"label\">Relations</div><div class=\"value\">${totalRelations}</div></div>\r\n <div class=\"card\"><div class=\"label\">Chains</div><div class=\"value\">${totalChains}</div></div>\r\n <div class=\"card\"><div class=\"label\">Steps</div><div class=\"value\">${totalSteps}</div></div>\r\n <div class=\"card\"><div class=\"label\">Files</div><div class=\"value green\">${result.generatedFiles.length}</div></div>\r\n <div class=\"card\"><div class=\"label\">Errors</div><div class=\"value${errorCount > 0 ? ' red' : ''}\">${errorCount}</div></div>\r\n <div class=\"card\"><div class=\"label\">Warnings</div><div class=\"value${warnCount > 0 ? ' yellow' : ''}\">${warnCount}</div></div>\r\n</div>\r\n\r\n<section>\r\n<h2>ER Diagrams</h2>\r\n<table>\r\n<thead><tr><th>Module</th><th>Tables</th><th>Relations</th></tr></thead>\r\n<tbody>${erSummaryRows(result.erDiagrams)}</tbody>\r\n</table>\r\n</section>\r\n\r\n<section>\r\n<h2>Chain Plans</h2>\r\n<table>\r\n<thead><tr><th>Module</th><th>Chains</th><th>Steps</th></tr></thead>\r\n<tbody>${chainSummaryRows(result.chainPlans)}</tbody>\r\n</table>\r\n</section>\r\n\r\n<section>\r\n<h2>Generated Files (${result.generatedFiles.length})</h2>\r\n<table>\r\n<thead><tr><th>File</th><th>Module</th><th>Chain</th></tr></thead>\r\n<tbody>${fileListRows(result.generatedFiles)}</tbody>\r\n</table>\r\n</section>\r\n\r\n${\n context?.quality || context?.metrics\n ? `<section>\n<h2>Execution Quality</h2>\n<table>\n<thead><tr><th>Item</th><th>Value</th></tr></thead>\n<tbody>\n${context.metrics ? `<tr><td>Passed</td><td>${context.metrics.passed}</td></tr><tr><td>Failed</td><td>${context.metrics.failed}</td></tr><tr><td>Skipped</td><td>${context.metrics.skipped}</td></tr><tr><td>TimedOut</td><td>${context.metrics.timedOut}</td></tr>` : ''}\n${context.quality ? `<tr><td>Gate Level</td><td>${escapeHtml(context.quality.level)}</td></tr><tr><td>Setup Fail</td><td>${String(context.quality.setupFail)}</td></tr><tr><td>Skip Ratio</td><td>${(context.quality.skipRatio * 100).toFixed(2)}%</td></tr><tr><td>Auth Fail Ratio</td><td>${(context.quality.authFailRatio * 100).toFixed(2)}%</td></tr><tr><td>Effective Execution Rate</td><td>${(context.quality.effectiveExecutionRate * 100).toFixed(2)}%</td></tr><tr><td>Auth Status</td><td>${escapeHtml(context.quality.authStatus)}</td></tr><tr><td>Backend Status</td><td>${escapeHtml(context.quality.backendStatus)}</td></tr><tr><td>Reasons</td><td>${escapeHtml(context.quality.reasons.join(', ') || '-')}</td></tr>` : ''}\n</tbody>\n</table>\n</section>`\n : ''\n}\n\n${\r\n result.validationErrors.length > 0\r\n ? `<section>\r\n<h2>Validation Issues (${result.validationErrors.length})</h2>\r\n<table>\r\n<thead><tr><th>Severity</th><th>Module</th><th>Field</th><th>Message</th></tr></thead>\r\n<tbody>${validationRows(result.validationErrors)}</tbody>\r\n</table>\r\n</section>`\r\n : ''\r\n}\r\n\r\n<footer>\r\n Generated by <a href=\"https://github.com/opencroc/opencroc\">OpenCroc</a>\r\n</footer>\r\n</body>\r\n</html>`;\r\n\r\n return {\r\n format: 'html',\r\n content: html,\r\n filename: 'opencroc-report.html',\r\n };\r\n}\r\n\r\n// ===== Report Orchestrator =====\r\n\r\nconst REPORTERS: Record<string, (result: PipelineRunResult, context?: ReportExecutionContext) => ReportOutput> = {\n html: generateHtmlReport,\r\n json: generateJsonReport,\r\n markdown: generateMarkdownReport,\r\n};\r\n\r\n/**\r\n * Generate reports in the specified formats.\r\n */\r\nexport function generateReports(\r\n result: PipelineRunResult,\r\n formats: ('html' | 'json' | 'markdown')[] = ['html'],\r\n context?: ReportExecutionContext,\n): ReportOutput[] {\r\n return formats.map((fmt) => {\r\n const gen = REPORTERS[fmt];\r\n if (!gen) throw new Error(`Unknown report format: \"${fmt}\". Available: ${Object.keys(REPORTERS).join(', ')}`);\r\n return gen(result, context);\n });\r\n}\r\n\r\n// ===== Advanced Reporters (v1.2) =====\r\nexport {\r\n classifyFailure,\r\n buildFailureSummary,\r\n aggregateLogCompletion,\r\n parseApiDomain,\r\n buildBackendChecklist,\r\n renderChecklistMarkdown,\r\n} from './checklist-reporter.js';\r\n\r\nexport {\r\n buildWorkorders,\r\n renderWorkordersMarkdown,\r\n} from './workorder-reporter.js';\r\nexport type { BuildWorkordersOptions } from './workorder-reporter.js';\r\n\r\nexport {\r\n TokenTracker,\r\n renderTokenReportMarkdown,\r\n} from './token-reporter.js';\r\n","/**\r\n * Checklist Reporter — generates backend fix checklists from test results.\r\n *\r\n * Groups failures by API domain, lists affected tests and endpoints,\r\n * and produces both structured data and Markdown output.\r\n */\r\n\r\nimport type {\r\n TestResultRecord,\r\n FailureCategory,\r\n FailureSummary,\r\n BackendDomainItem,\r\n LogCompletionSummary,\r\n} from '../types.js';\r\n\r\n// ===== Failure classification =====\r\n\r\nexport function classifyFailure(error?: string): FailureCategory {\r\n if (!error) return 'other';\r\n if (error.includes('[BACKEND_5XX]')) return 'backend-5xx';\r\n if (error.includes('[MIXED_5XX]')) return 'mixed-5xx';\r\n if (error.includes('[SLOW_API_FATAL]')) return 'slow-api';\r\n if (error.includes('[LOG_COMPLETION_FAIL]')) return 'log-fail';\r\n if (error.includes('[LOG_COMPLETION_TIMEOUT]')) return 'log-timeout';\r\n if (/waitForSelector|toHaveURL|Timeout/i.test(error)) return 'frontend-load';\r\n return 'other';\r\n}\r\n\r\n// ===== Failure summary =====\r\n\r\nexport function buildFailureSummary(records: TestResultRecord[]): FailureSummary {\r\n const failed = records.filter(r => r.status === 'failed');\r\n const cats = failed.map(r => classifyFailure(r.error));\r\n return {\r\n totalFailed: failed.length,\r\n backend5xx: cats.filter(c => c === 'backend-5xx').length,\r\n mixed5xx: cats.filter(c => c === 'mixed-5xx').length,\r\n slowApi: cats.filter(c => c === 'slow-api').length,\r\n logFail: cats.filter(c => c === 'log-fail').length,\r\n logTimeout: cats.filter(c => c === 'log-timeout').length,\r\n frontendLoad: cats.filter(c => c === 'frontend-load').length,\r\n other: cats.filter(c => c === 'other').length,\r\n };\r\n}\r\n\r\n// ===== Log completion aggregation =====\r\n\r\nexport function aggregateLogCompletion(records: TestResultRecord[]): LogCompletionSummary {\r\n let totalCandidates = 0;\r\n let succeeded = 0;\r\n let failed = 0;\r\n let timedOut = 0;\r\n const timedOutFreq = new Map<string, { method: string; path: string; count: number }>();\r\n\r\n for (const r of records) {\r\n const lc = r.logCompletion;\r\n if (!lc || lc.candidateCount === 0) continue;\r\n\r\n totalCandidates += lc.candidateCount;\r\n succeeded += lc.succeeded.length;\r\n failed += lc.failed.length;\r\n timedOut += lc.timedOut.length;\r\n\r\n for (const item of lc.timedOut) {\r\n const key = `${item.method}:${item.path}`;\r\n const existing = timedOutFreq.get(key);\r\n if (existing) existing.count += 1;\r\n else timedOutFreq.set(key, { method: item.method, path: item.path, count: 1 });\r\n }\r\n }\r\n\r\n const timedOutTop5 = Array.from(timedOutFreq.values())\r\n .sort((a, b) => b.count - a.count)\r\n .slice(0, 5)\r\n .map(t => ({ method: t.method, path: t.path, occurrences: t.count }));\r\n\r\n const matchRate = totalCandidates > 0 ? (succeeded + failed) / totalCandidates * 100 : 0;\r\n const effectiveRate = totalCandidates > 0 ? succeeded / totalCandidates * 100 : 0;\r\n\r\n return { totalCandidates, succeeded, failed, timedOut, matchRate, effectiveRate, timedOutTop5 };\r\n}\r\n\r\n// ===== URL extraction helpers =====\r\n\r\nfunction extractUrls(error?: string): string[] {\r\n if (!error) return [];\r\n const matched = error.match(/https?:\\/\\/[^\\s\\n]+/g);\r\n return matched ? Array.from(new Set(matched)) : [];\r\n}\r\n\r\nexport function parseApiDomain(urlStr: string): string | null {\r\n try {\r\n const u = new URL(urlStr);\r\n const segments = u.pathname.split('/').filter(Boolean);\r\n const v1Index = segments.findIndex(s => s === 'v1');\r\n if (v1Index === -1 || v1Index + 1 >= segments.length) return segments[0] || null;\r\n const afterV1 = segments.slice(v1Index + 1);\r\n if (afterV1.length === 0) return null;\r\n const first = afterV1[0];\r\n if (/^\\d+$/.test(first) && afterV1.length > 1) return afterV1[1];\r\n return first;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n// ===== Backend checklist =====\r\n\r\nexport function buildBackendChecklist(records: TestResultRecord[]): BackendDomainItem[] {\r\n const domainMap = new Map<string, { tests: Set<string>; endpoints: Set<string> }>();\r\n const failed = records.filter(r => r.status === 'failed');\r\n\r\n for (const item of failed) {\r\n const cat = classifyFailure(item.error);\r\n if (cat !== 'backend-5xx' && cat !== 'mixed-5xx') continue;\r\n const urls = extractUrls(item.error);\r\n for (const url of urls) {\r\n const domain = parseApiDomain(url);\r\n if (!domain) continue;\r\n const current = domainMap.get(domain) ?? { tests: new Set<string>(), endpoints: new Set<string>() };\r\n current.tests.add(item.title);\r\n current.endpoints.add(url);\r\n domainMap.set(domain, current);\r\n }\r\n }\r\n\r\n return Array.from(domainMap.entries())\r\n .map(([domain, v]) => ({\r\n domain,\r\n tests: Array.from(v.tests).sort(),\r\n endpoints: Array.from(v.endpoints).sort(),\r\n }))\r\n .sort((a, b) => b.tests.length - a.tests.length || a.domain.localeCompare(b.domain));\r\n}\r\n\r\n// ===== Markdown renderer =====\r\n\r\nexport function renderChecklistMarkdown(\r\n items: BackendDomainItem[],\r\n summary: FailureSummary,\r\n logSummary?: LogCompletionSummary,\r\n): string {\r\n const lines: string[] = [\r\n '# Backend Fix Checklist',\r\n '',\r\n ];\r\n\r\n if (logSummary) {\r\n lines.push(\r\n `- Log match rate: ${logSummary.matchRate.toFixed(2)}% (candidates=${logSummary.totalCandidates}, succeeded=${logSummary.succeeded}, failed=${logSummary.failed}, timedOut=${logSummary.timedOut})`,\r\n `- Effective success rate: ${logSummary.effectiveRate.toFixed(2)}%`,\r\n );\r\n }\r\n lines.push(\r\n `- Backend 5xx: ${summary.backend5xx}`,\r\n `- Mixed 5xx: ${summary.mixed5xx}`,\r\n `- Slow API: ${summary.slowApi}`,\r\n `- Log fail: ${summary.logFail}`,\r\n `- Log timeout: ${summary.logTimeout}`,\r\n `- Frontend load: ${summary.frontendLoad}`,\r\n `- Other: ${summary.other}`,\r\n '',\r\n );\r\n\r\n if (logSummary && logSummary.timedOutTop5.length > 0) {\r\n lines.push('### Timed-out APIs Top 5', '', '| # | Method | Path | Occurrences |', '|---|--------|------|-------------|');\r\n logSummary.timedOutTop5.forEach((t, i) => {\r\n lines.push(`| ${i + 1} | ${t.method} | ${t.path} | ${t.occurrences} |`);\r\n });\r\n lines.push('');\r\n }\r\n\r\n if (items.length === 0) {\r\n lines.push('No backend 5xx failures this run.');\r\n return lines.join('\\n') + '\\n';\r\n }\r\n\r\n for (const item of items) {\r\n lines.push(\r\n `## ${item.domain}`,\r\n '',\r\n `- Failed tests: ${item.tests.length}`,\r\n '- Affected tests:',\r\n );\r\n for (const t of item.tests) lines.push(` - ${t}`);\r\n lines.push('- Failed endpoints:');\r\n for (const e of item.endpoints) lines.push(` - ${e}`);\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n') + '\\n';\r\n}\r\n","/**\r\n * Workorder Reporter — auto-generates prioritized backend work orders.\r\n *\r\n * Priority rules:\r\n * - P0: ≥3 affected tests OR log completion rate < 90%\r\n * - P1: 2 affected tests\r\n * - P2: 1 affected test\r\n *\r\n * Each workorder includes objective, affected scope, and acceptance criteria.\r\n */\r\n\r\nimport type {\r\n BackendDomainItem,\r\n FailureSummary,\r\n LogCompletionSummary,\r\n WorkorderItem,\r\n} from '../types.js';\r\n\r\n// ===== Priority assignment =====\r\n\r\nfunction assignPriority(item: BackendDomainItem, isLogRate: boolean): 'P0' | 'P1' | 'P2' {\r\n if (isLogRate) return 'P0';\r\n if (item.tests.length >= 3) return 'P0';\r\n if (item.tests.length === 2) return 'P1';\r\n return 'P2';\r\n}\r\n\r\n// ===== Workorder builder =====\r\n\r\nexport interface BuildWorkordersOptions {\r\n checklist: BackendDomainItem[];\r\n summary: FailureSummary;\r\n logSummary?: LogCompletionSummary;\r\n logRateThreshold?: number;\r\n}\r\n\r\nexport function buildWorkorders(opts: BuildWorkordersOptions): WorkorderItem[] {\r\n const { checklist, logSummary, logRateThreshold = 90 } = opts;\r\n const result: WorkorderItem[] = [];\r\n let idx = 1;\r\n\r\n // Auto P0 workorder if log completion rate is below threshold\r\n if (logSummary && logSummary.totalCandidates > 0 && logSummary.matchRate < logRateThreshold) {\r\n const logItem: BackendDomainItem = {\r\n domain: 'Log Completion Standards',\r\n tests: logSummary.timedOutTop5.map(t => `${t.method} ${t.path} (×${t.occurrences})`),\r\n endpoints: logSummary.timedOutTop5.map(t => t.path),\r\n };\r\n result.push({\r\n index: idx++,\r\n domain: logItem.domain,\r\n priority: 'P0',\r\n tests: logItem.tests,\r\n endpoints: logItem.endpoints,\r\n objective: 'Add missing end-phase structured logs for timed-out APIs',\r\n acceptanceCriteria: [\r\n `Log completion match rate ≥ ${logRateThreshold}%`,\r\n 'TimedOut API count drops to 0 or only SSE/long-polling endpoints remain',\r\n ],\r\n });\r\n }\r\n\r\n // Standard workorders from checklist\r\n for (const item of checklist) {\r\n const priority = assignPriority(item, false);\r\n result.push({\r\n index: idx++,\r\n domain: item.domain,\r\n priority,\r\n tests: item.tests,\r\n endpoints: item.endpoints,\r\n objective: 'Fix 500 errors and return a valid business response',\r\n acceptanceCriteria: [\r\n 'HTTP status returns 2xx for affected endpoints',\r\n 'No [BACKEND_5XX] errors in corresponding page traversal',\r\n 'All covered tests pass',\r\n ],\r\n });\r\n }\r\n\r\n return result;\r\n}\r\n\r\n// ===== Markdown renderer =====\r\n\r\nexport function renderWorkordersMarkdown(\r\n workorders: WorkorderItem[],\r\n summary: FailureSummary,\r\n logSummary?: LogCompletionSummary,\r\n): string {\r\n const lines: string[] = [\r\n '# Backend Work Orders',\r\n '',\r\n ];\r\n\r\n if (logSummary) {\r\n lines.push(\r\n `- Log match rate: ${logSummary.matchRate.toFixed(2)}%`,\r\n `- Effective success rate: ${logSummary.effectiveRate.toFixed(2)}%`,\r\n );\r\n }\r\n lines.push(\r\n `- Total failed: ${summary.totalFailed}`,\r\n `- Backend 5xx: ${summary.backend5xx}`,\r\n `- Mixed 5xx: ${summary.mixed5xx}`,\r\n `- Slow API: ${summary.slowApi}`,\r\n `- Log fail: ${summary.logFail}`,\r\n `- Log timeout: ${summary.logTimeout}`,\r\n `- Frontend load: ${summary.frontendLoad}`,\r\n `- Other: ${summary.other}`,\r\n '',\r\n );\r\n\r\n if (workorders.length === 0) {\r\n lines.push('No backend work orders this run.');\r\n return lines.join('\\n') + '\\n';\r\n }\r\n\r\n for (const wo of workorders) {\r\n lines.push(\r\n `## Workorder ${wo.index} - ${wo.domain}`,\r\n '',\r\n `- Priority: ${wo.priority}`,\r\n `- Affected tests: ${wo.tests.length}`,\r\n '- Scope:',\r\n );\r\n for (const t of wo.tests) lines.push(` - ${t}`);\r\n if (wo.endpoints.length > 0) {\r\n lines.push('- Endpoints:');\r\n for (const e of wo.endpoints) lines.push(` - ${e}`);\r\n }\r\n lines.push(`- Objective: ${wo.objective}`);\r\n lines.push('- Acceptance criteria:');\r\n for (const c of wo.acceptanceCriteria) lines.push(` - ${c}`);\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n') + '\\n';\r\n}\r\n","/**\r\n * Token Usage Reporter — tracks and reports LLM token consumption.\r\n *\r\n * Aggregates usage entries by category and model, computes costs,\r\n * tracks budget utilization, and renders both structured data and Markdown.\r\n */\r\n\r\nimport type { TokenUsageEntry, TokenUsageSummary } from '../types.js';\r\n\r\n// ===== Token Tracker =====\r\n\r\nexport class TokenTracker {\r\n private entries: TokenUsageEntry[] = [];\r\n private budget: number | null = null;\r\n\r\n setBudget(maxTokens: number): void {\r\n this.budget = maxTokens;\r\n }\r\n\r\n record(entry: TokenUsageEntry): void {\r\n this.entries.push(entry);\r\n }\r\n\r\n reset(): void {\r\n this.entries = [];\r\n }\r\n\r\n getSummary(): TokenUsageSummary {\r\n const totalRequests = this.entries.length;\r\n let totalPromptTokens = 0;\r\n let totalCompletionTokens = 0;\r\n let totalEstimatedCost = 0;\r\n let totalLatency = 0;\r\n\r\n const byCategory: TokenUsageSummary['byCategory'] = {};\r\n const byModel: TokenUsageSummary['byModel'] = {};\r\n\r\n for (const e of this.entries) {\r\n totalPromptTokens += e.promptTokens;\r\n totalCompletionTokens += e.completionTokens;\r\n totalEstimatedCost += e.estimatedCost;\r\n totalLatency += e.latencyMs;\r\n\r\n // By category\r\n if (!byCategory[e.category]) {\r\n byCategory[e.category] = { requests: 0, promptTokens: 0, completionTokens: 0, totalTokens: 0, estimatedCost: 0 };\r\n }\r\n const cat = byCategory[e.category];\r\n cat.requests++;\r\n cat.promptTokens += e.promptTokens;\r\n cat.completionTokens += e.completionTokens;\r\n cat.totalTokens += e.promptTokens + e.completionTokens;\r\n cat.estimatedCost += e.estimatedCost;\r\n\r\n // By model\r\n if (!byModel[e.model]) {\r\n byModel[e.model] = { requests: 0, totalTokens: 0, estimatedCost: 0 };\r\n }\r\n const mod = byModel[e.model];\r\n mod.requests++;\r\n mod.totalTokens += e.promptTokens + e.completionTokens;\r\n mod.estimatedCost += e.estimatedCost;\r\n }\r\n\r\n const totalTokens = totalPromptTokens + totalCompletionTokens;\r\n const budgetUsedPercent = this.budget && this.budget > 0\r\n ? Math.round(totalTokens / this.budget * 10000) / 100\r\n : null;\r\n\r\n return {\r\n totalRequests,\r\n totalTokens,\r\n totalPromptTokens,\r\n totalCompletionTokens,\r\n totalEstimatedCost,\r\n avgLatencyMs: totalRequests > 0 ? Math.round(totalLatency / totalRequests) : 0,\r\n byCategory,\r\n byModel,\r\n budgetUsedPercent,\r\n budgetExceeded: budgetUsedPercent !== null && budgetUsedPercent > 100,\r\n };\r\n }\r\n}\r\n\r\n// ===== Markdown renderer =====\r\n\r\nexport function renderTokenReportMarkdown(summary: TokenUsageSummary): string {\r\n const lines: string[] = [\r\n '# AI Token Usage Report',\r\n '',\r\n `- Total requests: ${summary.totalRequests}`,\r\n `- Total tokens: ${summary.totalTokens.toLocaleString()}`,\r\n `- Prompt tokens: ${summary.totalPromptTokens.toLocaleString()}`,\r\n `- Completion tokens: ${summary.totalCompletionTokens.toLocaleString()}`,\r\n `- Estimated cost: ¥${summary.totalEstimatedCost.toFixed(4)}`,\r\n `- Average latency: ${summary.avgLatencyMs}ms`,\r\n ];\r\n\r\n if (summary.budgetUsedPercent !== null) {\r\n lines.push(`- Budget used: ${summary.budgetUsedPercent}%${summary.budgetExceeded ? ' **EXCEEDED**' : ''}`);\r\n }\r\n lines.push('');\r\n\r\n // By category\r\n const cats = Object.entries(summary.byCategory).sort((a, b) => b[1].totalTokens - a[1].totalTokens);\r\n if (cats.length > 0) {\r\n lines.push(\r\n '## By Category',\r\n '',\r\n '| Category | Requests | Prompt | Completion | Total | Cost |',\r\n '|----------|----------|--------|------------|-------|------|',\r\n );\r\n for (const [cat, d] of cats) {\r\n lines.push(`| ${cat} | ${d.requests} | ${d.promptTokens.toLocaleString()} | ${d.completionTokens.toLocaleString()} | ${d.totalTokens.toLocaleString()} | ¥${d.estimatedCost.toFixed(4)} |`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // By model\r\n const models = Object.entries(summary.byModel);\r\n if (models.length > 0) {\r\n lines.push(\r\n '## By Model',\r\n '',\r\n '| Model | Requests | Total Tokens | Cost |',\r\n '|-------|----------|-------------|------|',\r\n );\r\n for (const [model, d] of models) {\r\n lines.push(`| ${model} | ${d.requests} | ${d.totalTokens.toLocaleString()} | ¥${d.estimatedCost.toFixed(4)} |`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n') + '\\n';\r\n}\r\n","import type { PipelineRunResult } from '../types.js';\r\n\r\nexport interface DashboardData {\r\n generatedAt: string;\r\n durationMs: number;\r\n modules: string[];\r\n totals: {\r\n modules: number;\r\n tables: number;\r\n relations: number;\r\n chains: number;\r\n steps: number;\r\n files: number;\r\n errors: number;\r\n warnings: number;\r\n };\r\n moduleCards: Array<{\r\n module: string;\r\n tables: number;\r\n relations: number;\r\n chains: number;\r\n steps: number;\r\n }>;\r\n files: Array<{ filePath: string; module: string; chain: string }>;\r\n issues: Array<{ severity: string; module: string; field: string; message: string }>;\r\n}\r\n\r\nexport interface DashboardOutput {\r\n filename: string;\r\n content: string;\r\n}\r\n\r\nfunction escapeHtml(s: string): string {\r\n return s\r\n .replace(/&/g, '&')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n .replace(/\"/g, '"')\r\n .replace(/'/g, ''');\r\n}\r\n\r\nfunction number(v: unknown): number {\r\n return typeof v === 'number' && Number.isFinite(v) ? v : 0;\r\n}\r\n\r\nexport function buildDashboardDataFromPipeline(result: PipelineRunResult): DashboardData {\r\n const moduleCards = result.modules.map((mod) => {\r\n const er = result.erDiagrams.get(mod);\r\n const plan = result.chainPlans.get(mod);\r\n return {\r\n module: mod,\r\n tables: er?.tables.length ?? 0,\r\n relations: er?.relations.length ?? 0,\r\n chains: plan?.chains.length ?? 0,\r\n steps: plan?.totalSteps ?? 0,\r\n };\r\n });\r\n\r\n const totals = {\r\n modules: result.modules.length,\r\n tables: moduleCards.reduce((s, m) => s + m.tables, 0),\r\n relations: moduleCards.reduce((s, m) => s + m.relations, 0),\r\n chains: moduleCards.reduce((s, m) => s + m.chains, 0),\r\n steps: moduleCards.reduce((s, m) => s + m.steps, 0),\r\n files: result.generatedFiles.length,\r\n errors: result.validationErrors.filter((e) => e.severity === 'error').length,\r\n warnings: result.validationErrors.filter((e) => e.severity === 'warning').length,\r\n };\r\n\r\n return {\r\n generatedAt: new Date().toISOString(),\r\n durationMs: result.duration,\r\n modules: [...result.modules],\r\n totals,\r\n moduleCards,\r\n files: result.generatedFiles.map((f) => ({ filePath: f.filePath, module: f.module, chain: f.chain })),\r\n issues: result.validationErrors.map((e) => ({\r\n severity: e.severity,\r\n module: e.module,\r\n field: e.field,\r\n message: e.message,\r\n })),\r\n };\r\n}\r\n\r\nexport function buildDashboardDataFromReportJson(input: unknown): DashboardData {\r\n const src = (input ?? {}) as Record<string, unknown>;\r\n const modules = Array.isArray(src.modules) ? src.modules.map((m) => String(m)) : [];\r\n const er = (src.erDiagrams ?? {}) as Record<string, { tables?: unknown; relations?: unknown }>;\r\n const plans = (src.chainPlans ?? {}) as Record<string, { chains?: unknown; totalSteps?: unknown }>;\r\n const files = Array.isArray(src.generatedFiles)\r\n ? src.generatedFiles.map((f) => {\r\n const row = f as Record<string, unknown>;\r\n return {\r\n filePath: String(row.filePath ?? ''),\r\n module: String(row.module ?? ''),\r\n chain: String(row.chain ?? ''),\r\n };\r\n })\r\n : [];\r\n\r\n const rawIssues = Array.isArray(src.validationErrors) ? src.validationErrors : [];\r\n const issues = rawIssues.map((item) => {\r\n const row = item as Record<string, unknown>;\r\n return {\r\n severity: String(row.severity ?? 'warning'),\r\n module: String(row.module ?? 'unknown'),\r\n field: String(row.field ?? 'unknown'),\r\n message: String(row.message ?? ''),\r\n };\r\n });\r\n\r\n const moduleCards = modules.map((mod) => ({\r\n module: mod,\r\n tables: number(er[mod]?.tables),\r\n relations: number(er[mod]?.relations),\r\n chains: number(plans[mod]?.chains),\r\n steps: number(plans[mod]?.totalSteps),\r\n }));\r\n\r\n return {\r\n generatedAt: new Date().toISOString(),\r\n durationMs: number(src.duration),\r\n modules,\r\n totals: {\r\n modules: modules.length,\r\n tables: moduleCards.reduce((s, m) => s + m.tables, 0),\r\n relations: moduleCards.reduce((s, m) => s + m.relations, 0),\r\n chains: moduleCards.reduce((s, m) => s + m.chains, 0),\r\n steps: moduleCards.reduce((s, m) => s + m.steps, 0),\r\n files: files.length,\r\n errors: issues.filter((i) => i.severity === 'error').length,\r\n warnings: issues.filter((i) => i.severity === 'warning').length,\r\n },\r\n moduleCards,\r\n files,\r\n issues,\r\n };\r\n}\r\n\r\nexport function generateVisualDashboardHtml(data: DashboardData): string {\r\n const moduleCardHtml = data.moduleCards\r\n .map(\r\n (m) => `<article class=\"module-card reveal\">\r\n <h3>${escapeHtml(m.module)}</h3>\r\n <div class=\"meta\">${m.tables} tables · ${m.relations} relations</div>\r\n <div class=\"bars\">\r\n <div class=\"bar\"><span>Chains</span><strong>${m.chains}</strong></div>\r\n <div class=\"bar\"><span>Steps</span><strong>${m.steps}</strong></div>\r\n </div>\r\n</article>`,\r\n )\r\n .join('\\n');\r\n\r\n const fileRows = data.files\r\n .slice(0, 20)\r\n .map(\r\n (f) => `<tr><td><code>${escapeHtml(f.filePath)}</code></td><td>${escapeHtml(f.module)}</td><td>${escapeHtml(f.chain)}</td></tr>`,\r\n )\r\n .join('\\n');\r\n\r\n const issueRows = data.issues\r\n .map(\r\n (i) => `<tr class=\"${escapeHtml(i.severity)}\"><td>${escapeHtml(i.severity)}</td><td>${escapeHtml(i.module)}</td><td>${escapeHtml(i.field)}</td><td>${escapeHtml(i.message)}</td></tr>`,\r\n )\r\n .join('\\n');\r\n\r\n return `<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n <meta charset=\"utf-8\" />\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\r\n <title>OpenCroc Visual Dashboard</title>\r\n <style>\r\n @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=IBM+Plex+Mono:wght@400;500&display=swap');\r\n :root {\r\n --bg: #f4efe6;\r\n --ink: #18222c;\r\n --card: #fff8ef;\r\n --line: #d8c7b4;\r\n --accent: #0b7a75;\r\n --accent-2: #f26a2e;\r\n --ok: #2f7d32;\r\n --warn: #b7791f;\r\n --err: #c0392b;\r\n }\r\n * { box-sizing: border-box; }\r\n body {\r\n margin: 0;\r\n font-family: 'Space Grotesk', 'Segoe UI', sans-serif;\r\n color: var(--ink);\r\n background:\r\n radial-gradient(circle at 15% 10%, #f9e2c5 0%, transparent 32%),\r\n radial-gradient(circle at 85% 0%, #d3efe4 0%, transparent 28%),\r\n var(--bg);\r\n min-height: 100vh;\r\n }\r\n .wrap { max-width: 1160px; margin: 0 auto; padding: 24px 18px 40px; }\r\n .hero {\r\n border: 2px solid var(--line);\r\n border-radius: 18px;\r\n background: linear-gradient(130deg, #fff8ef 0%, #f8f2ea 45%, #f3ece3 100%);\r\n padding: 22px;\r\n box-shadow: 0 12px 24px rgba(24, 34, 44, 0.08);\r\n position: relative;\r\n overflow: hidden;\r\n }\r\n .hero::after {\r\n content: '';\r\n position: absolute;\r\n right: -42px;\r\n top: -38px;\r\n width: 160px;\r\n height: 160px;\r\n border-radius: 50%;\r\n background: conic-gradient(from 50deg, #f26a2e 0deg, #f7a35a 90deg, #0b7a75 220deg, #f26a2e 360deg);\r\n opacity: 0.14;\r\n }\r\n h1 { margin: 0; font-size: clamp(1.6rem, 3vw, 2.5rem); letter-spacing: -0.03em; }\r\n .subtitle { margin-top: 8px; font-size: 0.95rem; opacity: 0.82; }\r\n .kpi-grid {\r\n margin-top: 16px;\r\n display: grid;\r\n grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));\r\n gap: 10px;\r\n }\r\n .kpi {\r\n border: 1px solid var(--line);\r\n border-radius: 12px;\r\n padding: 10px 12px;\r\n background: #fffdf9;\r\n }\r\n .kpi .label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; opacity: 0.7; }\r\n .kpi .value { font-size: 1.45rem; font-weight: 700; margin-top: 4px; }\r\n .kpi.error .value { color: var(--err); }\r\n .kpi.warning .value { color: var(--warn); }\r\n .kpi.files .value { color: var(--accent); }\r\n\r\n .section-title {\r\n margin: 24px 0 10px;\r\n font-size: 1rem;\r\n text-transform: uppercase;\r\n letter-spacing: 0.08em;\r\n color: #344250;\r\n }\r\n\r\n .module-grid {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\r\n gap: 12px;\r\n }\r\n .module-card {\r\n border: 1px solid var(--line);\r\n border-radius: 14px;\r\n padding: 14px;\r\n background: var(--card);\r\n box-shadow: 0 8px 16px rgba(24, 34, 44, 0.06);\r\n }\r\n .module-card h3 { margin: 0 0 6px; font-size: 1.05rem; }\r\n .module-card .meta { font-size: 0.85rem; opacity: 0.78; }\r\n .bars { margin-top: 10px; display: grid; gap: 8px; }\r\n .bar { display: flex; justify-content: space-between; border-top: 1px dashed var(--line); padding-top: 7px; }\r\n\r\n table {\r\n width: 100%;\r\n border-collapse: collapse;\r\n border: 1px solid var(--line);\r\n border-radius: 12px;\r\n overflow: hidden;\r\n background: #fffdf9;\r\n font-family: 'IBM Plex Mono', 'Consolas', monospace;\r\n font-size: 0.82rem;\r\n }\r\n thead { background: #efe5d8; }\r\n th, td { text-align: left; padding: 8px 10px; border-bottom: 1px solid #eadfce; }\r\n tbody tr:last-child td { border-bottom: none; }\r\n tr.error td:first-child { color: var(--err); font-weight: 700; }\r\n tr.warning td:first-child { color: var(--warn); font-weight: 700; }\r\n\r\n code {\r\n font-family: 'IBM Plex Mono', 'Consolas', monospace;\r\n background: #f5ece0;\r\n border: 1px solid #eadfce;\r\n border-radius: 6px;\r\n padding: 1px 5px;\r\n }\r\n\r\n .reveal { opacity: 0; transform: translateY(12px); animation: rise .55s ease forwards; }\r\n .module-card.reveal:nth-child(2) { animation-delay: .06s; }\r\n .module-card.reveal:nth-child(3) { animation-delay: .12s; }\r\n .module-card.reveal:nth-child(4) { animation-delay: .18s; }\r\n .module-card.reveal:nth-child(5) { animation-delay: .24s; }\r\n @keyframes rise {\r\n to { opacity: 1; transform: translateY(0); }\r\n }\r\n\r\n @media (max-width: 700px) {\r\n .wrap { padding: 14px 12px 28px; }\r\n .hero { padding: 16px; }\r\n table { font-size: 0.76rem; }\r\n th, td { padding: 7px 8px; }\r\n }\r\n </style>\r\n</head>\r\n<body>\r\n <main class=\"wrap\">\r\n <section class=\"hero reveal\">\r\n <h1>OpenCroc Visual Dashboard</h1>\r\n <p class=\"subtitle\">Pipeline finished in ${data.durationMs}ms · Generated ${escapeHtml(data.generatedAt)}</p>\r\n <div class=\"kpi-grid\">\r\n <div class=\"kpi\"><div class=\"label\">Modules</div><div class=\"value\">${data.totals.modules}</div></div>\r\n <div class=\"kpi\"><div class=\"label\">Tables</div><div class=\"value\">${data.totals.tables}</div></div>\r\n <div class=\"kpi\"><div class=\"label\">Relations</div><div class=\"value\">${data.totals.relations}</div></div>\r\n <div class=\"kpi\"><div class=\"label\">Chains</div><div class=\"value\">${data.totals.chains}</div></div>\r\n <div class=\"kpi\"><div class=\"label\">Steps</div><div class=\"value\">${data.totals.steps}</div></div>\r\n <div class=\"kpi files\"><div class=\"label\">Files</div><div class=\"value\">${data.totals.files}</div></div>\r\n <div class=\"kpi error\"><div class=\"label\">Errors</div><div class=\"value\">${data.totals.errors}</div></div>\r\n <div class=\"kpi warning\"><div class=\"label\">Warnings</div><div class=\"value\">${data.totals.warnings}</div></div>\r\n </div>\r\n </section>\r\n\r\n <h2 class=\"section-title\">Module Health</h2>\r\n <section class=\"module-grid\">\r\n ${moduleCardHtml || '<article class=\"module-card\">No module data</article>'}\r\n </section>\r\n\r\n <h2 class=\"section-title\">Generated Files (Top 20)</h2>\r\n <section>\r\n <table>\r\n <thead><tr><th>File</th><th>Module</th><th>Chain</th></tr></thead>\r\n <tbody>${fileRows || '<tr><td colspan=\"3\">No files generated</td></tr>'}</tbody>\r\n </table>\r\n </section>\r\n\r\n <h2 class=\"section-title\">Validation Issues</h2>\r\n <section>\r\n <table>\r\n <thead><tr><th>Severity</th><th>Module</th><th>Field</th><th>Message</th></tr></thead>\r\n <tbody>${issueRows || '<tr><td colspan=\"4\">No validation issues</td></tr>'}</tbody>\r\n </table>\r\n </section>\r\n </main>\r\n</body>\r\n</html>`;\r\n}\r\n\r\nexport function generateVisualDashboard(result: PipelineRunResult): DashboardOutput {\r\n const data = buildDashboardDataFromPipeline(result);\r\n return {\r\n filename: 'opencroc-dashboard.html',\r\n content: generateVisualDashboardHtml(data),\r\n };\r\n}\r\n","/**\r\n * VSCode extension scaffold for OpenCroc.\r\n *\r\n * This module provides the extension activation logic, command definitions,\r\n * and tree view data provider for the OpenCroc sidebar panel.\r\n *\r\n * To build:\r\n * 1. Copy `vscode-extension/` from the opencroc repo\r\n * 2. Run `npm install && npm run compile`\r\n * 3. Press F5 in VS Code to launch the Extension Development Host\r\n */\r\n\r\n// ===== Extension Manifest Types (subset of vscode.d.ts for portability) =====\r\n\r\nexport interface ExtensionCommand {\r\n command: string;\r\n title: string;\r\n category: string;\r\n}\r\n\r\nexport interface TreeItem {\r\n label: string;\r\n description?: string;\r\n tooltip?: string;\r\n iconId?: string;\r\n children?: TreeItem[];\r\n command?: string;\r\n}\r\n\r\n// ===== Commands =====\r\n\r\nexport const EXTENSION_ID = 'opencroc.opencroc';\r\n\r\nexport const COMMANDS: ExtensionCommand[] = [\r\n { command: 'opencroc.init', title: 'Initialize Project', category: 'OpenCroc' },\r\n { command: 'opencroc.generate', title: 'Generate Tests', category: 'OpenCroc' },\r\n { command: 'opencroc.generateModule', title: 'Generate Tests for Module...', category: 'OpenCroc' },\r\n { command: 'opencroc.test', title: 'Run Tests', category: 'OpenCroc' },\r\n { command: 'opencroc.testModule', title: 'Run Tests for Module...', category: 'OpenCroc' },\r\n { command: 'opencroc.validate', title: 'Validate Configuration', category: 'OpenCroc' },\r\n { command: 'opencroc.heal', title: 'Self-Heal Failures', category: 'OpenCroc' },\r\n { command: 'opencroc.openReport', title: 'Open Report', category: 'OpenCroc' },\r\n { command: 'opencroc.ci', title: 'Generate CI Template', category: 'OpenCroc' },\r\n];\r\n\r\n// ===== Tree View Data =====\r\n\r\nexport function buildModuleTree(modules: string[]): TreeItem[] {\r\n return modules.map((mod) => ({\r\n label: mod,\r\n description: 'module',\r\n iconId: 'symbol-module',\r\n children: [\r\n { label: 'Generate Tests', command: 'opencroc.generateModule', iconId: 'play' },\r\n { label: 'Run Tests', command: 'opencroc.testModule', iconId: 'testing-run-icon' },\r\n { label: 'View ER Diagram', command: 'opencroc.openReport', iconId: 'graph' },\r\n ],\r\n }));\r\n}\r\n\r\nexport function buildStatusTree(stats: {\r\n modules: number;\r\n tables: number;\r\n relations: number;\r\n generatedFiles: number;\r\n errors: number;\r\n}): TreeItem[] {\r\n return [\r\n { label: `Modules: ${stats.modules}`, iconId: 'symbol-module' },\r\n { label: `Tables: ${stats.tables}`, iconId: 'database' },\r\n { label: `Relations: ${stats.relations}`, iconId: 'git-merge' },\r\n { label: `Generated: ${stats.generatedFiles} files`, iconId: 'file-code' },\r\n {\r\n label: stats.errors > 0 ? `Errors: ${stats.errors}` : 'No errors',\r\n iconId: stats.errors > 0 ? 'error' : 'pass',\r\n },\r\n ];\r\n}\r\n\r\n// ===== Package.json Generator =====\r\n\r\nexport function generateExtensionManifest(): Record<string, unknown> {\r\n return {\r\n name: 'opencroc',\r\n displayName: 'OpenCroc',\r\n description: 'AI-native E2E testing — generate, run, and self-heal tests from VS Code',\r\n version: '0.1.0',\r\n publisher: 'opencroc',\r\n license: 'MIT',\r\n repository: { type: 'git', url: 'https://github.com/opencroc/opencroc' },\r\n engines: { vscode: '^1.85.0' },\r\n categories: ['Testing'],\r\n keywords: ['e2e', 'testing', 'playwright', 'ai', 'self-healing'],\r\n activationEvents: ['workspaceContains:opencroc.config.ts', 'workspaceContains:opencroc.config.js'],\r\n main: './out/extension.js',\r\n contributes: {\r\n commands: COMMANDS.map((c) => ({\r\n command: c.command,\r\n title: c.title,\r\n category: c.category,\r\n })),\r\n viewsContainers: {\r\n activitybar: [\r\n {\r\n id: 'opencroc',\r\n title: 'OpenCroc',\r\n icon: 'resources/opencroc.svg',\r\n },\r\n ],\r\n },\r\n views: {\r\n opencroc: [\r\n { id: 'opencroc.status', name: 'Status' },\r\n { id: 'opencroc.modules', name: 'Modules' },\r\n ],\r\n },\r\n configuration: {\r\n title: 'OpenCroc',\r\n properties: {\r\n 'opencroc.autoGenerate': {\r\n type: 'boolean',\r\n default: false,\r\n description: 'Automatically regenerate tests on file save',\r\n },\r\n 'opencroc.reportFormat': {\r\n type: 'string',\r\n default: 'html',\r\n enum: ['html', 'json', 'markdown'],\r\n description: 'Default report format',\r\n },\r\n },\r\n },\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Generate the extension's entry point (activation function).\r\n * Returns TypeScript source code for `src/extension.ts`.\r\n */\r\nexport function generateExtensionEntrypoint(): string {\r\n return `import * as vscode from 'vscode';\r\nimport { exec } from 'child_process';\r\nimport { promisify } from 'util';\r\n\r\nconst run = promisify(exec);\r\n\r\nexport function activate(context: vscode.ExtensionContext) {\r\n const outputChannel = vscode.window.createOutputChannel('OpenCroc');\r\n\r\n async function runCommand(cmd: string) {\r\n const workspaceFolder = vscode.workspace.workspaceFolders?.[0];\r\n if (!workspaceFolder) {\r\n vscode.window.showErrorMessage('No workspace folder open');\r\n return;\r\n }\r\n outputChannel.show();\r\n outputChannel.appendLine(\\`> \\${cmd}\\`);\r\n try {\r\n const { stdout, stderr } = await run(cmd, { cwd: workspaceFolder.uri.fsPath });\r\n if (stdout) outputChannel.appendLine(stdout);\r\n if (stderr) outputChannel.appendLine(stderr);\r\n vscode.window.showInformationMessage(\\`OpenCroc: \\${cmd} completed\\`);\r\n } catch (err: unknown) {\r\n const message = err instanceof Error ? err.message : String(err);\r\n outputChannel.appendLine(\\`Error: \\${message}\\`);\r\n vscode.window.showErrorMessage(\\`OpenCroc: \\${message}\\`);\r\n }\r\n }\r\n\r\n context.subscriptions.push(\r\n vscode.commands.registerCommand('opencroc.init', () => runCommand('npx opencroc init --yes')),\r\n vscode.commands.registerCommand('opencroc.generate', () => runCommand('npx opencroc generate --all')),\r\n vscode.commands.registerCommand('opencroc.test', () => runCommand('npx opencroc test')),\r\n vscode.commands.registerCommand('opencroc.validate', () => runCommand('npx opencroc validate')),\r\n vscode.commands.registerCommand('opencroc.heal', () => runCommand('npx opencroc heal')),\r\n vscode.commands.registerCommand('opencroc.ci', async () => {\r\n const platform = await vscode.window.showQuickPick(['github', 'gitlab'], {\r\n placeHolder: 'Select CI platform',\r\n });\r\n if (platform) {\r\n await runCommand(\\`npx opencroc ci --platform=\\${platform}\\`);\r\n }\r\n }),\r\n vscode.commands.registerCommand('opencroc.generateModule', async () => {\r\n const mod = await vscode.window.showInputBox({ prompt: 'Module name' });\r\n if (mod) await runCommand(\\`npx opencroc generate --module=\\${mod}\\`);\r\n }),\r\n vscode.commands.registerCommand('opencroc.testModule', async () => {\r\n const mod = await vscode.window.showInputBox({ prompt: 'Module name' });\r\n if (mod) await runCommand(\\`npx opencroc test --module=\\${mod}\\`);\r\n }),\r\n );\r\n\r\n outputChannel.appendLine('OpenCroc extension activated');\r\n}\r\n\r\nexport function deactivate() {}\r\n`;\r\n}\r\n","export { generatePlaywrightConfig } from './playwright-config-generator.js';\r\nexport { generateGlobalSetup } from './global-setup-generator.js';\r\nexport { generateGlobalTeardown } from './global-teardown-generator.js';\r\nexport { generateAuthSetup } from './auth-setup-generator.js';\r\nexport { resilientFetch, waitForBackend } from './resilient-fetch.js';\r\nexport { NetworkMonitor } from './network-monitor.js';\r\nexport {\r\n extractParamNames,\r\n extractParamsFromHref,\r\n buildPath,\r\n extractIdFromText,\r\n resolveFromSeedData,\r\n} from './dynamic-route-resolver.js';\r\nexport {\r\n selectCandidates,\r\n selectCandidatesFromLogs,\r\n mergeCandidates,\r\n waitForLogCompletion,\r\n} from './log-completion-waiter.js';\r\nexport { createRulesEngine } from './critical-api-rules.js';\r\n","import type { OpenCrocConfig } from '../types.js';\r\n\r\n/**\r\n * Generate playwright.config.ts content based on OpenCroc config.\r\n */\r\nexport function generatePlaywrightConfig(config: OpenCrocConfig): string {\r\n const pw = config.playwright ?? {};\r\n const rt = config.runtime ?? {};\r\n const outDir = config.outDir || './opencroc-output';\r\n\r\n const baseURL = pw.baseURL ? `'${pw.baseURL}'` : \"process.env.BASE_URL || 'http://localhost:3000'\";\r\n const timeout = pw.timeout ?? 30_000;\r\n const workers = pw.workers ?? (null as number | null); // null → use expression\r\n const retries = pw.retries ?? (null as number | null);\r\n const actionTimeout = pw.actionTimeout ?? 10_000;\r\n const navigationTimeout = pw.navigationTimeout ?? timeout;\r\n const storageState = rt.auth?.storageStatePath || 'playwright/.auth/user.json';\r\n\r\n const hasAuth = !!(rt.auth?.loginUrl);\r\n\r\n const lines: string[] = [];\r\n lines.push(`import { defineConfig, devices } from '@playwright/test';`);\r\n lines.push('');\r\n lines.push('export default defineConfig({');\r\n lines.push(` testDir: '${outDir}',`);\r\n lines.push(` testMatch: ['**/*.spec.ts', '**/*.test.ts'],`);\r\n lines.push(` fullyParallel: false,`);\r\n lines.push(` forbidOnly: !!process.env.CI,`);\r\n lines.push(` retries: ${retries !== null ? retries : 'process.env.CI ? 1 : 0'},`);\r\n lines.push(` workers: ${workers !== null ? workers : 'process.env.CI ? 4 : 2'},`);\r\n lines.push(` timeout: ${timeout},`);\r\n lines.push(` globalSetup: './global-setup.ts',`);\r\n lines.push(` globalTeardown: './global-teardown.ts',`);\r\n lines.push(` reporter: [['list'], ['html', { open: 'never' }]],`);\r\n lines.push(` use: {`);\r\n lines.push(` baseURL: ${baseURL},`);\r\n lines.push(` trace: 'retain-on-failure',`);\r\n lines.push(` screenshot: 'only-on-failure',`);\r\n lines.push(` video: 'retain-on-failure',`);\r\n lines.push(` actionTimeout: ${actionTimeout},`);\r\n lines.push(` navigationTimeout: ${navigationTimeout},`);\r\n lines.push(` },`);\r\n\r\n // Projects\r\n lines.push(` projects: [`);\r\n\r\n if (hasAuth) {\r\n lines.push(` {`);\r\n lines.push(` name: 'setup',`);\r\n lines.push(` testMatch: '**/auth.setup.ts',`);\r\n lines.push(` use: { ...devices['Desktop Chrome'] },`);\r\n lines.push(` },`);\r\n lines.push(` {`);\r\n lines.push(` name: 'chromium',`);\r\n lines.push(` testIgnore: ['**/*.setup.ts'],`);\r\n lines.push(` dependencies: ['setup'],`);\r\n lines.push(` use: {`);\r\n lines.push(` ...devices['Desktop Chrome'],`);\r\n lines.push(` storageState: '${storageState}',`);\r\n lines.push(` },`);\r\n lines.push(` },`);\r\n lines.push(` {`);\r\n lines.push(` name: 'chromium-no-auth',`);\r\n lines.push(` testMatch: '**/login-flow.test.ts',`);\r\n lines.push(` testIgnore: ['**/*.setup.ts'],`);\r\n lines.push(` use: { ...devices['Desktop Chrome'] },`);\r\n lines.push(` },`);\r\n } else {\r\n lines.push(` {`);\r\n lines.push(` name: 'chromium',`);\r\n lines.push(` use: { ...devices['Desktop Chrome'] },`);\r\n lines.push(` },`);\r\n }\r\n\r\n // Extra projects from config\r\n if (rt.extraProjects) {\r\n for (const proj of rt.extraProjects) {\r\n lines.push(` {`);\r\n lines.push(` name: '${proj.name}',`);\r\n lines.push(` testMatch: '${proj.testMatch}',`);\r\n if (proj.dependencies?.length) {\r\n lines.push(` dependencies: [${proj.dependencies.map((d) => `'${d}'`).join(', ')}],`);\r\n }\r\n if (proj.useAuth !== false && hasAuth) {\r\n lines.push(` use: {`);\r\n lines.push(` ...devices['Desktop Chrome'],`);\r\n lines.push(` storageState: '${storageState}',`);\r\n lines.push(` },`);\r\n } else {\r\n lines.push(` use: { ...devices['Desktop Chrome'] },`);\r\n }\r\n lines.push(` },`);\r\n }\r\n }\r\n\r\n lines.push(` ],`);\r\n lines.push('});');\r\n lines.push('');\r\n\r\n return lines.join('\\n');\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\n\r\n/**\r\n * Generate global-setup.ts content for Playwright.\r\n * Handles backend readiness probe, seed endpoint call, and log cleanup.\r\n */\r\nexport function generateGlobalSetup(config: OpenCrocConfig): string {\r\n const pw = config.playwright ?? {};\r\n const rt = config.runtime ?? {};\r\n const baseURL = pw.baseURL || '';\r\n\r\n const hasSeedEndpoint = !!rt.db?.seedEndpoint;\r\n const hasLogEndpoint = !!rt.logEndpoint;\r\n const hasSeedFile = !!rt.db?.seedFile;\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`/**`);\r\n lines.push(` * Global setup — generated by OpenCroc.`);\r\n lines.push(` * Runs once before all test projects.`);\r\n lines.push(` */`);\r\n lines.push('');\r\n lines.push(`const BASE_URL = process.env.BASE_URL || '${baseURL || 'http://localhost:3000'}';`);\r\n lines.push('');\r\n\r\n // fetchWithRetry helper\r\n lines.push(`async function fetchWithRetry(`);\r\n lines.push(` url: string,`);\r\n lines.push(` options: RequestInit,`);\r\n lines.push(` retries = 3,`);\r\n lines.push(`): Promise<Response | null> {`);\r\n lines.push(` for (let i = 0; i < retries; i++) {`);\r\n lines.push(` try {`);\r\n lines.push(` const resp = await fetch(url, { ...options, signal: AbortSignal.timeout(10_000) });`);\r\n lines.push(` if (resp.ok) return resp;`);\r\n lines.push(` console.warn(\\`[global-setup] \\${options.method} \\${url} → \\${resp.status} (\\${i + 1}/\\${retries})\\`);`);\r\n lines.push(` } catch (err: unknown) {`);\r\n lines.push(` const msg = err instanceof Error ? err.message : String(err);`);\r\n lines.push(` console.warn(\\`[global-setup] \\${options.method} \\${url} error (\\${i + 1}/\\${retries}): \\${msg}\\`);`);\r\n lines.push(` }`);\r\n lines.push(` if (i < retries - 1) await new Promise((r) => setTimeout(r, 1000 * Math.pow(2, i)));`);\r\n lines.push(` }`);\r\n lines.push(` return null;`);\r\n lines.push(`}`);\r\n lines.push('');\r\n\r\n // waitForBackend helper\r\n lines.push(`async function waitForBackend(origin: string, timeoutMs = 30_000): Promise<void> {`);\r\n lines.push(` const start = Date.now();`);\r\n lines.push(` while (Date.now() - start < timeoutMs) {`);\r\n lines.push(` try {`);\r\n lines.push(` const res = await fetch(\\`\\${origin}/health\\`, { signal: AbortSignal.timeout(3_000) });`);\r\n lines.push(` if (res.ok) return;`);\r\n lines.push(` } catch {`);\r\n lines.push(` // not ready yet`);\r\n lines.push(` }`);\r\n lines.push(` await new Promise((r) => setTimeout(r, 1_000));`);\r\n lines.push(` }`);\r\n lines.push(` throw new Error(\\`Backend not ready after \\${timeoutMs}ms\\`);`);\r\n lines.push(`}`);\r\n lines.push('');\r\n\r\n // Main function\r\n lines.push(`export default async function globalSetup(): Promise<void> {`);\r\n lines.push(` console.log('[global-setup] Starting...');`);\r\n lines.push('');\r\n lines.push(` // Backend readiness probe`);\r\n lines.push(` try {`);\r\n lines.push(` await waitForBackend(BASE_URL, 30_000);`);\r\n lines.push(` console.log('[global-setup] Backend is ready.');`);\r\n lines.push(` } catch (e: unknown) {`);\r\n lines.push(` console.warn(\\`[global-setup] \\${e instanceof Error ? e.message : String(e)}\\`);`);\r\n lines.push(` }`);\r\n lines.push('');\r\n\r\n if (hasSeedEndpoint) {\r\n lines.push(` // Seed data via backend endpoint`);\r\n lines.push(` try {`);\r\n lines.push(` await fetchWithRetry(`);\r\n lines.push(` \\`\\${BASE_URL}${rt.db!.seedEndpoint}\\`,`);\r\n lines.push(` { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' },`);\r\n lines.push(` );`);\r\n lines.push(` console.log('[global-setup] Seed endpoint called.');`);\r\n lines.push(` } catch {`);\r\n lines.push(` console.warn('[global-setup] Seed endpoint failed.');`);\r\n lines.push(` }`);\r\n lines.push('');\r\n }\r\n\r\n if (hasLogEndpoint) {\r\n lines.push(` // Clear test logs`);\r\n lines.push(` try {`);\r\n lines.push(` await fetchWithRetry(\\`\\${BASE_URL}${rt.logEndpoint}\\`, { method: 'DELETE' });`);\r\n lines.push(` console.log('[global-setup] Test logs cleared.');`);\r\n lines.push(` } catch {`);\r\n lines.push(` console.warn('[global-setup] Failed to clear test logs.');`);\r\n lines.push(` }`);\r\n lines.push('');\r\n }\r\n\r\n if (hasSeedFile) {\r\n lines.push(` // SQL seed file execution (placeholder — wire to your DB helper)`);\r\n lines.push(` // import { executeSeedSQL } from './utils/db-helper';`);\r\n lines.push(` // await executeSeedSQL('${rt.db!.seedFile}');`);\r\n lines.push('');\r\n }\r\n\r\n lines.push(` console.log('[global-setup] Done.');`);\r\n lines.push(`}`);\r\n lines.push('');\r\n\r\n return lines.join('\\n');\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\n\r\n/**\r\n * Generate global-teardown.ts content for Playwright.\r\n * Handles cleanup endpoint call and optional SQL cleanup.\r\n */\r\nexport function generateGlobalTeardown(config: OpenCrocConfig): string {\r\n const pw = config.playwright ?? {};\r\n const rt = config.runtime ?? {};\r\n const baseURL = pw.baseURL || '';\r\n\r\n const hasCleanupEndpoint = !!rt.db?.cleanupEndpoint;\r\n const hasCleanupFile = !!rt.db?.cleanupFile;\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`/**`);\r\n lines.push(` * Global teardown — generated by OpenCroc.`);\r\n lines.push(` * Runs once after all test projects complete.`);\r\n lines.push(` */`);\r\n lines.push('');\r\n lines.push(`const BASE_URL = process.env.BASE_URL || '${baseURL || 'http://localhost:3000'}';`);\r\n lines.push('');\r\n\r\n lines.push(`export default async function globalTeardown(): Promise<void> {`);\r\n lines.push(` console.log('[global-teardown] Starting...');`);\r\n lines.push('');\r\n\r\n if (hasCleanupEndpoint) {\r\n lines.push(` // Cleanup via backend endpoint`);\r\n lines.push(` try {`);\r\n lines.push(` await fetch(\\`\\${BASE_URL}${rt.db!.cleanupEndpoint}\\`, { method: 'POST' });`);\r\n lines.push(` console.log('[global-teardown] Cleanup endpoint called.');`);\r\n lines.push(` } catch {`);\r\n lines.push(` console.warn('[global-teardown] Cleanup endpoint failed.');`);\r\n lines.push(` }`);\r\n lines.push('');\r\n }\r\n\r\n if (hasCleanupFile) {\r\n lines.push(` // SQL cleanup file execution (placeholder — wire to your DB helper)`);\r\n lines.push(` // import { executeSeedSQL } from './utils/db-helper';`);\r\n lines.push(` // await executeSeedSQL('${rt.db!.cleanupFile}');`);\r\n lines.push('');\r\n }\r\n\r\n lines.push(` console.log('[global-teardown] Done.');`);\r\n lines.push(`}`);\r\n lines.push('');\r\n\r\n return lines.join('\\n');\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\n\r\n/**\r\n * Generate auth.setup.ts content for Playwright.\r\n * Creates an authentication setup project that stores state for reuse.\r\n */\r\nexport function generateAuthSetup(config: OpenCrocConfig): string {\r\n const rt = config.runtime ?? {};\r\n const pw = config.playwright ?? {};\r\n const auth = rt.auth ?? {};\r\n const baseURL = pw.baseURL || '';\r\n const storageStatePath = auth.storageStatePath || 'playwright/.auth/user.json';\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`import { test as setup, expect } from '@playwright/test';`);\r\n lines.push(`import * as fs from 'fs/promises';`);\r\n lines.push(`import * as path from 'path';`);\r\n lines.push('');\r\n\r\n lines.push(`const authFile = '${storageStatePath}';`);\r\n lines.push('');\r\n\r\n if (auth.loginUrl) {\r\n // API-based authentication\r\n lines.push(`setup('authenticate', async ({ request }) => {`);\r\n lines.push(` const loginUrl = process.env.AUTH_LOGIN_URL || '${auth.loginUrl}';`);\r\n lines.push(` const username = process.env.AUTH_USERNAME || '${auth.username || 'admin'}';`);\r\n lines.push(` const password = process.env.AUTH_PASSWORD || '${auth.password || ''}';`);\r\n lines.push('');\r\n lines.push(` // API login`);\r\n lines.push(` const response = await request.post(loginUrl, {`);\r\n lines.push(` data: { username, password },`);\r\n lines.push(` });`);\r\n lines.push(` expect(response.ok()).toBeTruthy();`);\r\n lines.push('');\r\n lines.push(` const body = await response.json();`);\r\n lines.push(` const token = body.data?.token || body.token || '';`);\r\n lines.push(` console.log('[auth.setup] Login successful, token obtained:', !!token);`);\r\n lines.push('');\r\n lines.push(` // Save storage state with auth cookie/localStorage`);\r\n lines.push(` await fs.mkdir(path.dirname(authFile), { recursive: true });`);\r\n lines.push('');\r\n lines.push(` // Build storage state JSON`);\r\n lines.push(` const baseURL = process.env.BASE_URL || '${baseURL || 'http://localhost:3000'}';`);\r\n lines.push(` const origin = new URL(baseURL).origin;`);\r\n lines.push(` const storageState = {`);\r\n lines.push(` cookies: [],`);\r\n lines.push(` origins: [`);\r\n lines.push(` {`);\r\n lines.push(` origin,`);\r\n lines.push(` localStorage: [`);\r\n lines.push(` { name: 'token', value: token },`);\r\n lines.push(` ],`);\r\n lines.push(` },`);\r\n lines.push(` ],`);\r\n lines.push(` };`);\r\n lines.push('');\r\n lines.push(` await fs.writeFile(authFile, JSON.stringify(storageState, null, 2));`);\r\n lines.push(` console.log(\\`[auth.setup] Storage state saved → \\${authFile}\\`);`);\r\n lines.push(`});`);\r\n } else {\r\n // Browser-based authentication (placeholder)\r\n lines.push(`setup('authenticate', async ({ browser }) => {`);\r\n lines.push(` const context = await browser.newContext();`);\r\n lines.push(` const page = await context.newPage();`);\r\n lines.push('');\r\n lines.push(` // TODO: Implement your login flow here`);\r\n lines.push(` // await page.goto('/login');`);\r\n lines.push(` // await page.fill('[name=username]', 'admin');`);\r\n lines.push(` // await page.fill('[name=password]', 'password');`);\r\n lines.push(` // await page.click('button[type=submit]');`);\r\n lines.push(` // await page.waitForURL('/dashboard');`);\r\n lines.push('');\r\n lines.push(` await fs.mkdir(path.dirname(authFile), { recursive: true });`);\r\n lines.push(` await context.storageState({ path: authFile });`);\r\n lines.push(` console.log(\\`[auth.setup] Storage state saved → \\${authFile}\\`);`);\r\n lines.push('');\r\n lines.push(` await context.close();`);\r\n lines.push(`});`);\r\n }\r\n\r\n lines.push('');\r\n\r\n return lines.join('\\n');\r\n}\r\n","/**\r\n * Resilient HTTP fetch with exponential backoff retry.\r\n * Framework-level utility — no Playwright dependency required.\r\n */\r\n\r\nexport interface AttemptRecord {\r\n attempt: number;\r\n status: number;\r\n url: string;\r\n method: string;\r\n latencyMs: number;\r\n error?: string;\r\n}\r\n\r\nexport interface ResilientFetchOptions {\r\n /** HTTP method */\r\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\r\n /** Request body (will be JSON-stringified if object) */\r\n body?: string | Record<string, unknown>;\r\n /** Request headers */\r\n headers?: Record<string, string>;\r\n /** Max retry count (default: 3) */\r\n maxRetries?: number;\r\n /** Base delay in ms for exponential backoff (default: 1000) */\r\n baseDelayMs?: number;\r\n /** Per-request timeout in ms (default: 10000) */\r\n timeoutMs?: number;\r\n /** If true, throw on final failure; if false, return error result (default: false) */\r\n throwOnFailure?: boolean;\r\n}\r\n\r\nexport interface ResilientFetchResult {\r\n ok: boolean;\r\n status: number;\r\n data: unknown;\r\n attempts: AttemptRecord[];\r\n}\r\n\r\nconst RETRYABLE_STATUSES = new Set([408, 429, 500, 502, 503, 504]);\r\n\r\nfunction isRetryable(status: number): boolean {\r\n return RETRYABLE_STATUSES.has(status);\r\n}\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((r) => setTimeout(r, ms));\r\n}\r\n\r\nasync function safeJson(resp: Response): Promise<unknown> {\r\n try {\r\n return await resp.json();\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Make an HTTP request with automatic retry and exponential backoff.\r\n *\r\n * Retries on: network errors, 408, 429, 5xx.\r\n * Does NOT retry on: 4xx (except 408/429).\r\n */\r\nexport async function resilientFetch(\r\n url: string,\r\n options: ResilientFetchOptions = {},\r\n): Promise<ResilientFetchResult> {\r\n const {\r\n method = 'GET',\r\n body,\r\n headers = {},\r\n maxRetries = 3,\r\n baseDelayMs = 1000,\r\n timeoutMs = 10_000,\r\n throwOnFailure = false,\r\n } = options;\r\n\r\n const attempts: AttemptRecord[] = [];\r\n let lastStatus = 0;\r\n let lastBody: unknown = null;\r\n\r\n const requestHeaders: Record<string, string> = { ...headers };\r\n if (body && typeof body === 'object' && !requestHeaders['Content-Type']) {\r\n requestHeaders['Content-Type'] = 'application/json';\r\n }\r\n\r\n for (let i = 0; i <= maxRetries; i++) {\r\n const start = Date.now();\r\n\r\n try {\r\n const resp = await fetch(url, {\r\n method,\r\n headers: requestHeaders,\r\n body: body ? (typeof body === 'string' ? body : JSON.stringify(body)) : undefined,\r\n signal: AbortSignal.timeout(timeoutMs),\r\n });\r\n\r\n const latency = Date.now() - start;\r\n lastStatus = resp.status;\r\n lastBody = await safeJson(resp);\r\n\r\n attempts.push({ attempt: i + 1, status: lastStatus, url, method, latencyMs: latency });\r\n\r\n if (resp.ok) {\r\n return { ok: true, status: lastStatus, data: lastBody, attempts };\r\n }\r\n\r\n if (isRetryable(lastStatus) && i < maxRetries) {\r\n const delay = baseDelayMs * Math.pow(2, i);\r\n await sleep(delay);\r\n continue;\r\n }\r\n\r\n // Non-retryable error\r\n break;\r\n } catch (err) {\r\n const latency = Date.now() - start;\r\n const errMsg = err instanceof Error ? err.message : String(err);\r\n attempts.push({ attempt: i + 1, status: 0, url, method, latencyMs: latency, error: errMsg });\r\n\r\n if (i < maxRetries) {\r\n const delay = baseDelayMs * Math.pow(2, i);\r\n await sleep(delay);\r\n continue;\r\n }\r\n break;\r\n }\r\n }\r\n\r\n const result: ResilientFetchResult = { ok: false, status: lastStatus, data: lastBody, attempts };\r\n\r\n if (throwOnFailure) {\r\n const summary = attempts.map((a) => `[${a.attempt}] ${a.status || 'ERR'} ${a.latencyMs}ms`).join(', ');\r\n throw new Error(`resilientFetch failed: ${method} ${url} (${attempts.length} attempts): ${summary}`);\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Wait for a backend to become healthy by polling a health endpoint.\r\n */\r\nexport async function waitForBackend(\r\n baseUrl: string,\r\n options: { timeoutMs?: number; intervalMs?: number; healthPath?: string } = {},\r\n): Promise<void> {\r\n const { timeoutMs = 30_000, intervalMs = 1_000, healthPath = '/health' } = options;\r\n const healthUrl = new URL(healthPath, baseUrl).href;\r\n const start = Date.now();\r\n\r\n while (Date.now() - start < timeoutMs) {\r\n try {\r\n const resp = await fetch(healthUrl, { method: 'GET', signal: AbortSignal.timeout(3_000) });\r\n if (resp.ok) return;\r\n } catch {\r\n // not ready yet\r\n }\r\n await sleep(intervalMs);\r\n }\r\n\r\n throw new Error(`Backend not ready: ${healthUrl} timed out after ${timeoutMs}ms`);\r\n}\r\n","/**\r\n * Playwright network request/response monitor.\r\n * Attaches to a Page and records API calls, errors, and response times.\r\n */\r\n\r\nexport interface NetworkError {\r\n url: string;\r\n status: number;\r\n method: string;\r\n responseBody: string;\r\n requestPayload?: string;\r\n timestamp: string;\r\n pageUrl: string;\r\n}\r\n\r\nexport interface ApiRecord {\r\n url: string;\r\n status: number;\r\n method: string;\r\n durationMs: number;\r\n timestamp: string;\r\n pageUrl: string;\r\n}\r\n\r\nexport interface NetworkMonitorOptions {\r\n /** URL pattern to track (default: '/api/') */\r\n apiPattern?: string;\r\n /** Whether to capture response bodies for errors (default: true) */\r\n captureErrorBody?: boolean;\r\n}\r\n\r\n/** Minimal Playwright Page interface — avoids hard dependency on @playwright/test */\r\ninterface PlaywrightPage {\r\n url(): string;\r\n on(event: 'request', handler: (req: PlaywrightRequest) => void): void;\r\n on(event: 'response', handler: (res: PlaywrightResponse) => void): void;\r\n}\r\n\r\ninterface PlaywrightRequest {\r\n url(): string;\r\n method(): string;\r\n postData(): string | null;\r\n}\r\n\r\ninterface PlaywrightResponse {\r\n url(): string;\r\n status(): number;\r\n request(): PlaywrightRequest;\r\n text(): Promise<string>;\r\n}\r\n\r\nexport class NetworkMonitor {\r\n private errors: NetworkError[] = [];\r\n private records: ApiRecord[] = [];\r\n private requestStarts = new WeakMap<PlaywrightRequest, number>();\r\n private readonly apiPattern: string;\r\n private readonly captureErrorBody: boolean;\r\n\r\n constructor(options: NetworkMonitorOptions = {}) {\r\n this.apiPattern = options.apiPattern ?? '/api/';\r\n this.captureErrorBody = options.captureErrorBody ?? true;\r\n }\r\n\r\n /**\r\n * Attach the monitor to a Playwright Page.\r\n * Call this once per page — typically in a test fixture or beforeEach.\r\n */\r\n attach(page: PlaywrightPage): void {\r\n page.on('request', (request) => {\r\n if (request.url().includes(this.apiPattern)) {\r\n this.requestStarts.set(request, Date.now());\r\n }\r\n });\r\n\r\n page.on('response', async (response) => {\r\n const request = response.request();\r\n const isApiCall = response.url().includes(this.apiPattern);\r\n const startedAt = this.requestStarts.get(request);\r\n\r\n if (isApiCall && startedAt) {\r\n this.records.push({\r\n url: response.url(),\r\n status: response.status(),\r\n method: request.method(),\r\n durationMs: Date.now() - startedAt,\r\n timestamp: new Date().toISOString(),\r\n pageUrl: page.url(),\r\n });\r\n }\r\n\r\n if (response.status() >= 400) {\r\n let body = '';\r\n if (this.captureErrorBody) {\r\n try {\r\n body = await response.text();\r\n } catch {\r\n body = 'Unable to read';\r\n }\r\n }\r\n\r\n this.errors.push({\r\n url: response.url(),\r\n status: response.status(),\r\n method: request.method(),\r\n responseBody: body,\r\n requestPayload: request.postData() ?? undefined,\r\n timestamp: new Date().toISOString(),\r\n pageUrl: page.url(),\r\n });\r\n }\r\n });\r\n }\r\n\r\n /** All captured API records. */\r\n getRecords(): ApiRecord[] {\r\n return [...this.records];\r\n }\r\n\r\n /** All captured network errors (status >= 400). */\r\n getErrors(): NetworkError[] {\r\n return [...this.errors];\r\n }\r\n\r\n /** API calls slower than the given threshold. */\r\n getSlowRequests(thresholdMs: number): ApiRecord[] {\r\n return this.records.filter((r) => r.durationMs >= thresholdMs);\r\n }\r\n\r\n /** 5xx server errors. */\r\n get5xxErrors(): NetworkError[] {\r\n return this.errors.filter((e) => e.status >= 500);\r\n }\r\n\r\n /** 4xx client errors. */\r\n get4xxErrors(): NetworkError[] {\r\n return this.errors.filter((e) => e.status >= 400 && e.status < 500);\r\n }\r\n\r\n /** Whether any network errors have been captured. */\r\n hasErrors(): boolean {\r\n return this.errors.length > 0;\r\n }\r\n\r\n /** Reset all captured data. */\r\n clear(): void {\r\n this.errors = [];\r\n this.records = [];\r\n this.requestStarts = new WeakMap();\r\n }\r\n}\r\n","/**\r\n * Dynamic route parameter resolver.\r\n * Extracts path parameters by matching URL templates against actual hrefs.\r\n * Framework-level utility — no app-specific dependencies.\r\n */\r\n\r\nexport interface ResolvedRoute {\r\n /** Original path template (e.g. '/users/:id/detail') */\r\n originalPath: string;\r\n /** Resolved path with actual values (e.g. '/users/42/detail') */\r\n resolvedPath: string;\r\n /** Extracted parameter map (e.g. { id: '42' }) */\r\n params: Record<string, string>;\r\n /** How the parameters were resolved */\r\n resolveMethod: 'href-extraction' | 'seed-data' | 'text-extraction';\r\n}\r\n\r\n/**\r\n * Extract parameter names from a path template.\r\n * @example extractParamNames('/users/:id/posts/:postId') → ['id', 'postId']\r\n */\r\nexport function extractParamNames(pathTemplate: string): string[] {\r\n return (pathTemplate.match(/:([^/]+)/g) ?? []).map((m) => m.substring(1));\r\n}\r\n\r\n/**\r\n * Extract parameter values by matching a URL template against an actual href.\r\n * Returns null if the href doesn't match the template structure.\r\n *\r\n * @example\r\n * extractParamsFromHref('/users/:id/detail', '/users/42/detail')\r\n * // → { id: '42' }\r\n */\r\nexport function extractParamsFromHref(\r\n pathTemplate: string,\r\n href: string,\r\n): Record<string, string> | null {\r\n const templateParts = pathTemplate.split('/');\r\n const hrefParts = href.split('/');\r\n\r\n if (templateParts.length > hrefParts.length) return null;\r\n\r\n const params: Record<string, string> = {};\r\n\r\n for (let i = 0; i < templateParts.length; i++) {\r\n if (templateParts[i].startsWith(':') && hrefParts[i]) {\r\n params[templateParts[i].substring(1)] = hrefParts[i];\r\n }\r\n }\r\n\r\n const names = extractParamNames(pathTemplate);\r\n return names.every((n) => params[n]) ? params : null;\r\n}\r\n\r\n/**\r\n * Build a concrete path from a template and parameter values.\r\n *\r\n * @example\r\n * buildPath('/users/:id/posts/:postId', { id: '42', postId: '7' })\r\n * // → '/users/42/posts/7'\r\n */\r\nexport function buildPath(pathTemplate: string, params: Record<string, string>): string {\r\n let result = pathTemplate;\r\n for (const [key, value] of Object.entries(params)) {\r\n result = result.replace(`:${key}`, value);\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Try to extract an ID-like value from a text string.\r\n * Matches numeric IDs and UUIDs.\r\n */\r\nexport function extractIdFromText(text: string): string | null {\r\n const match = text.match(/\\b(\\d+|[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})\\b/i);\r\n return match?.[1] ?? null;\r\n}\r\n\r\n/**\r\n * Resolve dynamic route parameters from a seed data map.\r\n *\r\n * @param pathTemplate - URL template with :params\r\n * @param seedData - Map of route keys to param objects\r\n * @param routeKey - Optional explicit key; defaults to normalized path\r\n */\r\nexport function resolveFromSeedData(\r\n pathTemplate: string,\r\n seedData: Record<string, Record<string, string>>,\r\n routeKey?: string,\r\n): ResolvedRoute | null {\r\n const key = routeKey ?? pathTemplate.replace(/\\//g, '_').replace(/:/g, '');\r\n const params = seedData[key];\r\n if (!params) return null;\r\n\r\n return {\r\n originalPath: pathTemplate,\r\n resolvedPath: buildPath(pathTemplate, params),\r\n params,\r\n resolveMethod: 'seed-data',\r\n };\r\n}\r\n","/**\r\n * Log-driven API completion detection.\r\n *\r\n * Polls a backend log endpoint to verify that API requests have fully completed\r\n * (not just returned HTTP 200, but the backend has finished all processing).\r\n * This closes the gap between \"HTTP response received\" and \"backend actually done\".\r\n */\r\n\r\n// ===== Types =====\r\n\r\nexport interface CandidateApiRequest {\r\n /** Backend-assigned request ID (if available) */\r\n requestId?: string;\r\n /** HTTP method */\r\n method: string;\r\n /** API path (e.g. /api/users) */\r\n path: string;\r\n /** Full URL */\r\n url: string;\r\n}\r\n\r\nexport interface LogCompletionResult {\r\n /** Total candidates being tracked */\r\n candidateCount: number;\r\n /** Requests confirmed completed successfully */\r\n succeeded: CandidateApiRequest[];\r\n /** Requests confirmed completed with failure */\r\n failed: Array<{ request: CandidateApiRequest; reason: string }>;\r\n /** Requests that never got a completion log within timeout */\r\n timedOut: CandidateApiRequest[];\r\n /** Number of poll iterations performed */\r\n pollCount: number;\r\n /** Total elapsed ms */\r\n elapsedMs: number;\r\n}\r\n\r\nexport interface LogEntry {\r\n /** Backend-assigned request ID */\r\n requestId?: string;\r\n /** HTTP method */\r\n method?: string;\r\n /** API path */\r\n apiPath?: string;\r\n /** Event phase: 'start' | 'end' */\r\n eventPhase?: string;\r\n /** Event status: 'success' | 'fail' */\r\n eventStatus?: string;\r\n /** HTTP status code */\r\n status?: number;\r\n /** Nested metadata (some backends put fields here) */\r\n meta?: Record<string, unknown>;\r\n}\r\n\r\nexport interface LogPollerOptions {\r\n /** Function that fetches end-phase logs from the backend. Return parsed log entries. */\r\n fetchLogs: () => Promise<LogEntry[]>;\r\n /** Timeout in ms (default: 25000) */\r\n timeoutMs?: number;\r\n /** Initial poll delay in ms (default: 200) */\r\n initialDelayMs?: number;\r\n /** Max poll delay in ms (default: 2000) */\r\n maxDelayMs?: number;\r\n}\r\n\r\n// ===== Ignore list =====\r\n\r\nconst IGNORE_KEYWORDS = [\r\n '/health', '/metrics', '/heartbeat', '/ping', '/alive',\r\n '/beacon', '/track', '/analytics', '/poll', '/stream', '/sse',\r\n];\r\n\r\nfunction extractPath(url: string): string {\r\n try {\r\n return new URL(url).pathname;\r\n } catch {\r\n return url;\r\n }\r\n}\r\n\r\nfunction shouldIgnore(path: string): boolean {\r\n const lower = path.toLowerCase();\r\n return IGNORE_KEYWORDS.some((kw) => lower.includes(kw));\r\n}\r\n\r\n// ===== Candidate selection =====\r\n\r\nexport interface ApiResponseRecord {\r\n url: string;\r\n method: string;\r\n requestId?: string;\r\n}\r\n\r\n/**\r\n * Select candidate API requests from network-captured responses.\r\n * Deduplicates by requestId or method+path.\r\n */\r\nexport function selectCandidates(responses: ApiResponseRecord[], maxCount = 20): CandidateApiRequest[] {\r\n const unique = new Map<string, CandidateApiRequest>();\r\n\r\n for (const item of responses) {\r\n if (!item.url.includes('/api/')) continue;\r\n const path = extractPath(item.url);\r\n if (shouldIgnore(path)) continue;\r\n const method = item.method.toUpperCase();\r\n if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) continue;\r\n\r\n const key = item.requestId ? `rid:${item.requestId}` : `mp:${method}:${path}`;\r\n if (!unique.has(key)) {\r\n unique.set(key, { requestId: item.requestId, method, path, url: item.url });\r\n }\r\n }\r\n\r\n return Array.from(unique.values()).slice(0, maxCount);\r\n}\r\n\r\n/**\r\n * Select candidates from start-phase log entries.\r\n */\r\nexport function selectCandidatesFromLogs(logs: LogEntry[], maxCount = 20): CandidateApiRequest[] {\r\n const unique = new Map<string, CandidateApiRequest>();\r\n\r\n for (const log of logs) {\r\n const phase = getField(log, 'eventPhase');\r\n if (phase !== 'start') continue;\r\n\r\n const method = getField(log, 'method').toUpperCase();\r\n if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) continue;\r\n\r\n const rawPath = getField(log, 'apiPath') || getField(log, 'url');\r\n const path = extractPath(rawPath);\r\n if (!path.includes('/api/') || shouldIgnore(path)) continue;\r\n\r\n const requestId = getField(log, 'requestId') || undefined;\r\n const key = requestId ? `rid:${requestId}` : `mp:${method}:${path}`;\r\n if (!unique.has(key)) {\r\n unique.set(key, { requestId, method, path, url: rawPath });\r\n }\r\n }\r\n\r\n return Array.from(unique.values()).slice(0, maxCount);\r\n}\r\n\r\n/**\r\n * Merge multiple candidate lists, deduplicating by key.\r\n */\r\nexport function mergeCandidates(...groups: CandidateApiRequest[][]): CandidateApiRequest[] {\r\n const merged = new Map<string, CandidateApiRequest>();\r\n for (const group of groups) {\r\n for (const item of group) {\r\n const key = item.requestId ? `rid:${item.requestId}` : `mp:${item.method}:${item.path}`;\r\n if (!merged.has(key)) merged.set(key, item);\r\n }\r\n }\r\n return Array.from(merged.values()).slice(0, 30);\r\n}\r\n\r\n// ===== Log matching =====\r\n\r\nfunction getField(log: LogEntry, field: string): string {\r\n const direct = (log as Record<string, unknown>)[field];\r\n if (direct != null) return String(direct);\r\n const meta = log.meta?.[field];\r\n if (meta != null) return String(meta);\r\n return '';\r\n}\r\n\r\nfunction matchLog(request: CandidateApiRequest, logs: LogEntry[]): LogEntry | undefined {\r\n if (request.requestId) {\r\n const byId = logs.find((l) => getField(l, 'requestId') === request.requestId);\r\n if (byId) return byId;\r\n }\r\n return logs.find((l) => {\r\n const method = getField(l, 'method').toUpperCase();\r\n const apiPath = getField(l, 'apiPath') || getField(l, 'url');\r\n return method === request.method && apiPath.includes(request.path);\r\n });\r\n}\r\n\r\nfunction inferStatus(log: LogEntry): 'success' | 'fail' {\r\n const eventStatus = getField(log, 'eventStatus').toLowerCase();\r\n if (eventStatus === 'success' || eventStatus === 'fail') return eventStatus as 'success' | 'fail';\r\n const status = Number(getField(log, 'status'));\r\n if (!Number.isNaN(status) && status >= 400) return 'fail';\r\n return 'success';\r\n}\r\n\r\n// ===== Core poller =====\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((r) => setTimeout(r, ms));\r\n}\r\n\r\n/**\r\n * Poll backend logs until all candidate API requests have completion entries,\r\n * or the timeout is reached.\r\n *\r\n * @example\r\n * ```ts\r\n * const result = await waitForLogCompletion(candidates, {\r\n * fetchLogs: async () => {\r\n * const resp = await fetch(`${origin}/internal/test-logs?eventPhase=end&since=${since}`);\r\n * const body = await resp.json();\r\n * return body.data ?? [];\r\n * },\r\n * timeoutMs: 20_000,\r\n * });\r\n * ```\r\n */\r\nexport async function waitForLogCompletion(\r\n candidates: CandidateApiRequest[],\r\n options: LogPollerOptions,\r\n): Promise<LogCompletionResult> {\r\n const {\r\n fetchLogs,\r\n timeoutMs = 25_000,\r\n initialDelayMs = 200,\r\n maxDelayMs = 2_000,\r\n } = options;\r\n\r\n const pending = [...candidates];\r\n const succeeded: CandidateApiRequest[] = [];\r\n const failed: LogCompletionResult['failed'] = [];\r\n const startedAt = Date.now();\r\n let pollCount = 0;\r\n\r\n while (pending.length > 0 && Date.now() - startedAt < timeoutMs) {\r\n const logs = await fetchLogs();\r\n pollCount++;\r\n\r\n for (let i = pending.length - 1; i >= 0; i--) {\r\n const candidate = pending[i];\r\n const log = matchLog(candidate, logs);\r\n if (!log) continue;\r\n\r\n if (inferStatus(log) === 'fail') {\r\n failed.push({ request: candidate, reason: 'LOG_COMPLETION_FAIL' });\r\n } else {\r\n succeeded.push(candidate);\r\n }\r\n pending.splice(i, 1);\r\n }\r\n\r\n if (pending.length === 0) break;\r\n\r\n // Progressive backoff: 200ms → 500ms → 1s → 2s\r\n const step = pollCount;\r\n const delay = step <= 1 ? initialDelayMs : step === 2 ? 500 : Math.min(maxDelayMs, 1000 * 2 ** (step - 3));\r\n await sleep(delay);\r\n }\r\n\r\n return {\r\n candidateCount: candidates.length,\r\n succeeded,\r\n failed,\r\n timedOut: pending,\r\n pollCount,\r\n elapsedMs: Date.now() - startedAt,\r\n };\r\n}\r\n","/**\r\n * Critical API rules engine.\r\n *\r\n * Define per-endpoint validation rules with performance thresholds and\r\n * behavior flags. Evaluate captured API records against rules to surface\r\n * violations (slow responses, unexpected empty data, fatal timeouts).\r\n */\r\n\r\n// ===== Types =====\r\n\r\nexport interface CriticalApiRule {\r\n /** Route path this rule applies to (e.g. '/users/list') */\r\n routePath: string;\r\n /** Human-readable name */\r\n name: string;\r\n /** URL substring to match against captured API URLs */\r\n urlIncludes: string;\r\n /** HTTP method filter (optional; matches all if omitted) */\r\n method?: string;\r\n /** Whether an empty/null response body is acceptable (default: false) */\r\n allowEmpty?: boolean;\r\n /** Response time warning threshold in ms */\r\n warnMs?: number;\r\n /** Response time fatal threshold in ms */\r\n fatalMs?: number;\r\n}\r\n\r\nexport interface ApiRuleViolation {\r\n rule: CriticalApiRule;\r\n /** 'warn' for exceeded warnMs, 'fatal' for exceeded fatalMs, 'empty' for unexpected empty response */\r\n severity: 'warn' | 'fatal' | 'empty';\r\n /** Actual duration in ms (for timing violations) */\r\n actualMs?: number;\r\n /** Description of the violation */\r\n message: string;\r\n}\r\n\r\nexport interface ApiRecordForRules {\r\n url: string;\r\n method: string;\r\n durationMs: number;\r\n /** Response body (for empty checks) */\r\n responseBody?: string | null;\r\n}\r\n\r\n// ===== Rules registry =====\r\n\r\n/**\r\n * Create a rules engine that evaluates API records against a set of critical rules.\r\n */\r\nexport function createRulesEngine(rules: CriticalApiRule[]) {\r\n return {\r\n /** Get all rules. */\r\n getRules(): CriticalApiRule[] {\r\n return [...rules];\r\n },\r\n\r\n /** Get rules matching a specific route path. */\r\n getRulesByRoute(routePath: string): CriticalApiRule[] {\r\n return rules.filter((r) => r.routePath === routePath);\r\n },\r\n\r\n /** Get rules matching a specific URL. */\r\n getRulesByUrl(url: string): CriticalApiRule[] {\r\n return rules.filter((r) => url.includes(r.urlIncludes));\r\n },\r\n\r\n /**\r\n * Evaluate a single API record against all matching rules.\r\n * Returns violations (empty array if all rules pass).\r\n */\r\n evaluate(record: ApiRecordForRules): ApiRuleViolation[] {\r\n const violations: ApiRuleViolation[] = [];\r\n const matchingRules = rules.filter((r) => {\r\n if (!record.url.includes(r.urlIncludes)) return false;\r\n if (r.method && r.method.toUpperCase() !== record.method.toUpperCase()) return false;\r\n return true;\r\n });\r\n\r\n for (const rule of matchingRules) {\r\n // Fatal threshold check\r\n if (rule.fatalMs && record.durationMs >= rule.fatalMs) {\r\n violations.push({\r\n rule,\r\n severity: 'fatal',\r\n actualMs: record.durationMs,\r\n message: `${rule.name}: ${record.durationMs}ms exceeds fatal threshold ${rule.fatalMs}ms`,\r\n });\r\n }\r\n // Warn threshold check (only if not already fatal)\r\n else if (rule.warnMs && record.durationMs >= rule.warnMs) {\r\n violations.push({\r\n rule,\r\n severity: 'warn',\r\n actualMs: record.durationMs,\r\n message: `${rule.name}: ${record.durationMs}ms exceeds warn threshold ${rule.warnMs}ms`,\r\n });\r\n }\r\n\r\n // Empty response check\r\n if (!rule.allowEmpty) {\r\n const body = record.responseBody;\r\n if (body === null || body === undefined || body === '' || body === '{}' || body === '[]' || body === 'null') {\r\n violations.push({\r\n rule,\r\n severity: 'empty',\r\n message: `${rule.name}: response body is empty but allowEmpty=false`,\r\n });\r\n }\r\n }\r\n }\r\n\r\n return violations;\r\n },\r\n\r\n /**\r\n * Evaluate multiple API records and return all violations.\r\n */\r\n evaluateAll(records: ApiRecordForRules[]): ApiRuleViolation[] {\r\n return records.flatMap((r) => this.evaluate(r));\r\n },\r\n\r\n /**\r\n * Summary: group violations by severity.\r\n */\r\n summarize(violations: ApiRuleViolation[]): { fatal: number; warn: number; empty: number } {\r\n return {\r\n fatal: violations.filter((v) => v.severity === 'fatal').length,\r\n warn: violations.filter((v) => v.severity === 'warn').length,\r\n empty: violations.filter((v) => v.severity === 'empty').length,\r\n };\r\n },\r\n };\r\n}\r\n","/**\r\n * Full orchestration engine: generate → execute → analyze → heal → report.\r\n *\r\n * Runs a multi-phase pipeline with per-phase tracking, failure detection,\r\n * token budget management, and structured result reporting.\r\n */\r\n\r\nimport { writeFileSync, mkdirSync, existsSync, readdirSync } from 'node:fs';\r\nimport { dirname, join } from 'node:path';\r\nimport { execFileSync } from 'node:child_process';\r\nimport type {\r\n OpenCrocConfig,\r\n PipelineRunResult,\r\n SelfHealingConfig,\r\n SelfHealingResult,\r\n} from '../types.js';\r\nimport { createPipeline } from '../pipeline/index.js';\r\nimport { createSelfHealingLoop } from '../self-healing/index.js';\r\nimport { generateReports } from '../reporters/index.js';\r\nimport type { ReportOutput } from '../reporters/index.js';\r\n\r\n// ===== Types =====\r\n\r\nexport type PhaseStatus = 'success' | 'warn' | 'error' | 'skipped';\r\n\r\nexport interface PhaseResult<T = unknown> {\r\n phase: string;\r\n status: PhaseStatus;\r\n output?: T;\r\n error?: string;\r\n durationMs: number;\r\n}\r\n\r\nexport interface OrchestrationOptions {\r\n /** Which phases to run (default: all) */\r\n phases?: OrchestrationPhase[];\r\n /** Enable self-healing phase (default: false) */\r\n selfHeal?: boolean;\r\n /** Max self-healing iterations */\r\n maxHealIterations?: number;\r\n /** Report formats to generate */\r\n reportFormats?: ('html' | 'json' | 'markdown')[];\r\n /** Run Playwright in headed mode */\r\n headed?: boolean;\r\n /** Module filter */\r\n module?: string;\r\n /** LLM token budget (0 = unlimited) */\r\n tokenBudget?: number;\r\n /** Abort on phase error (default: false — continue where possible) */\r\n abortOnError?: boolean;\r\n}\r\n\r\nexport type OrchestrationPhase = 'generate' | 'execute' | 'analyze' | 'heal' | 'report';\r\n\r\nexport interface ExecutionMetrics {\r\n passed: number;\r\n failed: number;\r\n skipped: number;\r\n timedOut: number;\r\n}\r\n\r\nexport interface OrchestrationSummary {\r\n overallStatus: 'success' | 'partial-fail' | 'fatal-fail';\r\n phases: PhaseResult[];\r\n totalDurationMs: number;\r\n modules: string[];\r\n executionMetrics?: ExecutionMetrics;\r\n reports?: ReportOutput[];\r\n healingResult?: SelfHealingResult;\r\n recommendation?: string;\r\n}\r\n\r\nconst ALL_PHASES: OrchestrationPhase[] = ['generate', 'execute', 'analyze', 'heal', 'report'];\r\n\r\n// ===== Helpers =====\r\n\r\nfunction discoverTestFiles(outDir: string, moduleFilter?: string): string[] {\r\n const absDir = join(process.cwd(), outDir);\r\n if (!existsSync(absDir)) return [];\r\n\r\n const files: string[] = [];\r\n const entries = readdirSync(absDir, { withFileTypes: true, recursive: true });\r\n for (const entry of entries) {\r\n if (!entry.isFile()) continue;\r\n if (!entry.name.endsWith('.spec.ts') && !entry.name.endsWith('.test.ts')) continue;\r\n const fullPath = join(\r\n entry.parentPath || (entry as unknown as { path: string }).path || absDir,\r\n entry.name,\r\n );\r\n if (moduleFilter && !fullPath.includes(moduleFilter)) continue;\r\n files.push(fullPath);\r\n }\r\n return files;\r\n}\r\n\r\nfunction parsePlaywrightOutput(stderr: string): ExecutionMetrics {\r\n const metrics: ExecutionMetrics = { passed: 0, failed: 0, skipped: 0, timedOut: 0 };\r\n\r\n // Playwright summary line: \"X passed\", \"Y failed\", \"Z skipped\"\r\n const passedMatch = stderr.match(/(\\d+)\\s+passed/);\r\n const failedMatch = stderr.match(/(\\d+)\\s+failed/);\r\n const skippedMatch = stderr.match(/(\\d+)\\s+skipped/);\r\n const timedOutMatch = stderr.match(/(\\d+)\\s+timed?\\s*out/i);\r\n\r\n if (passedMatch) metrics.passed = parseInt(passedMatch[1], 10);\r\n if (failedMatch) metrics.failed = parseInt(failedMatch[1], 10);\r\n if (skippedMatch) metrics.skipped = parseInt(skippedMatch[1], 10);\r\n if (timedOutMatch) metrics.timedOut = parseInt(timedOutMatch[1], 10);\r\n\r\n return metrics;\r\n}\r\n\r\n// ===== Orchestrator =====\r\n\r\nexport function createOrchestrator(config: OpenCrocConfig, options: OrchestrationOptions = {}) {\r\n const {\r\n phases = ALL_PHASES,\r\n selfHeal = false,\r\n maxHealIterations = 3,\r\n reportFormats = ['html', 'json'],\r\n headed = false,\r\n module: moduleFilter,\r\n tokenBudget = 0,\r\n abortOnError = false,\r\n } = options;\r\n\r\n const outDir = config.outDir || './opencroc-output';\r\n const phaseResults: PhaseResult[] = [];\r\n let pipelineResult: PipelineRunResult | undefined;\r\n let executionMetrics: ExecutionMetrics | undefined;\r\n let healingResult: SelfHealingResult | undefined;\r\n let reports: ReportOutput[] | undefined;\r\n let tokensUsed = 0;\r\n\r\n function isBudgetExceeded(): boolean {\r\n return tokenBudget > 0 && tokensUsed >= tokenBudget;\r\n }\r\n\r\n function shouldRun(phase: OrchestrationPhase): boolean {\r\n if (phase === 'heal' && !selfHeal) return false;\r\n return phases.includes(phase);\r\n }\r\n\r\n async function runPhase<T>(\r\n name: string,\r\n fn: () => Promise<T>,\r\n ): Promise<PhaseResult<T>> {\r\n const start = Date.now();\r\n try {\r\n const output = await fn();\r\n const result: PhaseResult<T> = {\r\n phase: name,\r\n status: 'success',\r\n output,\r\n durationMs: Date.now() - start,\r\n };\r\n phaseResults.push(result);\r\n return result;\r\n } catch (err) {\r\n const result: PhaseResult<T> = {\r\n phase: name,\r\n status: 'error',\r\n error: err instanceof Error ? err.message : String(err),\r\n durationMs: Date.now() - start,\r\n };\r\n phaseResults.push(result);\r\n return result;\r\n }\r\n }\r\n\r\n function skipPhase(name: string, reason: string): PhaseResult {\r\n const result: PhaseResult = {\r\n phase: name,\r\n status: 'skipped',\r\n error: reason,\r\n durationMs: 0,\r\n };\r\n phaseResults.push(result);\r\n return result;\r\n }\r\n\r\n return {\r\n async run(): Promise<OrchestrationSummary> {\r\n const orchestrationStart = Date.now();\r\n\r\n // ── Phase 1: Generate ──\r\n if (shouldRun('generate')) {\r\n const genResult = await runPhase('generate', async () => {\r\n if (moduleFilter) config.modules = [moduleFilter];\r\n const pipeline = createPipeline(config);\r\n pipelineResult = await pipeline.run();\r\n\r\n // Write generated files\r\n for (const file of pipelineResult.generatedFiles) {\r\n const dir = dirname(file.filePath);\r\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\r\n writeFileSync(file.filePath, file.content, 'utf-8');\r\n }\r\n\r\n return pipelineResult;\r\n });\r\n\r\n if (genResult.status === 'error' && abortOnError) {\r\n return buildSummary(orchestrationStart);\r\n }\r\n }\r\n\r\n // ── Phase 2: Execute ──\r\n if (shouldRun('execute')) {\r\n const testFiles = discoverTestFiles(outDir, moduleFilter);\r\n\r\n if (testFiles.length === 0) {\r\n skipPhase('execute', 'No test files found');\r\n } else {\r\n const execResult = await runPhase('execute', async () => {\r\n const args = ['test', ...testFiles];\r\n if (!headed) args.push('--reporter=list');\r\n else args.push('--headed');\r\n\r\n const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';\r\n\r\n try {\r\n execFileSync(npxCmd, ['playwright', ...args], {\r\n cwd: process.cwd(),\r\n stdio: ['ignore', 'pipe', 'pipe'],\r\n timeout: 300_000,\r\n });\r\n return { passed: testFiles.length, failed: 0, skipped: 0, timedOut: 0 } as ExecutionMetrics;\r\n } catch (err) {\r\n const stderr = (err as { stderr?: Buffer })?.stderr?.toString() ?? '';\r\n const metrics = parsePlaywrightOutput(stderr);\r\n if (metrics.passed === 0 && metrics.failed === 0) {\r\n metrics.failed = testFiles.length;\r\n }\r\n executionMetrics = metrics;\r\n if (metrics.failed > 0) {\r\n throw new Error(`${metrics.failed} test(s) failed, ${metrics.passed} passed`, { cause: err });\r\n }\r\n return metrics;\r\n }\r\n });\r\n\r\n if (!executionMetrics && execResult.output) {\r\n executionMetrics = execResult.output as ExecutionMetrics;\r\n }\r\n\r\n if (execResult.status === 'error' && abortOnError) {\r\n return buildSummary(orchestrationStart);\r\n }\r\n }\r\n }\r\n\r\n // ── Phase 3: Analyze ──\r\n if (shouldRun('analyze')) {\r\n if (!pipelineResult || !executionMetrics || executionMetrics.failed === 0) {\r\n skipPhase('analyze', 'No failures to analyze');\r\n } else {\r\n await runPhase('analyze', async () => {\r\n // Re-run pipeline validation for failure context\r\n const pipeline = createPipeline(config);\r\n const validationResult = await pipeline.run(['validate']);\r\n return {\r\n validationErrors: validationResult.validationErrors,\r\n failedTestCount: executionMetrics!.failed,\r\n };\r\n });\r\n }\r\n }\r\n\r\n // ── Phase 4: Heal ──\r\n if (shouldRun('heal')) {\r\n if (isBudgetExceeded()) {\r\n skipPhase('heal', 'Token budget exceeded');\r\n } else if (!executionMetrics || executionMetrics.failed === 0) {\r\n skipPhase('heal', 'No failures to heal');\r\n } else {\r\n const healResult = await runPhase('heal', async () => {\r\n const healConfig: SelfHealingConfig = {\r\n enabled: true,\r\n maxIterations: maxHealIterations,\r\n mode: config.selfHealing?.mode || 'config-only',\r\n };\r\n\r\n const loop = createSelfHealingLoop(healConfig);\r\n const result = await loop.run(outDir);\r\n tokensUsed += result.totalTokensUsed;\r\n healingResult = result;\r\n return result;\r\n });\r\n\r\n if (healResult.status === 'success' && healingResult && healingResult.remaining.length > 0) {\r\n healResult.status = 'warn';\r\n phaseResults[phaseResults.length - 1] = healResult;\r\n }\r\n }\r\n }\r\n\r\n // ── Phase 5: Report ──\r\n if (shouldRun('report')) {\r\n if (!pipelineResult) {\r\n skipPhase('report', 'No pipeline results to report');\r\n } else {\r\n await runPhase('report', async () => {\r\n reports = generateReports(pipelineResult!, reportFormats);\r\n\r\n if (!existsSync(outDir)) mkdirSync(outDir, { recursive: true });\r\n for (const r of reports) {\r\n writeFileSync(join(outDir, r.filename), r.content, 'utf-8');\r\n }\r\n\r\n return reports;\r\n });\r\n }\r\n }\r\n\r\n return buildSummary(orchestrationStart);\r\n },\r\n };\r\n\r\n function buildSummary(startTime: number): OrchestrationSummary {\r\n const errorCount = phaseResults.filter((p) => p.status === 'error').length;\r\n const allSuccess = phaseResults.every((p) => p.status === 'success' || p.status === 'skipped');\r\n\r\n let overallStatus: OrchestrationSummary['overallStatus'];\r\n if (allSuccess) overallStatus = 'success';\r\n else if (errorCount > 1) overallStatus = 'fatal-fail';\r\n else overallStatus = 'partial-fail';\r\n\r\n let recommendation: string | undefined;\r\n if (executionMetrics && executionMetrics.failed > 0 && !selfHeal) {\r\n recommendation = 'Test failures detected. Consider running with --self-heal to attempt automated fixes.';\r\n } else if (healingResult && healingResult.remaining.length > 0) {\r\n recommendation = `${healingResult.remaining.length} issue(s) could not be auto-fixed. Manual review needed.`;\r\n }\r\n\r\n return {\r\n overallStatus,\r\n phases: phaseResults,\r\n totalDurationMs: Date.now() - startTime,\r\n modules: pipelineResult?.modules ?? [],\r\n executionMetrics,\r\n reports,\r\n healingResult,\r\n recommendation,\r\n };\r\n }\r\n}\r\n","/**\r\n * Orchestration summary reporter.\r\n * Writes phase-by-phase JSON and a human-readable console summary.\r\n */\r\n\r\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport type { OrchestrationSummary, PhaseResult } from './index.js';\r\n\r\nexport interface OrchestrationReportOptions {\r\n outputDir: string;\r\n module?: string;\r\n}\r\n\r\n/**\r\n * Write the orchestration summary to a JSON file.\r\n * Returns the written file path.\r\n */\r\nexport function writeOrchestrationSummary(\r\n summary: OrchestrationSummary,\r\n options: OrchestrationReportOptions,\r\n): string {\r\n const { outputDir, module: mod } = options;\r\n if (!existsSync(outputDir)) mkdirSync(outputDir, { recursive: true });\r\n\r\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\r\n const moduleName = mod ?? 'all';\r\n const filename = `orchestration-${moduleName}-${timestamp}.json`;\r\n const filePath = join(outputDir, filename);\r\n\r\n const serializable = {\r\n ...summary,\r\n phases: summary.phases.map((p) => ({\r\n phase: p.phase,\r\n status: p.status,\r\n error: p.error,\r\n durationMs: p.durationMs,\r\n })),\r\n // Strip report content to avoid massive JSON\r\n reports: summary.reports?.map((r) => ({\r\n format: r.format,\r\n filename: r.filename,\r\n })),\r\n };\r\n\r\n writeFileSync(filePath, JSON.stringify(serializable, null, 2), 'utf-8');\r\n return filePath;\r\n}\r\n\r\n/**\r\n * Format a phase result as a single console line.\r\n */\r\nfunction formatPhase(p: PhaseResult): string {\r\n const icons: Record<string, string> = {\r\n success: '✓',\r\n warn: '⚠',\r\n error: '✗',\r\n skipped: '○',\r\n };\r\n const icon = icons[p.status] ?? '?';\r\n const dur = p.durationMs > 0 ? ` (${p.durationMs}ms)` : '';\r\n const err = p.error ? ` — ${p.error}` : '';\r\n return ` ${icon} ${p.phase}${dur}${err}`;\r\n}\r\n\r\n/**\r\n * Print a human-readable console summary.\r\n */\r\nexport function printOrchestrationSummary(summary: OrchestrationSummary): string[] {\r\n const lines: string[] = [];\r\n\r\n lines.push('');\r\n lines.push(' ═══════════════════════════════════════');\r\n lines.push(' Orchestration Summary');\r\n lines.push(' ═══════════════════════════════════════');\r\n lines.push('');\r\n\r\n for (const p of summary.phases) {\r\n lines.push(formatPhase(p));\r\n }\r\n\r\n lines.push('');\r\n lines.push(` Overall : ${summary.overallStatus}`);\r\n lines.push(` Modules : ${summary.modules.join(', ') || '(none)'}`);\r\n lines.push(` Duration : ${summary.totalDurationMs}ms`);\r\n\r\n if (summary.executionMetrics) {\r\n const m = summary.executionMetrics;\r\n lines.push(` Tests : ${m.passed} passed, ${m.failed} failed, ${m.skipped} skipped`);\r\n }\r\n\r\n if (summary.healingResult) {\r\n const h = summary.healingResult;\r\n lines.push(` Healing : ${h.fixed.length} fixed, ${h.remaining.length} remaining (${h.iterations} iterations)`);\r\n }\r\n\r\n if (summary.reports) {\r\n lines.push(` Reports : ${summary.reports.map((r) => r.format).join(', ')}`);\r\n }\r\n\r\n if (summary.recommendation) {\r\n lines.push('');\r\n lines.push(` → ${summary.recommendation}`);\r\n }\r\n\r\n lines.push('');\r\n\r\n return lines;\r\n}\r\n","/**\r\n * Language Detector\r\n *\r\n * Detects programming languages, frameworks, and project type\r\n * from a project directory without reading source code ASTs.\r\n * Uses file extensions, config files, and package manifests.\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\nimport type { ProjectType, FrameworkDetection } from '../graph/types.js';\r\n\r\n// ===== Language Detection by File Extension =====\r\n\r\nconst EXTENSION_MAP: Record<string, string> = {\r\n '.ts': 'typescript', '.tsx': 'typescript', '.mts': 'typescript', '.cts': 'typescript',\r\n '.js': 'javascript', '.jsx': 'javascript', '.mjs': 'javascript', '.cjs': 'javascript',\r\n '.py': 'python', '.pyw': 'python', '.pyi': 'python',\r\n '.go': 'go',\r\n '.java': 'java', '.kt': 'kotlin', '.kts': 'kotlin',\r\n '.rs': 'rust',\r\n '.rb': 'ruby',\r\n '.php': 'php',\r\n '.cs': 'csharp',\r\n '.cpp': 'cpp', '.cc': 'cpp', '.cxx': 'cpp', '.c': 'c', '.h': 'c',\r\n '.swift': 'swift',\r\n '.dart': 'dart',\r\n '.vue': 'vue',\r\n '.svelte': 'svelte',\r\n '.astro': 'astro',\r\n '.sql': 'sql',\r\n '.graphql': 'graphql', '.gql': 'graphql',\r\n '.proto': 'protobuf',\r\n '.yaml': 'yaml', '.yml': 'yaml',\r\n '.json': 'json',\r\n '.toml': 'toml',\r\n '.md': 'markdown',\r\n '.html': 'html', '.htm': 'html',\r\n '.css': 'css', '.scss': 'scss', '.less': 'less', '.sass': 'sass',\r\n '.sh': 'shell', '.bash': 'shell', '.zsh': 'shell',\r\n '.ps1': 'powershell',\r\n '.dockerfile': 'docker',\r\n '.tf': 'terraform',\r\n '.lua': 'lua',\r\n '.r': 'r', '.R': 'r',\r\n '.scala': 'scala',\r\n '.ex': 'elixir', '.exs': 'elixir',\r\n '.erl': 'erlang',\r\n '.zig': 'zig',\r\n};\r\n\r\n/** Directories to skip during scanning */\r\nconst SKIP_DIRS = new Set([\r\n 'node_modules', '.git', '.svn', '.hg', 'dist', 'build', 'out', 'target',\r\n '__pycache__', '.cache', '.next', '.nuxt', '.output', 'vendor', 'venv',\r\n '.venv', 'env', '.env', 'coverage', '.idea', '.vscode', '.vs',\r\n '.turbo', '.nx', 'bower_components', 'jspm_packages',\r\n]);\r\n\r\n/** Max depth to scan */\r\nconst MAX_DEPTH = 8;\r\n\r\n/** Max files to scan for detection (avoid huge repos) */\r\nconst MAX_FILES = 10000;\r\n\r\nexport interface LanguageDetectionResult {\r\n /** Language → file count */\r\n languages: Record<string, number>;\r\n /** Language → total line count */\r\n linesByLanguage: Record<string, number>;\r\n /** Total files found */\r\n totalFiles: number;\r\n /** Total lines of code */\r\n totalLines: number;\r\n /** Primary language */\r\n primaryLanguage: string;\r\n /** Detected frameworks */\r\n frameworks: FrameworkDetection[];\r\n /** Detected project type */\r\n projectType: ProjectType;\r\n /** Package manager */\r\n packageManager?: string;\r\n /** All discovered source files */\r\n files: Array<{ path: string; language: string; lines: number; size: number }>;\r\n}\r\n\r\n/**\r\n * Detect languages, frameworks, and project type from a directory.\r\n */\r\nexport function detectProject(rootDir: string): LanguageDetectionResult {\r\n const absRoot = path.resolve(rootDir);\r\n const languages: Record<string, number> = {};\r\n const linesByLanguage: Record<string, number> = {};\r\n const files: Array<{ path: string; language: string; lines: number; size: number }> = [];\r\n let totalFiles = 0;\r\n let totalLines = 0;\r\n\r\n // Recursive file scan\r\n function walk(dir: string, depth: number): void {\r\n if (depth > MAX_DEPTH || totalFiles > MAX_FILES) return;\r\n let entries: fs.Dirent[];\r\n try {\r\n entries = fs.readdirSync(dir, { withFileTypes: true });\r\n } catch {\r\n return;\r\n }\r\n for (const entry of entries) {\r\n if (totalFiles > MAX_FILES) break;\r\n const fullPath = path.join(dir, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n if (!SKIP_DIRS.has(entry.name) && !entry.name.startsWith('.')) {\r\n walk(fullPath, depth + 1);\r\n }\r\n continue;\r\n }\r\n\r\n if (!entry.isFile()) continue;\r\n\r\n const ext = path.extname(entry.name).toLowerCase();\r\n // Special file name detection\r\n const lang = detectLanguageByFile(entry.name, ext);\r\n if (!lang) continue;\r\n\r\n let lineCount = 0;\r\n let fileSize = 0;\r\n try {\r\n const stat = fs.statSync(fullPath);\r\n fileSize = stat.size;\r\n // Only count lines for reasonable files (< 1MB)\r\n if (fileSize < 1_048_576) {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n lineCount = content.split('\\n').length;\r\n }\r\n } catch {\r\n continue;\r\n }\r\n\r\n languages[lang] = (languages[lang] || 0) + 1;\r\n linesByLanguage[lang] = (linesByLanguage[lang] || 0) + lineCount;\r\n totalFiles++;\r\n totalLines += lineCount;\r\n\r\n const relPath = path.relative(absRoot, fullPath).replace(/\\\\/g, '/');\r\n files.push({ path: relPath, language: lang, lines: lineCount, size: fileSize });\r\n }\r\n }\r\n\r\n walk(absRoot, 0);\r\n\r\n // Determine primary language (by file count, ignoring config-only languages)\r\n const codeLangs = Object.entries(languages)\r\n .filter(([k]) => !['json', 'yaml', 'toml', 'markdown', 'html', 'css', 'scss', 'less', 'sass'].includes(k))\r\n .sort((a, b) => b[1] - a[1]);\r\n const primaryLanguage = codeLangs[0]?.[0] || 'unknown';\r\n\r\n // Detect frameworks\r\n const frameworks = detectFrameworks(absRoot, languages, files);\r\n\r\n // Detect project type\r\n const projectType = detectProjectType(absRoot, languages, frameworks);\r\n\r\n // Detect package manager\r\n const packageManager = detectPackageManager(absRoot);\r\n\r\n return {\r\n languages,\r\n linesByLanguage,\r\n totalFiles,\r\n totalLines,\r\n primaryLanguage,\r\n frameworks,\r\n projectType,\r\n packageManager,\r\n files,\r\n };\r\n}\r\n\r\nfunction detectLanguageByFile(fileName: string, ext: string): string | null {\r\n // Special file names\r\n if (fileName === 'Dockerfile' || fileName.startsWith('Dockerfile.')) return 'docker';\r\n if (fileName === 'Makefile') return 'makefile';\r\n if (fileName === 'CMakeLists.txt') return 'cmake';\r\n if (fileName === 'Vagrantfile') return 'ruby';\r\n if (fileName === 'Gemfile') return 'ruby';\r\n if (fileName === 'Rakefile') return 'ruby';\r\n if (fileName === 'Cargo.toml') return 'rust';\r\n if (fileName === 'go.mod' || fileName === 'go.sum') return 'go';\r\n\r\n return EXTENSION_MAP[ext] || null;\r\n}\r\n\r\n// ===== Framework Detection =====\r\n\r\ninterface FrameworkRule {\r\n name: string;\r\n detect: (root: string, langs: Record<string, number>, files: Array<{ path: string }>) => FrameworkDetection | null;\r\n}\r\n\r\nconst FRAMEWORK_RULES: FrameworkRule[] = [\r\n // --- Node.js / JavaScript ---\r\n {\r\n name: 'express',\r\n detect: (root) => detectFromPackageJson(root, 'express', 'Express'),\r\n },\r\n {\r\n name: 'nestjs',\r\n detect: (root) => detectFromPackageJson(root, '@nestjs/core', 'NestJS'),\r\n },\r\n {\r\n name: 'fastify',\r\n detect: (root) => detectFromPackageJson(root, 'fastify', 'Fastify'),\r\n },\r\n {\r\n name: 'koa',\r\n detect: (root) => detectFromPackageJson(root, 'koa', 'Koa'),\r\n },\r\n {\r\n name: 'hapi',\r\n detect: (root) => detectFromPackageJson(root, '@hapi/hapi', 'Hapi'),\r\n },\r\n {\r\n name: 'nextjs',\r\n detect: (root) => detectFromPackageJson(root, 'next', 'Next.js'),\r\n },\r\n {\r\n name: 'nuxtjs',\r\n detect: (root) => detectFromPackageJson(root, 'nuxt', 'Nuxt.js'),\r\n },\r\n {\r\n name: 'react',\r\n detect: (root) => detectFromPackageJson(root, 'react', 'React'),\r\n },\r\n {\r\n name: 'vue',\r\n detect: (root) => detectFromPackageJson(root, 'vue', 'Vue'),\r\n },\r\n {\r\n name: 'angular',\r\n detect: (root) => detectFromPackageJson(root, '@angular/core', 'Angular'),\r\n },\r\n {\r\n name: 'svelte',\r\n detect: (root) => detectFromPackageJson(root, 'svelte', 'Svelte'),\r\n },\r\n {\r\n name: 'electron',\r\n detect: (root) => detectFromPackageJson(root, 'electron', 'Electron'),\r\n },\r\n {\r\n name: 'sequelize',\r\n detect: (root) => detectFromPackageJson(root, 'sequelize', 'Sequelize'),\r\n },\r\n {\r\n name: 'typeorm',\r\n detect: (root) => detectFromPackageJson(root, 'typeorm', 'TypeORM'),\r\n },\r\n {\r\n name: 'prisma',\r\n detect: (root) => detectFromPackageJson(root, 'prisma', 'Prisma') || detectFromPackageJson(root, '@prisma/client', 'Prisma'),\r\n },\r\n {\r\n name: 'mongoose',\r\n detect: (root) => detectFromPackageJson(root, 'mongoose', 'Mongoose'),\r\n },\r\n {\r\n name: 'playwright',\r\n detect: (root) => detectFromPackageJson(root, '@playwright/test', 'Playwright'),\r\n },\r\n // --- Python ---\r\n {\r\n name: 'django',\r\n detect: (root) => detectFromRequirements(root, 'django', 'Django') || detectFromFile(root, 'manage.py', 'Django'),\r\n },\r\n {\r\n name: 'flask',\r\n detect: (root) => detectFromRequirements(root, 'flask', 'Flask'),\r\n },\r\n {\r\n name: 'fastapi',\r\n detect: (root) => detectFromRequirements(root, 'fastapi', 'FastAPI'),\r\n },\r\n {\r\n name: 'pytorch',\r\n detect: (root) => detectFromRequirements(root, 'torch', 'PyTorch'),\r\n },\r\n {\r\n name: 'tensorflow',\r\n detect: (root) => detectFromRequirements(root, 'tensorflow', 'TensorFlow'),\r\n },\r\n // --- Go ---\r\n {\r\n name: 'gin',\r\n detect: (root) => detectFromGoMod(root, 'github.com/gin-gonic/gin', 'Gin'),\r\n },\r\n {\r\n name: 'echo',\r\n detect: (root) => detectFromGoMod(root, 'github.com/labstack/echo', 'Echo'),\r\n },\r\n {\r\n name: 'fiber',\r\n detect: (root) => detectFromGoMod(root, 'github.com/gofiber/fiber', 'Fiber'),\r\n },\r\n // --- Java ---\r\n {\r\n name: 'spring-boot',\r\n detect: (root) => detectFromFile(root, 'pom.xml', 'Spring Boot', 'spring-boot') || detectFromFile(root, 'build.gradle', 'Spring Boot', 'spring-boot'),\r\n },\r\n // --- Rust ---\r\n {\r\n name: 'actix-web',\r\n detect: (root) => detectFromCargoToml(root, 'actix-web', 'Actix Web'),\r\n },\r\n {\r\n name: 'axum',\r\n detect: (root) => detectFromCargoToml(root, 'axum', 'Axum'),\r\n },\r\n // --- Ruby ---\r\n {\r\n name: 'rails',\r\n detect: (root) => detectFromFile(root, 'Gemfile', 'Ruby on Rails', 'rails'),\r\n },\r\n // --- PHP ---\r\n {\r\n name: 'laravel',\r\n detect: (root) => detectFromFile(root, 'artisan', 'Laravel'),\r\n },\r\n];\r\n\r\nfunction detectFromPackageJson(root: string, dep: string, name: string): FrameworkDetection | null {\r\n // Search in root and common subdirs\r\n const candidates = [\r\n path.join(root, 'package.json'),\r\n path.join(root, 'backend', 'package.json'),\r\n path.join(root, 'server', 'package.json'),\r\n path.join(root, 'api', 'package.json'),\r\n path.join(root, 'frontend', 'package.json'),\r\n path.join(root, 'web', 'package.json'),\r\n path.join(root, 'client', 'package.json'),\r\n ];\r\n\r\n for (const pkgPath of candidates) {\r\n try {\r\n if (!fs.existsSync(pkgPath)) continue;\r\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));\r\n const allDeps = { ...pkg.dependencies, ...pkg.devDependencies, ...pkg.peerDependencies };\r\n if (dep in allDeps) {\r\n return {\r\n name,\r\n version: allDeps[dep]?.replace(/[\\^~>=<]*/g, ''),\r\n confidence: 0.95,\r\n evidence: `Found \"${dep}\" in ${path.relative(root, pkgPath)}`,\r\n };\r\n }\r\n } catch {\r\n continue;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction detectFromRequirements(root: string, dep: string, name: string): FrameworkDetection | null {\r\n const candidates = [\r\n path.join(root, 'requirements.txt'),\r\n path.join(root, 'Pipfile'),\r\n path.join(root, 'pyproject.toml'),\r\n path.join(root, 'setup.py'),\r\n path.join(root, 'setup.cfg'),\r\n ];\r\n\r\n for (const filePath of candidates) {\r\n try {\r\n if (!fs.existsSync(filePath)) continue;\r\n const content = fs.readFileSync(filePath, 'utf-8');\r\n const pattern = new RegExp(`^${dep}([>=<~!\\\\s]|$)`, 'im');\r\n if (pattern.test(content)) {\r\n return {\r\n name,\r\n confidence: 0.9,\r\n evidence: `Found \"${dep}\" in ${path.basename(filePath)}`,\r\n };\r\n }\r\n } catch {\r\n continue;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction detectFromGoMod(root: string, module: string, name: string): FrameworkDetection | null {\r\n const goModPath = path.join(root, 'go.mod');\r\n try {\r\n if (!fs.existsSync(goModPath)) return null;\r\n const content = fs.readFileSync(goModPath, 'utf-8');\r\n if (content.includes(module)) {\r\n return {\r\n name,\r\n confidence: 0.95,\r\n evidence: `Found \"${module}\" in go.mod`,\r\n };\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n return null;\r\n}\r\n\r\nfunction detectFromCargoToml(root: string, crate: string, name: string): FrameworkDetection | null {\r\n const cargoPath = path.join(root, 'Cargo.toml');\r\n try {\r\n if (!fs.existsSync(cargoPath)) return null;\r\n const content = fs.readFileSync(cargoPath, 'utf-8');\r\n if (content.includes(crate)) {\r\n return {\r\n name,\r\n confidence: 0.9,\r\n evidence: `Found \"${crate}\" in Cargo.toml`,\r\n };\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n return null;\r\n}\r\n\r\nfunction detectFromFile(root: string, fileName: string, name: string, searchTerm?: string): FrameworkDetection | null {\r\n const filePath = path.join(root, fileName);\r\n try {\r\n if (!fs.existsSync(filePath)) return null;\r\n if (searchTerm) {\r\n const content = fs.readFileSync(filePath, 'utf-8');\r\n if (!content.toLowerCase().includes(searchTerm.toLowerCase())) return null;\r\n }\r\n return {\r\n name,\r\n confidence: 0.8,\r\n evidence: `Found ${fileName}${searchTerm ? ` containing \"${searchTerm}\"` : ''}`,\r\n };\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nfunction detectFrameworks(root: string, langs: Record<string, number>, files: Array<{ path: string }>): FrameworkDetection[] {\r\n const detected: FrameworkDetection[] = [];\r\n for (const rule of FRAMEWORK_RULES) {\r\n const result = rule.detect(root, langs, files);\r\n if (result) detected.push(result);\r\n }\r\n return detected;\r\n}\r\n\r\n// ===== Project Type Detection =====\r\n\r\nfunction detectProjectType(root: string, langs: Record<string, number>, frameworks: FrameworkDetection[]): ProjectType {\r\n const frameworkNames = new Set(frameworks.map(f => f.name.toLowerCase()));\r\n\r\n // Monorepo detection\r\n const hasLerna = fs.existsSync(path.join(root, 'lerna.json'));\r\n const hasPnpmWorkspace = fs.existsSync(path.join(root, 'pnpm-workspace.yaml'));\r\n const hasNxJson = fs.existsSync(path.join(root, 'nx.json'));\r\n const hasTurboJson = fs.existsSync(path.join(root, 'turbo.json'));\r\n let hasWorkspaces = false;\r\n try {\r\n const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf-8'));\r\n hasWorkspaces = Array.isArray(pkg.workspaces) || typeof pkg.workspaces === 'object';\r\n } catch {\r\n // ignore\r\n }\r\n if (hasLerna || hasPnpmWorkspace || hasNxJson || hasTurboJson || hasWorkspaces) {\r\n return 'monorepo';\r\n }\r\n\r\n // Library detection\r\n try {\r\n const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf-8'));\r\n if (pkg.main || pkg.exports || pkg.module) {\r\n const hasNoServer = !frameworkNames.has('express') && !frameworkNames.has('fastify') &&\r\n !frameworkNames.has('koa') && !frameworkNames.has('nestjs');\r\n const hasNoFrontend = !frameworkNames.has('react') && !frameworkNames.has('vue') &&\r\n !frameworkNames.has('angular') && !frameworkNames.has('svelte');\r\n if (hasNoServer && hasNoFrontend && pkg.keywords) return 'library';\r\n }\r\n if (pkg.bin) return 'cli-tool';\r\n } catch {\r\n // ignore\r\n }\r\n\r\n // SSR frameworks\r\n if (frameworkNames.has('next.js') || frameworkNames.has('nuxt.js')) return 'frontend-ssr';\r\n\r\n // Mobile\r\n if (frameworkNames.has('electron')) return 'fullstack';\r\n if (langs['dart']) return 'mobile';\r\n if (langs['swift'] && !langs['typescript'] && !langs['python']) return 'mobile';\r\n\r\n // Fullstack detection (has both frontend and backend frameworks)\r\n const hasBackend = frameworkNames.has('express') || frameworkNames.has('fastify') ||\r\n frameworkNames.has('nestjs') || frameworkNames.has('koa') ||\r\n frameworkNames.has('django') || frameworkNames.has('flask') ||\r\n frameworkNames.has('fastapi') || frameworkNames.has('gin') ||\r\n frameworkNames.has('spring boot') || frameworkNames.has('rails') ||\r\n frameworkNames.has('laravel');\r\n const hasFrontend = frameworkNames.has('react') || frameworkNames.has('vue') ||\r\n frameworkNames.has('angular') || frameworkNames.has('svelte');\r\n\r\n if (hasBackend && hasFrontend) return 'fullstack';\r\n if (hasBackend) return 'backend-api';\r\n if (hasFrontend) return 'frontend-spa';\r\n\r\n // Rust/Go API\r\n if (frameworkNames.has('actix web') || frameworkNames.has('axum') ||\r\n frameworkNames.has('gin') || frameworkNames.has('echo') || frameworkNames.has('fiber')) {\r\n return 'backend-api';\r\n }\r\n\r\n return 'unknown';\r\n}\r\n\r\n// ===== Package Manager Detection =====\r\n\r\nfunction detectPackageManager(root: string): string | undefined {\r\n if (fs.existsSync(path.join(root, 'pnpm-lock.yaml'))) return 'pnpm';\r\n if (fs.existsSync(path.join(root, 'yarn.lock'))) return 'yarn';\r\n if (fs.existsSync(path.join(root, 'bun.lockb'))) return 'bun';\r\n if (fs.existsSync(path.join(root, 'package-lock.json'))) return 'npm';\r\n if (fs.existsSync(path.join(root, 'Pipfile.lock'))) return 'pipenv';\r\n if (fs.existsSync(path.join(root, 'poetry.lock'))) return 'poetry';\r\n if (fs.existsSync(path.join(root, 'go.sum'))) return 'go-modules';\r\n if (fs.existsSync(path.join(root, 'Cargo.lock'))) return 'cargo';\r\n if (fs.existsSync(path.join(root, 'Gemfile.lock'))) return 'bundler';\r\n if (fs.existsSync(path.join(root, 'composer.lock'))) return 'composer';\r\n return undefined;\r\n}\r\n","/**\r\n * Universal Project Scanner\r\n *\r\n * Scans any project directory and extracts entities (modules, classes,\r\n * functions, APIs, models) and relationships. Works with any language\r\n * by combining:\r\n * 1. Static analysis (ts-morph for TS/JS)\r\n * 2. Pattern matching (regex for Python/Go/Java/etc.)\r\n * 3. Config file parsing (package.json, OpenAPI, etc.)\r\n * 4. LLM fallback (for unknown patterns)\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\nimport type {\r\n ScanResult,\r\n ExtractedEntity,\r\n ExtractedRelationship,\r\n GraphNodeType,\r\n GraphEdgeRelation,\r\n DiscoveredFile,\r\n} from '../graph/types.js';\r\nimport { detectProject, type LanguageDetectionResult } from './language-detector.js';\r\n\r\nexport interface ScanOptions {\r\n /** Project root directory */\r\n rootDir: string;\r\n /** Max files to deeply analyze (default: 500) */\r\n maxDeepScan?: number;\r\n /** Enable LLM fallback for unknown patterns */\r\n useLlm?: boolean;\r\n /** Progress callback */\r\n onProgress?: (phase: string, percent: number, detail?: string) => void;\r\n}\r\n\r\n/**\r\n * Scan a project and extract all entities and relationships.\r\n */\r\nexport async function scanProject(options: ScanOptions): Promise<ScanResult> {\r\n const { rootDir, maxDeepScan = 500, onProgress } = options;\r\n const startTime = Date.now();\r\n\r\n onProgress?.('detecting', 0, 'Detecting languages and frameworks...');\r\n\r\n // Phase 1: Language detection\r\n const detection = detectProject(rootDir);\r\n\r\n onProgress?.('detecting', 100, `Found ${detection.totalFiles} files, primary: ${detection.primaryLanguage}`);\r\n\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n // Phase 2: Extract entities by language\r\n const sourceFiles = detection.files.filter(f => {\r\n const lang = f.language;\r\n return !['json', 'yaml', 'toml', 'markdown', 'html', 'css', 'scss', 'less', 'sass', 'docker', 'shell', 'powershell'].includes(lang);\r\n });\r\n\r\n const filesToAnalyze = sourceFiles.slice(0, maxDeepScan);\r\n\r\n for (let i = 0; i < filesToAnalyze.length; i++) {\r\n const file = filesToAnalyze[i]!;\r\n const percent = Math.round((i / filesToAnalyze.length) * 100);\r\n if (i % 20 === 0) {\r\n onProgress?.('scanning', percent, `Scanning ${file.path}...`);\r\n }\r\n\r\n const fullPath = path.join(rootDir, file.path);\r\n try {\r\n const extracted = extractEntitiesFromFile(fullPath, file.path, file.language);\r\n entities.push(...extracted.entities);\r\n relationships.push(...extracted.relationships);\r\n } catch {\r\n // Skip files that fail to parse\r\n }\r\n }\r\n\r\n onProgress?.('scanning', 100, `Extracted ${entities.length} entities`);\r\n\r\n // Phase 3: Extract from config files\r\n onProgress?.('configs', 0, 'Parsing config files...');\r\n const configEntities = extractFromConfigs(rootDir, detection);\r\n entities.push(...configEntities.entities);\r\n relationships.push(...configEntities.relationships);\r\n onProgress?.('configs', 100, 'Config parsing complete');\r\n\r\n // Phase 4: Infer cross-file relationships\r\n onProgress?.('relations', 0, 'Building relationships...');\r\n const inferredRelations = inferRelationships(entities, rootDir);\r\n relationships.push(...inferredRelations);\r\n onProgress?.('relations', 100, `${relationships.length} total relationships`);\r\n\r\n // Convert detection files to DiscoveredFile format\r\n const discoveredFiles: DiscoveredFile[] = detection.files.map(f => ({\r\n path: f.path,\r\n language: f.language,\r\n category: categorizeFile(f.path, f.language),\r\n lines: f.lines,\r\n size: f.size,\r\n }));\r\n\r\n return {\r\n languages: detection.languages,\r\n frameworks: detection.frameworks,\r\n files: discoveredFiles,\r\n entities,\r\n relationships,\r\n duration: Date.now() - startTime,\r\n };\r\n}\r\n\r\n// ===== File Entity Extraction =====\r\n\r\ninterface ExtractionResult {\r\n entities: ExtractedEntity[];\r\n relationships: ExtractedRelationship[];\r\n}\r\n\r\nfunction extractEntitiesFromFile(fullPath: string, relPath: string, language: string): ExtractionResult {\r\n switch (language) {\r\n case 'typescript':\r\n case 'javascript':\r\n return extractFromTsJs(fullPath, relPath, language);\r\n case 'python':\r\n return extractFromPython(fullPath, relPath);\r\n case 'go':\r\n return extractFromGo(fullPath, relPath);\r\n case 'java':\r\n case 'kotlin':\r\n return extractFromJavaKotlin(fullPath, relPath, language);\r\n case 'rust':\r\n return extractFromRust(fullPath, relPath);\r\n case 'ruby':\r\n return extractFromRuby(fullPath, relPath);\r\n case 'php':\r\n return extractFromPHP(fullPath, relPath);\r\n case 'vue':\r\n case 'svelte':\r\n return extractFromTsJs(fullPath, relPath, 'typescript'); // Extract script section\r\n default:\r\n return { entities: [], relationships: [] };\r\n }\r\n}\r\n\r\n// ===== TypeScript / JavaScript Extraction =====\r\n\r\nfunction extractFromTsJs(fullPath: string, relPath: string, language: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({\r\n id: fileId,\r\n name: path.basename(relPath),\r\n type: 'file',\r\n filePath: relPath,\r\n language,\r\n metadata: {},\r\n });\r\n\r\n // Extract classes\r\n const classRegex = /(?:export\\s+)?(?:abstract\\s+)?class\\s+(\\w+)(?:\\s+extends\\s+(\\w+))?(?:\\s+implements\\s+([\\w,\\s]+))?\\s*\\{/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = classRegex.exec(content)) !== null) {\r\n const className = match[1]!;\r\n const extendsClass = match[2];\r\n const classId = `class:${relPath}:${className}`;\r\n\r\n entities.push({\r\n id: classId,\r\n name: className,\r\n type: detectClassType(className, content),\r\n filePath: relPath,\r\n line: getLineNumber(content, match.index),\r\n language,\r\n metadata: { extends: extendsClass },\r\n });\r\n\r\n relationships.push({ sourceId: classId, targetId: fileId, relation: 'belongs-to' });\r\n\r\n if (extendsClass) {\r\n relationships.push({\r\n sourceId: classId,\r\n targetId: `class:*:${extendsClass}`,\r\n relation: 'extends',\r\n });\r\n }\r\n }\r\n\r\n // Extract functions (top-level and exported)\r\n const funcRegex = /(?:export\\s+)?(?:async\\s+)?function\\s+(\\w+)\\s*\\(/g;\r\n while ((match = funcRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({\r\n id: funcId,\r\n name: funcName,\r\n type: 'function',\r\n filePath: relPath,\r\n line: getLineNumber(content, match.index),\r\n language,\r\n metadata: {},\r\n });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Extract arrow function exports\r\n const arrowFuncRegex = /export\\s+(?:const|let)\\s+(\\w+)\\s*=\\s*(?:async\\s+)?\\(/g;\r\n while ((match = arrowFuncRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({\r\n id: funcId,\r\n name: funcName,\r\n type: 'function',\r\n filePath: relPath,\r\n line: getLineNumber(content, match.index),\r\n language,\r\n metadata: { arrow: true },\r\n });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Extract Express/Fastify routes\r\n const routeRegex = /(?:router|app)\\.(get|post|put|patch|delete)\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/gi;\r\n while ((match = routeRegex.exec(content)) !== null) {\r\n const method = match[1]!.toUpperCase();\r\n const routePath = match[2]!;\r\n const apiId = `api:${method}:${routePath}`;\r\n entities.push({\r\n id: apiId,\r\n name: `${method} ${routePath}`,\r\n type: 'api',\r\n filePath: relPath,\r\n line: getLineNumber(content, match.index),\r\n language,\r\n metadata: { method, path: routePath },\r\n });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Extract imports\r\n const importRegex = /(?:import\\s+.*from\\s+['\"`]([^'\"`]+)['\"`]|require\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]\\s*\\))/g;\r\n while ((match = importRegex.exec(content)) !== null) {\r\n const importPath = match[1] || match[2]!;\r\n if (importPath.startsWith('.')) {\r\n // Relative import → file dependency\r\n const resolved = resolveRelativeImport(relPath, importPath);\r\n relationships.push({\r\n sourceId: fileId,\r\n targetId: `file:${resolved}`,\r\n relation: 'imports',\r\n });\r\n } else {\r\n // External dependency\r\n const depName = importPath.startsWith('@') ? importPath.split('/').slice(0, 2).join('/') : importPath.split('/')[0]!;\r\n const depId = `dep:${depName}`;\r\n entities.push({\r\n id: depId,\r\n name: depName,\r\n type: 'dependency',\r\n filePath: '',\r\n language: 'external',\r\n metadata: { external: true },\r\n });\r\n relationships.push({ sourceId: fileId, targetId: depId, relation: 'depends-on' });\r\n }\r\n }\r\n\r\n // Extract Sequelize/TypeORM model definitions\r\n if (content.includes('.init(') || content.includes('Model.init') || content.includes('@Entity') || content.includes('defineModel')) {\r\n const tableMatch = content.match(/tableName:\\s*['\"`](\\w+)['\"`]/);\r\n if (tableMatch) {\r\n const tableName = tableMatch[1]!;\r\n const modelId = `model:${tableName}`;\r\n entities.push({\r\n id: modelId,\r\n name: tableName,\r\n type: 'model',\r\n filePath: relPath,\r\n language,\r\n metadata: { orm: 'sequelize' },\r\n });\r\n relationships.push({ sourceId: modelId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Python Extraction =====\r\n\r\nfunction extractFromPython(fullPath: string, relPath: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language: 'python', metadata: {} });\r\n\r\n // Classes\r\n const classRegex = /^class\\s+(\\w+)(?:\\(([^)]*)\\))?\\s*:/gm;\r\n let match: RegExpExecArray | null;\r\n while ((match = classRegex.exec(content)) !== null) {\r\n const className = match[1]!;\r\n const bases = match[2];\r\n const classId = `class:${relPath}:${className}`;\r\n entities.push({\r\n id: classId, name: className,\r\n type: detectPythonClassType(className, bases || '', content),\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'python', metadata: { bases },\r\n });\r\n relationships.push({ sourceId: classId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Functions\r\n const funcRegex = /^(?:async\\s+)?def\\s+(\\w+)\\s*\\(/gm;\r\n while ((match = funcRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n if (funcName.startsWith('_') && funcName !== '__init__') continue;\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({\r\n id: funcId, name: funcName, type: 'function',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'python', metadata: {},\r\n });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // FastAPI/Flask routes\r\n const routeRegex = /@(?:app|router)\\.(get|post|put|patch|delete)\\s*\\(\\s*['\"]([^'\"]+)['\"]/gi;\r\n while ((match = routeRegex.exec(content)) !== null) {\r\n const method = match[1]!.toUpperCase();\r\n const routePath = match[2]!;\r\n const apiId = `api:${method}:${routePath}`;\r\n entities.push({\r\n id: apiId, name: `${method} ${routePath}`, type: 'api',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'python', metadata: { method, path: routePath },\r\n });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Django URL patterns\r\n const djangoUrlRegex = /path\\s*\\(\\s*['\"]([^'\"]+)['\"],\\s*(\\w+)/g;\r\n while ((match = djangoUrlRegex.exec(content)) !== null) {\r\n const routePath = match[1]!;\r\n const apiId = `api:ANY:${routePath}`;\r\n entities.push({\r\n id: apiId, name: routePath, type: 'route',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'python', metadata: { handler: match[2] },\r\n });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Django models\r\n const djangoModelRegex = /class\\s+(\\w+)\\((?:models\\.)?Model\\)/g;\r\n while ((match = djangoModelRegex.exec(content)) !== null) {\r\n const modelName = match[1]!;\r\n const modelId = `model:${modelName}`;\r\n entities.push({\r\n id: modelId, name: modelName, type: 'model',\r\n filePath: relPath, language: 'python', metadata: { orm: 'django' },\r\n });\r\n relationships.push({ sourceId: modelId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // SQLAlchemy models\r\n const sqlalchemyRegex = /class\\s+(\\w+)\\(.*(?:Base|DeclarativeBase|db\\.Model)\\)/g;\r\n while ((match = sqlalchemyRegex.exec(content)) !== null) {\r\n const modelName = match[1]!;\r\n const modelId = `model:${modelName}`;\r\n entities.push({\r\n id: modelId, name: modelName, type: 'model',\r\n filePath: relPath, language: 'python', metadata: { orm: 'sqlalchemy' },\r\n });\r\n relationships.push({ sourceId: modelId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Imports\r\n const importRegex = /^(?:from\\s+([\\w.]+)\\s+import|import\\s+([\\w.]+))/gm;\r\n while ((match = importRegex.exec(content)) !== null) {\r\n const mod = match[1] || match[2]!;\r\n if (mod.startsWith('.')) {\r\n relationships.push({ sourceId: fileId, targetId: `file:${mod}`, relation: 'imports' });\r\n } else {\r\n const depName = mod.split('.')[0]!;\r\n entities.push({ id: `dep:${depName}`, name: depName, type: 'dependency', filePath: '', language: 'external', metadata: { external: true } });\r\n relationships.push({ sourceId: fileId, targetId: `dep:${depName}`, relation: 'depends-on' });\r\n }\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Go Extraction =====\r\n\r\nfunction extractFromGo(fullPath: string, relPath: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language: 'go', metadata: {} });\r\n\r\n // Structs\r\n const structRegex = /type\\s+(\\w+)\\s+struct\\s*\\{/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = structRegex.exec(content)) !== null) {\r\n const structName = match[1]!;\r\n const structId = `class:${relPath}:${structName}`;\r\n entities.push({\r\n id: structId, name: structName,\r\n type: structName.endsWith('Model') || structName.endsWith('Entity') ? 'model' : 'class',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'go', metadata: {},\r\n });\r\n relationships.push({ sourceId: structId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Functions\r\n const funcRegex = /func\\s+(?:\\(\\w+\\s+\\*?\\w+\\)\\s+)?(\\w+)\\s*\\(/g;\r\n while ((match = funcRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n if (funcName[0] !== funcName[0]!.toUpperCase()) continue; // Skip unexported\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({\r\n id: funcId, name: funcName, type: 'function',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'go', metadata: {},\r\n });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Gin/Echo routes\r\n const ginRouteRegex = /\\.(GET|POST|PUT|PATCH|DELETE)\\s*\\(\\s*\"([^\"]+)\"/gi;\r\n while ((match = ginRouteRegex.exec(content)) !== null) {\r\n const method = match[1]!.toUpperCase();\r\n const routePath = match[2]!;\r\n const apiId = `api:${method}:${routePath}`;\r\n entities.push({\r\n id: apiId, name: `${method} ${routePath}`, type: 'api',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'go', metadata: { method, path: routePath },\r\n });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Java/Kotlin Extraction =====\r\n\r\nfunction extractFromJavaKotlin(fullPath: string, relPath: string, language: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language, metadata: {} });\r\n\r\n // Classes\r\n const classRegex = /(?:public\\s+)?(?:abstract\\s+)?(?:class|interface|enum)\\s+(\\w+)(?:\\s+extends\\s+(\\w+))?/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = classRegex.exec(content)) !== null) {\r\n const className = match[1]!;\r\n const classId = `class:${relPath}:${className}`;\r\n entities.push({\r\n id: classId, name: className,\r\n type: content.includes('@Entity') || content.includes('@Table') ? 'model' : 'class',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language, metadata: {},\r\n });\r\n relationships.push({ sourceId: classId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Spring Boot endpoints\r\n const springRegex = /@(?:Get|Post|Put|Patch|Delete|Request)Mapping\\s*\\(\\s*(?:value\\s*=\\s*)?[\"']([^\"']+)[\"']/g;\r\n while ((match = springRegex.exec(content)) !== null) {\r\n const routePath = match[1]!;\r\n const apiId = `api:ANY:${routePath}`;\r\n entities.push({\r\n id: apiId, name: routePath, type: 'api',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language, metadata: { path: routePath },\r\n });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Rust Extraction =====\r\n\r\nfunction extractFromRust(fullPath: string, relPath: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language: 'rust', metadata: {} });\r\n\r\n // Structs\r\n const structRegex = /pub\\s+struct\\s+(\\w+)/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = structRegex.exec(content)) !== null) {\r\n const structName = match[1]!;\r\n const structId = `class:${relPath}:${structName}`;\r\n entities.push({ id: structId, name: structName, type: 'class', filePath: relPath, line: getLineNumber(content, match.index), language: 'rust', metadata: {} });\r\n relationships.push({ sourceId: structId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Functions\r\n const funcRegex = /pub\\s+(?:async\\s+)?fn\\s+(\\w+)/g;\r\n while ((match = funcRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({ id: funcId, name: funcName, type: 'function', filePath: relPath, line: getLineNumber(content, match.index), language: 'rust', metadata: {} });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Ruby Extraction =====\r\n\r\nfunction extractFromRuby(fullPath: string, relPath: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language: 'ruby', metadata: {} });\r\n\r\n // Classes\r\n const classRegex = /class\\s+(\\w+)(?:\\s*<\\s*(\\w+))?/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = classRegex.exec(content)) !== null) {\r\n const className = match[1]!;\r\n const base = match[2];\r\n const classId = `class:${relPath}:${className}`;\r\n const type: GraphNodeType = base === 'ApplicationRecord' || base === 'ActiveRecord::Base' ? 'model' : 'class';\r\n entities.push({ id: classId, name: className, type, filePath: relPath, line: getLineNumber(content, match.index), language: 'ruby', metadata: { extends: base } });\r\n relationships.push({ sourceId: classId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Methods\r\n const defRegex = /def\\s+(?:self\\.)?(\\w+)/g;\r\n while ((match = defRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n if (funcName.startsWith('_')) continue;\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({ id: funcId, name: funcName, type: 'function', filePath: relPath, line: getLineNumber(content, match.index), language: 'ruby', metadata: {} });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== PHP Extraction =====\r\n\r\nfunction extractFromPHP(fullPath: string, relPath: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language: 'php', metadata: {} });\r\n\r\n // Classes\r\n const classRegex = /(?:abstract\\s+)?class\\s+(\\w+)(?:\\s+extends\\s+(\\w+))?/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = classRegex.exec(content)) !== null) {\r\n const className = match[1]!;\r\n const base = match[2];\r\n const classId = `class:${relPath}:${className}`;\r\n const type: GraphNodeType = base === 'Model' || base === 'Eloquent' ? 'model' : 'class';\r\n entities.push({ id: classId, name: className, type, filePath: relPath, line: getLineNumber(content, match.index), language: 'php', metadata: {} });\r\n relationships.push({ sourceId: classId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Laravel routes\r\n const laravelRouteRegex = /Route::(get|post|put|patch|delete)\\s*\\(\\s*['\"]([^'\"]+)['\"]/gi;\r\n while ((match = laravelRouteRegex.exec(content)) !== null) {\r\n const method = match[1]!.toUpperCase();\r\n const routePath = match[2]!;\r\n const apiId = `api:${method}:${routePath}`;\r\n entities.push({ id: apiId, name: `${method} ${routePath}`, type: 'api', filePath: relPath, line: getLineNumber(content, match.index), language: 'php', metadata: { method, path: routePath } });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Config File Extraction =====\r\n\r\nfunction extractFromConfigs(rootDir: string, _detection: LanguageDetectionResult): ExtractionResult {\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n // Extract dependencies from package.json\r\n const pkgPath = path.join(rootDir, 'package.json');\r\n if (fs.existsSync(pkgPath)) {\r\n try {\r\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));\r\n const allDeps = { ...pkg.dependencies };\r\n for (const [name, version] of Object.entries(allDeps)) {\r\n const depId = `dep:${name}`;\r\n entities.push({\r\n id: depId, name, type: 'dependency',\r\n filePath: 'package.json', language: 'external',\r\n metadata: { version, source: 'npm', external: true },\r\n });\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n // Extract from OpenAPI/Swagger spec\r\n const openAPIFiles = ['openapi.json', 'openapi.yaml', 'openapi.yml', 'swagger.json', 'swagger.yaml'];\r\n for (const apiFile of openAPIFiles) {\r\n const apiPath = path.join(rootDir, apiFile);\r\n if (fs.existsSync(apiPath)) {\r\n try {\r\n const content = fs.readFileSync(apiPath, 'utf-8');\r\n // Simple path extraction from OpenAPI\r\n const pathRegex = /\"(\\/[^\"]+)\":\\s*\\{/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = pathRegex.exec(content)) !== null) {\r\n const routePath = match[1]!;\r\n const apiId = `api:ANY:${routePath}`;\r\n entities.push({\r\n id: apiId, name: routePath, type: 'api',\r\n filePath: apiFile, language: 'openapi',\r\n metadata: { source: 'openapi' },\r\n });\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n }\r\n\r\n // Extract Docker services\r\n const composeFiles = ['docker-compose.yml', 'docker-compose.yaml', 'compose.yml', 'compose.yaml'];\r\n for (const composeFile of composeFiles) {\r\n const composePath = path.join(rootDir, composeFile);\r\n if (fs.existsSync(composePath)) {\r\n try {\r\n const content = fs.readFileSync(composePath, 'utf-8');\r\n // Simple service extraction\r\n const serviceRegex = /^\\s{2}(\\w[\\w-]*):\\s*$/gm;\r\n let match: RegExpExecArray | null;\r\n while ((match = serviceRegex.exec(content)) !== null) {\r\n const serviceName = match[1]!;\r\n if (serviceName === 'services' || serviceName === 'volumes' || serviceName === 'networks') continue;\r\n entities.push({\r\n id: `service:${serviceName}`, name: serviceName,\r\n type: detectServiceType(serviceName),\r\n filePath: composeFile, language: 'docker',\r\n metadata: { source: 'docker-compose' },\r\n });\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Relationship Inference =====\r\n\r\nfunction inferRelationships(entities: ExtractedEntity[], _rootDir: string): ExtractedRelationship[] {\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n // Group entities by type\r\n const models = entities.filter(e => e.type === 'model');\r\n const apis = entities.filter(e => e.type === 'api');\r\n // const classes = entities.filter(e => e.type === 'class' || e.type === 'service');\r\n\r\n // Infer API → Model relationships by path patterns\r\n for (const api of apis) {\r\n const apiPath = (api.metadata.path as string) || api.name;\r\n for (const model of models) {\r\n const modelName = model.name.toLowerCase().replace(/_/g, '');\r\n const pathLower = apiPath.toLowerCase().replace(/[/-]/g, '');\r\n if (pathLower.includes(modelName) || modelName.includes(pathLower.split('/').pop() || '')) {\r\n const method = (api.metadata.method as string) || 'ANY';\r\n const relation: GraphEdgeRelation = ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method) ? 'writes' : 'reads';\r\n relationships.push({ sourceId: api.id, targetId: model.id, relation });\r\n }\r\n }\r\n }\r\n\r\n // Infer module groupings from directory structure\r\n const fileEntities = entities.filter(e => e.type === 'file');\r\n for (const file of fileEntities) {\r\n const dir = path.dirname(file.filePath).split('/')[0];\r\n if (dir && dir !== '.') {\r\n const moduleId = `module:${dir}`;\r\n // Only add module entity if not already exists\r\n if (!entities.some(e => e.id === moduleId)) {\r\n entities.push({\r\n id: moduleId, name: dir, type: 'module',\r\n filePath: dir, language: 'directory',\r\n metadata: {},\r\n });\r\n }\r\n relationships.push({ sourceId: file.id, targetId: moduleId, relation: 'belongs-to' });\r\n }\r\n }\r\n\r\n return relationships;\r\n}\r\n\r\n// ===== Helpers =====\r\n\r\nfunction getLineNumber(content: string, index: number): number {\r\n return content.slice(0, index).split('\\n').length;\r\n}\r\n\r\nfunction resolveRelativeImport(currentFile: string, importPath: string): string {\r\n const dir = path.dirname(currentFile);\r\n let resolved = path.posix.join(dir, importPath);\r\n // Normalize: add .ts extension if missing\r\n if (!path.extname(resolved)) {\r\n resolved += '.ts';\r\n }\r\n return resolved;\r\n}\r\n\r\nfunction categorizeFile(filePath: string, language: string): 'source' | 'config' | 'test' | 'docs' | 'build' | 'asset' | 'other' {\r\n const lower = filePath.toLowerCase();\r\n if (lower.includes('.test.') || lower.includes('.spec.') || lower.includes('__tests__') || lower.includes('/test/') || lower.includes('/tests/')) return 'test';\r\n if (['json', 'yaml', 'toml'].includes(language) || lower.includes('config') || lower.includes('.env')) return 'config';\r\n if (language === 'markdown' || lower.includes('/docs/') || lower.includes('/doc/')) return 'docs';\r\n if (language === 'docker' || lower.includes('makefile') || lower.includes('webpack') || lower.includes('rollup') || lower.includes('vite')) return 'build';\r\n if (['html', 'css', 'scss', 'less'].includes(language)) return 'asset';\r\n return 'source';\r\n}\r\n\r\nfunction detectClassType(name: string, content: string): GraphNodeType {\r\n if (content.includes('.init(') || content.includes('@Entity') || content.includes('tableName')) return 'model';\r\n if (name.includes('Controller') || name.includes('Handler')) return 'service';\r\n if (name.includes('Service') || name.includes('Provider')) return 'service';\r\n if (name.includes('Middleware')) return 'middleware';\r\n if (name.includes('Component') || name.includes('Widget')) return 'component';\r\n return 'class';\r\n}\r\n\r\nfunction detectPythonClassType(name: string, bases: string, _content: string): GraphNodeType {\r\n if (bases.includes('Model') || bases.includes('Base') || bases.includes('db.Model')) return 'model';\r\n if (name.includes('View') || name.includes('ViewSet') || bases.includes('APIView')) return 'service';\r\n if (name.includes('Serializer')) return 'class';\r\n return 'class';\r\n}\r\n\r\nfunction detectServiceType(name: string): GraphNodeType {\r\n const lower = name.toLowerCase();\r\n if (lower.includes('redis') || lower.includes('memcache')) return 'cache';\r\n if (lower.includes('rabbit') || lower.includes('kafka') || lower.includes('nats')) return 'queue';\r\n if (lower.includes('postgres') || lower.includes('mysql') || lower.includes('mongo') || lower.includes('db')) return 'database';\r\n return 'external-api';\r\n}\r\n","/**\r\n * GitHub Cloner\r\n *\r\n * Clone a GitHub/GitLab/any git repository and scan it.\r\n * Supports: HTTPS URLs, shorthand (user/repo), and local paths.\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as os from 'node:os';\r\nimport * as path from 'node:path';\r\nimport { execSync } from 'node:child_process';\r\nimport { scanProject, type ScanOptions } from './project-scanner.js';\r\nimport type { ScanResult } from '../graph/types.js';\r\n\r\nexport interface CloneOptions extends Omit<ScanOptions, 'rootDir'> {\r\n /** GitHub URL, shorthand (user/repo), or local path */\r\n target: string;\r\n /** Where to clone into (default: os temp dir) */\r\n cloneDir?: string;\r\n /** Branch/tag to clone (default: default branch) */\r\n branch?: string;\r\n /** Shallow clone depth (default: 1) */\r\n depth?: number;\r\n /** Keep cloned repo after scan (default: false for remote, true for local) */\r\n keepClone?: boolean;\r\n}\r\n\r\ninterface ResolvedTarget {\r\n type: 'local' | 'git';\r\n path: string;\r\n url?: string;\r\n repoName: string;\r\n}\r\n\r\n/**\r\n * Clone (if needed) and scan a project.\r\n */\r\nexport async function cloneAndScan(options: CloneOptions): Promise<ScanResult & { clonedPath?: string }> {\r\n const { target, cloneDir, branch, depth = 1, keepClone, onProgress, ...scanOpts } = options;\r\n\r\n const resolved = resolveTarget(target);\r\n\r\n let projectDir: string;\r\n\r\n if (resolved.type === 'local') {\r\n // Local path — scan directly\r\n projectDir = resolved.path;\r\n onProgress?.('clone', 100, `Using local directory: ${projectDir}`);\r\n } else {\r\n // Git URL — clone first\r\n const tempBase = cloneDir || path.join(os.tmpdir(), 'opencroc-scan');\r\n fs.mkdirSync(tempBase, { recursive: true });\r\n projectDir = path.join(tempBase, resolved.repoName);\r\n\r\n // Clean previous clone\r\n if (fs.existsSync(projectDir)) {\r\n fs.rmSync(projectDir, { recursive: true, force: true });\r\n }\r\n\r\n onProgress?.('clone', 10, `Cloning ${resolved.url}...`);\r\n\r\n const branchArg = branch ? `--branch ${branch}` : '';\r\n const depthArg = depth > 0 ? `--depth ${depth}` : '';\r\n const cmd = `git clone ${branchArg} ${depthArg} --single-branch ${resolved.url} \"${projectDir}\"`;\r\n\r\n try {\r\n execSync(cmd, {\r\n stdio: 'pipe',\r\n timeout: 120_000, // 2 minutes max\r\n });\r\n } catch (err) {\r\n throw new Error(`Failed to clone repository: ${(err as Error).message}`);\r\n }\r\n\r\n onProgress?.('clone', 100, `Cloned to ${projectDir}`);\r\n }\r\n\r\n // Scan the project\r\n const scanResult = await scanProject({\r\n rootDir: projectDir,\r\n ...scanOpts,\r\n onProgress,\r\n });\r\n\r\n // Cleanup if remote and not keeping\r\n if (resolved.type === 'git' && !keepClone) {\r\n try {\r\n fs.rmSync(projectDir, { recursive: true, force: true });\r\n } catch {\r\n // Best effort cleanup\r\n }\r\n }\r\n\r\n return {\r\n ...scanResult,\r\n clonedPath: resolved.type === 'git' ? projectDir : undefined,\r\n };\r\n}\r\n\r\n/**\r\n * Resolve a target string into a local path or git URL.\r\n */\r\nfunction resolveTarget(target: string): ResolvedTarget {\r\n // Local path — resolve first so relative paths work correctly\r\n const resolved = path.resolve(target);\r\n if (fs.existsSync(resolved)) {\r\n return {\r\n type: 'local',\r\n path: resolved,\r\n repoName: path.basename(resolved),\r\n };\r\n }\r\n\r\n // Full git URL (https://github.com/user/repo, git@github.com:user/repo.git)\r\n if (target.startsWith('https://') || target.startsWith('http://') || target.startsWith('git@')) {\r\n let url = target;\r\n // Ensure .git suffix\r\n if (!url.endsWith('.git')) url += '.git';\r\n const repoName = path.basename(url, '.git');\r\n return { type: 'git', path: '', url, repoName };\r\n }\r\n\r\n // Shorthand: user/repo → https://github.com/user/repo.git\r\n if (/^[\\w.-]+\\/[\\w.-]+$/.test(target)) {\r\n const url = `https://github.com/${target}.git`;\r\n const repoName = target.split('/')[1]!;\r\n return { type: 'git', path: '', url, repoName };\r\n }\r\n\r\n throw new Error(\r\n `Cannot resolve target \"${target}\". Expected: local path, GitHub URL, or shorthand (user/repo).`\r\n );\r\n}\r\n","/**\r\n * Knowledge Graph Builder\r\n *\r\n * Transforms raw ScanResult entities and relationships into a\r\n * fully connected KnowledgeGraph with deduplication, wildcard\r\n * resolution, module grouping, and statistics.\r\n */\r\n\r\nimport type {\r\n KnowledgeGraph,\r\n GraphNode,\r\n GraphEdge,\r\n ProjectMetadata,\r\n ProjectStats,\r\n ScanResult,\r\n ExtractedEntity,\r\n} from './types.js';\r\n\r\nexport interface GraphBuildOptions {\r\n /** Project name (from package.json or dir name) */\r\n projectName: string;\r\n /** Source type */\r\n source: 'local' | 'github' | 'gitlab' | 'url';\r\n sourceUrl?: string;\r\n /** Project root path */\r\n rootPath: string;\r\n}\r\n\r\n/**\r\n * Build a KnowledgeGraph from scan results.\r\n */\r\nexport function buildKnowledgeGraph(scanResult: ScanResult, options: GraphBuildOptions): KnowledgeGraph {\r\n const startTime = Date.now();\r\n\r\n // Deduplicate entities by ID\r\n const entityMap = new Map<string, ExtractedEntity>();\r\n for (const entity of scanResult.entities) {\r\n if (!entityMap.has(entity.id)) {\r\n entityMap.set(entity.id, entity);\r\n }\r\n }\r\n\r\n // Convert entities to graph nodes\r\n const nodes: GraphNode[] = [];\r\n for (const entity of entityMap.values()) {\r\n nodes.push({\r\n id: entity.id,\r\n label: entity.name,\r\n type: entity.type,\r\n filePath: entity.filePath || undefined,\r\n line: entity.line,\r\n module: inferModule(entity),\r\n language: entity.language,\r\n metadata: entity.metadata,\r\n status: 'idle',\r\n });\r\n }\r\n\r\n // Resolve wildcard references and build edges\r\n const edges: GraphEdge[] = [];\r\n const edgeSet = new Set<string>();\r\n\r\n for (const rel of scanResult.relationships) {\r\n let targetId = rel.targetId;\r\n\r\n // Resolve wildcard references (e.g., class:*:ClassName)\r\n if (targetId.includes(':*:')) {\r\n const suffix = targetId.split(':*:')[1]!;\r\n const resolved = findMatchingEntity(entityMap, targetId.split(':')[0]!, suffix);\r\n if (resolved) {\r\n targetId = resolved;\r\n } else {\r\n continue; // Can't resolve — skip\r\n }\r\n }\r\n\r\n // Skip self-references\r\n if (rel.sourceId === targetId) continue;\r\n\r\n // Skip if either node doesn't exist\r\n if (!entityMap.has(rel.sourceId) && !entityMap.has(targetId)) continue;\r\n\r\n // Deduplicate edges\r\n const edgeKey = `${rel.sourceId}->${targetId}:${rel.relation}`;\r\n if (edgeSet.has(edgeKey)) continue;\r\n edgeSet.add(edgeKey);\r\n\r\n edges.push({\r\n id: `edge-${edges.length}`,\r\n source: rel.sourceId,\r\n target: targetId,\r\n relation: rel.relation,\r\n metadata: rel.metadata,\r\n });\r\n }\r\n\r\n // Build project metadata\r\n const projectInfo = buildProjectMetadata(scanResult, options, nodes);\r\n\r\n return {\r\n nodes,\r\n edges,\r\n projectInfo,\r\n builtAt: new Date().toISOString(),\r\n buildDuration: Date.now() - startTime,\r\n };\r\n}\r\n\r\n/**\r\n * Query the knowledge graph for nodes matching criteria.\r\n */\r\nexport function queryNodes(graph: KnowledgeGraph, filter: Partial<Pick<GraphNode, 'type' | 'language' | 'module'>>): GraphNode[] {\r\n return graph.nodes.filter(n => {\r\n if (filter.type && n.type !== filter.type) return false;\r\n if (filter.language && n.language !== filter.language) return false;\r\n if (filter.module && n.module !== filter.module) return false;\r\n return true;\r\n });\r\n}\r\n\r\n/**\r\n * Get all neighbors of a node (incoming + outgoing).\r\n */\r\nexport function getNeighbors(graph: KnowledgeGraph, nodeId: string): { incoming: GraphEdge[]; outgoing: GraphEdge[] } {\r\n return {\r\n incoming: graph.edges.filter(e => e.target === nodeId),\r\n outgoing: graph.edges.filter(e => e.source === nodeId),\r\n };\r\n}\r\n\r\n/**\r\n * BFS traversal from a node, returning all reachable nodes within maxDepth.\r\n */\r\nexport function bfsTraversal(graph: KnowledgeGraph, startNodeId: string, maxDepth = 3): string[] {\r\n const visited = new Set<string>();\r\n const queue: Array<{ id: string; depth: number }> = [{ id: startNodeId, depth: 0 }];\r\n visited.add(startNodeId);\r\n\r\n // Build adjacency list\r\n const adjacency = new Map<string, string[]>();\r\n for (const edge of graph.edges) {\r\n if (!adjacency.has(edge.source)) adjacency.set(edge.source, []);\r\n adjacency.get(edge.source)!.push(edge.target);\r\n // Bidirectional for impact analysis\r\n if (!adjacency.has(edge.target)) adjacency.set(edge.target, []);\r\n adjacency.get(edge.target)!.push(edge.source);\r\n }\r\n\r\n while (queue.length > 0) {\r\n const current = queue.shift()!;\r\n if (current.depth >= maxDepth) continue;\r\n\r\n const neighbors = adjacency.get(current.id) || [];\r\n for (const neighbor of neighbors) {\r\n if (!visited.has(neighbor)) {\r\n visited.add(neighbor);\r\n queue.push({ id: neighbor, depth: current.depth + 1 });\r\n }\r\n }\r\n }\r\n\r\n visited.delete(startNodeId);\r\n return [...visited];\r\n}\r\n\r\n/**\r\n * Find all paths between two nodes (up to maxPaths).\r\n */\r\nexport function findPaths(\r\n graph: KnowledgeGraph,\r\n fromId: string,\r\n toId: string,\r\n maxPaths = 5,\r\n maxDepth = 6,\r\n): string[][] {\r\n const paths: string[][] = [];\r\n\r\n // Build directed adjacency\r\n const adjacency = new Map<string, string[]>();\r\n for (const edge of graph.edges) {\r\n if (!adjacency.has(edge.source)) adjacency.set(edge.source, []);\r\n adjacency.get(edge.source)!.push(edge.target);\r\n }\r\n\r\n function dfs(current: string, target: string, path: string[], visited: Set<string>): void {\r\n if (paths.length >= maxPaths) return;\r\n if (path.length > maxDepth) return;\r\n\r\n if (current === target) {\r\n paths.push([...path]);\r\n return;\r\n }\r\n\r\n const neighbors = adjacency.get(current) || [];\r\n for (const neighbor of neighbors) {\r\n if (!visited.has(neighbor)) {\r\n visited.add(neighbor);\r\n path.push(neighbor);\r\n dfs(neighbor, target, path, visited);\r\n path.pop();\r\n visited.delete(neighbor);\r\n }\r\n }\r\n }\r\n\r\n const visited = new Set([fromId]);\r\n dfs(fromId, toId, [fromId], visited);\r\n return paths;\r\n}\r\n\r\n/**\r\n * Generate a Mermaid diagram from the knowledge graph.\r\n */\r\nexport function toMermaid(graph: KnowledgeGraph, options?: { maxNodes?: number; nodeTypes?: string[] }): string {\r\n const maxNodes = options?.maxNodes || 50;\r\n const nodeTypes = options?.nodeTypes;\r\n\r\n let filteredNodes = graph.nodes;\r\n if (nodeTypes) {\r\n filteredNodes = filteredNodes.filter(n => nodeTypes.includes(n.type));\r\n }\r\n filteredNodes = filteredNodes.slice(0, maxNodes);\r\n\r\n const nodeIds = new Set(filteredNodes.map(n => n.id));\r\n const filteredEdges = graph.edges.filter(e => nodeIds.has(e.source) && nodeIds.has(e.target));\r\n\r\n const lines: string[] = ['graph TD'];\r\n\r\n // Style definitions\r\n lines.push(' classDef model fill:#4ecca3,color:#000,stroke:#2d9970');\r\n lines.push(' classDef api fill:#e94560,color:#fff,stroke:#c23049');\r\n lines.push(' classDef service fill:#3498db,color:#fff,stroke:#2378b8');\r\n lines.push(' classDef module fill:#f39c12,color:#000,stroke:#c27d0e');\r\n lines.push(' classDef component fill:#9b59b6,color:#fff,stroke:#7d3c98');\r\n lines.push(' classDef file fill:#555,color:#fff,stroke:#333');\r\n\r\n // Nodes\r\n for (const node of filteredNodes) {\r\n const safeId = sanitizeMermaidId(node.id);\r\n const safeLabel = node.label.replace(/\"/g, \"'\");\r\n lines.push(` ${safeId}[\"${safeLabel}\"]:::${node.type}`);\r\n }\r\n\r\n // Edges\r\n for (const edge of filteredEdges) {\r\n const safeSource = sanitizeMermaidId(edge.source);\r\n const safeTarget = sanitizeMermaidId(edge.target);\r\n const label = edge.relation;\r\n lines.push(` ${safeSource} -->|${label}| ${safeTarget}`);\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\n/**\r\n * Get graph statistics summary.\r\n */\r\nexport function getGraphStats(graph: KnowledgeGraph): Record<string, number> {\r\n const stats: Record<string, number> = {\r\n totalNodes: graph.nodes.length,\r\n totalEdges: graph.edges.length,\r\n };\r\n\r\n // Count by node type\r\n for (const node of graph.nodes) {\r\n const key = `${node.type}Count`;\r\n stats[key] = (stats[key] || 0) + 1;\r\n }\r\n\r\n // Count by edge relation\r\n for (const edge of graph.edges) {\r\n const key = `${edge.relation}Count`;\r\n stats[key] = (stats[key] || 0) + 1;\r\n }\r\n\r\n return stats;\r\n}\r\n\r\n// ===== Helpers =====\r\n\r\nfunction inferModule(entity: ExtractedEntity): string | undefined {\r\n if (!entity.filePath) return undefined;\r\n const parts = entity.filePath.split('/');\r\n if (parts.length > 1) {\r\n // Use first meaningful directory as module\r\n const dir = parts[0]!;\r\n if (dir === 'src' && parts.length > 2) return parts[1];\r\n return dir;\r\n }\r\n return undefined;\r\n}\r\n\r\nfunction findMatchingEntity(entityMap: Map<string, ExtractedEntity>, typePrefix: string, nameSuffix: string): string | null {\r\n for (const [id, entity] of entityMap) {\r\n if (id.startsWith(`${typePrefix}:`) && entity.name === nameSuffix) {\r\n return id;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction buildProjectMetadata(scanResult: ScanResult, options: GraphBuildOptions, nodes: GraphNode[]): ProjectMetadata {\r\n const stats: ProjectStats = {\r\n totalFiles: scanResult.files.length,\r\n totalLines: scanResult.files.reduce((sum, f) => sum + f.lines, 0),\r\n modules: nodes.filter(n => n.type === 'module').length,\r\n classes: nodes.filter(n => n.type === 'class').length,\r\n functions: nodes.filter(n => n.type === 'function').length,\r\n apiEndpoints: nodes.filter(n => n.type === 'api').length,\r\n dataModels: nodes.filter(n => n.type === 'model').length,\r\n dependencies: nodes.filter(n => n.type === 'dependency').length,\r\n linesByLanguage: scanResult.languages,\r\n };\r\n\r\n return {\r\n name: options.projectName,\r\n source: options.source,\r\n sourceUrl: options.sourceUrl,\r\n rootPath: options.rootPath,\r\n languages: scanResult.languages,\r\n frameworks: scanResult.frameworks.map(f => f.name),\r\n packageManager: undefined,\r\n projectType: 'unknown',\r\n stats,\r\n };\r\n}\r\n\r\nfunction sanitizeMermaidId(id: string): string {\r\n return id.replace(/[^a-zA-Z0-9_]/g, '_');\r\n}\r\n","/**\r\n * AI Insight Engine\r\n *\r\n * Multi-perspective analysis powered by LLM. Generates:\r\n * - Risk reports (security, performance, data integrity, logic)\r\n * - Impact analysis (change blast radius)\r\n * - Multi-role reports (developer, architect, tester, product, student, executive)\r\n * - Digital twin simulation (AI-predicted test outcomes)\r\n */\r\n\r\nimport type {\r\n KnowledgeGraph,\r\n RiskAnnotation,\r\n RiskCategory,\r\n RiskSeverity,\r\n ImpactAnalysis,\r\n PerspectiveReport,\r\n ReportPerspective,\r\n ReportSection,\r\n SimulationScenario,\r\n SimulationResult,\r\n} from '../graph/types.js';\r\nimport { bfsTraversal, getNeighbors, toMermaid } from '../graph/index.js';\r\nimport type { LlmProvider } from '../types.js';\r\n\r\nexport interface InsightOptions {\r\n /** LLM provider for AI-enhanced analysis */\r\n llm?: LlmProvider;\r\n /** Enable LLM-based analysis (requires llm provider) */\r\n useLlm?: boolean;\r\n /** Progress callback */\r\n onProgress?: (phase: string, percent: number, detail?: string) => void;\r\n}\r\n\r\n// ===================================================================\r\n// Risk Analysis\r\n// ===================================================================\r\n\r\n/**\r\n * Analyze a knowledge graph for risks across all categories.\r\n * Combines rule-based static analysis with optional LLM enhancement.\r\n */\r\nexport async function analyzeRisks(\r\n graph: KnowledgeGraph,\r\n options?: InsightOptions,\r\n): Promise<RiskAnnotation[]> {\r\n const risks: RiskAnnotation[] = [];\r\n let riskCounter = 0;\r\n\r\n options?.onProgress?.('risk-analysis', 0, 'Starting risk analysis...');\r\n\r\n // --- Rule-based risk detection ---\r\n\r\n // 1. Security: Unprotected API endpoints\r\n const apis = graph.nodes.filter(n => n.type === 'api');\r\n const middlewares = graph.nodes.filter(n => n.type === 'middleware');\r\n const hasAuthMiddleware = middlewares.some(m =>\r\n m.label.toLowerCase().includes('auth') || m.label.toLowerCase().includes('jwt') || m.label.toLowerCase().includes('session')\r\n );\r\n\r\n for (const api of apis) {\r\n const incoming = graph.edges.filter(e => e.target === api.id);\r\n const hasAuth = incoming.some(e => {\r\n const sourceNode = graph.nodes.find(n => n.id === e.source);\r\n return sourceNode?.type === 'middleware' &&\r\n (sourceNode.label.toLowerCase().includes('auth') || e.relation === 'middleware-of');\r\n });\r\n\r\n if (!hasAuth && !hasAuthMiddleware) {\r\n const apiPath = (api.metadata.path as string) || api.label;\r\n const isSensitive = /user|admin|password|token|secret|key|delete|payment/i.test(apiPath);\r\n if (isSensitive) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'security',\r\n severity: 'high',\r\n title: `Potentially unprotected sensitive endpoint: ${api.label}`,\r\n description: `The endpoint ${api.label} appears to handle sensitive data but no authentication middleware was detected in the graph.`,\r\n affectedNodes: [api.id],\r\n suggestion: 'Add authentication middleware to protect this endpoint.',\r\n confidence: 0.6,\r\n });\r\n }\r\n }\r\n }\r\n\r\n options?.onProgress?.('risk-analysis', 20, 'Checking data integrity...');\r\n\r\n // 2. Data Integrity: Models without validation\r\n const models = graph.nodes.filter(n => n.type === 'model');\r\n for (const model of models) {\r\n const writeEdges = graph.edges.filter(e => e.target === model.id && e.relation === 'writes');\r\n if (writeEdges.length > 3) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'data-integrity',\r\n severity: 'medium',\r\n title: `High write fan-in on model: ${model.label}`,\r\n description: `Model \"${model.label}\" is written to by ${writeEdges.length} different endpoints. This increases risk of data conflicts and race conditions.`,\r\n affectedNodes: [model.id, ...writeEdges.map(e => e.source)],\r\n suggestion: 'Consider adding transaction boundaries or an optimistic locking strategy.',\r\n confidence: 0.7,\r\n });\r\n }\r\n }\r\n\r\n // 3. Data Integrity: Cascade delete risk\r\n const foreignKeyEdges = graph.edges.filter(e => e.relation === 'foreign-key' || e.relation === 'cascade-delete');\r\n for (const fk of foreignKeyEdges) {\r\n const sourceNode = graph.nodes.find(n => n.id === fk.source);\r\n const targetNode = graph.nodes.find(n => n.id === fk.target);\r\n if (sourceNode && targetNode) {\r\n // Check how many other tables reference the target\r\n const dependents = graph.edges.filter(e =>\r\n (e.relation === 'foreign-key' || e.relation === 'cascade-delete') && e.target === fk.target\r\n );\r\n if (dependents.length >= 3) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'data-integrity',\r\n severity: 'high',\r\n title: `Cascade risk: ${targetNode.label} has ${dependents.length} dependent tables`,\r\n description: `Deleting records from \"${targetNode.label}\" could cascade to ${dependents.length} other tables.`,\r\n affectedNodes: [fk.target, ...dependents.map(d => d.source)],\r\n suggestion: 'Implement soft deletes or add cascade protection.',\r\n confidence: 0.85,\r\n });\r\n }\r\n }\r\n }\r\n\r\n options?.onProgress?.('risk-analysis', 40, 'Checking performance...');\r\n\r\n // 4. Performance: Large modules (God-module smell)\r\n const moduleNodes = graph.nodes.filter(n => n.type === 'module');\r\n for (const mod of moduleNodes) {\r\n const children = graph.edges.filter(e => e.target === mod.id && e.relation === 'belongs-to');\r\n if (children.length > 50) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'maintainability',\r\n severity: 'medium',\r\n title: `Large module: ${mod.label} (${children.length} entities)`,\r\n description: `Module \"${mod.label}\" contains ${children.length} entities. Consider splitting for better maintainability.`,\r\n affectedNodes: [mod.id],\r\n suggestion: 'Split into smaller, focused sub-modules.',\r\n confidence: 0.75,\r\n });\r\n }\r\n }\r\n\r\n // 5. Reliability: Circular dependencies\r\n const cycles = detectCycles(graph);\r\n for (const cycle of cycles) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'logic',\r\n severity: 'high',\r\n title: `Circular dependency detected: ${cycle.map(id => graph.nodes.find(n => n.id === id)?.label || id).join(' → ')}`,\r\n description: `A circular dependency was found involving ${cycle.length} entities. This can cause initialization issues and makes testing harder.`,\r\n affectedNodes: cycle,\r\n suggestion: 'Break the cycle by introducing an interface or Event-based decoupling.',\r\n confidence: 0.9,\r\n });\r\n }\r\n\r\n options?.onProgress?.('risk-analysis', 60, 'Checking maintainability...');\r\n\r\n // 6. Maintainability: High coupling\r\n for (const node of graph.nodes) {\r\n if (node.type === 'file' || node.type === 'dependency') continue;\r\n const outgoing = graph.edges.filter(e => e.source === node.id);\r\n const incoming = graph.edges.filter(e => e.target === node.id);\r\n const coupling = outgoing.length + incoming.length;\r\n if (coupling > 15) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'maintainability',\r\n severity: 'medium',\r\n title: `High coupling: ${node.label} (${coupling} connections)`,\r\n description: `\"${node.label}\" has ${coupling} connections (${outgoing.length} outgoing, ${incoming.length} incoming). Changes here will have wide impact.`,\r\n affectedNodes: [node.id],\r\n suggestion: 'Consider extracting shared logic or adding an abstraction layer.',\r\n confidence: 0.7,\r\n });\r\n }\r\n }\r\n\r\n // 7. Security: Potential injection points (APIs with dynamic path params)\r\n for (const api of apis) {\r\n const apiPath = (api.metadata.path as string) || api.label;\r\n if (apiPath.includes(':') || apiPath.includes('{')) {\r\n const method = (api.metadata.method as string) || '';\r\n if (['DELETE', 'PUT', 'PATCH'].includes(method)) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'security',\r\n severity: 'low',\r\n title: `Verify input validation: ${api.label}`,\r\n description: `Endpoint ${api.label} accepts path parameters. Ensure proper input validation and authorization checks.`,\r\n affectedNodes: [api.id],\r\n suggestion: 'Add input validation middleware and verify the user has permission to modify the specified resource.',\r\n confidence: 0.5,\r\n });\r\n }\r\n }\r\n }\r\n\r\n options?.onProgress?.('risk-analysis', 80, `Found ${risks.length} risks`);\r\n\r\n // --- LLM-enhanced risk detection (optional) ---\r\n if (options?.useLlm && options.llm) {\r\n try {\r\n const llmRisks = await getLlmRisks(graph, risks, options.llm);\r\n risks.push(...llmRisks);\r\n } catch {\r\n // LLM enhancement failed — rule-based results are still valid\r\n }\r\n }\r\n\r\n // Sort by severity\r\n const severityOrder: Record<RiskSeverity, number> = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };\r\n risks.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);\r\n\r\n options?.onProgress?.('risk-analysis', 100, `Analysis complete: ${risks.length} risks found`);\r\n\r\n return risks;\r\n}\r\n\r\n// ===================================================================\r\n// Impact Analysis\r\n// ===================================================================\r\n\r\n/**\r\n * Analyze the impact of changing a specific node.\r\n */\r\nexport function analyzeImpact(graph: KnowledgeGraph, nodeId: string): ImpactAnalysis {\r\n const node = graph.nodes.find(n => n.id === nodeId);\r\n if (!node) {\r\n return {\r\n sourceNode: nodeId,\r\n directImpact: [],\r\n transitiveImpact: [],\r\n riskLevel: 'low',\r\n summary: `Node \"${nodeId}\" not found in the graph.`,\r\n mermaidText: '',\r\n };\r\n }\r\n\r\n // Direct neighbors\r\n const { incoming, outgoing } = getNeighbors(graph, nodeId);\r\n const directNodes = new Set([\r\n ...incoming.map(e => e.source),\r\n ...outgoing.map(e => e.target),\r\n ]);\r\n directNodes.delete(nodeId);\r\n\r\n // Transitive impact (BFS depth 3)\r\n const transitiveNodes = bfsTraversal(graph, nodeId, 3);\r\n\r\n // Calculate risk level\r\n const totalImpact = transitiveNodes.length;\r\n let riskLevel: RiskSeverity;\r\n if (totalImpact > 20) riskLevel = 'critical';\r\n else if (totalImpact > 10) riskLevel = 'high';\r\n else if (totalImpact > 5) riskLevel = 'medium';\r\n else riskLevel = 'low';\r\n\r\n // Generate summary\r\n const summary = `Changing \"${node.label}\" directly affects ${directNodes.size} entities and transitively impacts ${transitiveNodes.length} entities (risk: ${riskLevel}).`;\r\n\r\n // Generate Mermaid diagram\r\n const impactNodeIds = new Set([nodeId, ...directNodes, ...transitiveNodes.slice(0, 20)]);\r\n const impactNodes = graph.nodes.filter(n => impactNodeIds.has(n.id));\r\n const impactEdges = graph.edges.filter(e => impactNodeIds.has(e.source) && impactNodeIds.has(e.target));\r\n\r\n let mermaidText = 'graph TD\\n';\r\n mermaidText += ` style ${sanitizeId(nodeId)} fill:#e94560,color:#fff\\n`;\r\n for (const dn of directNodes) {\r\n mermaidText += ` style ${sanitizeId(dn)} fill:#f39c12,color:#000\\n`;\r\n }\r\n for (const n of impactNodes) {\r\n mermaidText += ` ${sanitizeId(n.id)}[\"${n.label.replace(/\"/g, \"'\")}\"]\\n`;\r\n }\r\n for (const e of impactEdges) {\r\n mermaidText += ` ${sanitizeId(e.source)} -->|${e.relation}| ${sanitizeId(e.target)}\\n`;\r\n }\r\n\r\n return {\r\n sourceNode: nodeId,\r\n directImpact: [...directNodes],\r\n transitiveImpact: transitiveNodes,\r\n riskLevel,\r\n summary,\r\n mermaidText,\r\n };\r\n}\r\n\r\n// ===================================================================\r\n// Multi-Perspective Reports\r\n// ===================================================================\r\n\r\n/**\r\n * Generate a report from a specific perspective.\r\n */\r\nexport async function generateReport(\r\n graph: KnowledgeGraph,\r\n perspective: ReportPerspective,\r\n risks: RiskAnnotation[],\r\n options?: InsightOptions,\r\n): Promise<PerspectiveReport> {\r\n // If LLM available, use it for rich narrative\r\n if (options?.useLlm && options.llm) {\r\n return generateLlmReport(graph, perspective, risks, options.llm);\r\n }\r\n\r\n // Fallback: rule-based report generation\r\n switch (perspective) {\r\n case 'developer':\r\n return buildDeveloperReport(graph, risks);\r\n case 'architect':\r\n return buildArchitectReport(graph, risks);\r\n case 'tester':\r\n return buildTesterReport(graph, risks);\r\n case 'product':\r\n return buildProductReport(graph, risks);\r\n case 'student':\r\n return buildStudentReport(graph, risks);\r\n case 'executive':\r\n return buildExecutiveReport(graph, risks);\r\n default:\r\n return buildDeveloperReport(graph, risks);\r\n }\r\n}\r\n\r\nfunction buildDeveloperReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const { projectInfo } = graph;\r\n const stats = projectInfo.stats;\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'Project Overview',\r\n content: `**${projectInfo.name}** is a ${projectInfo.projectType} project using ${projectInfo.frameworks.join(', ') || 'unknown frameworks'}.\\n\\n` +\r\n `- **Files**: ${stats.totalFiles} | **Lines**: ${stats.totalLines.toLocaleString()}\\n` +\r\n `- **Languages**: ${Object.entries(projectInfo.languages).map(([k, v]) => `${k}(${v})`).join(', ')}\\n` +\r\n `- **APIs**: ${stats.apiEndpoints} | **Models**: ${stats.dataModels} | **Functions**: ${stats.functions}`,\r\n },\r\n {\r\n heading: 'Architecture Map',\r\n content: 'Module-level dependency graph:',\r\n visualization: {\r\n type: 'mermaid',\r\n data: toMermaid(graph, { nodeTypes: ['module', 'model', 'api'], maxNodes: 30 }),\r\n },\r\n },\r\n {\r\n heading: 'API Endpoints',\r\n content: graph.nodes\r\n .filter(n => n.type === 'api')\r\n .map(a => `- \\`${a.label}\\` (${a.filePath || 'unknown'})`)\r\n .join('\\n') || 'No API endpoints detected.',\r\n },\r\n {\r\n heading: 'Data Models',\r\n content: graph.nodes\r\n .filter(n => n.type === 'model')\r\n .map(m => `- **${m.label}** (${m.filePath || 'unknown'})`)\r\n .join('\\n') || 'No data models detected.',\r\n },\r\n {\r\n heading: 'Risk Report',\r\n content: risks.length === 0\r\n ? 'No significant risks detected.'\r\n : risks.slice(0, 10).map(r =>\r\n `- **[${r.severity.toUpperCase()}]** ${r.title}\\n ${r.description}`\r\n ).join('\\n\\n'),\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'developer',\r\n title: `Developer Report: ${projectInfo.name}`,\r\n summary: `${projectInfo.name} — ${stats.apiEndpoints} APIs, ${stats.dataModels} models, ${risks.length} risks detected.`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction buildArchitectReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const { projectInfo } = graph;\r\n const modules = graph.nodes.filter(n => n.type === 'module');\r\n const criticalRisks = risks.filter(r => r.severity === 'critical' || r.severity === 'high');\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'System Architecture',\r\n content: `**Type**: ${projectInfo.projectType}\\n**Frameworks**: ${projectInfo.frameworks.join(', ')}\\n**Modules**: ${modules.length}\\n\\n` +\r\n `The system is organized into ${modules.length} modules with ${graph.edges.length} relationships.`,\r\n visualization: {\r\n type: 'mermaid',\r\n data: toMermaid(graph, { nodeTypes: ['module'], maxNodes: 20 }),\r\n },\r\n },\r\n {\r\n heading: 'Module Coupling Analysis',\r\n content: modules.map(m => {\r\n const edges = graph.edges.filter(e => e.source === m.id || e.target === m.id);\r\n return `- **${m.label}**: ${edges.length} connections`;\r\n }).join('\\n'),\r\n },\r\n {\r\n heading: 'Technical Debt & Risk',\r\n content: criticalRisks.length === 0\r\n ? 'No critical or high-severity risks.'\r\n : criticalRisks.map(r => `- **[${r.severity}]** ${r.title}\\n _Suggestion_: ${r.suggestion || 'N/A'}`).join('\\n\\n'),\r\n },\r\n {\r\n heading: 'Recommendations',\r\n content: generateArchitectRecommendations(graph, risks),\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'architect',\r\n title: `Architecture Report: ${projectInfo.name}`,\r\n summary: `${modules.length} modules, ${graph.edges.length} relationships, ${criticalRisks.length} critical/high risks.`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction buildTesterReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const apis = graph.nodes.filter(n => n.type === 'api');\r\n const tests = graph.nodes.filter(n => n.type === 'test');\r\n const riskyApis = risks.filter(r => r.category === 'security' || r.category === 'data-integrity');\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'Test Coverage Overview',\r\n content: `- **API Endpoints**: ${apis.length}\\n- **Test Files Found**: ${tests.length}\\n- **Estimated Coverage**: ${tests.length > 0 ? Math.min(Math.round(tests.length / Math.max(apis.length, 1) * 100), 100) : 0}%`,\r\n },\r\n {\r\n heading: 'Priority Test Targets',\r\n content: 'Endpoints with highest risk that need testing first:\\n\\n' +\r\n riskyApis.slice(0, 10).map((r, i) => `${i + 1}. **${r.title}** (${r.severity})\\n ${r.description}`).join('\\n\\n'),\r\n },\r\n {\r\n heading: 'Edge Cases to Consider',\r\n content: apis.slice(0, 10).map(api => {\r\n const method = (api.metadata.method as string) || 'ANY';\r\n const suggestions: string[] = [];\r\n if (method === 'POST' || method === 'PUT') suggestions.push('Empty body', 'Invalid types', 'Missing required fields', 'Extremely long strings');\r\n if (method === 'DELETE') suggestions.push('Non-existent ID', 'Already deleted', 'ID with dependencies');\r\n if (method === 'GET') suggestions.push('Invalid query params', 'Large pagination', 'Non-existent ID');\r\n return `- **${api.label}**: ${suggestions.join(', ')}`;\r\n }).join('\\n'),\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'tester',\r\n title: `Testing Report: ${graph.projectInfo.name}`,\r\n summary: `${apis.length} endpoints to test, ${riskyApis.length} high-risk areas identified.`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction buildProductReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const { projectInfo } = graph;\r\n const modules = graph.nodes.filter(n => n.type === 'module');\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'What Does This System Do?',\r\n content: `This is a **${projectInfo.projectType}** system built with ${projectInfo.frameworks.join(', ')}. ` +\r\n `It contains ${modules.length} functional modules and ${projectInfo.stats.apiEndpoints} service interfaces.`,\r\n },\r\n {\r\n heading: 'Feature Map',\r\n content: modules.map(m => {\r\n const children = graph.edges.filter(e => e.target === m.id).length;\r\n return `- **${m.label}** — ${children} components`;\r\n }).join('\\n'),\r\n },\r\n {\r\n heading: 'Health Status',\r\n content: (() => {\r\n const critical = risks.filter(r => r.severity === 'critical').length;\r\n const high = risks.filter(r => r.severity === 'high').length;\r\n if (critical > 0) return `⚠️ **Needs Attention**: ${critical} critical issues found that could affect users.`;\r\n if (high > 3) return `⚡ **Minor Concerns**: ${high} areas that should be improved.`;\r\n return '✅ **Healthy**: No critical issues detected. System is in good shape.';\r\n })(),\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'product',\r\n title: `Product Overview: ${projectInfo.name}`,\r\n summary: `${modules.length} feature modules, ${risks.filter(r => r.severity === 'critical').length} critical issues.`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction buildStudentReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const { projectInfo } = graph;\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'What is this project?',\r\n content: `This is a **${projectInfo.projectType}** project. Let\\'s break it down step by step!\\n\\n` +\r\n `**Languages used**: ${Object.keys(projectInfo.languages).join(', ')}\\n` +\r\n `**Frameworks**: ${projectInfo.frameworks.join(', ') || 'None detected'}\\n\\n` +\r\n `Think of this project like a building:\\n` +\r\n `- The **frameworks** are the building\\'s foundation\\n` +\r\n `- The **modules** are different rooms\\n` +\r\n `- The **APIs** are the doors and windows (interfaces to the outside world)\\n` +\r\n `- The **models** are the furniture and storage (data structures)`,\r\n },\r\n {\r\n heading: 'How is it organized?',\r\n content: `The project has **${projectInfo.stats.modules}** modules (think: folders of related code).\\n\\n` +\r\n `Each module typically contains:\\n` +\r\n `1. **Controllers/Routes** — Handle incoming requests (like a receptionist)\\n` +\r\n `2. **Services** — Business logic (like the workers)\\n` +\r\n `3. **Models** — Data structures (like forms and documents)\\n\\n` +\r\n 'Here\\'s a simplified view:',\r\n visualization: {\r\n type: 'mermaid',\r\n data: toMermaid(graph, { nodeTypes: ['module', 'model'], maxNodes: 15 }),\r\n },\r\n },\r\n {\r\n heading: 'Key Concepts to Learn',\r\n content: `Based on this project, you should study:\\n\\n` +\r\n (projectInfo.frameworks.includes('Express') ? '- **Express.js** — Node.js web framework for building APIs\\n' : '') +\r\n (projectInfo.frameworks.includes('React') ? '- **React** — Frontend UI library for building user interfaces\\n' : '') +\r\n (projectInfo.frameworks.includes('Sequelize') ? '- **Sequelize** — ORM for database operations\\n' : '') +\r\n `- **REST APIs** — How the frontend talks to the backend\\n` +\r\n `- **MVC Pattern** — Model-View-Controller architecture\\n` +\r\n `- **Authentication** — How users log in and stay logged in`,\r\n },\r\n {\r\n heading: 'Things to Watch Out For',\r\n content: risks.length > 0\r\n ? `Here are ${Math.min(risks.length, 5)} interesting issues found:\\n\\n` +\r\n risks.slice(0, 5).map((r, i) => `${i + 1}. **${r.title}**\\n _Why it matters_: ${r.description}\\n _How to fix_: ${r.suggestion || 'Research this topic!'}`).join('\\n\\n')\r\n : 'This project looks clean! No major issues found.',\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'student',\r\n title: `Learning Guide: ${projectInfo.name}`,\r\n summary: `A ${projectInfo.projectType} project — great for learning ${Object.keys(projectInfo.languages).join(', ')}!`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction buildExecutiveReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const { projectInfo } = graph;\r\n const critical = risks.filter(r => r.severity === 'critical').length;\r\n const high = risks.filter(r => r.severity === 'high').length;\r\n\r\n // Health score: 100 - (critical * 20 + high * 10 + medium * 3)\r\n const medium = risks.filter(r => r.severity === 'medium').length;\r\n const healthScore = Math.max(0, 100 - (critical * 20 + high * 10 + medium * 3));\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'Health Score',\r\n content: `# ${healthScore}/100\\n\\n` +\r\n (healthScore >= 80 ? '✅ System is healthy and well-maintained.' :\r\n healthScore >= 60 ? '⚡ System needs some attention. Address high-priority items.' :\r\n '⚠️ System has significant issues that need immediate attention.'),\r\n },\r\n {\r\n heading: 'Key Metrics',\r\n content: `| Metric | Value |\\n|--------|-------|\\n` +\r\n `| Codebase Size | ${projectInfo.stats.totalLines.toLocaleString()} lines |\\n` +\r\n `| Technologies | ${projectInfo.frameworks.length} frameworks |\\n` +\r\n `| API Surface | ${projectInfo.stats.apiEndpoints} endpoints |\\n` +\r\n `| Data Models | ${projectInfo.stats.dataModels} tables |\\n` +\r\n `| Critical Issues | ${critical} |\\n` +\r\n `| High Issues | ${high} |`,\r\n },\r\n {\r\n heading: 'Top 3 Risks Needing Action',\r\n content: risks.slice(0, 3).map((r, i) =>\r\n `${i + 1}. **${r.title}** (${r.severity})`\r\n ).join('\\n') || 'No significant risks.',\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'executive',\r\n title: `Executive Summary: ${projectInfo.name}`,\r\n summary: `Health: ${healthScore}/100 | ${critical} critical, ${high} high risks | ${projectInfo.stats.apiEndpoints} APIs`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\n// ===================================================================\r\n// Digital Twin Simulation\r\n// ===================================================================\r\n\r\n/**\r\n * Run AI-powered simulation on a scenario (requires LLM).\r\n */\r\nexport async function simulateScenario(\r\n graph: KnowledgeGraph,\r\n scenario: SimulationScenario,\r\n llm: LlmProvider,\r\n): Promise<SimulationResult> {\r\n // Build context from graph\r\n const relatedNodes = scenario.steps\r\n .map(s => s.endpoint)\r\n .filter(Boolean)\r\n .flatMap(endpoint => graph.nodes.filter(n => n.type === 'api' && n.label.includes(endpoint!)))\r\n .map(n => n.id);\r\n\r\n const context = relatedNodes.flatMap(nodeId => {\r\n const neighbors = getNeighbors(graph, nodeId);\r\n return [\r\n ...neighbors.outgoing.map(e => {\r\n const target = graph.nodes.find(n => n.id === e.target);\r\n return `${e.relation}: ${target?.label || e.target}`;\r\n }),\r\n ];\r\n });\r\n\r\n const prompt = `You are an expert software engineer analyzing a system.\r\n\r\nProject: ${graph.projectInfo.name}\r\nFrameworks: ${graph.projectInfo.frameworks.join(', ')}\r\n\r\nScenario: ${scenario.name}\r\nDescription: ${scenario.description}\r\n\r\nSteps:\r\n${scenario.steps.map((s, i) => `${i + 1}. ${s.action} — ${s.endpoint || 'N/A'}`).join('\\n')}\r\n\r\nRelated context from knowledge graph:\r\n${context.join('\\n')}\r\n\r\nPredict:\r\n1. What would happen when executing this scenario?\r\n2. What anomalies or edge cases could occur?\r\n3. Rate the risk (0-100) of this scenario failing in production.\r\n\r\nRespond in JSON: { \"prediction\": \"...\", \"anomalies\": [\"...\"], \"riskScore\": N, \"confidence\": 0.X }`;\r\n\r\n const response = await llm.chat([{ role: 'user', content: prompt }]);\r\n\r\n try {\r\n const parsed = JSON.parse(cleanJsonResponse(response));\r\n return {\r\n scenario,\r\n prediction: parsed.prediction || 'Unable to predict.',\r\n anomalies: parsed.anomalies || [],\r\n riskScore: parsed.riskScore || 50,\r\n confidence: parsed.confidence || 0.5,\r\n };\r\n } catch {\r\n return {\r\n scenario,\r\n prediction: response,\r\n anomalies: [],\r\n riskScore: 50,\r\n confidence: 0.3,\r\n };\r\n }\r\n}\r\n\r\n// ===================================================================\r\n// Helpers\r\n// ===================================================================\r\n\r\nfunction detectCycles(graph: KnowledgeGraph): string[][] {\r\n const cycles: string[][] = [];\r\n const adjacency = new Map<string, string[]>();\r\n\r\n // Build adjacency (only import/depends-on edges for cycle detection)\r\n for (const edge of graph.edges) {\r\n if (edge.relation !== 'imports' && edge.relation !== 'depends-on' && edge.relation !== 'calls') continue;\r\n if (!adjacency.has(edge.source)) adjacency.set(edge.source, []);\r\n adjacency.get(edge.source)!.push(edge.target);\r\n }\r\n\r\n const visited = new Set<string>();\r\n const inStack = new Set<string>();\r\n const path: string[] = [];\r\n\r\n function dfs(node: string): void {\r\n if (cycles.length >= 5) return; // Limit cycle count\r\n visited.add(node);\r\n inStack.add(node);\r\n path.push(node);\r\n\r\n for (const neighbor of adjacency.get(node) || []) {\r\n if (!visited.has(neighbor)) {\r\n dfs(neighbor);\r\n } else if (inStack.has(neighbor)) {\r\n // Found cycle\r\n const cycleStart = path.indexOf(neighbor);\r\n if (cycleStart >= 0) {\r\n cycles.push([...path.slice(cycleStart), neighbor]);\r\n }\r\n }\r\n }\r\n\r\n path.pop();\r\n inStack.delete(node);\r\n }\r\n\r\n for (const node of adjacency.keys()) {\r\n if (!visited.has(node)) {\r\n dfs(node);\r\n }\r\n }\r\n\r\n return cycles;\r\n}\r\n\r\nfunction generateArchitectRecommendations(_graph: KnowledgeGraph, risks: RiskAnnotation[]): string {\r\n const items: string[] = [];\r\n\r\n const securityRisks = risks.filter(r => r.category === 'security');\r\n if (securityRisks.length > 0) {\r\n items.push(`1. **Security Hardening**: Address ${securityRisks.length} security findings before next release.`);\r\n }\r\n\r\n const couplingRisks = risks.filter(r => r.category === 'maintainability');\r\n if (couplingRisks.length > 2) {\r\n items.push(`2. **Reduce Coupling**: ${couplingRisks.length} modules show high coupling. Consider introducing service boundaries.`);\r\n }\r\n\r\n const dataRisks = risks.filter(r => r.category === 'data-integrity');\r\n if (dataRisks.length > 0) {\r\n items.push(`3. **Data Protection**: ${dataRisks.length} data integrity concerns. Add transaction boundaries and cascade protections.`);\r\n }\r\n\r\n if (items.length === 0) {\r\n items.push('Architecture looks solid. Continue monitoring coupling metrics as the system grows.');\r\n }\r\n\r\n return items.join('\\n\\n');\r\n}\r\n\r\nasync function getLlmRisks(graph: KnowledgeGraph, existingRisks: RiskAnnotation[], llm: LlmProvider): Promise<RiskAnnotation[]> {\r\n const prompt = `Analyze this project knowledge graph for additional risks not already identified.\r\n\r\nProject: ${graph.projectInfo.name}\r\nType: ${graph.projectInfo.projectType}\r\nFrameworks: ${graph.projectInfo.frameworks.join(', ')}\r\nStats: ${graph.projectInfo.stats.apiEndpoints} APIs, ${graph.projectInfo.stats.dataModels} models\r\n\r\nAlready identified risks (${existingRisks.length}):\r\n${existingRisks.slice(0, 5).map(r => `- [${r.severity}] ${r.title}`).join('\\n')}\r\n\r\nAPI Endpoints: ${graph.nodes.filter(n => n.type === 'api').slice(0, 20).map(n => n.label).join(', ')}\r\nModels: ${graph.nodes.filter(n => n.type === 'model').slice(0, 20).map(n => n.label).join(', ')}\r\n\r\nReturn up to 3 additional risks in JSON array format:\r\n[{ \"category\": \"security|performance|data-integrity|logic|maintainability|reliability\", \"severity\": \"critical|high|medium|low\", \"title\": \"...\", \"description\": \"...\", \"suggestion\": \"...\" }]`;\r\n\r\n const response = await llm.chat([{ role: 'user', content: prompt }]);\r\n\r\n try {\r\n const parsed = JSON.parse(cleanJsonResponse(response));\r\n if (!Array.isArray(parsed)) return [];\r\n return parsed.slice(0, 3).map((r: Record<string, string>, i: number) => ({\r\n id: `risk-llm-${i}`,\r\n category: (r.category || 'logic') as RiskCategory,\r\n severity: (r.severity || 'medium') as RiskSeverity,\r\n title: r.title || 'LLM-detected risk',\r\n description: r.description || '',\r\n affectedNodes: [],\r\n suggestion: r.suggestion,\r\n confidence: 0.6,\r\n }));\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\nasync function generateLlmReport(\r\n graph: KnowledgeGraph,\r\n perspective: ReportPerspective,\r\n risks: RiskAnnotation[],\r\n llm: LlmProvider,\r\n): Promise<PerspectiveReport> {\r\n const perspectiveDescriptions: Record<ReportPerspective, string> = {\r\n developer: 'a software developer who wants technical details, code patterns, and API documentation',\r\n architect: 'a software architect who cares about modularity, coupling, tech debt, and system design',\r\n tester: 'a QA engineer who wants to know what to test, edge cases, and risk areas',\r\n product: 'a product manager who wants to understand features in business terms, not code',\r\n student: 'a computer science student learning from this codebase, explain concepts step by step',\r\n executive: 'a CTO/VP who wants a one-page health summary with actionable insights',\r\n };\r\n\r\n const prompt = `Generate a project analysis report for ${graph.projectInfo.name} from the perspective of ${perspectiveDescriptions[perspective]}.\r\n\r\nProject Info:\r\n- Type: ${graph.projectInfo.projectType}\r\n- Frameworks: ${graph.projectInfo.frameworks.join(', ')}\r\n- Stats: ${graph.projectInfo.stats.totalFiles} files, ${graph.projectInfo.stats.apiEndpoints} APIs, ${graph.projectInfo.stats.dataModels} models\r\n- Languages: ${Object.entries(graph.projectInfo.languages).map(([k, v]) => `${k}(${v} files)`).join(', ')}\r\n\r\nTop risks:\r\n${risks.slice(0, 5).map(r => `- [${r.severity}] ${r.title}`).join('\\n')}\r\n\r\nGenerate 3-5 report sections with clear headings and content. Use markdown formatting.\r\nRespond in JSON: { \"title\": \"...\", \"summary\": \"...\", \"sections\": [{ \"heading\": \"...\", \"content\": \"...\" }] }`;\r\n\r\n const response = await llm.chat([{ role: 'user', content: prompt }]);\r\n\r\n try {\r\n const parsed = JSON.parse(cleanJsonResponse(response));\r\n return {\r\n perspective,\r\n title: parsed.title || `${perspective} Report`,\r\n summary: parsed.summary || '',\r\n sections: (parsed.sections || []).map((s: Record<string, string>) => ({\r\n heading: s.heading || 'Section',\r\n content: s.content || '',\r\n })),\r\n generatedAt: new Date().toISOString(),\r\n };\r\n } catch {\r\n // Fallback to rule-based\r\n return buildDeveloperReport(graph, risks);\r\n }\r\n}\r\n\r\nfunction cleanJsonResponse(response: string): string {\r\n // Strip markdown code fences if present\r\n let cleaned = response.trim();\r\n if (cleaned.startsWith('```json')) cleaned = cleaned.slice(7);\r\n else if (cleaned.startsWith('```')) cleaned = cleaned.slice(3);\r\n if (cleaned.endsWith('```')) cleaned = cleaned.slice(0, -3);\r\n return cleaned.trim();\r\n}\r\n\r\nfunction sanitizeId(id: string): string {\r\n return id.replace(/[^a-zA-Z0-9_]/g, '_');\r\n}\r\n"],"mappings":"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","names":["fs","path","Project","SyntaxKind","basePath","fullPath","path","path","fs","path","fs","path","Project","SyntaxKind","fs","path","Project","SyntaxKind","Project","SyntaxKind","basePath","producer","path","extractPathParams","Project","backendRoot","fs","path","Project","SyntaxKind","HTTP_METHODS","METHOD_MAP","fs","path","createOpenAIProvider","createOllamaProvider","createLlmProvider","createOpenAIProvider","createOllamaProvider","existsSync","readFileSync","fs","createSequelizeAdapter","fs","path","Project","classNameToTableName","parseControllerDirectory","fs","path","parseControllerDirectory","fs","path","Project","SyntaxKind","Node","parseControllerDirectory","fs","path","createSequelizeAdapter","escapeHtml","path","sleep","writeFileSync","mkdirSync","existsSync","readdirSync","dirname","join","join","existsSync","readdirSync","dirname","mkdirSync","writeFileSync","writeFileSync","mkdirSync","existsSync","join","fs","path","fs","path","fs","path","bfsTraversal","path","visited","detectCycles","bfsTraversal","sanitizeId","path"]}
|