@codeyam/codeyam-cli 0.1.21 → 0.1.22
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/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +31 -8
- package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/ParentScopeManager.ts +10 -3
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.ts +16 -6
- package/analyzer-template/packages/analyze/index.ts +4 -1
- package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +28 -2
- package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities.ts +5 -36
- package/analyzer-template/packages/analyze/src/lib/files/analyze/trackEntityCircularDependencies.ts +21 -0
- package/analyzer-template/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.ts +82 -10
- package/analyzer-template/packages/analyze/src/lib/files/analyzeNextRoute.ts +8 -3
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +235 -58
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +170 -26
- package/codeyam-cli/src/commands/__tests__/editor.auditNoAutoAnalysis.test.js +63 -0
- package/codeyam-cli/src/commands/__tests__/editor.auditNoAutoAnalysis.test.js.map +1 -0
- package/codeyam-cli/src/commands/editor.js +412 -78
- package/codeyam-cli/src/commands/editor.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorAudit.test.js +354 -1
- package/codeyam-cli/src/utils/__tests__/editorAudit.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorPreview.test.js +11 -3
- package/codeyam-cli/src/utils/__tests__/editorPreview.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js +33 -1
- package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/manualEntityAnalysis.test.js +302 -0
- package/codeyam-cli/src/utils/__tests__/manualEntityAnalysis.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/testRunner.test.js +217 -0
- package/codeyam-cli/src/utils/__tests__/testRunner.test.js.map +1 -0
- package/codeyam-cli/src/utils/analysisRunner.js +28 -1
- package/codeyam-cli/src/utils/analysisRunner.js.map +1 -1
- package/codeyam-cli/src/utils/analyzer.js +4 -2
- package/codeyam-cli/src/utils/analyzer.js.map +1 -1
- package/codeyam-cli/src/utils/editorAudit.js +98 -3
- package/codeyam-cli/src/utils/editorAudit.js.map +1 -1
- package/codeyam-cli/src/utils/editorPreview.js +5 -3
- package/codeyam-cli/src/utils/editorPreview.js.map +1 -1
- package/codeyam-cli/src/utils/entityChangeStatus.server.js +16 -0
- package/codeyam-cli/src/utils/entityChangeStatus.server.js.map +1 -1
- package/codeyam-cli/src/utils/manualEntityAnalysis.js +196 -0
- package/codeyam-cli/src/utils/manualEntityAnalysis.js.map +1 -0
- package/codeyam-cli/src/utils/queue/job.js +20 -2
- package/codeyam-cli/src/utils/queue/job.js.map +1 -1
- package/codeyam-cli/src/utils/testRunner.js +199 -1
- package/codeyam-cli/src/utils/testRunner.js.map +1 -1
- package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js +35 -0
- package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js.map +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/MiniClaudeChat-CQENLSrF.js +36 -0
- package/codeyam-cli/src/webserver/build/client/assets/cy-logo-cli-Coe5NhbS.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{cy-logo-cli-CJzc4vOH.svg → cy-logo-cli-DoA97ML3.svg} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/editor.entity.(_sha)-aIHKLB-m.js +96 -0
- package/codeyam-cli/src/webserver/build/client/assets/{editorPreview-NTuLi4Xg.js → editorPreview-CluPkvXJ.js} +6 -6
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-Blfy9UlN.js → entity._sha._-ByHz6rAQ.js} +13 -12
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.dev-BA5L8bU-.js → entity._sha.scenarios._scenarioId.dev-CmLO432x.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.fullscreen-D4dmRgvO.js → entity._sha.scenarios._scenarioId.fullscreen-Bz9sCUF_.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/globals-oyPmV37k.css +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{manifest-5025e428.js → manifest-bcbb3d49.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{root-BCx1S8Z3.js → root-D2_tktnk.js} +6 -6
- package/codeyam-cli/src/webserver/build/server/assets/analysisRunner-DjF-soOH.js +16 -0
- package/codeyam-cli/src/webserver/build/server/assets/{index-C91yWWCI.js → index-nAvHGWbz.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{init-Dkas-RUS.js → init-XhpIt-OT.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/server-build-DVwiibFu.js +644 -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/src/webserver/idleDetector.js +15 -0
- package/codeyam-cli/src/webserver/idleDetector.js.map +1 -1
- package/codeyam-cli/src/webserver/terminalServer.js +8 -2
- package/codeyam-cli/src/webserver/terminalServer.js.map +1 -1
- package/codeyam-cli/templates/skills/codeyam-editor/SKILL.md +2 -2
- package/package.json +1 -1
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +23 -9
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/ParentScopeManager.js +9 -2
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/ParentScopeManager.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js +14 -4
- package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js.map +1 -1
- package/packages/analyze/index.js +1 -1
- package/packages/analyze/index.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +16 -2
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities.js +6 -26
- package/packages/analyze/src/lib/files/analyze/analyzeEntities.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/trackEntityCircularDependencies.js +14 -0
- package/packages/analyze/src/lib/files/analyze/trackEntityCircularDependencies.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js +44 -11
- package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js.map +1 -1
- package/packages/analyze/src/lib/files/analyzeNextRoute.js +5 -1
- package/packages/analyze/src/lib/files/analyzeNextRoute.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +116 -28
- package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +139 -24
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/cy-logo-cli-DODLxLcw.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/editor.entity.(_sha)-Dx-h1rJK.js +0 -130
- package/codeyam-cli/src/webserver/build/client/assets/globals-BrPXT1iR.css +0 -1
- package/codeyam-cli/src/webserver/build/server/assets/analysisRunner-C1kjC9UJ.js +0 -13
- package/codeyam-cli/src/webserver/build/server/assets/server-build-pulXLTrG.js +0 -640
package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts
CHANGED
|
@@ -41,6 +41,19 @@ function getTypeParameter(functionName: string): string | null {
|
|
|
41
41
|
return null;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Check if a schema path contains a Set/Map collection method call.
|
|
46
|
+
* Paths like `.has(articleId)`, `.delete(articleId)`, `.add(articleId)` represent
|
|
47
|
+
* membership checks on Sets/Maps, not meaningful data flow for schema generation.
|
|
48
|
+
* These create massive combinatorial explosions when every filter field (filterRatings,
|
|
49
|
+
* filterPublications, filterAuthors, etc.) × every method (has, delete, add) gets
|
|
50
|
+
* tracked as a separate equivalency.
|
|
51
|
+
*/
|
|
52
|
+
const COLLECTION_METHOD_PATTERN = /\.(?:has|delete|add|clear|get|set)\(/;
|
|
53
|
+
function isCollectionMethodPath(path: string): boolean {
|
|
54
|
+
return COLLECTION_METHOD_PATTERN.test(path);
|
|
55
|
+
}
|
|
56
|
+
|
|
44
57
|
// Primitive types that should not have child paths
|
|
45
58
|
const PRIMITIVE_TYPES = new Set([
|
|
46
59
|
'number',
|
|
@@ -142,12 +155,26 @@ function bestValueFromOptions(options: Array<string | undefined>) {
|
|
|
142
155
|
return options[0] ?? 'unknown';
|
|
143
156
|
}
|
|
144
157
|
|
|
158
|
+
/** Timeout (ms) for the merge operation. Throws DataStructureTimeoutError if exceeded.
|
|
159
|
+
* All successful merges complete in <300ms. Anything exceeding 2s is pathological. */
|
|
160
|
+
const MERGE_TIMEOUT_MS = 2_000;
|
|
161
|
+
|
|
162
|
+
export class DataStructureTimeoutError extends Error {
|
|
163
|
+
constructor(entityName: string, elapsedMs: number) {
|
|
164
|
+
super(
|
|
165
|
+
`Data structure merge timed out for ${entityName} after ${Math.round(elapsedMs / 1000)}s (limit: ${MERGE_TIMEOUT_MS / 1000}s)`,
|
|
166
|
+
);
|
|
167
|
+
this.name = 'DataStructureTimeoutError';
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
145
171
|
export default function mergeInDependentDataStructure({
|
|
146
172
|
importedExports,
|
|
147
173
|
dependentAnalyses,
|
|
148
174
|
rootScopeName,
|
|
149
175
|
dataStructure,
|
|
150
176
|
dependencySchemas,
|
|
177
|
+
timeoutMs = MERGE_TIMEOUT_MS,
|
|
151
178
|
}: {
|
|
152
179
|
importedExports: Pick<
|
|
153
180
|
Entity['metadata']['importedExports'][0],
|
|
@@ -169,7 +196,23 @@ export default function mergeInDependentDataStructure({
|
|
|
169
196
|
[name: string]: DataStructureInfo;
|
|
170
197
|
};
|
|
171
198
|
};
|
|
199
|
+
/** Override the default timeout (ms). Set to 0 to disable. */
|
|
200
|
+
timeoutMs?: number;
|
|
172
201
|
}) {
|
|
202
|
+
const mergeStartTime = Date.now();
|
|
203
|
+
const mergeDeadline = timeoutMs > 0 ? mergeStartTime + timeoutMs : 0;
|
|
204
|
+
|
|
205
|
+
/** Call in hot loops. Throws DataStructureTimeoutError if deadline exceeded.
|
|
206
|
+
* Date.now() is ~20ns — negligible vs the ms-scale string ops in each iteration. */
|
|
207
|
+
const checkDeadline = () => {
|
|
208
|
+
if (!mergeDeadline) return;
|
|
209
|
+
if (Date.now() > mergeDeadline) {
|
|
210
|
+
throw new DataStructureTimeoutError(
|
|
211
|
+
rootScopeName,
|
|
212
|
+
Date.now() - mergeStartTime,
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
};
|
|
173
216
|
const mergedDataStructure: Omit<
|
|
174
217
|
DataStructure,
|
|
175
218
|
'equivalentSignatureVariables'
|
|
@@ -310,7 +353,17 @@ export default function mergeInDependentDataStructure({
|
|
|
310
353
|
);
|
|
311
354
|
};
|
|
312
355
|
|
|
356
|
+
// Cache translatePath results — the same path is often translated multiple times
|
|
357
|
+
// (once per equivalency entry that references it). Avoids redundant
|
|
358
|
+
// splitOutsideParenthesesAndArrays calls on long paths.
|
|
359
|
+
const translatePathCache = new Map<string, string>();
|
|
360
|
+
|
|
313
361
|
const translatePath = (path: string, dependencyName: string) => {
|
|
362
|
+
const cacheKey = `${dependencyName}\0${path}`;
|
|
363
|
+
const cached = translatePathCache.get(cacheKey);
|
|
364
|
+
if (cached !== undefined) return cached;
|
|
365
|
+
|
|
366
|
+
let result = path;
|
|
314
367
|
if (path.startsWith(dependencyName)) {
|
|
315
368
|
const pathParts = splitOutsideParenthesesAndArrays(path);
|
|
316
369
|
if (pathParts.length > 1) {
|
|
@@ -318,33 +371,26 @@ export default function mergeInDependentDataStructure({
|
|
|
318
371
|
// Check if this function has multiple DIFFERENT type parameters.
|
|
319
372
|
// If so, DON'T normalize to returnValue - keep the full path to avoid
|
|
320
373
|
// merging different type-parameterized variants together.
|
|
321
|
-
// e.g., useFetcher<{ data: UserData }>().functionCallReturnValue.data
|
|
322
|
-
// should NOT be merged with useFetcher<{ data: ConfigData }>().functionCallReturnValue.data
|
|
323
374
|
const baseName = cleanFunctionName(pathParts[0]);
|
|
324
|
-
if (functionsWithMultipleTypeParams.has(baseName)) {
|
|
325
|
-
|
|
375
|
+
if (!functionsWithMultipleTypeParams.has(baseName)) {
|
|
376
|
+
// functionCallReturnValue immediately follows - normalize to returnValue
|
|
377
|
+
result = joinParenthesesAndArrays([
|
|
378
|
+
'returnValue',
|
|
379
|
+
...pathParts.slice(2),
|
|
380
|
+
]);
|
|
326
381
|
}
|
|
327
|
-
// functionCallReturnValue immediately follows - normalize to returnValue
|
|
328
|
-
// e.g., useAuth().functionCallReturnValue.user -> returnValue.user
|
|
329
|
-
return joinParenthesesAndArrays([
|
|
330
|
-
'returnValue',
|
|
331
|
-
...pathParts.slice(2),
|
|
332
|
-
]);
|
|
333
382
|
} else if (
|
|
334
383
|
pathParts[0].endsWith(')') &&
|
|
335
384
|
pathParts[1].startsWith('signature[')
|
|
336
385
|
) {
|
|
337
|
-
// Hook-style with signature access
|
|
338
|
-
|
|
339
|
-
return joinParenthesesAndArrays(pathParts.slice(1));
|
|
386
|
+
// Hook-style with signature access
|
|
387
|
+
result = joinParenthesesAndArrays(pathParts.slice(1));
|
|
340
388
|
}
|
|
341
|
-
// For all other cases (object-style APIs like getSupabase().auth and
|
|
342
|
-
// direct object references like supabase.from), preserve the path as-is.
|
|
343
|
-
// The prefix must be kept for proper schema lookups in constructMockCode
|
|
344
|
-
// and gatherDataForMocks.
|
|
345
389
|
}
|
|
346
390
|
}
|
|
347
|
-
|
|
391
|
+
|
|
392
|
+
translatePathCache.set(cacheKey, result);
|
|
393
|
+
return result;
|
|
348
394
|
};
|
|
349
395
|
|
|
350
396
|
const gatherAllEquivalentSchemaPaths = (
|
|
@@ -358,6 +404,7 @@ export default function mergeInDependentDataStructure({
|
|
|
358
404
|
'signatureSchema' | 'returnValueSchema'
|
|
359
405
|
>,
|
|
360
406
|
) => {
|
|
407
|
+
checkDeadline();
|
|
361
408
|
if (!sourceAndUsageEquivalencies) return;
|
|
362
409
|
|
|
363
410
|
// Pre-computed normalized schema index cache.
|
|
@@ -380,6 +427,7 @@ export default function mergeInDependentDataStructure({
|
|
|
380
427
|
if (cached) return cached;
|
|
381
428
|
const byFirstPart = new Map<string, NormalizedEntry[]>();
|
|
382
429
|
for (const path in schema) {
|
|
430
|
+
checkDeadline();
|
|
383
431
|
let parts = splitOutsideParenthesesAndArrays(path);
|
|
384
432
|
if (parts[0].startsWith(functionName)) {
|
|
385
433
|
const baseName = cleanFunctionName(parts[0]);
|
|
@@ -441,6 +489,7 @@ export default function mergeInDependentDataStructure({
|
|
|
441
489
|
// Use espIndex Map for O(1) lookup instead of O(E) linear search.
|
|
442
490
|
// Falls back to linear search only when Map hit has a signature index conflict.
|
|
443
491
|
for (const pathInfo of allPaths) {
|
|
492
|
+
checkDeadline();
|
|
444
493
|
if (equivalentSchemaPathsEntry) break;
|
|
445
494
|
const candidate = espIndex.get(
|
|
446
495
|
espIndexKey(pathInfo.path, pathInfo.functionName),
|
|
@@ -572,20 +621,43 @@ export default function mergeInDependentDataStructure({
|
|
|
572
621
|
for (const equivalencies of allEquivalencies) {
|
|
573
622
|
const schemaPathEntries = Object.entries(equivalencies);
|
|
574
623
|
for (const [schemaPath, usages] of schemaPathEntries) {
|
|
624
|
+
checkDeadline();
|
|
625
|
+
|
|
626
|
+
// Skip equivalency entries whose source path is a Set/Map membership operation.
|
|
627
|
+
// Patterns like `.has(articleId)`, `.delete(articleId)`, `.add(articleId)` on
|
|
628
|
+
// Sets/Maps represent membership checks, not meaningful data flow for schema generation.
|
|
629
|
+
// In the Margo LibraryPage case, these account for 74% of all equivalency targets
|
|
630
|
+
// (19,444 of 26,340) and cause a combinatorial explosion in the merge.
|
|
631
|
+
if (isCollectionMethodPath(schemaPath)) continue;
|
|
632
|
+
|
|
575
633
|
// First, check if the raw schemaPath starts with a function call to a dependency.
|
|
576
634
|
// If so, use that dependency name for translation (so translatePath can strip the prefix).
|
|
577
635
|
const extractedFuncName = extractFunctionNameFromPath(schemaPath);
|
|
578
636
|
const effectiveFunctionName = extractedFuncName || functionName;
|
|
579
637
|
const translatedPath = translatePath(schemaPath, effectiveFunctionName);
|
|
580
638
|
|
|
581
|
-
const
|
|
639
|
+
const allPathsRaw: { path: string; functionName?: string }[] = [
|
|
582
640
|
{ path: translatedPath, functionName: effectiveFunctionName },
|
|
583
|
-
...usages
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
641
|
+
...usages
|
|
642
|
+
.filter((u) => !isCollectionMethodPath(u.schemaPath))
|
|
643
|
+
.map((u) => ({
|
|
644
|
+
path: translatePath(u.schemaPath, u.scopeNodeName),
|
|
645
|
+
functionName: u.scopeNodeName,
|
|
646
|
+
})),
|
|
587
647
|
].filter((pathInfo) => !pathInfo.path.includes('.map('));
|
|
588
648
|
|
|
649
|
+
// Deduplicate by translated path + function name.
|
|
650
|
+
// Multiple call variants (e.g., loadView(viewKey(null,null)) vs loadView(viewKey(newTag,newCol)))
|
|
651
|
+
// translate to the same path after stripping arguments. Processing duplicates
|
|
652
|
+
// creates O(n²) work in the schema matching loops below.
|
|
653
|
+
const seenPathKeys = new Set<string>();
|
|
654
|
+
const allPaths = allPathsRaw.filter((p) => {
|
|
655
|
+
const key = `${p.functionName ?? ''}::${p.path}`;
|
|
656
|
+
if (seenPathKeys.has(key)) return false;
|
|
657
|
+
seenPathKeys.add(key);
|
|
658
|
+
return true;
|
|
659
|
+
});
|
|
660
|
+
|
|
589
661
|
// Fix 38: Derive base paths from property access paths.
|
|
590
662
|
// When we have equivalent paths like:
|
|
591
663
|
// Parent: signature[0].scenarios[].name
|
|
@@ -617,6 +689,7 @@ export default function mergeInDependentDataStructure({
|
|
|
617
689
|
|
|
618
690
|
// For each child path, find its equivalent parent path and derive bases
|
|
619
691
|
for (const childPathInfo of childPaths) {
|
|
692
|
+
checkDeadline();
|
|
620
693
|
const childParts = splitOutsideParenthesesAndArrays(
|
|
621
694
|
childPathInfo.path,
|
|
622
695
|
);
|
|
@@ -743,6 +816,7 @@ export default function mergeInDependentDataStructure({
|
|
|
743
816
|
});
|
|
744
817
|
}
|
|
745
818
|
for (const equivalentRoot of entry.equivalentRoots) {
|
|
819
|
+
checkDeadline();
|
|
746
820
|
const dataStructures =
|
|
747
821
|
equivalentRoot.function &&
|
|
748
822
|
equivalentRoot.function.name !== rootScopeName
|
|
@@ -803,6 +877,7 @@ export default function mergeInDependentDataStructure({
|
|
|
803
877
|
path: schemaPath,
|
|
804
878
|
parts: schemaPathParts,
|
|
805
879
|
} of candidates) {
|
|
880
|
+
checkDeadline();
|
|
806
881
|
if (schemaPathParts.length < pathParts.length) continue;
|
|
807
882
|
|
|
808
883
|
// Check if all path parts match (allowing function call variants)
|
|
@@ -910,6 +985,7 @@ export default function mergeInDependentDataStructure({
|
|
|
910
985
|
// where we want both X().functionCallReturnValue and Y().functionCallReturnValue as bases
|
|
911
986
|
const allBasePaths = new Set<string>();
|
|
912
987
|
for (const path of Object.keys(dataStructure.returnValueSchema)) {
|
|
988
|
+
checkDeadline();
|
|
913
989
|
const parts = splitOutsideParenthesesAndArrays(path);
|
|
914
990
|
// Find all positions of functionCallReturnValue and create base paths for each
|
|
915
991
|
for (let i = 0; i < parts.length; i++) {
|
|
@@ -944,6 +1020,7 @@ export default function mergeInDependentDataStructure({
|
|
|
944
1020
|
|
|
945
1021
|
const basePathParts = splitOutsideParenthesesAndArrays(basePath);
|
|
946
1022
|
for (const schemaPath in dataStructure.returnValueSchema) {
|
|
1023
|
+
checkDeadline();
|
|
947
1024
|
const schemaPathParts = splitOutsideParenthesesAndArrays(schemaPath);
|
|
948
1025
|
if (schemaPathParts.length < basePathParts.length) continue;
|
|
949
1026
|
|
|
@@ -984,6 +1061,7 @@ export default function mergeInDependentDataStructure({
|
|
|
984
1061
|
// We do this before the main merge to ensure the connection happens regardless
|
|
985
1062
|
// of processing order.
|
|
986
1063
|
for (const esp of equivalentSchemaPaths) {
|
|
1064
|
+
checkDeadline();
|
|
987
1065
|
for (const root of esp.equivalentRoots) {
|
|
988
1066
|
if (root.schemaRootPath.endsWith('[]')) {
|
|
989
1067
|
// Find a matching parent entry with the base array path
|
|
@@ -1004,6 +1082,7 @@ export default function mergeInDependentDataStructure({
|
|
|
1004
1082
|
for (const [postfixPath, postfixValue] of Object.entries(
|
|
1005
1083
|
esp.equivalentPostfixes,
|
|
1006
1084
|
)) {
|
|
1085
|
+
checkDeadline();
|
|
1007
1086
|
const transformedPostfix = joinParenthesesAndArrays(
|
|
1008
1087
|
['[]', postfixPath].filter(Boolean),
|
|
1009
1088
|
);
|
|
@@ -1093,6 +1172,7 @@ export default function mergeInDependentDataStructure({
|
|
|
1093
1172
|
);
|
|
1094
1173
|
|
|
1095
1174
|
for (const esp of sortedEquivalentSchemaPaths) {
|
|
1175
|
+
checkDeadline();
|
|
1096
1176
|
if (esp.equivalentRoots.length === 0) continue;
|
|
1097
1177
|
let bestCandidateLength: number | undefined;
|
|
1098
1178
|
let bestCandidate: (typeof equivalentSchemaPaths)[0] | undefined;
|
|
@@ -1174,6 +1254,7 @@ export default function mergeInDependentDataStructure({
|
|
|
1174
1254
|
// dependencySchemas contains usage information (how dependencies are called),
|
|
1175
1255
|
// not internal implementation, so we want this for mocked dependencies too
|
|
1176
1256
|
for (const dependency of importedExports) {
|
|
1257
|
+
checkDeadline();
|
|
1177
1258
|
const dependentDataStructure =
|
|
1178
1259
|
dependencySchemas?.[dependency.filePath]?.[dependency.name];
|
|
1179
1260
|
if (!dependentDataStructure) continue;
|
|
@@ -1198,18 +1279,36 @@ export default function mergeInDependentDataStructure({
|
|
|
1198
1279
|
}
|
|
1199
1280
|
}
|
|
1200
1281
|
|
|
1282
|
+
const gatherElapsed = Date.now() - mergeStartTime;
|
|
1283
|
+
|
|
1201
1284
|
equivalentSchemaPaths = mergeAllEquivalentSchemaPaths();
|
|
1202
1285
|
|
|
1286
|
+
const mergeEspElapsed = Date.now() - mergeStartTime;
|
|
1287
|
+
|
|
1203
1288
|
// Collect schemas that need cleaning — batch the calls for the end instead of
|
|
1204
1289
|
// calling cleanSchema inside the inner root loop (which was O(roots * schemaSize)).
|
|
1205
1290
|
const schemasToClean = new Set<{ [key: string]: string }>();
|
|
1206
1291
|
|
|
1207
1292
|
for (const esp of equivalentSchemaPaths) {
|
|
1293
|
+
checkDeadline();
|
|
1208
1294
|
// Pre-compute which postfixes have children to avoid O(n²) lookups in the inner loop.
|
|
1209
1295
|
// A postfix "has children" if there are other postfixes that extend it.
|
|
1210
1296
|
const postfixesWithChildren = new Set<string>();
|
|
1211
1297
|
const postfixKeys = Object.keys(esp.equivalentPostfixes);
|
|
1212
1298
|
|
|
1299
|
+
// Pre-parse ALL postfix paths once. These parsed parts are reused in:
|
|
1300
|
+
// 1. The children detection loop below
|
|
1301
|
+
// 2. The inner postfix application loop (lines that split postfixPath and equivalentRoot.postfix)
|
|
1302
|
+
// This eliminates thousands of redundant splitOutsideParenthesesAndArrays calls.
|
|
1303
|
+
const postfixPartsCache = new Map<string, string[]>();
|
|
1304
|
+
for (const postfixPath of postfixKeys) {
|
|
1305
|
+
if (!postfixPath) continue;
|
|
1306
|
+
postfixPartsCache.set(
|
|
1307
|
+
postfixPath,
|
|
1308
|
+
splitOutsideParenthesesAndArrays(postfixPath),
|
|
1309
|
+
);
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1213
1312
|
// Check for empty postfix having children (any other postfixes exist)
|
|
1214
1313
|
if (postfixKeys.length > 1 && '' in esp.equivalentPostfixes) {
|
|
1215
1314
|
postfixesWithChildren.add('');
|
|
@@ -1221,7 +1320,7 @@ export default function mergeInDependentDataStructure({
|
|
|
1221
1320
|
const postfixPrefixSet = new Set<string>();
|
|
1222
1321
|
for (const postfixPath of postfixKeys) {
|
|
1223
1322
|
if (!postfixPath) continue;
|
|
1224
|
-
const parts =
|
|
1323
|
+
const parts = postfixPartsCache.get(postfixPath)!;
|
|
1225
1324
|
for (let i = 1; i < parts.length; i++) {
|
|
1226
1325
|
postfixPrefixSet.add(joinParenthesesAndArrays(parts.slice(0, i)));
|
|
1227
1326
|
}
|
|
@@ -1242,7 +1341,13 @@ export default function mergeInDependentDataStructure({
|
|
|
1242
1341
|
return true;
|
|
1243
1342
|
});
|
|
1244
1343
|
|
|
1344
|
+
// Cap schema size to prevent combinatorial explosion.
|
|
1345
|
+
// Successful merges produce <3K ret keys. Beyond 5K, further postfixes
|
|
1346
|
+
// add noise but no useful data — they're cross-products of unrelated equivalencies.
|
|
1347
|
+
const SCHEMA_KEY_CAP = 5_000;
|
|
1348
|
+
|
|
1245
1349
|
for (const equivalentRoot of uniqueRoots) {
|
|
1350
|
+
checkDeadline();
|
|
1246
1351
|
let merged:
|
|
1247
1352
|
| {
|
|
1248
1353
|
signatureSchema: { [key: string]: string };
|
|
@@ -1262,9 +1367,13 @@ export default function mergeInDependentDataStructure({
|
|
|
1262
1367
|
? merged.signatureSchema
|
|
1263
1368
|
: merged.returnValueSchema;
|
|
1264
1369
|
|
|
1370
|
+
// Skip if this schema has already grown past the cap
|
|
1371
|
+
if (Object.keys(schema).length > SCHEMA_KEY_CAP) continue;
|
|
1372
|
+
|
|
1265
1373
|
for (const [postfixPath, postfixValue] of Object.entries(
|
|
1266
1374
|
esp.equivalentPostfixes,
|
|
1267
1375
|
)) {
|
|
1376
|
+
checkDeadline();
|
|
1268
1377
|
let relevantPostfix = postfixPath;
|
|
1269
1378
|
if (equivalentRoot.postfix) {
|
|
1270
1379
|
// Check if postfixPath starts with equivalentRoot.postfix at a path boundary.
|
|
@@ -1284,10 +1393,18 @@ export default function mergeInDependentDataStructure({
|
|
|
1284
1393
|
}
|
|
1285
1394
|
|
|
1286
1395
|
const postFixPathParts =
|
|
1396
|
+
postfixPartsCache.get(postfixPath) ??
|
|
1287
1397
|
splitOutsideParenthesesAndArrays(postfixPath);
|
|
1288
|
-
|
|
1398
|
+
// Cache equivalentRoot.postfix parts — same root reused across all postfixes
|
|
1399
|
+
if (!postfixPartsCache.has(equivalentRoot.postfix)) {
|
|
1400
|
+
postfixPartsCache.set(
|
|
1401
|
+
equivalentRoot.postfix,
|
|
1402
|
+
splitOutsideParenthesesAndArrays(equivalentRoot.postfix),
|
|
1403
|
+
);
|
|
1404
|
+
}
|
|
1405
|
+
const equivalentRootPostFixParts = postfixPartsCache.get(
|
|
1289
1406
|
equivalentRoot.postfix,
|
|
1290
|
-
)
|
|
1407
|
+
)!;
|
|
1291
1408
|
relevantPostfix = joinParenthesesAndArrays(
|
|
1292
1409
|
postFixPathParts.slice(equivalentRootPostFixParts.length),
|
|
1293
1410
|
);
|
|
@@ -1385,11 +1502,15 @@ export default function mergeInDependentDataStructure({
|
|
|
1385
1502
|
}
|
|
1386
1503
|
}
|
|
1387
1504
|
|
|
1505
|
+
const postfixElapsed = Date.now() - mergeStartTime;
|
|
1506
|
+
|
|
1388
1507
|
// Batch-clean all modified schemas once (instead of once per root per ESP entry)
|
|
1389
1508
|
for (const schema of schemasToClean) {
|
|
1390
1509
|
cleanSchema(schema, { stage: 'afterMergePostfix' });
|
|
1391
1510
|
}
|
|
1392
1511
|
|
|
1512
|
+
const cleanElapsed = Date.now() - mergeStartTime;
|
|
1513
|
+
|
|
1393
1514
|
// Propagate equivalency-derived attributes to generic function call variants.
|
|
1394
1515
|
// When attributes are traced via equivalencies (e.g., fileComparisons from buildDataMap.signature[2]),
|
|
1395
1516
|
// they get written to non-generic paths (returnValue.data.x or funcName().functionCallReturnValue.data.x).
|
|
@@ -1415,6 +1536,7 @@ export default function mergeInDependentDataStructure({
|
|
|
1415
1536
|
);
|
|
1416
1537
|
|
|
1417
1538
|
for (const path in schemaToSearchForGenericVariants) {
|
|
1539
|
+
checkDeadline();
|
|
1418
1540
|
const match = path.match(genericRegex);
|
|
1419
1541
|
if (match) {
|
|
1420
1542
|
genericVariants.add(match[0]);
|
|
@@ -1428,6 +1550,7 @@ export default function mergeInDependentDataStructure({
|
|
|
1428
1550
|
const pathsToAdd: [string, string][] = [];
|
|
1429
1551
|
|
|
1430
1552
|
for (const path in returnValueSchema) {
|
|
1553
|
+
checkDeadline();
|
|
1431
1554
|
const value = returnValueSchema[path];
|
|
1432
1555
|
|
|
1433
1556
|
// Handle returnValue. paths
|
|
@@ -1481,6 +1604,7 @@ export default function mergeInDependentDataStructure({
|
|
|
1481
1604
|
// This includes both returnValue. (dot) and returnValue[ (array) paths.
|
|
1482
1605
|
const pathsToNormalize: [string, string][] = [];
|
|
1483
1606
|
for (const path in depSchema.returnValueSchema) {
|
|
1607
|
+
checkDeadline();
|
|
1484
1608
|
if (
|
|
1485
1609
|
path === 'returnValue' ||
|
|
1486
1610
|
path.startsWith('returnValue.') ||
|
|
@@ -1521,6 +1645,7 @@ export default function mergeInDependentDataStructure({
|
|
|
1521
1645
|
|
|
1522
1646
|
// Now copy paths from the source schema (dependencySchemas)
|
|
1523
1647
|
for (const path in srcSchema.returnValueSchema) {
|
|
1648
|
+
checkDeadline();
|
|
1524
1649
|
const value = srcSchema.returnValueSchema[path];
|
|
1525
1650
|
|
|
1526
1651
|
// Normalize paths starting with 'returnValue' to use the standard format:
|
|
@@ -1714,9 +1839,11 @@ export default function mergeInDependentDataStructure({
|
|
|
1714
1839
|
if (!existingSchema) {
|
|
1715
1840
|
const depSchema = findOrCreateDependentSchemas({ filePath, name });
|
|
1716
1841
|
for (const path in srcSchema.returnValueSchema) {
|
|
1842
|
+
checkDeadline();
|
|
1717
1843
|
depSchema.returnValueSchema[path] = srcSchema.returnValueSchema[path];
|
|
1718
1844
|
}
|
|
1719
1845
|
for (const path in srcSchema.signatureSchema) {
|
|
1846
|
+
checkDeadline();
|
|
1720
1847
|
depSchema.signatureSchema[path] = srcSchema.signatureSchema[path];
|
|
1721
1848
|
}
|
|
1722
1849
|
|
|
@@ -1746,6 +1873,7 @@ export default function mergeInDependentDataStructure({
|
|
|
1746
1873
|
|
|
1747
1874
|
if (childSignatureSchema) {
|
|
1748
1875
|
for (const path in depSchema.signatureSchema) {
|
|
1876
|
+
checkDeadline();
|
|
1749
1877
|
const parentType = depSchema.signatureSchema[path];
|
|
1750
1878
|
const childType = childSignatureSchema[path];
|
|
1751
1879
|
|
|
@@ -1794,6 +1922,7 @@ export default function mergeInDependentDataStructure({
|
|
|
1794
1922
|
|
|
1795
1923
|
// Copy only paths that belong to this variant
|
|
1796
1924
|
for (const path in srcSchema.returnValueSchema) {
|
|
1925
|
+
checkDeadline();
|
|
1797
1926
|
if (path.startsWith(variant)) {
|
|
1798
1927
|
variantSchema.returnValueSchema[path] =
|
|
1799
1928
|
srcSchema.returnValueSchema[path];
|
|
@@ -1816,6 +1945,7 @@ export default function mergeInDependentDataStructure({
|
|
|
1816
1945
|
// EXCEPT: Skip mocked dependencies - we don't want their internal implementation details.
|
|
1817
1946
|
for (const filePath in dependentAnalyses) {
|
|
1818
1947
|
for (const name in dependentAnalyses[filePath]) {
|
|
1948
|
+
checkDeadline();
|
|
1819
1949
|
const dependentMergedDataStructure =
|
|
1820
1950
|
dependentAnalyses[filePath][name].metadata?.mergedDataStructure;
|
|
1821
1951
|
|
|
@@ -1832,6 +1962,7 @@ export default function mergeInDependentDataStructure({
|
|
|
1832
1962
|
// Copy over all paths from the dependent's returnValueSchema
|
|
1833
1963
|
// Only add paths that don't already exist (don't overwrite values set by equivalencies)
|
|
1834
1964
|
for (const path in dependentMergedDataStructure.returnValueSchema) {
|
|
1965
|
+
checkDeadline();
|
|
1835
1966
|
const translatedPath = translatePath(path, name);
|
|
1836
1967
|
if (!(translatedPath in depSchema.returnValueSchema)) {
|
|
1837
1968
|
depSchema.returnValueSchema[translatedPath] =
|
|
@@ -1841,6 +1972,7 @@ export default function mergeInDependentDataStructure({
|
|
|
1841
1972
|
|
|
1842
1973
|
// Copy over signature schema as well
|
|
1843
1974
|
for (const path in dependentMergedDataStructure.signatureSchema) {
|
|
1975
|
+
checkDeadline();
|
|
1844
1976
|
const translatedPath = translatePath(path, name);
|
|
1845
1977
|
if (!(translatedPath in depSchema.signatureSchema)) {
|
|
1846
1978
|
depSchema.signatureSchema[translatedPath] =
|
|
@@ -1867,6 +1999,7 @@ export default function mergeInDependentDataStructure({
|
|
|
1867
1999
|
|
|
1868
2000
|
// Merge in the nested dependency schemas
|
|
1869
2001
|
for (const path in nestedDepSchema.returnValueSchema) {
|
|
2002
|
+
checkDeadline();
|
|
1870
2003
|
if (!(path in targetDepSchema.returnValueSchema)) {
|
|
1871
2004
|
const value = nestedDepSchema.returnValueSchema[path];
|
|
1872
2005
|
targetDepSchema.returnValueSchema[path] = value;
|
|
@@ -1874,6 +2007,7 @@ export default function mergeInDependentDataStructure({
|
|
|
1874
2007
|
}
|
|
1875
2008
|
|
|
1876
2009
|
for (const path in nestedDepSchema.signatureSchema) {
|
|
2010
|
+
checkDeadline();
|
|
1877
2011
|
if (!(path in targetDepSchema.signatureSchema)) {
|
|
1878
2012
|
targetDepSchema.signatureSchema[path] =
|
|
1879
2013
|
nestedDepSchema.signatureSchema[path];
|
|
@@ -1885,5 +2019,15 @@ export default function mergeInDependentDataStructure({
|
|
|
1885
2019
|
}
|
|
1886
2020
|
}
|
|
1887
2021
|
|
|
2022
|
+
const totalElapsed = Date.now() - mergeStartTime;
|
|
2023
|
+
const retKeys = Object.keys(mergedDataStructure.returnValueSchema).length;
|
|
2024
|
+
|
|
2025
|
+
// Only log phase breakdown for slow merges (>2s)
|
|
2026
|
+
if (totalElapsed > 2000) {
|
|
2027
|
+
console.log(
|
|
2028
|
+
`CodeYam Log Level 2: ${rootScopeName} merge phases: gather=${gatherElapsed}ms mergeESP=${mergeEspElapsed - gatherElapsed}ms postfix=${postfixElapsed - mergeEspElapsed}ms clean=${cleanElapsed - postfixElapsed}ms depCopy=${totalElapsed - cleanElapsed}ms total=${totalElapsed}ms ret=${retKeys}`,
|
|
2029
|
+
);
|
|
2030
|
+
}
|
|
2031
|
+
|
|
1888
2032
|
return mergedDataStructure;
|
|
1889
2033
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Structural test: handleAudit must NOT call runAnalysisForEntities.
|
|
5
|
+
*
|
|
6
|
+
* Previously, handleAudit auto-ran targeted analysis for incomplete entities,
|
|
7
|
+
* which was slow (analyzer startup + AST scan) and contradicted the design
|
|
8
|
+
* intent (comment at line ~6255 says "We do NOT run handleAnalyzeImports here").
|
|
9
|
+
*
|
|
10
|
+
* This test ensures the auto-analysis doesn't creep back in.
|
|
11
|
+
*/
|
|
12
|
+
describe('handleAudit - no auto-analysis', () => {
|
|
13
|
+
it('should not call runAnalysisForEntities inside handleAudit', () => {
|
|
14
|
+
const editorTsPath = path.join(__dirname, '..', 'editor.ts');
|
|
15
|
+
const source = fs.readFileSync(editorTsPath, 'utf8');
|
|
16
|
+
// Extract the handleAudit function body.
|
|
17
|
+
// It starts with "async function handleAudit" and ends at the next
|
|
18
|
+
// top-level "async function" or "function" declaration (unindented).
|
|
19
|
+
const handleAuditStart = source.indexOf('async function handleAudit');
|
|
20
|
+
expect(handleAuditStart).toBeGreaterThan(-1);
|
|
21
|
+
// Find the next top-level function declaration after handleAudit starts.
|
|
22
|
+
// Top-level functions start at the beginning of a line (no indentation).
|
|
23
|
+
const afterStart = source.slice(handleAuditStart + 1);
|
|
24
|
+
const nextFnMatch = afterStart.match(/\n(?:async )?function [a-zA-Z]/);
|
|
25
|
+
const handleAuditEnd = nextFnMatch
|
|
26
|
+
? handleAuditStart + 1 + nextFnMatch.index
|
|
27
|
+
: source.length;
|
|
28
|
+
const handleAuditBody = source.slice(handleAuditStart, handleAuditEnd);
|
|
29
|
+
// The function body must NOT contain runAnalysisForEntities
|
|
30
|
+
expect(handleAuditBody).not.toContain('runAnalysisForEntities');
|
|
31
|
+
});
|
|
32
|
+
it('should report incomplete entities with guidance instead of auto-fixing', () => {
|
|
33
|
+
const editorTsPath = path.join(__dirname, '..', 'editor.ts');
|
|
34
|
+
const source = fs.readFileSync(editorTsPath, 'utf8');
|
|
35
|
+
const handleAuditStart = source.indexOf('async function handleAudit');
|
|
36
|
+
const afterStart = source.slice(handleAuditStart + 1);
|
|
37
|
+
const nextFnMatch = afterStart.match(/\n(?:async )?function [a-zA-Z]/);
|
|
38
|
+
const handleAuditEnd = nextFnMatch
|
|
39
|
+
? handleAuditStart + 1 + nextFnMatch.index
|
|
40
|
+
: source.length;
|
|
41
|
+
const handleAuditBody = source.slice(handleAuditStart, handleAuditEnd);
|
|
42
|
+
// Should still report incomplete entities
|
|
43
|
+
expect(handleAuditBody).toContain('incompleteEntities');
|
|
44
|
+
expect(handleAuditBody).toContain('formatIncompleteEntityGuidance');
|
|
45
|
+
});
|
|
46
|
+
it('should not call handleAnalyzeImports inside handleAudit', () => {
|
|
47
|
+
const editorTsPath = path.join(__dirname, '..', 'editor.ts');
|
|
48
|
+
const source = fs.readFileSync(editorTsPath, 'utf8');
|
|
49
|
+
const handleAuditStart = source.indexOf('async function handleAudit');
|
|
50
|
+
expect(handleAuditStart).toBeGreaterThan(-1);
|
|
51
|
+
const afterStart = source.slice(handleAuditStart + 1);
|
|
52
|
+
const nextFnMatch = afterStart.match(/\n(?:async )?function [a-zA-Z]/);
|
|
53
|
+
const handleAuditEnd = nextFnMatch
|
|
54
|
+
? handleAuditStart + 1 + nextFnMatch.index
|
|
55
|
+
: source.length;
|
|
56
|
+
const handleAuditBody = source.slice(handleAuditStart, handleAuditEnd);
|
|
57
|
+
// handleAnalyzeImports calls runAnalysisForEntities internally —
|
|
58
|
+
// it takes minutes on large projects and contradicts the audit's
|
|
59
|
+
// read-only design intent.
|
|
60
|
+
expect(handleAuditBody).not.toContain('handleAnalyzeImports');
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
//# sourceMappingURL=editor.auditNoAutoAnalysis.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor.auditNoAutoAnalysis.test.js","sourceRoot":"","sources":["../../../../../src/commands/__tests__/editor.auditNoAutoAnalysis.test.ts"],"names":[],"mappings":"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"}
|