@codeyam/codeyam-cli 0.1.0-staging.323686 → 0.1.0-staging.483fdc2
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 +2 -2
- package/analyzer-template/packages/ai/index.ts +6 -1
- package/analyzer-template/packages/ai/src/lib/analyzeScope.ts +39 -17
- package/analyzer-template/packages/ai/src/lib/astScopes/astScopeAnalyzer.ts +67 -9
- package/analyzer-template/packages/ai/src/lib/astScopes/processExpression.ts +308 -50
- package/analyzer-template/packages/ai/src/lib/astScopes/types.ts +15 -6
- package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +664 -242
- 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 +20 -1
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.ts +35 -13
- 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 +289 -83
- package/analyzer-template/packages/ai/src/lib/generateEntityScenarioData.ts +269 -1
- package/analyzer-template/packages/ai/src/lib/generateEntityScenarios.ts +9 -5
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlows.ts +11 -3
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionalEffects.ts +1 -1
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromConditionals.ts +297 -7
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlowsFromJsxUsages.ts +1 -1
- 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/resolvePathToControllable.ts +25 -13
- package/analyzer-template/packages/ai/src/lib/worker/SerializableDataStructure.ts +4 -3
- 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/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 +20 -6
- package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities.ts +14 -4
- package/analyzer-template/packages/analyze/src/lib/files/analyze/gatherEntityMap.ts +4 -2
- package/analyzer-template/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.ts +0 -3
- 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 +57 -13
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/gatherDataForMocks.ts +29 -0
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +35 -4
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.ts +117 -9
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +199 -17
- 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 +1 -1
- package/analyzer-template/packages/github/dist/types/src/types/ScenariosDataStructure.d.ts +5 -5
- 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/package.json +1 -1
- package/analyzer-template/packages/types/src/types/ScenariosDataStructure.ts +6 -5
- package/analyzer-template/packages/types/src/types/ScopeAnalysis.ts +6 -1
- package/analyzer-template/packages/utils/dist/types/src/types/ScenariosDataStructure.d.ts +5 -5
- 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/project/constructMockCode.ts +54 -9
- package/analyzer-template/project/writeMockDataTsx.ts +73 -2
- package/background/src/lib/virtualized/project/constructMockCode.js +45 -3
- package/background/src/lib/virtualized/project/constructMockCode.js.map +1 -1
- package/background/src/lib/virtualized/project/writeMockDataTsx.js +71 -2
- package/background/src/lib/virtualized/project/writeMockDataTsx.js.map +1 -1
- package/codeyam-cli/scripts/apply-setup.js +146 -0
- package/codeyam-cli/scripts/apply-setup.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/utils/install-skills.js +22 -0
- package/codeyam-cli/src/utils/install-skills.js.map +1 -1
- package/codeyam-cli/src/utils/reviewedRules.js +92 -0
- package/codeyam-cli/src/utils/reviewedRules.js.map +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/globals-CX9f-5xM.css +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{manifest-7522edd4.js → manifest-bba56ec1.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/memory-DuTFSyJ2.js +92 -0
- package/codeyam-cli/src/webserver/build/client/assets/{root-eVAaavTS.js → root-DTfSQARG.js} +6 -6
- package/codeyam-cli/src/webserver/build/server/assets/{index-DVzYx8PN.js → index-TD1f-DHV.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/server-build-BQ-1XyEa.js +258 -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.md +174 -233
- package/codeyam-cli/templates/codeyam:new-rule.md +41 -2
- package/codeyam-cli/templates/rule-reflection-hook.py +161 -0
- package/codeyam-cli/templates/rules-instructions.md +126 -0
- package/package.json +1 -1
- package/packages/ai/index.js +2 -1
- package/packages/ai/index.js.map +1 -1
- package/packages/ai/src/lib/analyzeScope.js +29 -12
- package/packages/ai/src/lib/analyzeScope.js.map +1 -1
- package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js +54 -8
- package/packages/ai/src/lib/astScopes/astScopeAnalyzer.js.map +1 -1
- package/packages/ai/src/lib/astScopes/processExpression.js +239 -43
- package/packages/ai/src/lib/astScopes/processExpression.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +503 -165
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.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 +22 -1
- package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.js +34 -9
- 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 +237 -73
- package/packages/ai/src/lib/dataStructure/helpers/fillInSchemaGapsAndUnknowns.js.map +1 -1
- package/packages/ai/src/lib/generateEntityScenarioData.js +195 -1
- package/packages/ai/src/lib/generateEntityScenarioData.js.map +1 -1
- package/packages/ai/src/lib/generateEntityScenarios.js +7 -1
- package/packages/ai/src/lib/generateEntityScenarios.js.map +1 -1
- package/packages/ai/src/lib/generateExecutionFlows.js +10 -2
- package/packages/ai/src/lib/generateExecutionFlows.js.map +1 -1
- package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js +209 -3
- package/packages/ai/src/lib/generateExecutionFlowsFromConditionals.js.map +1 -1
- 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/resolvePathToControllable.js +24 -14
- package/packages/ai/src/lib/resolvePathToControllable.js.map +1 -1
- package/packages/ai/src/lib/worker/SerializableDataStructure.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/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 +13 -5
- 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/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 +0 -3
- 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 +52 -10
- 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 +34 -4
- package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js +56 -8
- package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +168 -9
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.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/codeyam-cli/src/webserver/build/client/assets/globals-D3yhhV8x.css +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/memory-yxFcrxBX.js +0 -92
- package/codeyam-cli/src/webserver/build/server/assets/server-build-4Cr0uToj.js +0 -257
|
@@ -41,6 +41,7 @@ export interface BatchProcessorStats {
|
|
|
41
41
|
|
|
42
42
|
export class BatchSchemaProcessor {
|
|
43
43
|
private workQueue: WorkItem[] = [];
|
|
44
|
+
private queueIndex = 0;
|
|
44
45
|
private stats: BatchProcessorStats = {
|
|
45
46
|
itemsProcessed: 0,
|
|
46
47
|
itemsSkipped: 0, // Kept for API compatibility, always 0
|
|
@@ -71,17 +72,28 @@ export class BatchSchemaProcessor {
|
|
|
71
72
|
* Check if there are more items to process.
|
|
72
73
|
*/
|
|
73
74
|
hasWork(): boolean {
|
|
74
|
-
return this.workQueue.length
|
|
75
|
+
return this.queueIndex < this.workQueue.length;
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
/**
|
|
78
79
|
* Get the next work item from the queue.
|
|
79
80
|
*/
|
|
80
81
|
getNextWork(): WorkItem | undefined {
|
|
81
|
-
|
|
82
|
+
if (this.queueIndex >= this.workQueue.length) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const item = this.workQueue[this.queueIndex++];
|
|
82
87
|
if (item) {
|
|
83
88
|
this.stats.itemsProcessed++;
|
|
84
89
|
}
|
|
90
|
+
|
|
91
|
+
// Once we've consumed the queue, reset to avoid unbounded growth
|
|
92
|
+
if (this.queueIndex >= this.workQueue.length) {
|
|
93
|
+
this.workQueue = [];
|
|
94
|
+
this.queueIndex = 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
85
97
|
return item;
|
|
86
98
|
}
|
|
87
99
|
|
|
@@ -122,6 +134,7 @@ export class BatchSchemaProcessor {
|
|
|
122
134
|
*/
|
|
123
135
|
reset(): void {
|
|
124
136
|
this.workQueue = [];
|
|
137
|
+
this.queueIndex = 0;
|
|
125
138
|
this.stats = {
|
|
126
139
|
itemsProcessed: 0,
|
|
127
140
|
itemsSkipped: 0,
|
|
@@ -134,6 +147,6 @@ export class BatchSchemaProcessor {
|
|
|
134
147
|
* Get current queue size (for debugging/monitoring).
|
|
135
148
|
*/
|
|
136
149
|
getQueueSize(): number {
|
|
137
|
-
return this.workQueue.length;
|
|
150
|
+
return this.workQueue.length - this.queueIndex;
|
|
138
151
|
}
|
|
139
152
|
}
|
|
@@ -117,9 +117,10 @@ export class ScopeTreeManager {
|
|
|
117
117
|
*/
|
|
118
118
|
findNode(name: string): ScopeTreeNode | undefined {
|
|
119
119
|
const queue: ScopeTreeNode[] = [this.tree];
|
|
120
|
+
let index = 0;
|
|
120
121
|
|
|
121
|
-
while (queue.length
|
|
122
|
-
const node = queue
|
|
122
|
+
while (index < queue.length) {
|
|
123
|
+
const node = queue[index++]!;
|
|
123
124
|
if (node.name === name) {
|
|
124
125
|
return node;
|
|
125
126
|
}
|
|
@@ -135,9 +136,10 @@ export class ScopeTreeManager {
|
|
|
135
136
|
getAllNames(): string[] {
|
|
136
137
|
const names: string[] = [];
|
|
137
138
|
const queue: ScopeTreeNode[] = [this.tree];
|
|
139
|
+
let index = 0;
|
|
138
140
|
|
|
139
|
-
while (queue.length
|
|
140
|
-
const node = queue
|
|
141
|
+
while (index < queue.length) {
|
|
142
|
+
const node = queue[index++]!;
|
|
141
143
|
names.push(node.name);
|
|
142
144
|
queue.push(...node.children);
|
|
143
145
|
}
|
package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.ts
CHANGED
|
@@ -35,6 +35,24 @@ const getParts = (path: string): string[] => {
|
|
|
35
35
|
return parts;
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
+
function buildPrefixParts(parts: string[]): string[] {
|
|
39
|
+
if (parts.length === 0) return [];
|
|
40
|
+
const prefixes = new Array(parts.length);
|
|
41
|
+
let current = '';
|
|
42
|
+
for (let i = 0; i < parts.length; i++) {
|
|
43
|
+
const part = parts[i];
|
|
44
|
+
if (i === 0) {
|
|
45
|
+
current = part;
|
|
46
|
+
} else if (part.startsWith('[') || part.startsWith('(')) {
|
|
47
|
+
current += part;
|
|
48
|
+
} else {
|
|
49
|
+
current += `.${part}`;
|
|
50
|
+
}
|
|
51
|
+
prefixes[i] = current;
|
|
52
|
+
}
|
|
53
|
+
return prefixes;
|
|
54
|
+
}
|
|
55
|
+
|
|
38
56
|
/**
|
|
39
57
|
* Clear the module-level cache.
|
|
40
58
|
* Call this between entity analyses to prevent unbounded memory growth.
|
|
@@ -133,6 +151,7 @@ function scrub(
|
|
|
133
151
|
|
|
134
152
|
for (const keyPath of sortedKeys) {
|
|
135
153
|
const keyParts = getParts(keyPath);
|
|
154
|
+
const prefixParts = buildPrefixParts(keyParts);
|
|
136
155
|
|
|
137
156
|
if (
|
|
138
157
|
IGNORE_CLASSES_AND_OBJECTS.find(
|
|
@@ -145,7 +164,7 @@ function scrub(
|
|
|
145
164
|
|
|
146
165
|
// walk back through the prefixes: foo.bar.baz.qux → foo.bar.baz → foo.bar …
|
|
147
166
|
for (let cut = keyParts.length - 1; cut > 0; --cut) {
|
|
148
|
-
const prefix =
|
|
167
|
+
const prefix = prefixParts[cut - 1];
|
|
149
168
|
const rootKind = rootTable.get(prefix);
|
|
150
169
|
if (!rootKind) continue;
|
|
151
170
|
|
package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanNonObjectFunctions.ts
CHANGED
|
@@ -178,17 +178,36 @@ export function clearCleanNonObjectFunctionsCache(): {
|
|
|
178
178
|
// Maps parent prefix -> array of last parts (method names without parens)
|
|
179
179
|
type PrefixIndex = Map<string, string[]>;
|
|
180
180
|
|
|
181
|
+
function buildPrefixPartsWithRoot(parts: string[]): string[] {
|
|
182
|
+
const prefixes = new Array(parts.length + 1);
|
|
183
|
+
prefixes[0] = '';
|
|
184
|
+
let current = '';
|
|
185
|
+
for (let i = 0; i < parts.length; i++) {
|
|
186
|
+
const part = parts[i];
|
|
187
|
+
if (i === 0) {
|
|
188
|
+
current = part;
|
|
189
|
+
} else if (part.startsWith('[') || part.startsWith('(')) {
|
|
190
|
+
current += part;
|
|
191
|
+
} else {
|
|
192
|
+
current += `.${part}`;
|
|
193
|
+
}
|
|
194
|
+
prefixes[i + 1] = current;
|
|
195
|
+
}
|
|
196
|
+
return prefixes;
|
|
197
|
+
}
|
|
198
|
+
|
|
181
199
|
function buildPrefixIndex(allPaths: string[]): PrefixIndex {
|
|
182
200
|
const index: PrefixIndex = new Map();
|
|
183
201
|
|
|
184
202
|
for (const path of allPaths) {
|
|
185
203
|
const parts = cachedSplit(path);
|
|
186
204
|
if (parts.length < 1) continue;
|
|
205
|
+
const prefixes = buildPrefixPartsWithRoot(parts);
|
|
187
206
|
|
|
188
207
|
// For each possible prefix length, add the last part to that prefix's entry
|
|
189
208
|
// This allows lookup at any depth
|
|
190
209
|
for (let prefixLen = 0; prefixLen < parts.length; prefixLen++) {
|
|
191
|
-
const prefix =
|
|
210
|
+
const prefix = prefixes[prefixLen];
|
|
192
211
|
const lastPart = parts[prefixLen]?.split('(')?.[0];
|
|
193
212
|
if (lastPart) {
|
|
194
213
|
let existing = index.get(prefix);
|
|
@@ -1085,29 +1104,32 @@ function clearAttributes(
|
|
|
1085
1104
|
knownBasePaths.add(path);
|
|
1086
1105
|
}
|
|
1087
1106
|
|
|
1107
|
+
// OPTIMIZATION: Instead of O(keys × basePaths), use O(keys × keyDepth) where keyDepth is small
|
|
1108
|
+
// For each key, find all its prefixes and check if any is a known basePath (O(1) Set lookup)
|
|
1088
1109
|
for (const key in mapping) {
|
|
1089
1110
|
const keyParts = cachedSplit(key);
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
)
|
|
1097
|
-
|
|
1111
|
+
if (keyParts.length <= 1) continue; // No possible parent basePath
|
|
1112
|
+
|
|
1113
|
+
// Check each prefix of the key to see if it's a known basePath
|
|
1114
|
+
// Start from shortest prefix (most likely to match) for early exit
|
|
1115
|
+
for (let prefixLen = 1; prefixLen < keyParts.length; prefixLen++) {
|
|
1116
|
+
const prefix = joinParenthesesAndArrays(keyParts.slice(0, prefixLen));
|
|
1117
|
+
if (!knownBasePaths.has(prefix)) continue;
|
|
1118
|
+
|
|
1119
|
+
// Found a matching basePath - now check the conditions
|
|
1120
|
+
const basePath = prefix;
|
|
1121
|
+
|
|
1098
1122
|
// Preserve functionCallReturnValue for non-string types, UNLESS
|
|
1099
1123
|
// the method is a primitive-returning method (like some, every, includes, indexOf)
|
|
1100
1124
|
// whose return values are not mockable
|
|
1101
|
-
const methodPart = keyParts[
|
|
1125
|
+
const methodPart = keyParts[prefixLen];
|
|
1102
1126
|
const methodName = methodPart?.split('(')[0];
|
|
1103
1127
|
const isPrimitiveReturning = primitiveReturningMethodsSet.has(
|
|
1104
1128
|
methodName ?? '',
|
|
1105
1129
|
);
|
|
1106
1130
|
if (
|
|
1107
1131
|
mapping[basePath] !== 'string' &&
|
|
1108
|
-
keyParts[
|
|
1109
|
-
'functionCallReturnValue',
|
|
1110
|
-
) &&
|
|
1132
|
+
keyParts[prefixLen + 1]?.startsWith('functionCallReturnValue') &&
|
|
1111
1133
|
!isPrimitiveReturning
|
|
1112
1134
|
)
|
|
1113
1135
|
continue;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts type annotation strings that appear as values in mockData to actual values.
|
|
3
|
+
*
|
|
4
|
+
* The LLM sometimes echoes the schema type annotation as the actual value.
|
|
5
|
+
* For example, if the schema says { filePath: "string | undefined" },
|
|
6
|
+
* the LLM might return { filePath: "string | undefined" } instead of
|
|
7
|
+
* generating an actual value like { filePath: "/path/to/file.tsx" }.
|
|
8
|
+
*
|
|
9
|
+
* This causes runtime errors when the code tries to use these "values"
|
|
10
|
+
* as actual data (e.g., calling .length on the string "string | undefined").
|
|
11
|
+
*
|
|
12
|
+
* This function detects type annotation strings and converts them to
|
|
13
|
+
* appropriate default values:
|
|
14
|
+
* - "string" → ""
|
|
15
|
+
* - "number" → 0
|
|
16
|
+
* - "boolean" → false
|
|
17
|
+
* - "function" → () => {}
|
|
18
|
+
* - "Date" → new Date()
|
|
19
|
+
* - "T | undefined" → undefined
|
|
20
|
+
* - "T | null" → null
|
|
21
|
+
* - "string[]" → []
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
// Pattern to detect if a string looks like a TypeScript type annotation
|
|
25
|
+
// This matches common type patterns:
|
|
26
|
+
// - Primitive types: string, number, boolean, function, Date, object, any, unknown
|
|
27
|
+
// - Union types: string | undefined, number | null, T | null | undefined
|
|
28
|
+
// - Array types: string[], number[], T[]
|
|
29
|
+
// - Optional types: T?
|
|
30
|
+
const TYPE_ANNOTATION_PATTERN =
|
|
31
|
+
/^(string|number|boolean|function|Date|object|any|unknown|void|never|null|undefined|array)(\s*\|\s*(string|number|boolean|function|Date|object|any|unknown|void|never|null|undefined|array))*(\[\])?$/i;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Check if a string value looks like a TypeScript type annotation.
|
|
35
|
+
*/
|
|
36
|
+
function isTypeAnnotation(value: string): boolean {
|
|
37
|
+
if (typeof value !== 'string') return false;
|
|
38
|
+
|
|
39
|
+
const trimmed = value.trim();
|
|
40
|
+
|
|
41
|
+
// Quick check: type annotations are typically short
|
|
42
|
+
if (trimmed.length > 100) return false;
|
|
43
|
+
|
|
44
|
+
// Check against the pattern
|
|
45
|
+
if (TYPE_ANNOTATION_PATTERN.test(trimmed)) return true;
|
|
46
|
+
|
|
47
|
+
// Also check for common patterns that the regex might miss
|
|
48
|
+
const commonTypePatterns = [
|
|
49
|
+
'string',
|
|
50
|
+
'number',
|
|
51
|
+
'boolean',
|
|
52
|
+
'function',
|
|
53
|
+
'object',
|
|
54
|
+
'array',
|
|
55
|
+
'Date',
|
|
56
|
+
'any',
|
|
57
|
+
'unknown',
|
|
58
|
+
'void',
|
|
59
|
+
'never',
|
|
60
|
+
'null',
|
|
61
|
+
'undefined',
|
|
62
|
+
'string | undefined',
|
|
63
|
+
'string | null',
|
|
64
|
+
'string | null | undefined',
|
|
65
|
+
'number | undefined',
|
|
66
|
+
'number | null',
|
|
67
|
+
'number | null | undefined',
|
|
68
|
+
'boolean | undefined',
|
|
69
|
+
'boolean | null',
|
|
70
|
+
'boolean | null | undefined',
|
|
71
|
+
'Date | undefined',
|
|
72
|
+
'Date | null',
|
|
73
|
+
'function | undefined',
|
|
74
|
+
'object | undefined',
|
|
75
|
+
'object | null',
|
|
76
|
+
'string[]',
|
|
77
|
+
'number[]',
|
|
78
|
+
'boolean[]',
|
|
79
|
+
'any[]',
|
|
80
|
+
'string | number',
|
|
81
|
+
'string | number | undefined',
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
return commonTypePatterns.includes(trimmed);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Convert a type annotation string to an appropriate default value.
|
|
89
|
+
*/
|
|
90
|
+
function typeAnnotationToValue(typeAnnotation: string): unknown {
|
|
91
|
+
const trimmed = typeAnnotation.trim().toLowerCase();
|
|
92
|
+
|
|
93
|
+
// Handle undefined types first (they take precedence)
|
|
94
|
+
if (trimmed.includes('| undefined') || trimmed.includes('undefined |')) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Handle null types
|
|
99
|
+
if (trimmed.includes('| null') || trimmed.includes('null |')) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Handle array types
|
|
104
|
+
if (trimmed.endsWith('[]') || trimmed === 'array') {
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Handle primitive types
|
|
109
|
+
if (trimmed === 'string') return '';
|
|
110
|
+
if (trimmed === 'number') return 0;
|
|
111
|
+
if (trimmed === 'boolean') return false;
|
|
112
|
+
if (trimmed === 'function') return () => {};
|
|
113
|
+
if (trimmed === 'date') return new Date();
|
|
114
|
+
if (trimmed === 'object') return {};
|
|
115
|
+
if (trimmed === 'null') return null;
|
|
116
|
+
if (trimmed === 'undefined') return undefined;
|
|
117
|
+
if (trimmed === 'any' || trimmed === 'unknown') return undefined;
|
|
118
|
+
if (trimmed === 'void' || trimmed === 'never') return undefined;
|
|
119
|
+
|
|
120
|
+
// Handle union types - prefer the first concrete type
|
|
121
|
+
if (trimmed.includes(' | ')) {
|
|
122
|
+
const parts = trimmed.split(' | ').map((p) => p.trim());
|
|
123
|
+
for (const part of parts) {
|
|
124
|
+
if (part === 'string') return '';
|
|
125
|
+
if (part === 'number') return 0;
|
|
126
|
+
if (part === 'boolean') return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Fallback: return undefined for unknown type patterns
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Recursively convert type annotation strings to values in a mockData object.
|
|
136
|
+
* Mutates the object in place.
|
|
137
|
+
*/
|
|
138
|
+
export default function convertTypeAnnotationsToValues(
|
|
139
|
+
mockData: Record<string, unknown>,
|
|
140
|
+
): void {
|
|
141
|
+
for (const [key, value] of Object.entries(mockData)) {
|
|
142
|
+
if (typeof value === 'string' && isTypeAnnotation(value)) {
|
|
143
|
+
mockData[key] = typeAnnotationToValue(value);
|
|
144
|
+
} else if (Array.isArray(value)) {
|
|
145
|
+
// Recursively process array elements
|
|
146
|
+
for (const item of value) {
|
|
147
|
+
if (item !== null && typeof item === 'object' && !Array.isArray(item)) {
|
|
148
|
+
convertTypeAnnotationsToValues(item as Record<string, unknown>);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
} else if (
|
|
152
|
+
value !== null &&
|
|
153
|
+
typeof value === 'object' &&
|
|
154
|
+
!Array.isArray(value)
|
|
155
|
+
) {
|
|
156
|
+
// Recursively process nested objects
|
|
157
|
+
convertTypeAnnotationsToValues(value as Record<string, unknown>);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/deduplicateFunctionSchemas.ts
CHANGED
|
@@ -77,42 +77,52 @@ export default function deduplicateFunctionSchemas(
|
|
|
77
77
|
|
|
78
78
|
// If multiple variants with arguments exist, find the one with the most robust structure
|
|
79
79
|
if (withArgs.length > 1) {
|
|
80
|
-
//
|
|
81
|
-
const
|
|
82
|
-
// Find the end of the function call (the closing parenthesis)
|
|
80
|
+
// Pre-compute function call prefixes for all variants
|
|
81
|
+
const variantPrefixes = withArgs.map((variant) => {
|
|
83
82
|
const closingParenIndex = variant.lastIndexOf(')');
|
|
84
|
-
const functionCallPrefix =
|
|
85
|
-
closingParenIndex > -1
|
|
86
|
-
? variant.slice(0, closingParenIndex + 1)
|
|
87
|
-
: variant;
|
|
88
|
-
|
|
89
|
-
const relatedKeys = Object.keys(schema).filter((k) => {
|
|
90
|
-
// Check if this key is a child of the variant (starts with the function call)
|
|
91
|
-
return (
|
|
92
|
-
k.startsWith(functionCallPrefix + '.') ||
|
|
93
|
-
k.startsWith(functionCallPrefix + '[')
|
|
94
|
-
);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
83
|
return {
|
|
98
84
|
key: variant,
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return (
|
|
106
|
-
(remaining.match(/\./g) || []).length +
|
|
107
|
-
(remaining.match(/\[/g) || []).length
|
|
108
|
-
);
|
|
109
|
-
}),
|
|
110
|
-
),
|
|
85
|
+
prefix:
|
|
86
|
+
closingParenIndex > -1
|
|
87
|
+
? variant.slice(0, closingParenIndex + 1)
|
|
88
|
+
: variant,
|
|
89
|
+
depth: 0,
|
|
90
|
+
maxDepth: 0,
|
|
111
91
|
};
|
|
112
92
|
});
|
|
113
93
|
|
|
94
|
+
// Single pass through schema keys to count related keys for ALL variants at once.
|
|
95
|
+
// This is O(schemaSize × variants) but done in one pass instead of
|
|
96
|
+
// O(variants × schemaSize) with separate passes per variant.
|
|
97
|
+
const schemaKeys = Object.keys(schema);
|
|
98
|
+
for (const k of schemaKeys) {
|
|
99
|
+
for (const variantInfo of variantPrefixes) {
|
|
100
|
+
// Check if key starts with prefix followed by . or [
|
|
101
|
+
const prefixLen = variantInfo.prefix.length;
|
|
102
|
+
if (k.length > prefixLen) {
|
|
103
|
+
const nextChar = k[prefixLen];
|
|
104
|
+
if (
|
|
105
|
+
(nextChar === '.' || nextChar === '[') &&
|
|
106
|
+
k.startsWith(variantInfo.prefix)
|
|
107
|
+
) {
|
|
108
|
+
variantInfo.depth++;
|
|
109
|
+
// Count nesting depth by counting . and [ characters (faster than regex)
|
|
110
|
+
const remaining = k.slice(prefixLen);
|
|
111
|
+
let nestingDepth = 0;
|
|
112
|
+
for (let i = 0; i < remaining.length; i++) {
|
|
113
|
+
const c = remaining[i];
|
|
114
|
+
if (c === '.' || c === '[') nestingDepth++;
|
|
115
|
+
}
|
|
116
|
+
if (nestingDepth > variantInfo.maxDepth) {
|
|
117
|
+
variantInfo.maxDepth = nestingDepth;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
114
124
|
// Sort by depth (number of related keys) and then by max depth (nesting level)
|
|
115
|
-
|
|
125
|
+
variantPrefixes.sort((a, b) => {
|
|
116
126
|
if (b.depth !== a.depth) {
|
|
117
127
|
return b.depth - a.depth;
|
|
118
128
|
}
|
|
@@ -120,7 +130,7 @@ export default function deduplicateFunctionSchemas(
|
|
|
120
130
|
});
|
|
121
131
|
|
|
122
132
|
// Keep the one with the most robust structure, remove others
|
|
123
|
-
const keepVariant =
|
|
133
|
+
const keepVariant = variantPrefixes[0].key;
|
|
124
134
|
withArgs.forEach((variant) => {
|
|
125
135
|
if (variant !== keepVariant) {
|
|
126
136
|
keysToRemove.add(variant);
|