@codeyam/codeyam-cli 0.1.20 → 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/package.json +1 -1
- package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +36 -9
- 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/findOrCreateEntity.ts +1 -0
- 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/analyzeChange.ts +4 -0
- package/analyzer-template/packages/analyze/src/lib/files/analyzeInitial.ts +4 -0
- 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/analyzer-template/packages/aws/package.json +1 -1
- package/analyzer-template/packages/database/src/lib/loadEntity.ts +11 -4
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntity.d.ts +4 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntity.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntity.js +4 -4
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntity.js.map +1 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.d.ts +3 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.js +22 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.js.map +1 -1
- package/analyzer-template/packages/utils/src/lib/fs/rsyncCopy.ts +27 -0
- 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 +553 -93
- package/codeyam-cli/src/commands/editor.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorAudit.test.js +991 -31
- 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__/registerScenarioResult.test.js +127 -0
- package/codeyam-cli/src/utils/__tests__/registerScenarioResult.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 +11 -1
- package/codeyam-cli/src/utils/analyzer.js.map +1 -1
- package/codeyam-cli/src/utils/editorAudit.js +210 -14
- 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/registerScenarioResult.js +52 -0
- package/codeyam-cli/src/utils/registerScenarioResult.js.map +1 -0
- 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/app/lib/clientErrors.js +3 -0
- package/codeyam-cli/src/webserver/app/lib/clientErrors.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/api.editor-save-scenario-data-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-schema-l0sNRNKZ.js +1 -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-CCKUIm0S.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-CluPkvXJ.js +41 -0
- 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-KTQuL0aj.js → entity._sha.scenarios._scenarioId.dev-CmLO432x.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.fullscreen-C6eeL24i.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-bcbb3d49.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{root-BxUQigda.js → root-D2_tktnk.js} +26 -13
- package/codeyam-cli/src/webserver/build/server/assets/analysisRunner-DjF-soOH.js +16 -0
- package/codeyam-cli/src/webserver/build/server/assets/{index-CjLhfz6Z.js → index-nAvHGWbz.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{init-BEqlbI84.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 +18 -5
- 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 +27 -10
- 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/findOrCreateEntity.js +1 -0
- package/packages/analyze/src/lib/files/analyze/findOrCreateEntity.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/analyzeChange.js +1 -0
- package/packages/analyze/src/lib/files/analyzeChange.js.map +1 -1
- package/packages/analyze/src/lib/files/analyzeInitial.js +1 -0
- package/packages/analyze/src/lib/files/analyzeInitial.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/packages/database/src/lib/loadEntity.js +4 -4
- package/packages/database/src/lib/loadEntity.js.map +1 -1
- package/packages/utils/src/lib/fs/rsyncCopy.js +22 -1
- package/packages/utils/src/lib/fs/rsyncCopy.js.map +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/cy-logo-cli-DcX-ZS3p.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/editor.entity.(_sha)-DII1pg_z.js +0 -58
- package/codeyam-cli/src/webserver/build/client/assets/editorPreview-oepecPae.js +0 -41
- package/codeyam-cli/src/webserver/build/client/assets/globals-Yn9W3zp3.css +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-cdf2c0a7.js +0 -1
- package/codeyam-cli/src/webserver/build/server/assets/analysisRunner-B_PsTAb1.js +0 -13
- package/codeyam-cli/src/webserver/build/server/assets/server-build-YI63xTu4.js +0 -553
|
@@ -25,6 +25,18 @@ function getTypeParameter(functionName) {
|
|
|
25
25
|
}
|
|
26
26
|
return null;
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Check if a schema path contains a Set/Map collection method call.
|
|
30
|
+
* Paths like `.has(articleId)`, `.delete(articleId)`, `.add(articleId)` represent
|
|
31
|
+
* membership checks on Sets/Maps, not meaningful data flow for schema generation.
|
|
32
|
+
* These create massive combinatorial explosions when every filter field (filterRatings,
|
|
33
|
+
* filterPublications, filterAuthors, etc.) × every method (has, delete, add) gets
|
|
34
|
+
* tracked as a separate equivalency.
|
|
35
|
+
*/
|
|
36
|
+
const COLLECTION_METHOD_PATTERN = /\.(?:has|delete|add|clear|get|set)\(/;
|
|
37
|
+
function isCollectionMethodPath(path) {
|
|
38
|
+
return COLLECTION_METHOD_PATTERN.test(path);
|
|
39
|
+
}
|
|
28
40
|
// Primitive types that should not have child paths
|
|
29
41
|
const PRIMITIVE_TYPES = new Set([
|
|
30
42
|
'number',
|
|
@@ -107,7 +119,27 @@ function bestValueFromOptions(options) {
|
|
|
107
119
|
}
|
|
108
120
|
return options[0] ?? 'unknown';
|
|
109
121
|
}
|
|
110
|
-
|
|
122
|
+
/** Timeout (ms) for the merge operation. Throws DataStructureTimeoutError if exceeded.
|
|
123
|
+
* All successful merges complete in <300ms. Anything exceeding 2s is pathological. */
|
|
124
|
+
const MERGE_TIMEOUT_MS = 2000;
|
|
125
|
+
export class DataStructureTimeoutError extends Error {
|
|
126
|
+
constructor(entityName, elapsedMs) {
|
|
127
|
+
super(`Data structure merge timed out for ${entityName} after ${Math.round(elapsedMs / 1000)}s (limit: ${MERGE_TIMEOUT_MS / 1000}s)`);
|
|
128
|
+
this.name = 'DataStructureTimeoutError';
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
export default function mergeInDependentDataStructure({ importedExports, dependentAnalyses, rootScopeName, dataStructure, dependencySchemas, timeoutMs = MERGE_TIMEOUT_MS, }) {
|
|
132
|
+
const mergeStartTime = Date.now();
|
|
133
|
+
const mergeDeadline = timeoutMs > 0 ? mergeStartTime + timeoutMs : 0;
|
|
134
|
+
/** Call in hot loops. Throws DataStructureTimeoutError if deadline exceeded.
|
|
135
|
+
* Date.now() is ~20ns — negligible vs the ms-scale string ops in each iteration. */
|
|
136
|
+
const checkDeadline = () => {
|
|
137
|
+
if (!mergeDeadline)
|
|
138
|
+
return;
|
|
139
|
+
if (Date.now() > mergeDeadline) {
|
|
140
|
+
throw new DataStructureTimeoutError(rootScopeName, Date.now() - mergeStartTime);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
111
143
|
const mergedDataStructure = {
|
|
112
144
|
signatureSchema: { ...(dataStructure.signatureSchema ?? {}) },
|
|
113
145
|
returnValueSchema: { ...(dataStructure.returnValueSchema ?? {}) },
|
|
@@ -205,7 +237,16 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
205
237
|
const cleanSchema = (schema, context) => {
|
|
206
238
|
transformationTracer.traceSchemaTransform(rootScopeName, 'cleanKnownObjectFunctionsFromMapping', schema, cleanKnownObjectFunctionsFromMapping, context);
|
|
207
239
|
};
|
|
240
|
+
// Cache translatePath results — the same path is often translated multiple times
|
|
241
|
+
// (once per equivalency entry that references it). Avoids redundant
|
|
242
|
+
// splitOutsideParenthesesAndArrays calls on long paths.
|
|
243
|
+
const translatePathCache = new Map();
|
|
208
244
|
const translatePath = (path, dependencyName) => {
|
|
245
|
+
const cacheKey = `${dependencyName}\0${path}`;
|
|
246
|
+
const cached = translatePathCache.get(cacheKey);
|
|
247
|
+
if (cached !== undefined)
|
|
248
|
+
return cached;
|
|
249
|
+
let result = path;
|
|
209
250
|
if (path.startsWith(dependencyName)) {
|
|
210
251
|
const pathParts = splitOutsideParenthesesAndArrays(path);
|
|
211
252
|
if (pathParts.length > 1) {
|
|
@@ -213,34 +254,27 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
213
254
|
// Check if this function has multiple DIFFERENT type parameters.
|
|
214
255
|
// If so, DON'T normalize to returnValue - keep the full path to avoid
|
|
215
256
|
// merging different type-parameterized variants together.
|
|
216
|
-
// e.g., useFetcher<{ data: UserData }>().functionCallReturnValue.data
|
|
217
|
-
// should NOT be merged with useFetcher<{ data: ConfigData }>().functionCallReturnValue.data
|
|
218
257
|
const baseName = cleanFunctionName(pathParts[0]);
|
|
219
|
-
if (functionsWithMultipleTypeParams.has(baseName)) {
|
|
220
|
-
|
|
258
|
+
if (!functionsWithMultipleTypeParams.has(baseName)) {
|
|
259
|
+
// functionCallReturnValue immediately follows - normalize to returnValue
|
|
260
|
+
result = joinParenthesesAndArrays([
|
|
261
|
+
'returnValue',
|
|
262
|
+
...pathParts.slice(2),
|
|
263
|
+
]);
|
|
221
264
|
}
|
|
222
|
-
// functionCallReturnValue immediately follows - normalize to returnValue
|
|
223
|
-
// e.g., useAuth().functionCallReturnValue.user -> returnValue.user
|
|
224
|
-
return joinParenthesesAndArrays([
|
|
225
|
-
'returnValue',
|
|
226
|
-
...pathParts.slice(2),
|
|
227
|
-
]);
|
|
228
265
|
}
|
|
229
266
|
else if (pathParts[0].endsWith(')') &&
|
|
230
267
|
pathParts[1].startsWith('signature[')) {
|
|
231
|
-
// Hook-style with signature access
|
|
232
|
-
|
|
233
|
-
return joinParenthesesAndArrays(pathParts.slice(1));
|
|
268
|
+
// Hook-style with signature access
|
|
269
|
+
result = joinParenthesesAndArrays(pathParts.slice(1));
|
|
234
270
|
}
|
|
235
|
-
// For all other cases (object-style APIs like getSupabase().auth and
|
|
236
|
-
// direct object references like supabase.from), preserve the path as-is.
|
|
237
|
-
// The prefix must be kept for proper schema lookups in constructMockCode
|
|
238
|
-
// and gatherDataForMocks.
|
|
239
271
|
}
|
|
240
272
|
}
|
|
241
|
-
|
|
273
|
+
translatePathCache.set(cacheKey, result);
|
|
274
|
+
return result;
|
|
242
275
|
};
|
|
243
276
|
const gatherAllEquivalentSchemaPaths = (functionName, sourceAndUsageEquivalencies, dataStructure) => {
|
|
277
|
+
checkDeadline();
|
|
244
278
|
if (!sourceAndUsageEquivalencies)
|
|
245
279
|
return;
|
|
246
280
|
const normalizedSchemaCache = new Map();
|
|
@@ -252,6 +286,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
252
286
|
return cached;
|
|
253
287
|
const byFirstPart = new Map();
|
|
254
288
|
for (const path in schema) {
|
|
289
|
+
checkDeadline();
|
|
255
290
|
let parts = splitOutsideParenthesesAndArrays(path);
|
|
256
291
|
if (parts[0].startsWith(functionName)) {
|
|
257
292
|
const baseName = cleanFunctionName(parts[0]);
|
|
@@ -300,6 +335,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
300
335
|
// Use espIndex Map for O(1) lookup instead of O(E) linear search.
|
|
301
336
|
// Falls back to linear search only when Map hit has a signature index conflict.
|
|
302
337
|
for (const pathInfo of allPaths) {
|
|
338
|
+
checkDeadline();
|
|
303
339
|
if (equivalentSchemaPathsEntry)
|
|
304
340
|
break;
|
|
305
341
|
const candidate = espIndex.get(espIndexKey(pathInfo.path, pathInfo.functionName));
|
|
@@ -420,18 +456,40 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
420
456
|
for (const equivalencies of allEquivalencies) {
|
|
421
457
|
const schemaPathEntries = Object.entries(equivalencies);
|
|
422
458
|
for (const [schemaPath, usages] of schemaPathEntries) {
|
|
459
|
+
checkDeadline();
|
|
460
|
+
// Skip equivalency entries whose source path is a Set/Map membership operation.
|
|
461
|
+
// Patterns like `.has(articleId)`, `.delete(articleId)`, `.add(articleId)` on
|
|
462
|
+
// Sets/Maps represent membership checks, not meaningful data flow for schema generation.
|
|
463
|
+
// In the Margo LibraryPage case, these account for 74% of all equivalency targets
|
|
464
|
+
// (19,444 of 26,340) and cause a combinatorial explosion in the merge.
|
|
465
|
+
if (isCollectionMethodPath(schemaPath))
|
|
466
|
+
continue;
|
|
423
467
|
// First, check if the raw schemaPath starts with a function call to a dependency.
|
|
424
468
|
// If so, use that dependency name for translation (so translatePath can strip the prefix).
|
|
425
469
|
const extractedFuncName = extractFunctionNameFromPath(schemaPath);
|
|
426
470
|
const effectiveFunctionName = extractedFuncName || functionName;
|
|
427
471
|
const translatedPath = translatePath(schemaPath, effectiveFunctionName);
|
|
428
|
-
const
|
|
472
|
+
const allPathsRaw = [
|
|
429
473
|
{ path: translatedPath, functionName: effectiveFunctionName },
|
|
430
|
-
...usages
|
|
474
|
+
...usages
|
|
475
|
+
.filter((u) => !isCollectionMethodPath(u.schemaPath))
|
|
476
|
+
.map((u) => ({
|
|
431
477
|
path: translatePath(u.schemaPath, u.scopeNodeName),
|
|
432
478
|
functionName: u.scopeNodeName,
|
|
433
479
|
})),
|
|
434
480
|
].filter((pathInfo) => !pathInfo.path.includes('.map('));
|
|
481
|
+
// Deduplicate by translated path + function name.
|
|
482
|
+
// Multiple call variants (e.g., loadView(viewKey(null,null)) vs loadView(viewKey(newTag,newCol)))
|
|
483
|
+
// translate to the same path after stripping arguments. Processing duplicates
|
|
484
|
+
// creates O(n²) work in the schema matching loops below.
|
|
485
|
+
const seenPathKeys = new Set();
|
|
486
|
+
const allPaths = allPathsRaw.filter((p) => {
|
|
487
|
+
const key = `${p.functionName ?? ''}::${p.path}`;
|
|
488
|
+
if (seenPathKeys.has(key))
|
|
489
|
+
return false;
|
|
490
|
+
seenPathKeys.add(key);
|
|
491
|
+
return true;
|
|
492
|
+
});
|
|
435
493
|
// Fix 38: Derive base paths from property access paths.
|
|
436
494
|
// When we have equivalent paths like:
|
|
437
495
|
// Parent: signature[0].scenarios[].name
|
|
@@ -454,6 +512,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
454
512
|
const derivedBasePathSet = new Set();
|
|
455
513
|
// For each child path, find its equivalent parent path and derive bases
|
|
456
514
|
for (const childPathInfo of childPaths) {
|
|
515
|
+
checkDeadline();
|
|
457
516
|
const childParts = splitOutsideParenthesesAndArrays(childPathInfo.path);
|
|
458
517
|
// Look for a parent path that shares a common suffix with this child path
|
|
459
518
|
for (const parentPathInfo of parentPaths) {
|
|
@@ -545,6 +604,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
545
604
|
});
|
|
546
605
|
}
|
|
547
606
|
for (const equivalentRoot of entry.equivalentRoots) {
|
|
607
|
+
checkDeadline();
|
|
548
608
|
const dataStructures = equivalentRoot.function &&
|
|
549
609
|
equivalentRoot.function.name !== rootScopeName
|
|
550
610
|
? [
|
|
@@ -582,6 +642,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
582
642
|
: lookupPart;
|
|
583
643
|
const candidates = schemaIndex.byFirstPart.get(lookupBase) || [];
|
|
584
644
|
for (const { path: schemaPath, parts: schemaPathParts, } of candidates) {
|
|
645
|
+
checkDeadline();
|
|
585
646
|
if (schemaPathParts.length < pathParts.length)
|
|
586
647
|
continue;
|
|
587
648
|
// Check if all path parts match (allowing function call variants)
|
|
@@ -676,6 +737,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
676
737
|
// where we want both X().functionCallReturnValue and Y().functionCallReturnValue as bases
|
|
677
738
|
const allBasePaths = new Set();
|
|
678
739
|
for (const path of Object.keys(dataStructure.returnValueSchema)) {
|
|
740
|
+
checkDeadline();
|
|
679
741
|
const parts = splitOutsideParenthesesAndArrays(path);
|
|
680
742
|
// Find all positions of functionCallReturnValue and create base paths for each
|
|
681
743
|
for (let i = 0; i < parts.length; i++) {
|
|
@@ -702,6 +764,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
702
764
|
espIndex.set(espIndexKey(newRoot.schemaRootPath, newRootFuncName), entry);
|
|
703
765
|
const basePathParts = splitOutsideParenthesesAndArrays(basePath);
|
|
704
766
|
for (const schemaPath in dataStructure.returnValueSchema) {
|
|
767
|
+
checkDeadline();
|
|
705
768
|
const schemaPathParts = splitOutsideParenthesesAndArrays(schemaPath);
|
|
706
769
|
if (schemaPathParts.length < basePathParts.length)
|
|
707
770
|
continue;
|
|
@@ -734,6 +797,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
734
797
|
// We do this before the main merge to ensure the connection happens regardless
|
|
735
798
|
// of processing order.
|
|
736
799
|
for (const esp of equivalentSchemaPaths) {
|
|
800
|
+
checkDeadline();
|
|
737
801
|
for (const root of esp.equivalentRoots) {
|
|
738
802
|
if (root.schemaRootPath.endsWith('[]')) {
|
|
739
803
|
// Find a matching parent entry with the base array path
|
|
@@ -746,6 +810,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
746
810
|
// Add transformed postfixes from child (array element) to parent (array)
|
|
747
811
|
// so they can be applied with [] prefix to parent paths
|
|
748
812
|
for (const [postfixPath, postfixValue] of Object.entries(esp.equivalentPostfixes)) {
|
|
813
|
+
checkDeadline();
|
|
749
814
|
const transformedPostfix = joinParenthesesAndArrays(['[]', postfixPath].filter(Boolean));
|
|
750
815
|
if (!(transformedPostfix in parentEntry.equivalentPostfixes)) {
|
|
751
816
|
parentEntry.equivalentPostfixes[transformedPostfix] =
|
|
@@ -798,6 +863,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
798
863
|
const sortedEquivalentSchemaPaths = equivalentSchemaPaths.sort((a, b) => Math.max(...a.equivalentRoots.map((er) => splitOutsideParenthesesAndArrays(er.schemaRootPath).length)) -
|
|
799
864
|
Math.max(...b.equivalentRoots.map((er) => splitOutsideParenthesesAndArrays(er.schemaRootPath).length)));
|
|
800
865
|
for (const esp of sortedEquivalentSchemaPaths) {
|
|
866
|
+
checkDeadline();
|
|
801
867
|
if (esp.equivalentRoots.length === 0)
|
|
802
868
|
continue;
|
|
803
869
|
let bestCandidateLength;
|
|
@@ -857,6 +923,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
857
923
|
// dependencySchemas contains usage information (how dependencies are called),
|
|
858
924
|
// not internal implementation, so we want this for mocked dependencies too
|
|
859
925
|
for (const dependency of importedExports) {
|
|
926
|
+
checkDeadline();
|
|
860
927
|
const dependentDataStructure = dependencySchemas?.[dependency.filePath]?.[dependency.name];
|
|
861
928
|
if (!dependentDataStructure)
|
|
862
929
|
continue;
|
|
@@ -872,15 +939,28 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
872
939
|
gatherAllEquivalentSchemaPaths(name, childMergedDataStructure);
|
|
873
940
|
}
|
|
874
941
|
}
|
|
942
|
+
const gatherElapsed = Date.now() - mergeStartTime;
|
|
875
943
|
equivalentSchemaPaths = mergeAllEquivalentSchemaPaths();
|
|
944
|
+
const mergeEspElapsed = Date.now() - mergeStartTime;
|
|
876
945
|
// Collect schemas that need cleaning — batch the calls for the end instead of
|
|
877
946
|
// calling cleanSchema inside the inner root loop (which was O(roots * schemaSize)).
|
|
878
947
|
const schemasToClean = new Set();
|
|
879
948
|
for (const esp of equivalentSchemaPaths) {
|
|
949
|
+
checkDeadline();
|
|
880
950
|
// Pre-compute which postfixes have children to avoid O(n²) lookups in the inner loop.
|
|
881
951
|
// A postfix "has children" if there are other postfixes that extend it.
|
|
882
952
|
const postfixesWithChildren = new Set();
|
|
883
953
|
const postfixKeys = Object.keys(esp.equivalentPostfixes);
|
|
954
|
+
// Pre-parse ALL postfix paths once. These parsed parts are reused in:
|
|
955
|
+
// 1. The children detection loop below
|
|
956
|
+
// 2. The inner postfix application loop (lines that split postfixPath and equivalentRoot.postfix)
|
|
957
|
+
// This eliminates thousands of redundant splitOutsideParenthesesAndArrays calls.
|
|
958
|
+
const postfixPartsCache = new Map();
|
|
959
|
+
for (const postfixPath of postfixKeys) {
|
|
960
|
+
if (!postfixPath)
|
|
961
|
+
continue;
|
|
962
|
+
postfixPartsCache.set(postfixPath, splitOutsideParenthesesAndArrays(postfixPath));
|
|
963
|
+
}
|
|
884
964
|
// Check for empty postfix having children (any other postfixes exist)
|
|
885
965
|
if (postfixKeys.length > 1 && '' in esp.equivalentPostfixes) {
|
|
886
966
|
postfixesWithChildren.add('');
|
|
@@ -892,7 +972,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
892
972
|
for (const postfixPath of postfixKeys) {
|
|
893
973
|
if (!postfixPath)
|
|
894
974
|
continue;
|
|
895
|
-
const parts =
|
|
975
|
+
const parts = postfixPartsCache.get(postfixPath);
|
|
896
976
|
for (let i = 1; i < parts.length; i++) {
|
|
897
977
|
postfixPrefixSet.add(joinParenthesesAndArrays(parts.slice(0, i)));
|
|
898
978
|
}
|
|
@@ -912,7 +992,12 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
912
992
|
seenRootKeys.add(key);
|
|
913
993
|
return true;
|
|
914
994
|
});
|
|
995
|
+
// Cap schema size to prevent combinatorial explosion.
|
|
996
|
+
// Successful merges produce <3K ret keys. Beyond 5K, further postfixes
|
|
997
|
+
// add noise but no useful data — they're cross-products of unrelated equivalencies.
|
|
998
|
+
const SCHEMA_KEY_CAP = 5000;
|
|
915
999
|
for (const equivalentRoot of uniqueRoots) {
|
|
1000
|
+
checkDeadline();
|
|
916
1001
|
let merged;
|
|
917
1002
|
if (equivalentRoot.function) {
|
|
918
1003
|
merged = findOrCreateDependentSchemas(equivalentRoot.function);
|
|
@@ -925,7 +1010,11 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
925
1010
|
const schema = equivalentRoot.schemaRootPath.startsWith('signature[')
|
|
926
1011
|
? merged.signatureSchema
|
|
927
1012
|
: merged.returnValueSchema;
|
|
1013
|
+
// Skip if this schema has already grown past the cap
|
|
1014
|
+
if (Object.keys(schema).length > SCHEMA_KEY_CAP)
|
|
1015
|
+
continue;
|
|
928
1016
|
for (const [postfixPath, postfixValue] of Object.entries(esp.equivalentPostfixes)) {
|
|
1017
|
+
checkDeadline();
|
|
929
1018
|
let relevantPostfix = postfixPath;
|
|
930
1019
|
if (equivalentRoot.postfix) {
|
|
931
1020
|
// Check if postfixPath starts with equivalentRoot.postfix at a path boundary.
|
|
@@ -943,8 +1032,13 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
943
1032
|
// This means "entity" matched "entityCode" which is wrong - they're different properties.
|
|
944
1033
|
continue;
|
|
945
1034
|
}
|
|
946
|
-
const postFixPathParts =
|
|
947
|
-
|
|
1035
|
+
const postFixPathParts = postfixPartsCache.get(postfixPath) ??
|
|
1036
|
+
splitOutsideParenthesesAndArrays(postfixPath);
|
|
1037
|
+
// Cache equivalentRoot.postfix parts — same root reused across all postfixes
|
|
1038
|
+
if (!postfixPartsCache.has(equivalentRoot.postfix)) {
|
|
1039
|
+
postfixPartsCache.set(equivalentRoot.postfix, splitOutsideParenthesesAndArrays(equivalentRoot.postfix));
|
|
1040
|
+
}
|
|
1041
|
+
const equivalentRootPostFixParts = postfixPartsCache.get(equivalentRoot.postfix);
|
|
948
1042
|
relevantPostfix = joinParenthesesAndArrays(postFixPathParts.slice(equivalentRootPostFixParts.length));
|
|
949
1043
|
}
|
|
950
1044
|
const newSchemaPath = joinParenthesesAndArrays([
|
|
@@ -1028,10 +1122,12 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
1028
1122
|
schemasToClean.add(schema);
|
|
1029
1123
|
}
|
|
1030
1124
|
}
|
|
1125
|
+
const postfixElapsed = Date.now() - mergeStartTime;
|
|
1031
1126
|
// Batch-clean all modified schemas once (instead of once per root per ESP entry)
|
|
1032
1127
|
for (const schema of schemasToClean) {
|
|
1033
1128
|
cleanSchema(schema, { stage: 'afterMergePostfix' });
|
|
1034
1129
|
}
|
|
1130
|
+
const cleanElapsed = Date.now() - mergeStartTime;
|
|
1035
1131
|
// Propagate equivalency-derived attributes to generic function call variants.
|
|
1036
1132
|
// When attributes are traced via equivalencies (e.g., fileComparisons from buildDataMap.signature[2]),
|
|
1037
1133
|
// they get written to non-generic paths (returnValue.data.x or funcName().functionCallReturnValue.data.x).
|
|
@@ -1050,6 +1146,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
1050
1146
|
const genericVariants = new Set();
|
|
1051
1147
|
const genericRegex = new RegExp(`^${depName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}<[^>]+>\\(\\)`);
|
|
1052
1148
|
for (const path in schemaToSearchForGenericVariants) {
|
|
1149
|
+
checkDeadline();
|
|
1053
1150
|
const match = path.match(genericRegex);
|
|
1054
1151
|
if (match) {
|
|
1055
1152
|
genericVariants.add(match[0]);
|
|
@@ -1061,6 +1158,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
1061
1158
|
// create corresponding paths for each generic variant
|
|
1062
1159
|
const pathsToAdd = [];
|
|
1063
1160
|
for (const path in returnValueSchema) {
|
|
1161
|
+
checkDeadline();
|
|
1064
1162
|
const value = returnValueSchema[path];
|
|
1065
1163
|
// Handle returnValue. paths
|
|
1066
1164
|
if (path.startsWith('returnValue.')) {
|
|
@@ -1107,6 +1205,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
1107
1205
|
// This includes both returnValue. (dot) and returnValue[ (array) paths.
|
|
1108
1206
|
const pathsToNormalize = [];
|
|
1109
1207
|
for (const path in depSchema.returnValueSchema) {
|
|
1208
|
+
checkDeadline();
|
|
1110
1209
|
if (path === 'returnValue' ||
|
|
1111
1210
|
path.startsWith('returnValue.') ||
|
|
1112
1211
|
path.startsWith('returnValue[')) {
|
|
@@ -1140,6 +1239,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
1140
1239
|
}
|
|
1141
1240
|
// Now copy paths from the source schema (dependencySchemas)
|
|
1142
1241
|
for (const path in srcSchema.returnValueSchema) {
|
|
1242
|
+
checkDeadline();
|
|
1143
1243
|
const value = srcSchema.returnValueSchema[path];
|
|
1144
1244
|
// Normalize paths starting with 'returnValue' to use the standard format:
|
|
1145
1245
|
// 'returnValue.foo' -> 'dependencyName().functionCallReturnValue.foo'
|
|
@@ -1300,9 +1400,11 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
1300
1400
|
if (!existingSchema) {
|
|
1301
1401
|
const depSchema = findOrCreateDependentSchemas({ filePath, name });
|
|
1302
1402
|
for (const path in srcSchema.returnValueSchema) {
|
|
1403
|
+
checkDeadline();
|
|
1303
1404
|
depSchema.returnValueSchema[path] = srcSchema.returnValueSchema[path];
|
|
1304
1405
|
}
|
|
1305
1406
|
for (const path in srcSchema.signatureSchema) {
|
|
1407
|
+
checkDeadline();
|
|
1306
1408
|
depSchema.signatureSchema[path] = srcSchema.signatureSchema[path];
|
|
1307
1409
|
}
|
|
1308
1410
|
// Clean known object functions (like String.prototype.replace, Array.prototype.map)
|
|
@@ -1328,6 +1430,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
1328
1430
|
const childSignatureSchema = childAnalysis?.metadata?.mergedDataStructure?.signatureSchema;
|
|
1329
1431
|
if (childSignatureSchema) {
|
|
1330
1432
|
for (const path in depSchema.signatureSchema) {
|
|
1433
|
+
checkDeadline();
|
|
1331
1434
|
const parentType = depSchema.signatureSchema[path];
|
|
1332
1435
|
const childType = childSignatureSchema[path];
|
|
1333
1436
|
if (parentType && childType) {
|
|
@@ -1367,6 +1470,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
1367
1470
|
});
|
|
1368
1471
|
// Copy only paths that belong to this variant
|
|
1369
1472
|
for (const path in srcSchema.returnValueSchema) {
|
|
1473
|
+
checkDeadline();
|
|
1370
1474
|
if (path.startsWith(variant)) {
|
|
1371
1475
|
variantSchema.returnValueSchema[path] =
|
|
1372
1476
|
srcSchema.returnValueSchema[path];
|
|
@@ -1388,6 +1492,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
1388
1492
|
// EXCEPT: Skip mocked dependencies - we don't want their internal implementation details.
|
|
1389
1493
|
for (const filePath in dependentAnalyses) {
|
|
1390
1494
|
for (const name in dependentAnalyses[filePath]) {
|
|
1495
|
+
checkDeadline();
|
|
1391
1496
|
const dependentMergedDataStructure = dependentAnalyses[filePath][name].metadata?.mergedDataStructure;
|
|
1392
1497
|
if (!dependentMergedDataStructure)
|
|
1393
1498
|
continue;
|
|
@@ -1400,6 +1505,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
1400
1505
|
// Copy over all paths from the dependent's returnValueSchema
|
|
1401
1506
|
// Only add paths that don't already exist (don't overwrite values set by equivalencies)
|
|
1402
1507
|
for (const path in dependentMergedDataStructure.returnValueSchema) {
|
|
1508
|
+
checkDeadline();
|
|
1403
1509
|
const translatedPath = translatePath(path, name);
|
|
1404
1510
|
if (!(translatedPath in depSchema.returnValueSchema)) {
|
|
1405
1511
|
depSchema.returnValueSchema[translatedPath] =
|
|
@@ -1408,6 +1514,7 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
1408
1514
|
}
|
|
1409
1515
|
// Copy over signature schema as well
|
|
1410
1516
|
for (const path in dependentMergedDataStructure.signatureSchema) {
|
|
1517
|
+
checkDeadline();
|
|
1411
1518
|
const translatedPath = translatePath(path, name);
|
|
1412
1519
|
if (!(translatedPath in depSchema.signatureSchema)) {
|
|
1413
1520
|
depSchema.signatureSchema[translatedPath] =
|
|
@@ -1427,12 +1534,14 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
1427
1534
|
});
|
|
1428
1535
|
// Merge in the nested dependency schemas
|
|
1429
1536
|
for (const path in nestedDepSchema.returnValueSchema) {
|
|
1537
|
+
checkDeadline();
|
|
1430
1538
|
if (!(path in targetDepSchema.returnValueSchema)) {
|
|
1431
1539
|
const value = nestedDepSchema.returnValueSchema[path];
|
|
1432
1540
|
targetDepSchema.returnValueSchema[path] = value;
|
|
1433
1541
|
}
|
|
1434
1542
|
}
|
|
1435
1543
|
for (const path in nestedDepSchema.signatureSchema) {
|
|
1544
|
+
checkDeadline();
|
|
1436
1545
|
if (!(path in targetDepSchema.signatureSchema)) {
|
|
1437
1546
|
targetDepSchema.signatureSchema[path] =
|
|
1438
1547
|
nestedDepSchema.signatureSchema[path];
|
|
@@ -1443,6 +1552,12 @@ export default function mergeInDependentDataStructure({ importedExports, depende
|
|
|
1443
1552
|
}
|
|
1444
1553
|
}
|
|
1445
1554
|
}
|
|
1555
|
+
const totalElapsed = Date.now() - mergeStartTime;
|
|
1556
|
+
const retKeys = Object.keys(mergedDataStructure.returnValueSchema).length;
|
|
1557
|
+
// Only log phase breakdown for slow merges (>2s)
|
|
1558
|
+
if (totalElapsed > 2000) {
|
|
1559
|
+
console.log(`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}`);
|
|
1560
|
+
}
|
|
1446
1561
|
return mergedDataStructure;
|
|
1447
1562
|
}
|
|
1448
1563
|
//# sourceMappingURL=mergeInDependentDataStructure.js.map
|