@codeyam/codeyam-cli 0.1.0-staging.483fdc2 → 0.1.0-staging.62d4615
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 +7 -7
- package/analyzer-template/log.txt +3 -3
- package/analyzer-template/package.json +3 -3
- package/analyzer-template/packages/ai/package.json +2 -2
- package/analyzer-template/packages/ai/src/lib/analyzeScope.ts +9 -1
- package/analyzer-template/packages/ai/src/lib/astScopes/patterns/forInStatementHandler.ts +10 -17
- package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +154 -1
- package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.ts +5 -1
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.ts +11 -2
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.ts +2 -2
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/coerceObjectsToPrimitivesBySchema.ts +70 -0
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.ts +70 -1
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.ts +20 -1
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.ts +84 -19
- package/analyzer-template/packages/ai/src/lib/generateEntityDataStructure.ts +58 -3
- package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +14 -0
- package/analyzer-template/packages/ai/src/lib/isolateScopes.ts +51 -3
- package/analyzer-template/packages/analyze/index.ts +2 -0
- package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +51 -3
- package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities.ts +5 -0
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/TransformationTracer.ts +1315 -0
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.ts +4 -0
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +9 -1
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +194 -15
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +260 -22
- package/analyzer-template/packages/analyze/src/lib/index.ts +1 -0
- package/analyzer-template/packages/database/package.json +1 -1
- package/analyzer-template/packages/github/dist/types/src/types/ProjectMetadata.d.ts +3 -0
- package/analyzer-template/packages/github/dist/types/src/types/ProjectMetadata.d.ts.map +1 -1
- package/analyzer-template/packages/types/src/types/ProjectMetadata.ts +1 -0
- package/analyzer-template/packages/utils/dist/types/src/types/ProjectMetadata.d.ts +3 -0
- package/analyzer-template/packages/utils/dist/types/src/types/ProjectMetadata.d.ts.map +1 -1
- package/analyzer-template/project/constructMockCode.ts +36 -1
- package/analyzer-template/project/writeMockDataTsx.ts +111 -17
- package/analyzer-template/project/writeScenarioComponents.ts +60 -12
- package/analyzer-template/project/writeSimpleRoot.ts +21 -11
- package/background/src/lib/virtualized/project/constructMockCode.js +30 -1
- package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
- package/background/src/lib/virtualized/project/writeMockDataTsx.js +95 -13
- package/background/src/lib/virtualized/project/writeMockDataTsx.js.map +1 -1
- package/background/src/lib/virtualized/project/writeScenarioComponents.js +60 -15
- package/background/src/lib/virtualized/project/writeScenarioComponents.js.map +1 -1
- package/background/src/lib/virtualized/project/writeSimpleRoot.js +21 -11
- package/background/src/lib/virtualized/project/writeSimpleRoot.js.map +1 -1
- package/codeyam-cli/scripts/apply-setup.js +43 -9
- package/codeyam-cli/scripts/apply-setup.js.map +1 -1
- package/codeyam-cli/src/commands/memory.js +12 -21
- package/codeyam-cli/src/commands/memory.js.map +1 -1
- package/codeyam-cli/src/utils/backgroundServer.js +4 -0
- package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
- package/codeyam-cli/src/utils/install-skills.js +23 -0
- package/codeyam-cli/src/utils/install-skills.js.map +1 -1
- package/codeyam-cli/src/utils/queue/job.js +4 -0
- package/codeyam-cli/src/utils/queue/job.js.map +1 -1
- package/codeyam-cli/src/utils/ruleReflection/__tests__/confusionDetector.test.js +82 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/confusionDetector.test.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/contextBuilder.test.js +128 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/contextBuilder.test.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/assertRules.js +67 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/assertRules.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/captureFixture.js +105 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/captureFixture.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/loadCapturedFixture.js +34 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/loadCapturedFixture.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/runClaude.js +162 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/runClaude.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/setupTempProject.js +75 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/helpers/setupTempProject.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/ruleReflectionE2E.test.js +285 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/integration/ruleReflectionE2E.test.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/promptBuilder.test.js +83 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/promptBuilder.test.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/transcriptParser.test.js +127 -0
- package/codeyam-cli/src/utils/ruleReflection/__tests__/transcriptParser.test.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/confusionDetector.js +50 -0
- package/codeyam-cli/src/utils/ruleReflection/confusionDetector.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/contextBuilder.js +96 -0
- package/codeyam-cli/src/utils/ruleReflection/contextBuilder.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/index.js +5 -0
- package/codeyam-cli/src/utils/ruleReflection/index.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/promptBuilder.js +33 -0
- package/codeyam-cli/src/utils/ruleReflection/promptBuilder.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/transcriptParser.js +85 -0
- package/codeyam-cli/src/utils/ruleReflection/transcriptParser.js.map +1 -0
- package/codeyam-cli/src/utils/ruleReflection/types.js +5 -0
- package/codeyam-cli/src/utils/ruleReflection/types.js.map +1 -0
- package/codeyam-cli/src/utils/rules/__tests__/ruleState.test.js +293 -0
- package/codeyam-cli/src/utils/rules/__tests__/ruleState.test.js.map +1 -0
- package/codeyam-cli/src/utils/rules/index.js +1 -0
- package/codeyam-cli/src/utils/rules/index.js.map +1 -1
- package/codeyam-cli/src/utils/rules/parser.js +0 -28
- package/codeyam-cli/src/utils/rules/parser.js.map +1 -1
- package/codeyam-cli/src/utils/rules/ruleState.js +150 -0
- package/codeyam-cli/src/utils/rules/ruleState.js.map +1 -0
- package/codeyam-cli/src/utils/rules/staleness.js +14 -9
- package/codeyam-cli/src/utils/rules/staleness.js.map +1 -1
- package/codeyam-cli/src/webserver/app/lib/database.js +1 -0
- package/codeyam-cli/src/webserver/app/lib/database.js.map +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/CopyButton-CA3JxPb7.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{EntityItem-DsN1wKrm.js → EntityItem-B86KKU7e.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeBadge-DLqD3qNt.js → EntityTypeBadge-B5ctlSYt.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-Ba2JVPzP.js → EntityTypeIcon-BqY8gDAW.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{InlineSpinner-C8lyxW9k.js → InlineSpinner-ClaLpuOo.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{InteractivePreview-aht4aafF.js → InteractivePreview-BDhPilK7.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{LibraryFunctionPreview-CVtiBnY5.js → LibraryFunctionPreview-VeqEBv9v.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{LoadingDots-B0GLXMsr.js → LoadingDots-Bs7Nn1Jr.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{LogViewer-xgeCVgSM.js → LogViewer-Bm3PmcCz.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{ReportIssueModal-OApQuNyq.js → ReportIssueModal-C6PKeMYR.js} +3 -8
- package/codeyam-cli/src/webserver/build/client/assets/{SafeScreenshot-DuDvi0jm.js → SafeScreenshot-Gq3Ocjo6.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-DzccYyI8.js → ScenarioViewer-BNLaXBHR.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{TruncatedFilePath-DyFZkK0l.js → TruncatedFilePath-CiwXDxLh.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{_index-BwqWJOgH.js → _index-B3TDXxnk.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{activity.(_tab)-BwavGCpm.js → activity.(_tab)-DD1r_QU0.js} +6 -11
- package/codeyam-cli/src/webserver/build/client/assets/agent-transcripts-DfKzxuoe.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.agent-transcripts-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.save-fixture-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/book-open-PttOB2SF.js +6 -0
- package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-Cx24_aWc.js → chevron-down-TJp6ofnp.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{chunk-EPOLDU6W-CXRTFQ3F.js → chunk-JZWAC4HX-JE9ZIoBl.js} +12 -12
- package/codeyam-cli/src/webserver/build/client/assets/{circle-check-BOARzkeR.js → circle-check-CXhHQYrI.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/copy-6y9ALfGT.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/{createLucideIcon-BdhJEx6B.js → createLucideIcon-Ca9fAY46.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{dev.empty-BBnGWYga.js → dev.empty-C5lqplTC.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-BJUiQqZF.js → entity._sha._-n38keI1k.js} +10 -10
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.fullscreen-DavjRmOY.js → entity._sha.scenarios._scenarioId.fullscreen-CBoafmVs.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.create-scenario-D1T4TGjf.js → entity._sha_.create-scenario-DGgZjdFg.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-CTBG2mmz.js → entity._sha_.edit._scenarioId-38yPijoD.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entry.client-CS2cb_eZ.js → entry.client-BSHEfydn.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{fileTableUtils-DMJ7zii9.js → fileTableUtils-DCPhhSMo.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{files-CJ6lTdTA.js → files-Dk8wkAS7.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{git-CPTZZ-JZ.js → git-DXnyr8uP.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/globals-Bh6jH0cL.css +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{index-lzqtyFU8.js → index-CcsFv748.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{index-B1h680n5.js → index-ChN9-fAY.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/labs-BUvfJMNR.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-B7B9V-bu.js → loader-circle-CTqLEAGU.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-d4e77269.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/memory-DCHBwHou.js +76 -0
- package/codeyam-cli/src/webserver/build/client/assets/pause-D6vreykR.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/root-D6oziHts.js +62 -0
- package/codeyam-cli/src/webserver/build/client/assets/{search-CxXUmBSd.js → search-B8VUL8nl.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{settings-CS5f3WzT.js → settings-B2X7lJgQ.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{simulations-DwFIBT09.js → simulations-CPoAg7Zo.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/terminal-BrCP7uQo.js +11 -0
- package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-B6LgvRJg.js → triangle-alert-BZz2NjYa.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useCustomSizes-C1v1PQzo.js → useCustomSizes-DNwUduNu.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-aSv48UbS.js → useLastLogLine-COky1GVF.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useReportContext-DYxHZQuP.js → useReportContext-CpZgwliL.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useToast-mBRpZPiu.js → useToast-Bv9JFvUO.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{index-TD1f-DHV.js → index-C0KrUQp-.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/server-build-C2h1v1XD.js +260 -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 +9 -10
- package/codeyam-cli/templates/codeyam:memory.md +10 -9
- package/codeyam-cli/templates/codeyam:new-rule.md +0 -39
- package/codeyam-cli/templates/rule-notification-hook.py +54 -0
- package/codeyam-cli/templates/rule-reflection-hook.py +356 -89
- package/codeyam-cli/templates/rules-instructions.md +19 -22
- package/package.json +2 -2
- package/packages/ai/src/lib/analyzeScope.js +7 -1
- package/packages/ai/src/lib/analyzeScope.js.map +1 -1
- package/packages/ai/src/lib/astScopes/patterns/forInStatementHandler.js +10 -14
- package/packages/ai/src/lib/astScopes/patterns/forInStatementHandler.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +134 -1
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.js +5 -1
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/frameworks/JavascriptFrameworkManager.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js +11 -2
- package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js +2 -2
- package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/coerceObjectsToPrimitivesBySchema.js +63 -0
- package/packages/ai/src/lib/dataStructure/helpers/coerceObjectsToPrimitivesBySchema.js.map +1 -0
- package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js +63 -1
- package/packages/ai/src/lib/dataStructure/helpers/convertDotNotation.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.js +15 -1
- package/packages/ai/src/lib/dataStructure/helpers/convertTypeAnnotationsToValues.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js +78 -17
- package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js.map +1 -1
- package/packages/ai/src/lib/generateEntityDataStructure.js +46 -2
- package/packages/ai/src/lib/generateEntityDataStructure.js.map +1 -1
- package/packages/ai/src/lib/generateEntityScenarioData.js +10 -0
- package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
- package/packages/ai/src/lib/isolateScopes.js +39 -3
- package/packages/ai/src/lib/isolateScopes.js.map +1 -1
- package/packages/analyze/index.js +1 -0
- package/packages/analyze/index.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +41 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities.js +3 -0
- package/packages/analyze/src/lib/files/analyze/analyzeEntities.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/TransformationTracer.js +880 -0
- package/packages/analyze/src/lib/files/scenarios/TransformationTracer.js.map +1 -0
- package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js +5 -1
- package/packages/analyze/src/lib/files/scenarios/enrichArrayTypesFromChildSignatures.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js +9 -1
- package/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +116 -13
- package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +231 -22
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
- package/packages/analyze/src/lib/index.js +1 -0
- package/packages/analyze/src/lib/index.js.map +1 -1
- package/codeyam-cli/src/utils/reviewedRules.js +0 -92
- package/codeyam-cli/src/utils/reviewedRules.js.map +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/copy-Bb-80kDT.js +0 -6
- package/codeyam-cli/src/webserver/build/client/assets/file-code-Dhef1kWN.js +0 -6
- package/codeyam-cli/src/webserver/build/client/assets/globals-CX9f-5xM.css +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-bba56ec1.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/memory-DuTFSyJ2.js +0 -92
- package/codeyam-cli/src/webserver/build/client/assets/root-DTfSQARG.js +0 -62
- package/codeyam-cli/src/webserver/build/server/assets/server-build-BQ-1XyEa.js +0 -258
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"buildTimestamp": "2026-02-
|
|
3
|
-
"buildTime":
|
|
4
|
-
"gitCommit": "
|
|
2
|
+
"buildTimestamp": "2026-02-09T18:13:24.937Z",
|
|
3
|
+
"buildTime": 1770660804937,
|
|
4
|
+
"gitCommit": "62d46157debb3cc4a12427c10951e3f6e656f734",
|
|
5
5
|
"nodeVersion": "v20.20.0",
|
|
6
|
-
"contentHash": "
|
|
7
|
-
"buildNumber":
|
|
8
|
-
"semanticVersion": "0.1.
|
|
9
|
-
"version": "0.1.
|
|
6
|
+
"contentHash": "e793537596b5586bd9f78099350b6ee878c8092b4ddc8bf4b0e5243712634ad3",
|
|
7
|
+
"buildNumber": 596,
|
|
8
|
+
"semanticVersion": "0.1.596",
|
|
9
|
+
"version": "0.1.596 (2026-02-09T18:13+e793537)"
|
|
10
10
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
|
-
[2/
|
|
3
|
-
[2/
|
|
2
|
+
[2/9/2026, 6:13:24 PM] > codeyam-combo@1.0.0 mergeDependencies
|
|
3
|
+
[2/9/2026, 6:13:24 PM] > node ./scripts/mergePackageJsonFiles.cjs
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
[2/
|
|
6
|
+
[2/9/2026, 6:13:24 PM] Merged dependencies into root package.json
|
|
7
7
|
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"jest": "^30.2.0",
|
|
31
31
|
"jsdom": "^27.4.0",
|
|
32
32
|
"jsonc-parser": "^3.2.1",
|
|
33
|
-
"lru-cache": "^11.2.
|
|
33
|
+
"lru-cache": "^11.2.5",
|
|
34
34
|
"openai": "^6.16.0",
|
|
35
35
|
"p-queue": "^8.1.0",
|
|
36
36
|
"p-retry": "^7.1.1",
|
|
@@ -44,11 +44,11 @@
|
|
|
44
44
|
"pluralize": "^8.0.0",
|
|
45
45
|
"yargs": "^18.0.0",
|
|
46
46
|
"json5": "^2.2.3",
|
|
47
|
-
"@anthropic-ai/sdk": "^0.
|
|
47
|
+
"@anthropic-ai/sdk": "^0.74.0",
|
|
48
48
|
"@aws-sdk/s3-request-presigner": "^3.940.0",
|
|
49
49
|
"better-sqlite3": "^12.4.1",
|
|
50
50
|
"fetch-retry": "^6.0.0",
|
|
51
|
-
"kysely": "^0.28.
|
|
51
|
+
"kysely": "^0.28.11",
|
|
52
52
|
"pg": "^8.16.3",
|
|
53
53
|
"@octokit/request": "^10.0.3",
|
|
54
54
|
"lucide-react": "^0.556.0",
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
"author": "",
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@anthropic-ai/sdk": "^0.
|
|
12
|
+
"@anthropic-ai/sdk": "^0.74.0",
|
|
13
13
|
"jsdom": "^27.4.0",
|
|
14
14
|
"p-queue": "^8.1.0",
|
|
15
15
|
"p-retry": "^7.1.1",
|
|
16
16
|
"piscina": "^5.1.4",
|
|
17
|
-
"lru-cache": "^11.2.
|
|
17
|
+
"lru-cache": "^11.2.5"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@types/jsdom": "^27.0.0"
|
|
@@ -123,10 +123,17 @@ function ensureWorkerPool() {
|
|
|
123
123
|
// Note: WORKER_PATH is null when __mocks__/analyzeScope.ts is active
|
|
124
124
|
const { WORKER_PATH } = analyzeScopeWorkerPaths();
|
|
125
125
|
|
|
126
|
+
// Disable workers when tracing is enabled - we need access to ScopeDataStructure
|
|
127
|
+
// instance in the main thread to capture pre-serialization state
|
|
128
|
+
const tracingEnabled =
|
|
129
|
+
process.env.CODEYAM_TRACE_TRANSFORMS === '1' ||
|
|
130
|
+
process.env.CODEYAM_TRACE_TRANSFORMS === 'true';
|
|
131
|
+
|
|
126
132
|
if (
|
|
127
133
|
process.env.USE_WORKER_THREADS &&
|
|
128
134
|
WORKER_PATH &&
|
|
129
|
-
fs.existsSync(WORKER_PATH)
|
|
135
|
+
fs.existsSync(WORKER_PATH) &&
|
|
136
|
+
!tracingEnabled
|
|
130
137
|
) {
|
|
131
138
|
console.log('CodeYam: Using worker threads for analyzeScope', {
|
|
132
139
|
WORKER_PATH,
|
|
@@ -159,6 +166,7 @@ function ensureWorkerPool() {
|
|
|
159
166
|
WORKER_PATH,
|
|
160
167
|
workerExists: WORKER_PATH ? fs.existsSync(WORKER_PATH) : false,
|
|
161
168
|
USE_WORKER_THREADS: process.env.USE_WORKER_THREADS,
|
|
169
|
+
tracingEnabled,
|
|
162
170
|
});
|
|
163
171
|
workerPool = null; // Explicitly set to indicate "no workers"
|
|
164
172
|
}
|
|
@@ -22,11 +22,8 @@ export class ForInStatementHandler implements PatternHandler {
|
|
|
22
22
|
// Process the expression being iterated over first (e.g., object)
|
|
23
23
|
context.processExpression(node.expression);
|
|
24
24
|
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// If the initializer is a variable declaration with an identifier, establish equivalence
|
|
29
|
-
// to indicate it's iterating over the keys of the expression
|
|
25
|
+
// If the initializer is a variable declaration with an identifier,
|
|
26
|
+
// type it as 'string' since for-in keys are always strings
|
|
30
27
|
if (ts.isVariableDeclarationList(node.initializer)) {
|
|
31
28
|
const declarations = node.initializer.declarations;
|
|
32
29
|
if (
|
|
@@ -36,25 +33,21 @@ export class ForInStatementHandler implements PatternHandler {
|
|
|
36
33
|
) {
|
|
37
34
|
const variableName = StructuredPath.fromBase(declarations[0].name.text);
|
|
38
35
|
|
|
39
|
-
//
|
|
36
|
+
// Type the key variable as 'string' — for-in keys are always strings.
|
|
37
|
+
// Note: We intentionally do NOT equivalence the key variable to
|
|
38
|
+
// expressionPath[*key*]. The key variable is the KEY (a string),
|
|
39
|
+
// while [*key*] in the schema represents the VALUE at a dynamic key.
|
|
40
|
+
// Creating that equivalence would cause the 'string' type to propagate
|
|
41
|
+
// to the value path. The value access (e.g., obj[key]) is handled
|
|
42
|
+
// correctly by the element access handler in processExpression.
|
|
40
43
|
context.addType(variableName, 'string');
|
|
41
|
-
|
|
42
|
-
if (expressionPath) {
|
|
43
|
-
// For for...in loops, the variable is equivalent to the keys of the object
|
|
44
|
-
// We represent this with a *key* suffix to indicate it's a key, not a value
|
|
45
|
-
context.addEquivalence(variableName, expressionPath.withKey('key'));
|
|
46
|
-
}
|
|
47
44
|
}
|
|
48
45
|
} else if (ts.isIdentifier(node.initializer)) {
|
|
49
46
|
// If the initializer is directly an identifier (rare but possible)
|
|
50
47
|
const variableName = StructuredPath.fromBase(node.initializer.text);
|
|
51
48
|
|
|
52
|
-
//
|
|
49
|
+
// See comment above — type as string but don't equivalence to value path
|
|
53
50
|
context.addType(variableName, 'string');
|
|
54
|
-
|
|
55
|
-
if (expressionPath) {
|
|
56
|
-
context.addEquivalence(variableName, expressionPath.withKey('key'));
|
|
57
|
-
}
|
|
58
51
|
} else {
|
|
59
52
|
context.processExpression(node.initializer);
|
|
60
53
|
}
|
|
@@ -799,6 +799,11 @@ export class ScopeDataStructure {
|
|
|
799
799
|
return;
|
|
800
800
|
}
|
|
801
801
|
|
|
802
|
+
// PERF: Early exit for paths with repeated function-call signature patterns
|
|
803
|
+
if (this.hasExcessivePatternRepetition(path)) {
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
|
|
802
807
|
// Update chain metadata for database tracking
|
|
803
808
|
if (equivalencyValueChain.length > 0) {
|
|
804
809
|
equivalencyValueChain[equivalencyValueChain.length - 1].addToSchemaId =
|
|
@@ -1486,6 +1491,15 @@ export class ScopeDataStructure {
|
|
|
1486
1491
|
|
|
1487
1492
|
const bestValue = selectBestValue(value1, value2);
|
|
1488
1493
|
|
|
1494
|
+
// PERF: Skip paths with repeated function-call signature patterns
|
|
1495
|
+
// to prevent recursive type expansion (e.g., string.localeCompare returns string)
|
|
1496
|
+
if (
|
|
1497
|
+
this.hasExcessivePatternRepetition(schemaPath) ||
|
|
1498
|
+
this.hasExcessivePatternRepetition(equivalentSchemaPath)
|
|
1499
|
+
) {
|
|
1500
|
+
continue;
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1489
1503
|
scopeNode.schema[schemaPath] = bestValue;
|
|
1490
1504
|
equivalentScopeNode.schema[equivalentSchemaPath] = bestValue;
|
|
1491
1505
|
} else if (
|
|
@@ -1499,6 +1513,11 @@ export class ScopeDataStructure {
|
|
|
1499
1513
|
...remainingSchemaPathParts,
|
|
1500
1514
|
]);
|
|
1501
1515
|
|
|
1516
|
+
// PERF: Skip paths with repeated function-call signature patterns
|
|
1517
|
+
if (this.hasExcessivePatternRepetition(newEquivalentPath)) {
|
|
1518
|
+
continue;
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1502
1521
|
equivalentScopeNode.schema[newEquivalentPath] =
|
|
1503
1522
|
scopeNode.schema[schemaPath];
|
|
1504
1523
|
}
|
|
@@ -1618,6 +1637,23 @@ export class ScopeDataStructure {
|
|
|
1618
1637
|
}
|
|
1619
1638
|
}
|
|
1620
1639
|
|
|
1640
|
+
// Check for repeated function calls that indicate recursive type expansion.
|
|
1641
|
+
// E.g., localeCompare(b[])...localeCompare(b[]) means string.localeCompare
|
|
1642
|
+
// returns a type that again has localeCompare, causing infinite expansion.
|
|
1643
|
+
// We extract all function call patterns like "funcName(args)" and check if
|
|
1644
|
+
// the same normalized call appears more than once.
|
|
1645
|
+
const funcCallPattern = /(?:^|\.)[^.([]+\([^)]*\)/g;
|
|
1646
|
+
const funcCallMatches = path.match(funcCallPattern);
|
|
1647
|
+
if (funcCallMatches && funcCallMatches.length > 1) {
|
|
1648
|
+
const seen = new Set<string>();
|
|
1649
|
+
for (const match of funcCallMatches) {
|
|
1650
|
+
// Strip leading dot and normalize array indices
|
|
1651
|
+
const normalized = match.replace(/^\./, '').replace(/\[\d+\]/g, '[]');
|
|
1652
|
+
if (seen.has(normalized)) return true;
|
|
1653
|
+
seen.add(normalized);
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1621
1657
|
// For longer paths, detect any repeated multi-part segments we haven't explicitly listed
|
|
1622
1658
|
const pathParts = this.splitPath(path);
|
|
1623
1659
|
if (pathParts.length <= 6) {
|
|
@@ -2574,6 +2610,7 @@ export class ScopeDataStructure {
|
|
|
2574
2610
|
relevantSubPathParts.every((part, i) => part === schemaPathParts[i]) &&
|
|
2575
2611
|
equivalentValue.scopeNodeName === scopeNode.name
|
|
2576
2612
|
) {
|
|
2613
|
+
// DEBUG
|
|
2577
2614
|
continue;
|
|
2578
2615
|
}
|
|
2579
2616
|
|
|
@@ -3291,6 +3328,14 @@ export class ScopeDataStructure {
|
|
|
3291
3328
|
}
|
|
3292
3329
|
}
|
|
3293
3330
|
|
|
3331
|
+
// Ensure parameter-to-signature equivalencies are fully propagated.
|
|
3332
|
+
// When a parameter variable (e.g., `node`) is equivalenced to `signature[N]`,
|
|
3333
|
+
// all sub-paths of that variable should also appear under `signature[N]`.
|
|
3334
|
+
// This handles cases where the sub-path was added to the schema via a propagation
|
|
3335
|
+
// chain that already included the variable↔signature equivalency, causing the
|
|
3336
|
+
// cycle detection to prevent the reverse mapping.
|
|
3337
|
+
this.propagateParameterToSignaturePaths(scopeNode);
|
|
3338
|
+
|
|
3294
3339
|
fillInSchemaGapsAndUnknowns(scopeNode, fillInUnknowns);
|
|
3295
3340
|
|
|
3296
3341
|
if (final) {
|
|
@@ -3305,6 +3350,50 @@ export class ScopeDataStructure {
|
|
|
3305
3350
|
}
|
|
3306
3351
|
}
|
|
3307
3352
|
|
|
3353
|
+
/**
|
|
3354
|
+
* For each equivalency where a simple variable maps to signature[N],
|
|
3355
|
+
* ensure all sub-paths of that variable are reflected under signature[N].
|
|
3356
|
+
*/
|
|
3357
|
+
private propagateParameterToSignaturePaths(scopeNode: ScopeNode) {
|
|
3358
|
+
// Find variable → signature[N] equivalencies
|
|
3359
|
+
for (const [varName, equivalencies] of Object.entries(
|
|
3360
|
+
scopeNode.equivalencies,
|
|
3361
|
+
)) {
|
|
3362
|
+
// Only process simple variable names (no dots, brackets, or parens)
|
|
3363
|
+
if (
|
|
3364
|
+
varName.includes('.') ||
|
|
3365
|
+
varName.includes('[') ||
|
|
3366
|
+
varName.includes('(')
|
|
3367
|
+
) {
|
|
3368
|
+
continue;
|
|
3369
|
+
}
|
|
3370
|
+
|
|
3371
|
+
for (const equiv of equivalencies) {
|
|
3372
|
+
if (
|
|
3373
|
+
equiv.scopeNodeName === scopeNode.name &&
|
|
3374
|
+
equiv.schemaPath.startsWith('signature[')
|
|
3375
|
+
) {
|
|
3376
|
+
const signaturePath = equiv.schemaPath;
|
|
3377
|
+
const varPrefix = varName + '.';
|
|
3378
|
+
const varBracketPrefix = varName + '[';
|
|
3379
|
+
|
|
3380
|
+
// Find all schema keys starting with the variable
|
|
3381
|
+
for (const key in scopeNode.schema) {
|
|
3382
|
+
if (key.startsWith(varPrefix) || key.startsWith(varBracketPrefix)) {
|
|
3383
|
+
const suffix = key.slice(varName.length);
|
|
3384
|
+
const sigKey = signaturePath + suffix;
|
|
3385
|
+
|
|
3386
|
+
// Only add if the signature path doesn't already exist
|
|
3387
|
+
if (!scopeNode.schema[sigKey]) {
|
|
3388
|
+
scopeNode.schema[sigKey] = scopeNode.schema[key];
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
}
|
|
3394
|
+
}
|
|
3395
|
+
}
|
|
3396
|
+
|
|
3308
3397
|
private filterAndConvertSchema({
|
|
3309
3398
|
filterPath,
|
|
3310
3399
|
newPath,
|
|
@@ -3391,6 +3480,9 @@ export class ScopeDataStructure {
|
|
|
3391
3480
|
equivalentValueSchemaPathParts.length,
|
|
3392
3481
|
),
|
|
3393
3482
|
]);
|
|
3483
|
+
// PERF: Skip keys with repeated function-call signature patterns
|
|
3484
|
+
// to prevent recursive type expansion (e.g., string.localeCompare returns string)
|
|
3485
|
+
if (this.hasExcessivePatternRepetition(newKey)) continue;
|
|
3394
3486
|
resolvedSchema[newKey] = value;
|
|
3395
3487
|
}
|
|
3396
3488
|
}
|
|
@@ -3413,6 +3505,8 @@ export class ScopeDataStructure {
|
|
|
3413
3505
|
if (!subSchema) continue;
|
|
3414
3506
|
|
|
3415
3507
|
for (const resolvedKey in subSchema) {
|
|
3508
|
+
// PERF: Skip keys with repeated function-call signature patterns
|
|
3509
|
+
if (this.hasExcessivePatternRepetition(resolvedKey)) continue;
|
|
3416
3510
|
if (
|
|
3417
3511
|
!resolvedSchema[resolvedKey] ||
|
|
3418
3512
|
subSchema[resolvedKey] === 'unknown'
|
|
@@ -3927,6 +4021,54 @@ export class ScopeDataStructure {
|
|
|
3927
4021
|
}
|
|
3928
4022
|
}
|
|
3929
4023
|
|
|
4024
|
+
// Enrich schema with deeply nested paths from internal function call scopes.
|
|
4025
|
+
// When a function call like traverse(tree) exists, and traverse's scope has
|
|
4026
|
+
// signature[0].children[path][entityName] (from propagateParameterToSignaturePaths),
|
|
4027
|
+
// we need to map those paths back to the argument variable (tree) in this scope.
|
|
4028
|
+
// This handles cases where cycle detection prevented the equivalency chain from
|
|
4029
|
+
// propagating deep paths during Phase 2 batch queue processing.
|
|
4030
|
+
for (const equivalenceKey in equivalencies ?? {}) {
|
|
4031
|
+
// Look for keys matching function call pattern: funcName(...).signature[N]
|
|
4032
|
+
const funcCallMatch = equivalenceKey.match(
|
|
4033
|
+
/^([^(]+)\(.*?\)\.(signature\[\d+\])$/,
|
|
4034
|
+
);
|
|
4035
|
+
if (!funcCallMatch) continue;
|
|
4036
|
+
|
|
4037
|
+
const calledFunctionName = funcCallMatch[1];
|
|
4038
|
+
const signatureParam = funcCallMatch[2]; // e.g., "signature[0]"
|
|
4039
|
+
|
|
4040
|
+
for (const equivalenceValue of equivalencies[equivalenceKey]) {
|
|
4041
|
+
if (equivalenceValue.scopeNodeName !== scopeName) continue;
|
|
4042
|
+
|
|
4043
|
+
const targetVariable = equivalenceValue.schemaPath;
|
|
4044
|
+
|
|
4045
|
+
// Get the called function's schema (includes propagated parameter paths)
|
|
4046
|
+
const childSchema = this.getSchema({
|
|
4047
|
+
scopeName: calledFunctionName,
|
|
4048
|
+
});
|
|
4049
|
+
if (!childSchema) continue;
|
|
4050
|
+
|
|
4051
|
+
// Map child function's signature paths to parent variable paths
|
|
4052
|
+
const sigPrefix = signatureParam + '.';
|
|
4053
|
+
const sigBracketPrefix = signatureParam + '[';
|
|
4054
|
+
for (const childKey in childSchema) {
|
|
4055
|
+
let suffix: string | null = null;
|
|
4056
|
+
if (childKey.startsWith(sigPrefix)) {
|
|
4057
|
+
suffix = childKey.slice(signatureParam.length);
|
|
4058
|
+
} else if (childKey.startsWith(sigBracketPrefix)) {
|
|
4059
|
+
suffix = childKey.slice(signatureParam.length);
|
|
4060
|
+
}
|
|
4061
|
+
|
|
4062
|
+
if (suffix !== null) {
|
|
4063
|
+
const parentKey = targetVariable + suffix;
|
|
4064
|
+
if (!schema[parentKey]) {
|
|
4065
|
+
schema[parentKey] = childSchema[childKey];
|
|
4066
|
+
}
|
|
4067
|
+
}
|
|
4068
|
+
}
|
|
4069
|
+
}
|
|
4070
|
+
}
|
|
4071
|
+
|
|
3930
4072
|
// Propagate nested paths from variables to their signature equivalents
|
|
3931
4073
|
// e.g., if workouts = signature[0].workouts, then workouts[].title becomes
|
|
3932
4074
|
// signature[0].workouts[].title
|
|
@@ -5336,11 +5478,22 @@ export class ScopeDataStructure {
|
|
|
5336
5478
|
}
|
|
5337
5479
|
}
|
|
5338
5480
|
|
|
5481
|
+
// Enrich the schema with inferred types by applying fillInSchemaGapsAndUnknowns.
|
|
5482
|
+
// This ensures the serialized schema has the same type inference as getReturnValue().
|
|
5483
|
+
// Without this, evidence like "entities[].analyses: array" becomes "unknown".
|
|
5484
|
+
const enrichedSchema = { ...efc.schema };
|
|
5485
|
+
const tempScopeNode = {
|
|
5486
|
+
name: efc.name,
|
|
5487
|
+
schema: enrichedSchema,
|
|
5488
|
+
equivalencies: efc.equivalencies ?? {},
|
|
5489
|
+
};
|
|
5490
|
+
fillInSchemaGapsAndUnknowns(tempScopeNode, true);
|
|
5491
|
+
|
|
5339
5492
|
return {
|
|
5340
5493
|
name: efc.name,
|
|
5341
5494
|
callSignature: efc.callSignature,
|
|
5342
5495
|
callScope: efc.callScope,
|
|
5343
|
-
schema:
|
|
5496
|
+
schema: enrichedSchema,
|
|
5344
5497
|
equivalencies: efc.equivalencies
|
|
5345
5498
|
? Object.entries(efc.equivalencies).reduce(
|
|
5346
5499
|
(acc, [key, vars]) => {
|
|
@@ -72,7 +72,11 @@ export class JavascriptFrameworkManager implements EquivalencyManager {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
finalize(scopeNode: ScopeNode, scopeDataStructure: ScopeDataStructure) {
|
|
75
|
-
cleanNonObjectFunctions
|
|
75
|
+
// Don't call cleanNonObjectFunctions with final=true here.
|
|
76
|
+
// The aggressive cleanup (transformKeyMapping, clearAttributes) removes method call
|
|
77
|
+
// evidence like .includes() before type inference can use it.
|
|
78
|
+
// Instead, defer final cleanup to toSerializable() when we're done with inference.
|
|
79
|
+
cleanNonObjectFunctions(scopeNode, scopeDataStructure, false);
|
|
76
80
|
cleanKnownObjectFunctions(scopeNode, scopeDataStructure);
|
|
77
81
|
this.handleUniformArrays(scopeNode, scopeDataStructure);
|
|
78
82
|
}
|
package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.ts
CHANGED
|
@@ -172,9 +172,18 @@ function scrub(
|
|
|
172
172
|
const rawMethod = rawToken.split('(')[0];
|
|
173
173
|
|
|
174
174
|
// Check if it's a prototype method (e.g., map, filter, toString)
|
|
175
|
+
// Only match when the token is actually a method reference/call:
|
|
176
|
+
// - Has parentheses (explicit call like map(), filter(x => x))
|
|
177
|
+
// - OR is typed as "function" (method reference like .split)
|
|
178
|
+
// Bare property names that happen to match method names
|
|
179
|
+
// (like .entries = "array", .values = "object") are preserved.
|
|
175
180
|
if (protoMethodSets[rootKind].has(rawMethod)) {
|
|
176
|
-
|
|
177
|
-
|
|
181
|
+
const isMethodCall = rawToken.includes('(');
|
|
182
|
+
const isMethodReference = mapping[keyPath] === 'function';
|
|
183
|
+
if (isMethodCall || isMethodReference) {
|
|
184
|
+
onRemove(keyPath);
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
178
187
|
}
|
|
179
188
|
|
|
180
189
|
// Check if it's a built-in property (e.g., length on arrays/strings)
|
package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.ts
CHANGED
|
@@ -510,7 +510,7 @@ function removeNonTransformingArrayMethods(variablePath: string): string {
|
|
|
510
510
|
const part = keyParts[i];
|
|
511
511
|
|
|
512
512
|
const arrayMethod = getMethodName(part);
|
|
513
|
-
if (isValidArrayMethod(arrayMethod)) {
|
|
513
|
+
if (isValidFunctionCall(part) && isValidArrayMethod(arrayMethod)) {
|
|
514
514
|
const nextPart = keyParts[i + 1];
|
|
515
515
|
if (
|
|
516
516
|
!nonTransformingArrayMethodsSet.has(arrayMethod) ||
|
|
@@ -550,7 +550,7 @@ function removeIsolatingArrayMethods(
|
|
|
550
550
|
const part = keyParts[i];
|
|
551
551
|
|
|
552
552
|
const arrayMethod = getMethodName(part);
|
|
553
|
-
if (isValidArrayMethod(arrayMethod)) {
|
|
553
|
+
if (isValidFunctionCall(part) && isValidArrayMethod(arrayMethod)) {
|
|
554
554
|
const nextPart = keyParts[i + 1];
|
|
555
555
|
const prevPart = i > 1 ? keyParts[i - 1] : undefined;
|
|
556
556
|
if (
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coerces object/array values to primitive types when the schema expects a primitive.
|
|
3
|
+
*
|
|
4
|
+
* The LLM sometimes generates an object or array where the schema expects a primitive
|
|
5
|
+
* type like "string", "number", or "boolean". For example:
|
|
6
|
+
* Schema: { body: "string" }
|
|
7
|
+
* LLM output: { body: { "env": "production" } }
|
|
8
|
+
*
|
|
9
|
+
* This causes runtime errors like `TypeError: body.match is not a function` because
|
|
10
|
+
* the code expects a string but gets an object.
|
|
11
|
+
*
|
|
12
|
+
* Coercion rules:
|
|
13
|
+
* - object/array → string: JSON.stringify
|
|
14
|
+
* - object/array → number: 0
|
|
15
|
+
* - object/array → boolean: false
|
|
16
|
+
*
|
|
17
|
+
* @param data The mock data object to coerce (mutated in place)
|
|
18
|
+
* @param schema The schema describing expected types
|
|
19
|
+
*/
|
|
20
|
+
export default function coerceObjectsToPrimitivesBySchema<T>(
|
|
21
|
+
data: T,
|
|
22
|
+
schema: unknown,
|
|
23
|
+
): T {
|
|
24
|
+
if (data === null || data === undefined) {
|
|
25
|
+
return data;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (typeof data !== 'object') {
|
|
29
|
+
return data;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (Array.isArray(data)) {
|
|
33
|
+
const itemSchema = Array.isArray(schema) ? schema[0] : undefined;
|
|
34
|
+
for (let i = 0; i < data.length; i++) {
|
|
35
|
+
data[i] = coerceObjectsToPrimitivesBySchema(data[i], itemSchema);
|
|
36
|
+
}
|
|
37
|
+
return data;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const dataObj = data as Record<string, unknown>;
|
|
41
|
+
const schemaObj = schema as Record<string, unknown> | undefined;
|
|
42
|
+
|
|
43
|
+
for (const key of Object.keys(dataObj)) {
|
|
44
|
+
const value = dataObj[key];
|
|
45
|
+
const fieldSchema = schemaObj?.[key];
|
|
46
|
+
|
|
47
|
+
if (value === null || value === undefined) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (typeof value === 'object' && typeof fieldSchema === 'string') {
|
|
52
|
+
// Schema expects a primitive but the value is an object/array.
|
|
53
|
+
// Coerce to the expected type.
|
|
54
|
+
const schemaType = fieldSchema.toLowerCase();
|
|
55
|
+
|
|
56
|
+
if (schemaType.includes('string')) {
|
|
57
|
+
dataObj[key] = JSON.stringify(value);
|
|
58
|
+
} else if (schemaType.includes('number')) {
|
|
59
|
+
dataObj[key] = 0;
|
|
60
|
+
} else if (schemaType.includes('boolean')) {
|
|
61
|
+
dataObj[key] = false;
|
|
62
|
+
}
|
|
63
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
64
|
+
// Both value and schema are objects — recurse
|
|
65
|
+
coerceObjectsToPrimitivesBySchema(value, fieldSchema);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return data;
|
|
70
|
+
}
|
|
@@ -25,12 +25,70 @@ function isSkippableLeafType(t: string) {
|
|
|
25
25
|
);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
// Matches paths containing [][] — e.g., "items[][]" or "items[][].text"
|
|
29
|
+
const DOUBLE_ARRAY_RE = /\[\]\[\]/;
|
|
30
|
+
|
|
31
|
+
// Matches a [].property segment — e.g., "items[].name" (but not "items[][]")
|
|
32
|
+
const ARRAY_OBJECT_PROPERTY_RE = /\[\]\.[^[\]]/;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* When scope analysis produces both `prefix[].property` (array of objects) and
|
|
36
|
+
* `prefix[][]` (array of arrays) for the same prefix, there's a conflict about
|
|
37
|
+
* what the array elements are. Object-property paths are more specific and come
|
|
38
|
+
* from actual property access; double-array paths come from mixed iteration
|
|
39
|
+
* patterns in the scope analysis. Drop the double-array paths when both exist.
|
|
40
|
+
*/
|
|
41
|
+
function resolveDoubleArrayConflicts(
|
|
42
|
+
schema: Record<string, string>,
|
|
43
|
+
): Record<string, string> {
|
|
44
|
+
// Collect prefixes that end in [] and have object property children
|
|
45
|
+
const objectArrayPrefixes = new Set<string>();
|
|
46
|
+
for (const path of Object.keys(schema)) {
|
|
47
|
+
if (!ARRAY_OBJECT_PROPERTY_RE.test(path)) continue;
|
|
48
|
+
// Extract every "...[]" prefix that is followed by ".prop"
|
|
49
|
+
let idx = 0;
|
|
50
|
+
while ((idx = path.indexOf('[].', idx)) !== -1) {
|
|
51
|
+
objectArrayPrefixes.add(path.slice(0, idx + 2)); // includes the "[]"
|
|
52
|
+
idx += 3;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (objectArrayPrefixes.size === 0) return schema;
|
|
57
|
+
|
|
58
|
+
// Check if any double-array paths actually conflict
|
|
59
|
+
let hasConflict = false;
|
|
60
|
+
for (const path of Object.keys(schema)) {
|
|
61
|
+
if (!DOUBLE_ARRAY_RE.test(path)) continue;
|
|
62
|
+
const idx = path.indexOf('[][]');
|
|
63
|
+
if (idx !== -1 && objectArrayPrefixes.has(path.slice(0, idx + 2))) {
|
|
64
|
+
hasConflict = true;
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!hasConflict) return schema;
|
|
70
|
+
|
|
71
|
+
// Filter out conflicting double-array paths
|
|
72
|
+
const resolved: Record<string, string> = {};
|
|
73
|
+
for (const [path, value] of Object.entries(schema)) {
|
|
74
|
+
if (DOUBLE_ARRAY_RE.test(path)) {
|
|
75
|
+
const idx = path.indexOf('[][]');
|
|
76
|
+
if (idx !== -1 && objectArrayPrefixes.has(path.slice(0, idx + 2))) {
|
|
77
|
+
continue; // drop this conflicting path
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
resolved[path] = value;
|
|
81
|
+
}
|
|
82
|
+
return resolved;
|
|
83
|
+
}
|
|
84
|
+
|
|
28
85
|
export default function convertDotNotation(
|
|
29
86
|
schema: Record<string, string>,
|
|
30
87
|
): JsonTypeDefinition {
|
|
88
|
+
const resolved = resolveDoubleArrayConflicts(schema);
|
|
31
89
|
const result: JsonTypeDefinition = {};
|
|
32
90
|
|
|
33
|
-
for (const [rawPath, typ] of Object.entries(
|
|
91
|
+
for (const [rawPath, typ] of Object.entries(resolved)) {
|
|
34
92
|
// Skip paths with .length after array notation from dynamic iteration
|
|
35
93
|
// e.g., metadata[].length, metadata[][].length
|
|
36
94
|
if (DYNAMIC_LENGTH_RE.test(rawPath)) continue;
|
|
@@ -218,6 +276,17 @@ export default function convertDotNotation(
|
|
|
218
276
|
// If the next segment after '[]' is another '[]' or a standalone index,
|
|
219
277
|
// we need an array at cursor[key][0], not an object (for patterns like "key[][]" or "key[][0]")
|
|
220
278
|
if (afterArray === '[]' || isStandaloneIndex(afterArray)) {
|
|
279
|
+
// But don't overwrite an existing populated object — object properties
|
|
280
|
+
// (from paths like key[].property) take precedence over double-array hints
|
|
281
|
+
// (from paths like key[][]) which come from mixed access patterns in scope analysis
|
|
282
|
+
if (
|
|
283
|
+
cursor[key][0] &&
|
|
284
|
+
typeof cursor[key][0] === 'object' &&
|
|
285
|
+
!Array.isArray(cursor[key][0]) &&
|
|
286
|
+
Object.keys(cursor[key][0]).length > 0
|
|
287
|
+
) {
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
221
290
|
if (!Array.isArray(cursor[key][0])) cursor[key][0] = [];
|
|
222
291
|
} else {
|
|
223
292
|
// Default case: create an object
|
|
@@ -81,7 +81,23 @@ function isTypeAnnotation(value: string): boolean {
|
|
|
81
81
|
'string | number | undefined',
|
|
82
82
|
];
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
if (commonTypePatterns.includes(trimmed)) return true;
|
|
85
|
+
|
|
86
|
+
// Check for arrow function type annotations like "() => void", "(event: MouseEvent) => void"
|
|
87
|
+
// These contain '=>' but the body is a type keyword, not a JS expression
|
|
88
|
+
if (trimmed.includes('=>')) {
|
|
89
|
+
const arrowIndex = trimmed.indexOf('=>');
|
|
90
|
+
const body = trimmed.slice(arrowIndex + 2).trim();
|
|
91
|
+
if (
|
|
92
|
+
/^(void|string|number|boolean|any|unknown|never|null|undefined|object|Date|Promise<\w+>)$/i.test(
|
|
93
|
+
body,
|
|
94
|
+
)
|
|
95
|
+
) {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return false;
|
|
85
101
|
}
|
|
86
102
|
|
|
87
103
|
/**
|
|
@@ -105,6 +121,9 @@ function typeAnnotationToValue(typeAnnotation: string): unknown {
|
|
|
105
121
|
return [];
|
|
106
122
|
}
|
|
107
123
|
|
|
124
|
+
// Handle arrow function type annotations like "() => void"
|
|
125
|
+
if (trimmed.includes('=>')) return () => {};
|
|
126
|
+
|
|
108
127
|
// Handle primitive types
|
|
109
128
|
if (trimmed === 'string') return '';
|
|
110
129
|
if (trimmed === 'number') return 0;
|