@codeyam/codeyam-cli 0.1.0-staging.1669d45 → 0.1.0-staging.2a88920
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/analyzer-template/.build-info.json +8 -8
- package/analyzer-template/log.txt +3 -3
- package/analyzer-template/package.json +5 -5
- package/analyzer-template/packages/ai/index.ts +15 -2
- package/analyzer-template/packages/ai/src/lib/analyzeScope.ts +87 -51
- package/analyzer-template/packages/ai/src/lib/astScopes/arrayDerivationDetector.ts +199 -0
- package/analyzer-template/packages/ai/src/lib/astScopes/astScopeAnalyzer.ts +98 -9
- package/analyzer-template/packages/ai/src/lib/astScopes/methodSemantics.ts +139 -23
- package/analyzer-template/packages/ai/src/lib/astScopes/patterns/variableDeclarationHandler.ts +6 -126
- package/analyzer-template/packages/ai/src/lib/astScopes/processExpression.ts +555 -28
- package/analyzer-template/packages/ai/src/lib/astScopes/types.ts +88 -7
- package/analyzer-template/packages/ai/src/lib/completionCall.ts +198 -34
- package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +772 -243
- package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.ts +205 -0
- package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.ts +10 -2
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/BatchSchemaProcessor.ts +16 -3
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/ScopeTreeManager.ts +6 -4
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.ts +43 -1
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.ts +122 -15
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.ts +160 -0
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/deduplicateFunctionSchemas.ts +40 -30
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.ts +319 -88
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/fixNullIdsBySchema.ts +129 -0
- package/analyzer-template/packages/ai/src/lib/dataStructureChunking.ts +156 -0
- package/analyzer-template/packages/ai/src/lib/e2eDataTracking.ts +334 -0
- package/analyzer-template/packages/ai/src/lib/extractCriticalDataKeys.ts +120 -0
- package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +642 -7
- package/analyzer-template/packages/ai/src/lib/generateEntityScenarios.ts +35 -6
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlows.ts +383 -6
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionalEffects.ts +1 -1
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionals.ts +1299 -51
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromJsxUsages.ts +239 -0
- package/analyzer-template/packages/ai/src/lib/mergeStatements.ts +90 -96
- package/analyzer-template/packages/ai/src/lib/promptGenerators/gatherAttributesMap.ts +10 -7
- package/analyzer-template/packages/ai/src/lib/promptGenerators/generateChunkPrompt.ts +82 -0
- package/analyzer-template/packages/ai/src/lib/promptGenerators/generateCriticalKeysPrompt.ts +103 -0
- package/analyzer-template/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.ts +23 -6
- package/analyzer-template/packages/ai/src/lib/promptGenerators/simplifyKeysForLLM.ts +391 -0
- package/analyzer-template/packages/ai/src/lib/resolvePathToControllable.ts +179 -45
- package/analyzer-template/packages/ai/src/lib/worker/SerializableDataStructure.ts +26 -4
- package/analyzer-template/packages/ai/src/lib/worker/analyzeScopeWorker.ts +114 -2
- package/analyzer-template/packages/analyze/src/lib/FileAnalyzer.ts +65 -59
- package/analyzer-template/packages/analyze/src/lib/ProjectAnalyzer.ts +113 -26
- package/analyzer-template/packages/analyze/src/lib/analysisContext.ts +44 -4
- package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getAllDeclaredEntityNodes.ts +19 -0
- package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getAllEntityNodes.ts +19 -0
- package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getAllExports.ts +11 -0
- package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getImportsAnalysis.ts +8 -0
- package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getResolvedModule.ts +49 -1
- package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getSourceFilesForAllImports.ts +2 -1
- package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +30 -19
- package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities.ts +14 -4
- package/analyzer-template/packages/analyze/src/lib/files/analyze/dependencyResolver.ts +6 -0
- package/analyzer-template/packages/analyze/src/lib/files/analyze/gatherEntityMap.ts +4 -2
- package/analyzer-template/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.ts +33 -10
- package/analyzer-template/packages/analyze/src/lib/files/analyzeRemixRoute.ts +4 -5
- package/analyzer-template/packages/analyze/src/lib/files/getImportedExports.ts +14 -12
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.ts +189 -76
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +29 -0
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +77 -9
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.ts +118 -10
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +276 -17
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeValidatedDataStructures.ts +56 -11
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/propagateArrayItemSchemas.ts +474 -0
- package/analyzer-template/packages/analyze/src/lib/files/setImportedExports.ts +2 -1
- package/analyzer-template/packages/analyze/src/lib/utils/getFileByPath.ts +19 -0
- package/analyzer-template/packages/aws/package.json +2 -2
- package/analyzer-template/packages/database/src/lib/kysely/db.ts +8 -1
- package/analyzer-template/packages/database/src/lib/kysely/tables/commitsTable.ts +6 -0
- package/analyzer-template/packages/database/src/lib/loadAnalyses.ts +58 -1
- package/analyzer-template/packages/database/src/lib/loadAnalysis.ts +13 -0
- package/analyzer-template/packages/database/src/lib/loadBranch.ts +16 -1
- package/analyzer-template/packages/database/src/lib/loadCommit.ts +11 -0
- package/analyzer-template/packages/database/src/lib/loadCommits.ts +28 -0
- package/analyzer-template/packages/database/src/lib/loadEntities.ts +26 -3
- package/analyzer-template/packages/database/src/lib/loadEntityBranches.ts +12 -0
- package/analyzer-template/packages/database/src/lib/updateCommitMetadata.ts +7 -14
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.js +8 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/db.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/analysesTable.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/commitsTable.d.ts +1 -0
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/commitsTable.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/commitsTable.js +3 -0
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/commitsTable.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadAnalyses.d.ts +2 -0
- package/analyzer-template/packages/github/dist/database/src/lib/loadAnalyses.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadAnalyses.js +45 -2
- package/analyzer-template/packages/github/dist/database/src/lib/loadAnalyses.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadAnalysis.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadAnalysis.js +8 -0
- package/analyzer-template/packages/github/dist/database/src/lib/loadAnalysis.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadBranch.js +11 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadBranch.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadCommit.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadCommit.js +7 -0
- package/analyzer-template/packages/github/dist/database/src/lib/loadCommit.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadCommits.d.ts +3 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadCommits.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadCommits.js +22 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadCommits.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.d.ts +3 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.js +23 -4
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntityBranches.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntityBranches.js +9 -0
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntityBranches.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.d.ts +2 -2
- package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js +5 -4
- package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js.map +1 -1
- package/analyzer-template/packages/github/dist/types/index.d.ts +1 -1
- package/analyzer-template/packages/github/dist/types/index.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/types/index.js.map +1 -1
- package/analyzer-template/packages/github/dist/types/src/types/Analysis.d.ts +25 -1
- package/analyzer-template/packages/github/dist/types/src/types/Analysis.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/types/src/types/Commit.d.ts +2 -0
- package/analyzer-template/packages/github/dist/types/src/types/Commit.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts +56 -6
- package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/types/src/types/ScopeAnalysis.d.ts +6 -1
- package/analyzer-template/packages/github/dist/types/src/types/ScopeAnalysis.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/utils/src/lib/safeFileName.d.ts +9 -1
- package/analyzer-template/packages/github/dist/utils/src/lib/safeFileName.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/utils/src/lib/safeFileName.js +29 -3
- package/analyzer-template/packages/github/dist/utils/src/lib/safeFileName.js.map +1 -1
- package/analyzer-template/packages/github/package.json +1 -1
- package/analyzer-template/packages/types/index.ts +1 -0
- package/analyzer-template/packages/types/src/types/Analysis.ts +25 -0
- package/analyzer-template/packages/types/src/types/Commit.ts +2 -0
- package/analyzer-template/packages/types/src/types/ScenariosDataStructure.ts +70 -6
- package/analyzer-template/packages/types/src/types/ScopeAnalysis.ts +6 -1
- package/analyzer-template/packages/utils/dist/types/index.d.ts +1 -1
- package/analyzer-template/packages/utils/dist/types/index.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/types/index.js.map +1 -1
- package/analyzer-template/packages/utils/dist/types/src/types/Analysis.d.ts +25 -1
- package/analyzer-template/packages/utils/dist/types/src/types/Analysis.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/types/src/types/Commit.d.ts +2 -0
- package/analyzer-template/packages/utils/dist/types/src/types/Commit.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts +56 -6
- package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/types/src/types/ScopeAnalysis.d.ts +6 -1
- package/analyzer-template/packages/utils/dist/types/src/types/ScopeAnalysis.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/safeFileName.d.ts +9 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/safeFileName.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/safeFileName.js +29 -3
- package/analyzer-template/packages/utils/dist/utils/src/lib/safeFileName.js.map +1 -1
- package/analyzer-template/packages/utils/src/lib/safeFileName.ts +48 -3
- package/analyzer-template/playwright/capture.ts +20 -8
- package/analyzer-template/playwright/captureStatic.ts +1 -1
- package/analyzer-template/project/analyzeBaselineCommit.ts +5 -0
- package/analyzer-template/project/analyzeRegularCommit.ts +5 -0
- package/analyzer-template/project/captureLibraryFunctionDirect.ts +29 -26
- package/analyzer-template/project/constructMockCode.ts +367 -37
- package/analyzer-template/project/createEntitiesAndSortFiles.ts +83 -0
- package/analyzer-template/project/loadReadyToBeCaptured.ts +65 -41
- package/analyzer-template/project/orchestrateCapture/AwsCaptureTaskRunner.ts +12 -4
- package/analyzer-template/project/orchestrateCapture/SequentialCaptureTaskRunner.ts +18 -7
- package/analyzer-template/project/orchestrateCapture/taskRunner.ts +4 -2
- package/analyzer-template/project/orchestrateCapture.ts +71 -6
- package/analyzer-template/project/reconcileMockDataKeys.ts +152 -9
- package/analyzer-template/project/runAnalysis.ts +4 -0
- package/analyzer-template/project/start.ts +35 -11
- package/analyzer-template/project/writeMockDataTsx.ts +127 -4
- package/analyzer-template/project/writeScenarioComponents.ts +101 -8
- package/analyzer-template/scripts/comboWorkerLoop.cjs +98 -50
- package/background/src/lib/virtualized/project/analyzeBaselineCommit.js +5 -0
- package/background/src/lib/virtualized/project/analyzeBaselineCommit.js.map +1 -1
- package/background/src/lib/virtualized/project/analyzeRegularCommit.js +5 -0
- package/background/src/lib/virtualized/project/analyzeRegularCommit.js.map +1 -1
- package/background/src/lib/virtualized/project/captureLibraryFunctionDirect.js +3 -3
- package/background/src/lib/virtualized/project/captureLibraryFunctionDirect.js.map +1 -1
- package/background/src/lib/virtualized/project/constructMockCode.js +300 -7
- package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
- package/background/src/lib/virtualized/project/createEntitiesAndSortFiles.js +73 -1
- package/background/src/lib/virtualized/project/createEntitiesAndSortFiles.js.map +1 -1
- package/background/src/lib/virtualized/project/loadReadyToBeCaptured.js +19 -8
- package/background/src/lib/virtualized/project/loadReadyToBeCaptured.js.map +1 -1
- package/background/src/lib/virtualized/project/orchestrateCapture/AwsCaptureTaskRunner.js +2 -2
- package/background/src/lib/virtualized/project/orchestrateCapture/AwsCaptureTaskRunner.js.map +1 -1
- package/background/src/lib/virtualized/project/orchestrateCapture/SequentialCaptureTaskRunner.js +7 -5
- package/background/src/lib/virtualized/project/orchestrateCapture/SequentialCaptureTaskRunner.js.map +1 -1
- package/background/src/lib/virtualized/project/orchestrateCapture.js +58 -6
- package/background/src/lib/virtualized/project/orchestrateCapture.js.map +1 -1
- package/background/src/lib/virtualized/project/reconcileMockDataKeys.js +126 -9
- package/background/src/lib/virtualized/project/reconcileMockDataKeys.js.map +1 -1
- package/background/src/lib/virtualized/project/runAnalysis.js +3 -0
- package/background/src/lib/virtualized/project/runAnalysis.js.map +1 -1
- package/background/src/lib/virtualized/project/start.js +32 -11
- package/background/src/lib/virtualized/project/start.js.map +1 -1
- package/background/src/lib/virtualized/project/writeMockDataTsx.js +101 -4
- package/background/src/lib/virtualized/project/writeMockDataTsx.js.map +1 -1
- package/background/src/lib/virtualized/project/writeScenarioComponents.js +57 -8
- package/background/src/lib/virtualized/project/writeScenarioComponents.js.map +1 -1
- package/codeyam-cli/src/cli.js +2 -0
- package/codeyam-cli/src/cli.js.map +1 -1
- package/codeyam-cli/src/commands/debug.js +7 -5
- package/codeyam-cli/src/commands/debug.js.map +1 -1
- package/codeyam-cli/src/commands/memory.js +273 -0
- package/codeyam-cli/src/commands/memory.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js +4 -0
- package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js.map +1 -1
- package/codeyam-cli/src/utils/analysisRunner.js +21 -2
- package/codeyam-cli/src/utils/analysisRunner.js.map +1 -1
- package/codeyam-cli/src/utils/install-skills.js +42 -6
- package/codeyam-cli/src/utils/install-skills.js.map +1 -1
- package/codeyam-cli/src/utils/queue/job.js +1 -0
- package/codeyam-cli/src/utils/queue/job.js.map +1 -1
- package/codeyam-cli/src/utils/queue/manager.js +6 -0
- package/codeyam-cli/src/utils/queue/manager.js.map +1 -1
- package/codeyam-cli/src/utils/rules/index.js +5 -0
- package/codeyam-cli/src/utils/rules/index.js.map +1 -0
- package/codeyam-cli/src/utils/rules/parser.js +106 -0
- package/codeyam-cli/src/utils/rules/parser.js.map +1 -0
- package/codeyam-cli/src/utils/rules/pathMatcher.js +18 -0
- package/codeyam-cli/src/utils/rules/pathMatcher.js.map +1 -0
- package/codeyam-cli/src/utils/rules/staleness.js +132 -0
- package/codeyam-cli/src/utils/rules/staleness.js.map +1 -0
- package/codeyam-cli/src/utils/setupClaudeCodeSettings.js +2 -0
- package/codeyam-cli/src/utils/setupClaudeCodeSettings.js.map +1 -1
- package/codeyam-cli/src/webserver/app/lib/database.js +7 -3
- package/codeyam-cli/src/webserver/app/lib/database.js.map +1 -1
- package/codeyam-cli/src/webserver/bootstrap.js +40 -0
- package/codeyam-cli/src/webserver/bootstrap.js.map +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/EntityItem-DsN1wKrm.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeBadge-COi5OvsN.js → EntityTypeBadge-DLqD3qNt.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-BwdQv49w.js → EntityTypeIcon-Ba2JVPzP.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{InlineSpinner-CEleMv_j.js → InlineSpinner-C8lyxW9k.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{InteractivePreview-D68KarMg.js → InteractivePreview-aht4aafF.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{LibraryFunctionPreview-L75Wvqgw.js → LibraryFunctionPreview-CVtiBnY5.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{LoadingDots-C53WM8qn.js → LoadingDots-B0GLXMsr.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{LogViewer-CrNkmy4i.js → LogViewer-xgeCVgSM.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/ReportIssueModal-OApQuNyq.js +16 -0
- package/codeyam-cli/src/webserver/build/client/assets/{SafeScreenshot-CQifa1n-.js → SafeScreenshot-DuDvi0jm.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-CyaBFX7l.js → ScenarioViewer-DzccYyI8.js} +3 -13
- package/codeyam-cli/src/webserver/build/client/assets/{TruncatedFilePath-D36O1rzU.js → TruncatedFilePath-DyFZkK0l.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/_index-BwqWJOgH.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/activity.(_tab)-BwavGCpm.js +32 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.health-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.memory-profile-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.restart-server-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-DgTPh8H-.js → chevron-down-Cx24_aWc.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{chunk-EPOLDU6W-DdQKK6on.js → chunk-EPOLDU6W-CXRTFQ3F.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{circle-check-Dmr2bb1R.js → circle-check-BOARzkeR.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/copy-Bb-80kDT.js +6 -0
- package/codeyam-cli/src/webserver/build/client/assets/{createLucideIcon-Do4ZLUYa.js → createLucideIcon-BdhJEx6B.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/dev.empty-BBnGWYga.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-CbdFyxZh.js → entity._sha._-BJUiQqZF.js} +12 -12
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.fullscreen-B4iCfs5M.js → entity._sha.scenarios._scenarioId.fullscreen-DavjRmOY.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.create-scenario-wDWZZO1W.js → entity._sha_.create-scenario-D1T4TGjf.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-BMbl7MeQ.js → entity._sha_.edit._scenarioId-CTBG2mmz.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entry.client-5wRKRIH9.js → entry.client-CS2cb_eZ.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/file-code-Dhef1kWN.js +6 -0
- package/codeyam-cli/src/webserver/build/client/assets/{fileTableUtils-DD3SDH7t.js → fileTableUtils-DMJ7zii9.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/files-CJ6lTdTA.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{git-zXjT7J0G.js → git-CPTZZ-JZ.js} +8 -8
- package/codeyam-cli/src/webserver/build/client/assets/globals-D3yhhV8x.css +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{index-DLbXwndH.js → index-B1h680n5.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{index-gPZ-lad1.js → index-lzqtyFU8.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-BsPXJ81F.js → loader-circle-B7B9V-bu.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-a78b90a2.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/memory--GCbFsBE.js +92 -0
- package/codeyam-cli/src/webserver/build/client/assets/root-eVAaavTS.js +62 -0
- package/codeyam-cli/src/webserver/build/client/assets/{search-P2FKIUql.js → search-CxXUmBSd.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{settings-B2eDuBj8.js → settings-CS5f3WzT.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{simulations-L18M6-kN.js → simulations-DwFIBT09.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-BDz7kbVA.js → triangle-alert-B6LgvRJg.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useCustomSizes-29dDmbH8.js → useCustomSizes-C1v1PQzo.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-BUm0UVJm.js → useLastLogLine-aSv48UbS.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useReportContext-CkIOKTrZ.js → useReportContext-DYxHZQuP.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useToast-KKw5kTn-.js → useToast-mBRpZPiu.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/index-BM6TDT1Y.js +1 -0
- package/codeyam-cli/src/webserver/build/server/assets/server-build-dYC34MHw.js +257 -0
- package/codeyam-cli/src/webserver/build/server/index.js +1 -1
- package/codeyam-cli/src/webserver/build-info.json +5 -5
- package/codeyam-cli/templates/codeyam-memory-hook.sh +200 -0
- package/codeyam-cli/templates/codeyam:debug.md +47 -3
- package/codeyam-cli/templates/codeyam:diagnose.md +203 -25
- package/codeyam-cli/templates/codeyam:memory.md +341 -0
- package/codeyam-cli/templates/codeyam:new-rule.md +13 -0
- package/codeyam-cli/templates/rule-reflection-hook.py +160 -0
- package/codeyam-cli/templates/rules-instructions.md +93 -0
- package/package.json +8 -5
- package/packages/ai/index.js +7 -3
- package/packages/ai/index.js.map +1 -1
- package/packages/ai/src/lib/analyzeScope.js +70 -29
- package/packages/ai/src/lib/analyzeScope.js.map +1 -1
- package/packages/ai/src/lib/astScopes/arrayDerivationDetector.js +150 -0
- package/packages/ai/src/lib/astScopes/arrayDerivationDetector.js.map +1 -0
- package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js +78 -8
- package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js.map +1 -1
- package/packages/ai/src/lib/astScopes/methodSemantics.js +109 -23
- package/packages/ai/src/lib/astScopes/methodSemantics.js.map +1 -1
- package/packages/ai/src/lib/astScopes/patterns/variableDeclarationHandler.js +1 -102
- package/packages/ai/src/lib/astScopes/patterns/variableDeclarationHandler.js.map +1 -1
- package/packages/ai/src/lib/astScopes/processExpression.js +440 -27
- package/packages/ai/src/lib/astScopes/processExpression.js.map +1 -1
- package/packages/ai/src/lib/completionCall.js +161 -30
- package/packages/ai/src/lib/completionCall.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +589 -166
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.js +179 -0
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/MuiManager.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.js +7 -1
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/ReactFrameworkManager.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/BatchSchemaProcessor.js +13 -3
- package/packages/ai/src/lib/dataStructure/helpers/BatchSchemaProcessor.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/ScopeTreeManager.js +6 -4
- package/packages/ai/src/lib/dataStructure/helpers/ScopeTreeManager.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js +41 -1
- package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js +104 -11
- package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.js +159 -0
- package/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.js.map +1 -0
- package/packages/ai/src/lib/dataStructure/helpers/deduplicateFunctionSchemas.js +37 -20
- package/packages/ai/src/lib/dataStructure/helpers/deduplicateFunctionSchemas.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js +265 -79
- package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/fixNullIdsBySchema.js +107 -0
- package/packages/ai/src/lib/dataStructure/helpers/fixNullIdsBySchema.js.map +1 -0
- package/packages/ai/src/lib/dataStructureChunking.js +111 -0
- package/packages/ai/src/lib/dataStructureChunking.js.map +1 -0
- package/packages/ai/src/lib/e2eDataTracking.js +241 -0
- package/packages/ai/src/lib/e2eDataTracking.js.map +1 -0
- package/packages/ai/src/lib/extractCriticalDataKeys.js +96 -0
- package/packages/ai/src/lib/extractCriticalDataKeys.js.map +1 -0
- package/packages/ai/src/lib/generateEntityScenarioData.js +525 -8
- package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
- package/packages/ai/src/lib/generateEntityScenarios.js +26 -2
- package/packages/ai/src/lib/generateEntityScenarios.js.map +1 -1
- package/packages/ai/src/lib/generateExecutionFlows.js +281 -4
- package/packages/ai/src/lib/generateExecutionFlows.js.map +1 -1
- package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js +946 -42
- package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js.map +1 -1
- package/packages/ai/src/lib/generateExecutionFlowsFromJsxUsages.js +194 -0
- package/packages/ai/src/lib/generateExecutionFlowsFromJsxUsages.js.map +1 -0
- package/packages/ai/src/lib/mergeStatements.js +70 -51
- package/packages/ai/src/lib/mergeStatements.js.map +1 -1
- package/packages/ai/src/lib/promptGenerators/gatherAttributesMap.js +10 -4
- package/packages/ai/src/lib/promptGenerators/gatherAttributesMap.js.map +1 -1
- package/packages/ai/src/lib/promptGenerators/generateChunkPrompt.js +54 -0
- package/packages/ai/src/lib/promptGenerators/generateChunkPrompt.js.map +1 -0
- package/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.js +15 -7
- package/packages/ai/src/lib/promptGenerators/generateEntityScenarioDataGenerator.js.map +1 -1
- package/packages/ai/src/lib/promptGenerators/simplifyKeysForLLM.js +335 -0
- package/packages/ai/src/lib/promptGenerators/simplifyKeysForLLM.js.map +1 -0
- package/packages/ai/src/lib/resolvePathToControllable.js +155 -41
- package/packages/ai/src/lib/resolvePathToControllable.js.map +1 -1
- package/packages/ai/src/lib/worker/SerializableDataStructure.js +7 -0
- package/packages/ai/src/lib/worker/SerializableDataStructure.js.map +1 -1
- package/packages/ai/src/lib/worker/analyzeScopeWorker.js +94 -1
- package/packages/ai/src/lib/worker/analyzeScopeWorker.js.map +1 -1
- package/packages/analyze/src/lib/FileAnalyzer.js +60 -36
- package/packages/analyze/src/lib/FileAnalyzer.js.map +1 -1
- package/packages/analyze/src/lib/ProjectAnalyzer.js +96 -26
- package/packages/analyze/src/lib/ProjectAnalyzer.js.map +1 -1
- package/packages/analyze/src/lib/analysisContext.js +30 -5
- package/packages/analyze/src/lib/analysisContext.js.map +1 -1
- package/packages/analyze/src/lib/asts/sourceFiles/getAllDeclaredEntityNodes.js +14 -0
- package/packages/analyze/src/lib/asts/sourceFiles/getAllDeclaredEntityNodes.js.map +1 -1
- package/packages/analyze/src/lib/asts/sourceFiles/getAllEntityNodes.js +14 -0
- package/packages/analyze/src/lib/asts/sourceFiles/getAllEntityNodes.js.map +1 -1
- package/packages/analyze/src/lib/asts/sourceFiles/getAllExports.js +6 -0
- package/packages/analyze/src/lib/asts/sourceFiles/getAllExports.js.map +1 -1
- package/packages/analyze/src/lib/asts/sourceFiles/getImportsAnalysis.js +6 -0
- package/packages/analyze/src/lib/asts/sourceFiles/getImportsAnalysis.js.map +1 -1
- package/packages/analyze/src/lib/asts/sourceFiles/getResolvedModule.js +39 -1
- package/packages/analyze/src/lib/asts/sourceFiles/getResolvedModule.js.map +1 -1
- package/packages/analyze/src/lib/asts/sourceFiles/getSourceFilesForAllImports.js +2 -1
- package/packages/analyze/src/lib/asts/sourceFiles/getSourceFilesForAllImports.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +21 -9
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities.js +14 -4
- package/packages/analyze/src/lib/files/analyze/analyzeEntities.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/dependencyResolver.js +5 -0
- package/packages/analyze/src/lib/files/analyze/dependencyResolver.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/gatherEntityMap.js +2 -1
- package/packages/analyze/src/lib/files/analyze/gatherEntityMap.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js +31 -10
- package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js.map +1 -1
- package/packages/analyze/src/lib/files/analyzeRemixRoute.js +3 -2
- package/packages/analyze/src/lib/files/analyzeRemixRoute.js.map +1 -1
- package/packages/analyze/src/lib/files/getImportedExports.js +11 -7
- package/packages/analyze/src/lib/files/getImportedExports.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js +160 -68
- package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js +25 -8
- package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +71 -9
- package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js +57 -9
- package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +233 -9
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/mergeValidatedDataStructures.js +46 -9
- package/packages/analyze/src/lib/files/scenarios/mergeValidatedDataStructures.js.map +1 -1
- package/packages/analyze/src/lib/files/setImportedExports.js +2 -1
- package/packages/analyze/src/lib/files/setImportedExports.js.map +1 -1
- package/packages/analyze/src/lib/utils/getFileByPath.js +12 -0
- package/packages/analyze/src/lib/utils/getFileByPath.js.map +1 -0
- package/packages/database/src/lib/kysely/db.js +8 -1
- package/packages/database/src/lib/kysely/db.js.map +1 -1
- package/packages/database/src/lib/kysely/tables/commitsTable.js +3 -0
- package/packages/database/src/lib/kysely/tables/commitsTable.js.map +1 -1
- package/packages/database/src/lib/loadAnalyses.js +45 -2
- package/packages/database/src/lib/loadAnalyses.js.map +1 -1
- package/packages/database/src/lib/loadAnalysis.js +8 -0
- package/packages/database/src/lib/loadAnalysis.js.map +1 -1
- package/packages/database/src/lib/loadBranch.js +11 -1
- package/packages/database/src/lib/loadBranch.js.map +1 -1
- package/packages/database/src/lib/loadCommit.js +7 -0
- package/packages/database/src/lib/loadCommit.js.map +1 -1
- package/packages/database/src/lib/loadCommits.js +22 -1
- package/packages/database/src/lib/loadCommits.js.map +1 -1
- package/packages/database/src/lib/loadEntities.js +23 -4
- package/packages/database/src/lib/loadEntities.js.map +1 -1
- package/packages/database/src/lib/loadEntityBranches.js +9 -0
- package/packages/database/src/lib/loadEntityBranches.js.map +1 -1
- package/packages/database/src/lib/updateCommitMetadata.js +5 -4
- package/packages/database/src/lib/updateCommitMetadata.js.map +1 -1
- package/packages/types/index.js.map +1 -1
- package/packages/utils/src/lib/safeFileName.js +29 -3
- package/packages/utils/src/lib/safeFileName.js.map +1 -1
- package/scripts/finalize-analyzer.cjs +3 -3
- package/codeyam-cli/src/webserver/build/client/assets/EntityItem-vauWK972.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/ReportIssueModal-DzJRkCkr.js +0 -11
- package/codeyam-cli/src/webserver/build/client/assets/_index-Be83mo_j.js +0 -11
- package/codeyam-cli/src/webserver/build/client/assets/activity.(_tab)-BN6wu6Y-.js +0 -37
- package/codeyam-cli/src/webserver/build/client/assets/dev.empty-Bn6aCAy_.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/files-DKyMFI90.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/globals-DTTQ3gY7.css +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-22590fcf.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/root-BsAarjAM.js +0 -57
- package/codeyam-cli/src/webserver/build/server/assets/index-BND5I5fv.js +0 -1
- package/codeyam-cli/src/webserver/build/server/assets/server-build-CFXnd7MG.js +0 -228
package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.ts
CHANGED
|
@@ -205,16 +205,88 @@ export default function fillInSchemaGapsAndUnknowns(
|
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Pre-built indexes that can be reused across multiple calls to fillInDirectSchemaGapsAndUnknowns.
|
|
210
|
+
* Build once with buildSchemaIndexes(), then pass to all calls processing the same schema.
|
|
211
|
+
*/
|
|
212
|
+
export interface SchemaIndexes {
|
|
213
|
+
functionKeysMapping: Record<string, string[]>;
|
|
214
|
+
prefixMaxDepth: Map<string, number>;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Build indexes for a schema that can be reused across multiple calls.
|
|
219
|
+
* This avoids rebuilding indexes (~1-2 seconds for 18k keys) on every call.
|
|
220
|
+
*
|
|
221
|
+
* @param schema - The schema to build indexes from (typically the full dependency schema)
|
|
222
|
+
* @returns Indexes that can be passed to fillInDirectSchemaGapsAndUnknowns
|
|
223
|
+
*/
|
|
224
|
+
export function buildSchemaIndexes(
|
|
225
|
+
schema: Record<string, string>,
|
|
226
|
+
): SchemaIndexes {
|
|
227
|
+
// Build functionKeysMapping + prefixMaxDepth in a single pass
|
|
228
|
+
// Avoid repeated split/join work by caching parts and building prefixes incrementally.
|
|
229
|
+
const functionKeysMapping: Record<string, string[]> = {};
|
|
230
|
+
const prefixMaxDepth = new Map<string, number>();
|
|
231
|
+
const partsCache = new Map<string, string[]>();
|
|
232
|
+
|
|
233
|
+
for (const key in schema) {
|
|
234
|
+
const parts = getCachedParts(partsCache, key);
|
|
235
|
+
const lastPart = parts[parts.length - 1];
|
|
236
|
+
const prefixes = buildPrefixParts(parts);
|
|
237
|
+
|
|
238
|
+
if (
|
|
239
|
+
key.endsWith(')') ||
|
|
240
|
+
schema[key] === 'function' ||
|
|
241
|
+
lastPart === 'length'
|
|
242
|
+
) {
|
|
243
|
+
const allButLastPart = parts.length > 1 ? prefixes[parts.length - 2] : '';
|
|
244
|
+
functionKeysMapping[allButLastPart] ||= [];
|
|
245
|
+
functionKeysMapping[allButLastPart].push(lastPart);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
for (let i = 0; i < prefixes.length; i++) {
|
|
249
|
+
const prefix = prefixes[i];
|
|
250
|
+
const existingMax = prefixMaxDepth.get(prefix) ?? 0;
|
|
251
|
+
if (parts.length > existingMax) {
|
|
252
|
+
prefixMaxDepth.set(prefix, parts.length);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return { functionKeysMapping, prefixMaxDepth };
|
|
258
|
+
}
|
|
259
|
+
|
|
208
260
|
export function fillInDirectSchemaGapsAndUnknowns({
|
|
209
261
|
scopeName,
|
|
210
262
|
schema,
|
|
211
263
|
mergedSchema,
|
|
212
264
|
attempts = 0,
|
|
265
|
+
// Pre-built indexes from buildSchemaIndexes() - use for cross-call caching
|
|
266
|
+
prebuiltIndexes,
|
|
267
|
+
// Internal: pre-computed indexes to avoid rebuilding on recursion
|
|
268
|
+
_functionKeysMapping,
|
|
269
|
+
_prefixMaxDepth,
|
|
270
|
+
_partsCache,
|
|
271
|
+
_prefixPartsCache,
|
|
272
|
+
_knownTypeCache,
|
|
273
|
+
_guessTypeCache,
|
|
274
|
+
_nameHintCache,
|
|
213
275
|
}: {
|
|
214
276
|
scopeName?: string;
|
|
215
277
|
schema: Record<string, string>;
|
|
216
278
|
mergedSchema?: Record<string, string>;
|
|
217
279
|
attempts?: number;
|
|
280
|
+
/** Pre-built indexes from buildSchemaIndexes() - pass to reuse across multiple calls */
|
|
281
|
+
prebuiltIndexes?: SchemaIndexes;
|
|
282
|
+
// Internal: pre-computed indexes to avoid rebuilding on recursion (used by recursive calls)
|
|
283
|
+
_functionKeysMapping?: Record<string, string[]>;
|
|
284
|
+
_prefixMaxDepth?: Map<string, number>;
|
|
285
|
+
_partsCache?: Map<string, string[]>;
|
|
286
|
+
_prefixPartsCache?: Map<string, string[]>;
|
|
287
|
+
_knownTypeCache?: Map<string, string | undefined>;
|
|
288
|
+
_guessTypeCache?: Map<string, string | undefined>;
|
|
289
|
+
_nameHintCache?: Map<string, string | undefined>;
|
|
218
290
|
}) {
|
|
219
291
|
try {
|
|
220
292
|
const existingSchema = (path: any) => {
|
|
@@ -225,105 +297,204 @@ export function fillInDirectSchemaGapsAndUnknowns({
|
|
|
225
297
|
}
|
|
226
298
|
};
|
|
227
299
|
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
300
|
+
const partsCache = _partsCache ?? new Map<string, string[]>();
|
|
301
|
+
const prefixPartsCache = _prefixPartsCache ?? new Map<string, string[]>();
|
|
302
|
+
const knownTypeCache =
|
|
303
|
+
_knownTypeCache ?? new Map<string, string | undefined>();
|
|
304
|
+
const guessTypeCache =
|
|
305
|
+
_guessTypeCache ?? new Map<string, string | undefined>();
|
|
306
|
+
const nameHintCache =
|
|
307
|
+
_nameHintCache ?? new Map<string, string | undefined>();
|
|
308
|
+
|
|
309
|
+
const getParts = (path: string) => getCachedParts(partsCache, path);
|
|
310
|
+
const getPrefixParts = (path: string) => {
|
|
311
|
+
const cached = prefixPartsCache.get(path);
|
|
312
|
+
if (cached) return cached;
|
|
313
|
+
const prefixes = buildPrefixParts(getParts(path));
|
|
314
|
+
prefixPartsCache.set(path, prefixes);
|
|
315
|
+
return prefixes;
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
// Index resolution priority:
|
|
319
|
+
// 1. _functionKeysMapping/_prefixMaxDepth (from recursive calls within this invocation)
|
|
320
|
+
// 2. prebuiltIndexes (from cross-call caching - built once, reused across multiple calls)
|
|
321
|
+
// 3. Build new indexes (fallback - expensive for large schemas)
|
|
322
|
+
const functionKeysMapping =
|
|
323
|
+
_functionKeysMapping ??
|
|
324
|
+
prebuiltIndexes?.functionKeysMapping ??
|
|
325
|
+
(() => {
|
|
326
|
+
const mapping: Record<string, string[]> = {};
|
|
327
|
+
for (const key in schema) {
|
|
328
|
+
const parts = getParts(key);
|
|
238
329
|
const lastPart = parts[parts.length - 1];
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
330
|
+
if (
|
|
331
|
+
key.endsWith(')') ||
|
|
332
|
+
schema[key] === 'function' ||
|
|
333
|
+
lastPart === 'length'
|
|
334
|
+
) {
|
|
335
|
+
const prefixes = getPrefixParts(key);
|
|
336
|
+
const allButLastPart =
|
|
337
|
+
parts.length > 1 ? prefixes[parts.length - 2] : '';
|
|
338
|
+
mapping[allButLastPart] ||= [];
|
|
339
|
+
mapping[allButLastPart].push(lastPart);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return mapping;
|
|
343
|
+
})();
|
|
344
|
+
|
|
345
|
+
// Build prefix index for O(1) lookups in checkIfObjectOrFunction
|
|
346
|
+
// Maps each prefix to the max depth of keys that have this prefix
|
|
347
|
+
// This replaces O(n) scans with O(1) lookups, fixing the O(n²) bottleneck
|
|
348
|
+
let prefixMaxDepth =
|
|
349
|
+
_prefixMaxDepth ?? prebuiltIndexes?.prefixMaxDepth ?? null;
|
|
350
|
+
if (!prefixMaxDepth) {
|
|
351
|
+
prefixMaxDepth = new Map<string, number>();
|
|
352
|
+
const targetSchema = mergedSchema ?? schema;
|
|
353
|
+
for (const key in targetSchema) {
|
|
354
|
+
const keyParts = getParts(key);
|
|
355
|
+
const prefixes = buildPrefixParts(keyParts);
|
|
356
|
+
// Record each prefix of this key with its max depth
|
|
357
|
+
for (let i = 0; i < prefixes.length; i++) {
|
|
358
|
+
const prefix = prefixes[i];
|
|
359
|
+
const existingMax = prefixMaxDepth.get(prefix) ?? 0;
|
|
360
|
+
if (keyParts.length > existingMax) {
|
|
361
|
+
prefixMaxDepth.set(prefix, keyParts.length);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
245
366
|
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
367
|
+
// O(1) replacement for checkIfObjectOrFunction
|
|
368
|
+
const checkIfObjectOrFunctionFast = (path: string): string | undefined => {
|
|
369
|
+
const maxDepth = prefixMaxDepth!.get(path);
|
|
370
|
+
|
|
371
|
+
if (maxDepth === undefined) return undefined; // No key starts with this path
|
|
372
|
+
|
|
373
|
+
const pathParts = getParts(path);
|
|
374
|
+
// Check if path's last part ends with ')' → function
|
|
375
|
+
const lastPart = pathParts[pathParts.length - 1];
|
|
376
|
+
if (lastPart?.endsWith(')')) {
|
|
377
|
+
return 'function';
|
|
253
378
|
}
|
|
254
379
|
|
|
255
|
-
|
|
256
|
-
|
|
380
|
+
// Check if there are deeper keys
|
|
381
|
+
if (maxDepth > pathParts.length) {
|
|
382
|
+
return 'object';
|
|
257
383
|
}
|
|
258
384
|
|
|
259
|
-
|
|
260
|
-
|
|
385
|
+
return undefined;
|
|
386
|
+
};
|
|
261
387
|
|
|
388
|
+
let changeMade = false;
|
|
389
|
+
const getKnownType = (path: string) => {
|
|
390
|
+
if (knownTypeCache.has(path)) return knownTypeCache.get(path);
|
|
391
|
+
const known = checkIfKnownType(path, functionKeysMapping);
|
|
392
|
+
knownTypeCache.set(path, known);
|
|
393
|
+
return known;
|
|
394
|
+
};
|
|
395
|
+
const guessTypeFromName = (lastPart: string, defaultType: string) => {
|
|
396
|
+
if (nameHintCache.has(lastPart)) {
|
|
397
|
+
return nameHintCache.get(lastPart) ?? defaultType;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
let hint: string | undefined;
|
|
262
401
|
if (isLikelyBoolean(lastPart)) {
|
|
263
|
-
|
|
402
|
+
hint = 'boolean';
|
|
264
403
|
} else if (isLikelyDate(lastPart)) {
|
|
265
|
-
|
|
404
|
+
hint = 'date';
|
|
266
405
|
} else if (isLikelyAction(lastPart)) {
|
|
267
|
-
|
|
406
|
+
hint = 'function';
|
|
268
407
|
} else if (pluralize.isPlural(lastPart)) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
408
|
+
// Default to number instead of array - safer for JSX rendering
|
|
409
|
+
// Arrays cause "Objects are not valid as a React child" errors when rendered directly
|
|
410
|
+
hint = 'number';
|
|
272
411
|
}
|
|
412
|
+
|
|
413
|
+
nameHintCache.set(lastPart, hint);
|
|
414
|
+
return hint ?? defaultType;
|
|
415
|
+
};
|
|
416
|
+
const guessTypeForPath = (path: string, defaultType = 'string') => {
|
|
417
|
+
const cacheKey = `${path}|${defaultType}`;
|
|
418
|
+
if (guessTypeCache.has(cacheKey)) {
|
|
419
|
+
return guessTypeCache.get(cacheKey);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
let knownType = getKnownType(path);
|
|
423
|
+
if (!knownType) {
|
|
424
|
+
// Use optimized O(1) prefix lookup instead of O(n) scan
|
|
425
|
+
knownType = checkIfObjectOrFunctionFast(path);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (knownType) {
|
|
429
|
+
guessTypeCache.set(cacheKey, knownType);
|
|
430
|
+
return knownType;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const keyParts = getParts(path);
|
|
434
|
+
const lastPart = keyParts[keyParts.length - 1];
|
|
435
|
+
const guessed = guessTypeFromName(lastPart, defaultType);
|
|
436
|
+
guessTypeCache.set(cacheKey, guessed);
|
|
437
|
+
return guessed;
|
|
273
438
|
};
|
|
274
439
|
|
|
275
440
|
for (const key in schema) {
|
|
276
441
|
if (!schema[key]) schema[key] = 'unknown';
|
|
277
442
|
if (schema[key].includes(' | unknown')) {
|
|
278
|
-
|
|
279
|
-
|
|
443
|
+
const cleaned = schema[key].replace(' | unknown', '');
|
|
444
|
+
if (schema[key] !== cleaned) {
|
|
445
|
+
schema[key] = cleaned;
|
|
446
|
+
changeMade = true;
|
|
447
|
+
}
|
|
280
448
|
} else if (schema[key].startsWith('unknown | ')) {
|
|
281
449
|
// Handle "unknown | undefined" -> "string | undefined"
|
|
282
450
|
const remainingType = schema[key].substring('unknown | '.length);
|
|
283
451
|
const newType = guessTypeForPath(key, 'string');
|
|
284
452
|
if (newType) {
|
|
285
|
-
|
|
286
|
-
|
|
453
|
+
const replacement = `${newType} | ${remainingType}`;
|
|
454
|
+
if (schema[key] !== replacement) {
|
|
455
|
+
schema[key] = replacement;
|
|
456
|
+
changeMade = true;
|
|
457
|
+
}
|
|
287
458
|
}
|
|
288
459
|
} else if (schema[key] === 'unknown') {
|
|
289
460
|
const newType = guessTypeForPath(key, 'string');
|
|
290
|
-
if (newType) {
|
|
461
|
+
if (newType && schema[key] !== newType) {
|
|
291
462
|
schema[key] = newType;
|
|
292
463
|
changeMade = true;
|
|
293
464
|
}
|
|
294
465
|
}
|
|
295
466
|
|
|
296
|
-
const keyParts =
|
|
467
|
+
const keyParts = getParts(key);
|
|
468
|
+
const prefixParts = getPrefixParts(key);
|
|
297
469
|
for (let i = 0; i < keyParts.length; i++) {
|
|
298
|
-
|
|
299
|
-
const lastSubPathPart =
|
|
300
|
-
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
changeMade = true;
|
|
470
|
+
if (i === 0) continue;
|
|
471
|
+
const lastSubPathPart = keyParts[i];
|
|
472
|
+
const previousSubPath = prefixParts[i - 1];
|
|
473
|
+
const isSignatureIndex =
|
|
474
|
+
lastSubPathPart.includes('signature[') &&
|
|
475
|
+
SIGNATURE_INDEX_REGEX.test(lastSubPathPart);
|
|
476
|
+
|
|
477
|
+
if (lastSubPathPart.includes('[')) {
|
|
478
|
+
const cleaned = cleanOutBoundary(lastSubPathPart);
|
|
479
|
+
if (cleaned.match(/\[\d*\]/) && !isSignatureIndex) {
|
|
480
|
+
// Fix 39: Don't overwrite explicit 'object' types with 'array'
|
|
481
|
+
// This handles spurious [] paths from components like JsonNode that handle
|
|
482
|
+
// both arrays and objects. When metadata is explicitly typed as 'object',
|
|
483
|
+
// paths like metadata[] (from dynamic iteration) should not change it.
|
|
484
|
+
if (
|
|
485
|
+
schema[previousSubPath] !== 'array' &&
|
|
486
|
+
schema[previousSubPath] !== 'object'
|
|
487
|
+
) {
|
|
488
|
+
schema[previousSubPath] = 'array';
|
|
489
|
+
changeMade = true;
|
|
490
|
+
}
|
|
320
491
|
}
|
|
321
492
|
}
|
|
322
493
|
|
|
323
494
|
const isFunction =
|
|
324
495
|
lastSubPathPart.endsWith(')') ||
|
|
325
496
|
lastSubPathPart === 'functionCallReturnValue' ||
|
|
326
|
-
|
|
497
|
+
isSignatureIndex;
|
|
327
498
|
|
|
328
499
|
if (
|
|
329
500
|
!isFunction &&
|
|
@@ -331,8 +502,7 @@ export function fillInDirectSchemaGapsAndUnknowns({
|
|
|
331
502
|
schema[previousSubPath],
|
|
332
503
|
)
|
|
333
504
|
) {
|
|
334
|
-
const newValue =
|
|
335
|
-
checkIfKnownType(previousSubPath, functionKeysMapping) ?? 'object';
|
|
505
|
+
const newValue = getKnownType(previousSubPath) ?? 'object';
|
|
336
506
|
|
|
337
507
|
if (
|
|
338
508
|
!schema[previousSubPath] ||
|
|
@@ -347,8 +517,7 @@ export function fillInDirectSchemaGapsAndUnknowns({
|
|
|
347
517
|
if (isFunction && !existingSchema(previousSubPath)) {
|
|
348
518
|
schema[previousSubPath] = previousSubPath.endsWith(')')
|
|
349
519
|
? 'function'
|
|
350
|
-
: (
|
|
351
|
-
'object');
|
|
520
|
+
: (getKnownType(previousSubPath) ?? 'object');
|
|
352
521
|
changeMade = true;
|
|
353
522
|
}
|
|
354
523
|
|
|
@@ -358,10 +527,12 @@ export function fillInDirectSchemaGapsAndUnknowns({
|
|
|
358
527
|
const functionReturnValuePath = `${previousSubPath}.functionCallReturnValue`;
|
|
359
528
|
|
|
360
529
|
// Extract the method name from lastSubPathPart (e.g., "then()" -> "then")
|
|
361
|
-
const
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
|
|
530
|
+
const parenIndex = lastSubPathPart.indexOf('(');
|
|
531
|
+
const methodName =
|
|
532
|
+
parenIndex === -1
|
|
533
|
+
? lastSubPathPart
|
|
534
|
+
: lastSubPathPart.slice(0, parenIndex);
|
|
535
|
+
const isPromiseMethod = PROMISE_METHODS.has(methodName);
|
|
365
536
|
const isPreviousAsync = schema[previousSubPath] === 'async-function';
|
|
366
537
|
|
|
367
538
|
// Don't set to 'function' if this is a promise method on an async function
|
|
@@ -386,6 +557,15 @@ export function fillInDirectSchemaGapsAndUnknowns({
|
|
|
386
557
|
schema,
|
|
387
558
|
mergedSchema,
|
|
388
559
|
attempts: ++attempts,
|
|
560
|
+
prebuiltIndexes,
|
|
561
|
+
// Pass pre-computed indexes to avoid rebuilding on each recursive call
|
|
562
|
+
_functionKeysMapping: functionKeysMapping,
|
|
563
|
+
_prefixMaxDepth: prefixMaxDepth,
|
|
564
|
+
_partsCache: partsCache,
|
|
565
|
+
_prefixPartsCache: prefixPartsCache,
|
|
566
|
+
_knownTypeCache: knownTypeCache,
|
|
567
|
+
_guessTypeCache: guessTypeCache,
|
|
568
|
+
_nameHintCache: nameHintCache,
|
|
389
569
|
});
|
|
390
570
|
}
|
|
391
571
|
|
|
@@ -395,9 +575,10 @@ export function fillInDirectSchemaGapsAndUnknowns({
|
|
|
395
575
|
// However, if the parent could be an 'object' or other type, keep .length as it may be
|
|
396
576
|
// a custom property.
|
|
397
577
|
for (const key of Object.keys(schema)) {
|
|
398
|
-
const parts =
|
|
578
|
+
const parts = getParts(key);
|
|
399
579
|
if (parts[parts.length - 1] === 'length') {
|
|
400
|
-
const
|
|
580
|
+
const prefixes = getPrefixParts(key);
|
|
581
|
+
const parentPath = parts.length > 1 ? prefixes[parts.length - 2] : '';
|
|
401
582
|
const parentType = schema[parentPath];
|
|
402
583
|
if (parentType) {
|
|
403
584
|
// Split union types and filter out nullable parts
|
|
@@ -434,6 +615,35 @@ export function fillInDirectSchemaGapsAndUnknowns({
|
|
|
434
615
|
}
|
|
435
616
|
}
|
|
436
617
|
|
|
618
|
+
const SIGNATURE_INDEX_REGEX = /signature\[\d+\]/;
|
|
619
|
+
const PROMISE_METHODS = new Set(['then', 'catch', 'finally']);
|
|
620
|
+
|
|
621
|
+
function getCachedParts(cache: Map<string, string[]>, path: string): string[] {
|
|
622
|
+
const cached = cache.get(path);
|
|
623
|
+
if (cached) return cached;
|
|
624
|
+
const parts = splitOutsideParenthesesAndArrays(path);
|
|
625
|
+
cache.set(path, parts);
|
|
626
|
+
return parts;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
function buildPrefixParts(parts: string[]): string[] {
|
|
630
|
+
if (parts.length === 0) return [];
|
|
631
|
+
const prefixes = new Array(parts.length);
|
|
632
|
+
let prefix = '';
|
|
633
|
+
for (let i = 0; i < parts.length; i++) {
|
|
634
|
+
const part = parts[i];
|
|
635
|
+
if (i === 0) {
|
|
636
|
+
prefix = part;
|
|
637
|
+
} else if (part.startsWith('[') || part.startsWith('(')) {
|
|
638
|
+
prefix += part;
|
|
639
|
+
} else {
|
|
640
|
+
prefix += `.${part}`;
|
|
641
|
+
}
|
|
642
|
+
prefixes[i] = prefix;
|
|
643
|
+
}
|
|
644
|
+
return prefixes;
|
|
645
|
+
}
|
|
646
|
+
|
|
437
647
|
function checkIfObjectOrFunction(path: string, schema: ScopeNode['schema']) {
|
|
438
648
|
const pathParts = splitOutsideParenthesesAndArrays(path);
|
|
439
649
|
for (const structureKey in schema) {
|
|
@@ -486,6 +696,17 @@ const STRONG_ARRAY_METHODS = new Set([
|
|
|
486
696
|
'with',
|
|
487
697
|
]);
|
|
488
698
|
|
|
699
|
+
/**
|
|
700
|
+
* Check if a method call argument looks like a string literal.
|
|
701
|
+
* String literals start with ' or " (e.g., includes('foo'), indexOf("bar"))
|
|
702
|
+
*/
|
|
703
|
+
function hasStringLiteralArgument(methodCall: string): boolean {
|
|
704
|
+
const parenIndex = methodCall.indexOf('(');
|
|
705
|
+
if (parenIndex === -1) return false;
|
|
706
|
+
const arg = methodCall.slice(parenIndex + 1).trim();
|
|
707
|
+
return arg.startsWith("'") || arg.startsWith('"') || arg.startsWith('`');
|
|
708
|
+
}
|
|
709
|
+
|
|
489
710
|
function checkIfKnownType(
|
|
490
711
|
key: string,
|
|
491
712
|
functionAndAttributesKeysMapping: Record<string, string[]>,
|
|
@@ -495,19 +716,20 @@ function checkIfKnownType(
|
|
|
495
716
|
let hasStrongArrayEvidence = false;
|
|
496
717
|
let hasOnlyAmbiguousArrayMethods = true;
|
|
497
718
|
let hasLengthAccess = false;
|
|
498
|
-
let
|
|
719
|
+
let hasIncludesOrIndexOfWithVariable = false;
|
|
720
|
+
|
|
721
|
+
const entries = functionAndAttributesKeysMapping[key];
|
|
722
|
+
if (!entries || entries.length === 0) return;
|
|
499
723
|
|
|
500
|
-
for (const functionOrAttributeName of
|
|
501
|
-
[]) {
|
|
724
|
+
for (const functionOrAttributeName of entries) {
|
|
502
725
|
// Extract the method name without arguments for checking against ambiguous list
|
|
503
726
|
const methodName = functionOrAttributeName.split('(')[0].trim();
|
|
504
727
|
|
|
728
|
+
const knownType = knownMethodCalls(functionOrAttributeName);
|
|
505
729
|
const couldBeArray =
|
|
506
|
-
|
|
507
|
-
functionOrAttributeName === 'length';
|
|
730
|
+
knownType.includes('array') || functionOrAttributeName === 'length';
|
|
508
731
|
const couldBeString =
|
|
509
|
-
|
|
510
|
-
functionOrAttributeName === 'length';
|
|
732
|
+
knownType.includes('string') || functionOrAttributeName === 'length';
|
|
511
733
|
|
|
512
734
|
// Track .length access
|
|
513
735
|
if (functionOrAttributeName === 'length') {
|
|
@@ -515,8 +737,15 @@ function checkIfKnownType(
|
|
|
515
737
|
}
|
|
516
738
|
|
|
517
739
|
// Track methods that exist on both arrays and strings (like includes, indexOf)
|
|
518
|
-
if (
|
|
519
|
-
|
|
740
|
+
// Check if .includes() or .indexOf() is called with a variable argument (not a string literal).
|
|
741
|
+
// Pattern: arr.includes(item) -> likely array (checking if item exists)
|
|
742
|
+
// Pattern: str.includes('substring') -> likely string (checking for substring)
|
|
743
|
+
if (
|
|
744
|
+
(methodName === 'includes' || methodName === 'indexOf') &&
|
|
745
|
+
functionOrAttributeName.includes('(') &&
|
|
746
|
+
!hasStringLiteralArgument(functionOrAttributeName)
|
|
747
|
+
) {
|
|
748
|
+
hasIncludesOrIndexOfWithVariable = true;
|
|
520
749
|
}
|
|
521
750
|
|
|
522
751
|
// Check if this is strong evidence of an array (unambiguous array methods)
|
|
@@ -549,18 +778,20 @@ function checkIfKnownType(
|
|
|
549
778
|
return 'array';
|
|
550
779
|
}
|
|
551
780
|
|
|
552
|
-
// When
|
|
553
|
-
// prefer array. This pattern (
|
|
554
|
-
// is
|
|
555
|
-
|
|
556
|
-
if (isArray && hasLengthAccess && hasArrayStringAmbiguousMethod) {
|
|
781
|
+
// When .includes() or .indexOf() is called with a variable argument AND we have .length,
|
|
782
|
+
// prefer array. This pattern (arr.length > 0 && arr.includes(item)) is common for arrays.
|
|
783
|
+
// But str.includes('literal') is common for strings - that case is handled by hasStringLiteralArgument.
|
|
784
|
+
if (isArray && hasLengthAccess && hasIncludesOrIndexOfWithVariable) {
|
|
557
785
|
return 'array';
|
|
558
786
|
}
|
|
559
787
|
|
|
788
|
+
// When both array and string are possible, prefer string.
|
|
789
|
+
// Strings have .length, .slice(), .includes(), etc. just like arrays.
|
|
790
|
+
// We only infer 'array' if we have STRONG evidence (like .map, .filter, .reduce).
|
|
560
791
|
if (isString) return 'string';
|
|
561
792
|
|
|
562
|
-
// Only infer array if we have strong evidence
|
|
563
|
-
//
|
|
793
|
+
// Only infer array if we have strong evidence (already handled above)
|
|
794
|
+
// or non-ambiguous array methods that don't exist on strings
|
|
564
795
|
if (isArray && !hasOnlyAmbiguousArrayMethods) {
|
|
565
796
|
return 'array';
|
|
566
797
|
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { awsLog } from '~codeyam/utils';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Fixes null values for ID fields when the schema indicates they should be non-null numbers.
|
|
5
|
+
*
|
|
6
|
+
* The LLM sometimes generates `null` for ID fields (e.g., `"id": null`) when the schema
|
|
7
|
+
* type is `"number"` or `"number | undefined"` (but NOT `"number | null"`). This causes
|
|
8
|
+
* runtime issues when code checks `if (!data?.id)` expecting a truthy value.
|
|
9
|
+
*
|
|
10
|
+
* This function traverses data and schema together:
|
|
11
|
+
* - If field name looks like an ID field AND value is null AND schema doesn't allow null,
|
|
12
|
+
* replace with a valid default value (1 for numbers, generated UUID for strings)
|
|
13
|
+
*
|
|
14
|
+
* @param data The data object with potential null ID values
|
|
15
|
+
* @param schema The schema describing expected types
|
|
16
|
+
* @param path Current path in the data structure (for logging)
|
|
17
|
+
* @returns The data with null IDs fixed (mutates original)
|
|
18
|
+
*/
|
|
19
|
+
export default function fixNullIdsBySchema<T>(
|
|
20
|
+
data: T,
|
|
21
|
+
schema: unknown,
|
|
22
|
+
path: string = '',
|
|
23
|
+
): T {
|
|
24
|
+
// Handle null/undefined data
|
|
25
|
+
if (data === null || data === undefined) {
|
|
26
|
+
return data;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Only process objects
|
|
30
|
+
if (typeof data !== 'object') {
|
|
31
|
+
return data;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Handle arrays
|
|
35
|
+
if (Array.isArray(data)) {
|
|
36
|
+
// For arrays, the schema should be an array with one element describing the item type
|
|
37
|
+
const itemSchema = Array.isArray(schema) ? schema[0] : undefined;
|
|
38
|
+
for (let i = 0; i < data.length; i++) {
|
|
39
|
+
data[i] = fixNullIdsBySchema(data[i], itemSchema, `${path}[${i}]`);
|
|
40
|
+
}
|
|
41
|
+
return data;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Handle objects
|
|
45
|
+
const dataObj = data as Record<string, unknown>;
|
|
46
|
+
const schemaObj = schema as Record<string, unknown> | undefined;
|
|
47
|
+
|
|
48
|
+
for (const key of Object.keys(dataObj)) {
|
|
49
|
+
const value = dataObj[key];
|
|
50
|
+
const fieldSchema = schemaObj?.[key];
|
|
51
|
+
const fieldPath = path ? `${path}.${key}` : key;
|
|
52
|
+
|
|
53
|
+
if (value === null && isIdField(key)) {
|
|
54
|
+
// Check if schema indicates this should be a non-null number
|
|
55
|
+
const replacement = getIdReplacementValue(fieldSchema);
|
|
56
|
+
if (replacement !== null) {
|
|
57
|
+
dataObj[key] = replacement;
|
|
58
|
+
awsLog(
|
|
59
|
+
`CodeYam: Fixed null ID field "${fieldPath}": null -> ${replacement}`,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
63
|
+
// Recursively process nested objects/arrays
|
|
64
|
+
fixNullIdsBySchema(value, fieldSchema, fieldPath);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return data;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Pattern for field names that are likely ID fields.
|
|
73
|
+
* Matches: id, Id, ID, userId, user_id, quoteId, quote_id, etc.
|
|
74
|
+
*/
|
|
75
|
+
const ID_FIELD_PATTERNS = [
|
|
76
|
+
/^id$/i, // Exact match for "id", "Id", "ID"
|
|
77
|
+
/Id$/, // Ends with "Id" (camelCase): userId, quoteId
|
|
78
|
+
/_id$/i, // Ends with "_id" (snake_case): user_id, quote_id
|
|
79
|
+
/^.*_id$/i, // Contains "_id": some_object_id
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Determines if a field name looks like an ID field.
|
|
84
|
+
*/
|
|
85
|
+
function isIdField(fieldName: string): boolean {
|
|
86
|
+
return ID_FIELD_PATTERNS.some((pattern) => pattern.test(fieldName));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Gets the replacement value for a null ID based on schema type.
|
|
91
|
+
* Returns null if the schema allows null values (no replacement needed).
|
|
92
|
+
*
|
|
93
|
+
* @param fieldSchema The schema type for the field
|
|
94
|
+
* @returns Replacement value (1 for numbers, generated string for strings) or null if no replacement
|
|
95
|
+
*/
|
|
96
|
+
function getIdReplacementValue(fieldSchema: unknown): number | string | null {
|
|
97
|
+
// If no schema for this field, be conservative - don't replace
|
|
98
|
+
if (fieldSchema === undefined || fieldSchema === null) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// If schema is a string type definition
|
|
103
|
+
if (typeof fieldSchema === 'string') {
|
|
104
|
+
// If schema explicitly allows null, don't replace
|
|
105
|
+
if (fieldSchema.includes('null')) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// If schema is a number type, return 1 as default
|
|
110
|
+
if (
|
|
111
|
+
fieldSchema === 'number' ||
|
|
112
|
+
fieldSchema.startsWith('number') ||
|
|
113
|
+
fieldSchema.includes('number')
|
|
114
|
+
) {
|
|
115
|
+
return 1;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// If schema is a string type, return a generated ID
|
|
119
|
+
if (
|
|
120
|
+
fieldSchema === 'string' ||
|
|
121
|
+
fieldSchema.startsWith('string') ||
|
|
122
|
+
fieldSchema.includes('string')
|
|
123
|
+
) {
|
|
124
|
+
return 'id-1';
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return null;
|
|
129
|
+
}
|