@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
|
@@ -525,7 +525,7 @@ function findControllableBaseForDerivedPath(
|
|
|
525
525
|
export default function resolvePathToControllable(
|
|
526
526
|
localPath: string,
|
|
527
527
|
attributesMap: Record<string, string>,
|
|
528
|
-
equivalentSignatureVariables: Record<string, string>,
|
|
528
|
+
equivalentSignatureVariables: Record<string, string | string[]>,
|
|
529
529
|
fullToShortPathMap: Record<string, string>,
|
|
530
530
|
): PathResolutionResult {
|
|
531
531
|
const chain: string[] = [localPath];
|
|
@@ -600,7 +600,11 @@ export default function resolvePathToControllable(
|
|
|
600
600
|
|
|
601
601
|
// 4. Equivalent variable resolution
|
|
602
602
|
const localVarName = extractLocalVariableName(localPath);
|
|
603
|
-
|
|
603
|
+
// Handle array case (OR expressions) - use first element if array
|
|
604
|
+
const rawDataSourceBase = equivalentSignatureVariables[localVarName];
|
|
605
|
+
const dataSourceBase = Array.isArray(rawDataSourceBase)
|
|
606
|
+
? rawDataSourceBase[0]
|
|
607
|
+
: rawDataSourceBase;
|
|
604
608
|
|
|
605
609
|
if (dataSourceBase) {
|
|
606
610
|
chain.push(`equivalent var: ${localVarName} → ${dataSourceBase}`);
|
|
@@ -626,18 +630,26 @@ export default function resolvePathToControllable(
|
|
|
626
630
|
baseVarName in equivalentSignatureVariables &&
|
|
627
631
|
baseVarName !== localVarName
|
|
628
632
|
) {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
633
|
+
// Handle array case (OR expressions) - use first element if array
|
|
634
|
+
const rawBaseDataSource = equivalentSignatureVariables[baseVarName];
|
|
635
|
+
const baseDataSource = Array.isArray(rawBaseDataSource)
|
|
636
|
+
? rawBaseDataSource[0]
|
|
637
|
+
: rawBaseDataSource;
|
|
638
|
+
if (baseDataSource) {
|
|
639
|
+
chain.push(
|
|
640
|
+
`transitive resolution: ${baseVarName} → ${baseDataSource}`,
|
|
641
|
+
);
|
|
642
|
+
// Append the array access suffix to the resolved base
|
|
643
|
+
if (baseDataSource.endsWith('()')) {
|
|
644
|
+
fullResolvedPath =
|
|
645
|
+
baseDataSource + '.functionCallReturnValue' + accessSuffix;
|
|
646
|
+
} else if (baseDataSource.endsWith('.functionCallReturnValue')) {
|
|
647
|
+
fullResolvedPath = baseDataSource + accessSuffix;
|
|
648
|
+
} else {
|
|
649
|
+
fullResolvedPath = baseDataSource + accessSuffix;
|
|
650
|
+
}
|
|
651
|
+
chain.push(`transitively resolved: ${fullResolvedPath}`);
|
|
639
652
|
}
|
|
640
|
-
chain.push(`transitively resolved: ${fullResolvedPath}`);
|
|
641
653
|
}
|
|
642
654
|
}
|
|
643
655
|
|
|
@@ -63,7 +63,7 @@ export interface EnrichedConditionalUsage {
|
|
|
63
63
|
/** For comparison conditions, the literal values being compared against */
|
|
64
64
|
comparedValues?: string[];
|
|
65
65
|
/** Where this conditional usage occurs */
|
|
66
|
-
location: 'if' | 'ternary' | 'logical-and' | 'switch';
|
|
66
|
+
location: 'if' | 'ternary' | 'logical-and' | 'switch' | 'unconditional';
|
|
67
67
|
/**
|
|
68
68
|
* The traced source data path in the format "scopeName.path"
|
|
69
69
|
* e.g., "useParams().functionCallReturnValue['*']"
|
|
@@ -120,7 +120,8 @@ export interface SerializableDataStructure {
|
|
|
120
120
|
functionResults: Record<string, SerializableFunctionResult>;
|
|
121
121
|
|
|
122
122
|
// Equivalent signature variables for root scope
|
|
123
|
-
|
|
123
|
+
// Values can be arrays for OR expressions where a variable maps to multiple sources
|
|
124
|
+
equivalentSignatureVariables: Record<string, string | string[]>;
|
|
124
125
|
|
|
125
126
|
environmentVariables: string[];
|
|
126
127
|
|
|
@@ -296,7 +297,7 @@ export function getSourceEquivalencies(
|
|
|
296
297
|
|
|
297
298
|
export function getEquivalentSignatureVariables(
|
|
298
299
|
dataStructure: SerializableDataStructure,
|
|
299
|
-
): Record<string, string> {
|
|
300
|
+
): Record<string, string | string[]> {
|
|
300
301
|
return dataStructure.equivalentSignatureVariables;
|
|
301
302
|
}
|
|
302
303
|
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
import { FunctionNode } from './types';
|
|
10
10
|
import getEntityType from './files/getEntityType';
|
|
11
11
|
import getEntityCode from './files/getEntityCode';
|
|
12
|
+
import { getFileByPathSafe } from './utils/getFileByPath';
|
|
12
13
|
|
|
13
14
|
export class FileAnalyzer {
|
|
14
15
|
public projectAnalyzer: lib.ProjectAnalyzer;
|
|
@@ -19,6 +20,7 @@ export class FileAnalyzer {
|
|
|
19
20
|
// Current per-file caching helps when multiple entities in the same file call getResolvedImportsRelevantToFunctionName,
|
|
20
21
|
// but a project-level cache would also benefit the recursive import chain traversals that cross file boundaries.
|
|
21
22
|
private resolvedImportsCache: Map<string, FunctionDependenciesMap>;
|
|
23
|
+
private allEntityNodesOnlyAliasesCache?: Record<string, ts.Node>;
|
|
22
24
|
|
|
23
25
|
constructor({
|
|
24
26
|
projectAnalyzer,
|
|
@@ -62,18 +64,23 @@ export class FileAnalyzer {
|
|
|
62
64
|
|
|
63
65
|
getAllEntityNodesOnlyAliases() {
|
|
64
66
|
if (!this.sourceFile) return {};
|
|
67
|
+
if (this.allEntityNodesOnlyAliasesCache) {
|
|
68
|
+
return this.allEntityNodesOnlyAliasesCache;
|
|
69
|
+
}
|
|
65
70
|
try {
|
|
66
71
|
const allEntityNodes = lib.asts.sourceFiles.getAllEntityNodes({
|
|
67
72
|
sourceFile: this.sourceFile,
|
|
68
73
|
});
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
const aliasesOnly = { ...allEntityNodes };
|
|
75
|
+
if (aliasesOnly.default) {
|
|
76
|
+
const namedDefault = Object.entries(aliasesOnly).find(
|
|
71
77
|
([otherEntityName, node]) =>
|
|
72
|
-
otherEntityName !== 'default' && node ===
|
|
78
|
+
otherEntityName !== 'default' && node === aliasesOnly.default,
|
|
73
79
|
);
|
|
74
|
-
if (namedDefault) delete
|
|
80
|
+
if (namedDefault) delete aliasesOnly.default;
|
|
75
81
|
}
|
|
76
|
-
|
|
82
|
+
this.allEntityNodesOnlyAliasesCache = aliasesOnly;
|
|
83
|
+
return aliasesOnly;
|
|
77
84
|
} catch (error) {
|
|
78
85
|
console.log('CodeYam ERROR: getAllEntityNodesOnlyAliases failed:', {
|
|
79
86
|
filePath: this.file?.path,
|
|
@@ -223,15 +230,11 @@ export class FileAnalyzer {
|
|
|
223
230
|
|
|
224
231
|
// Handle dist -> src mapping for workspace packages
|
|
225
232
|
let targetPath = resolvedPath;
|
|
226
|
-
let targetFile = this.projectAnalyzer
|
|
227
|
-
(f) => f.path === targetPath,
|
|
228
|
-
);
|
|
233
|
+
let targetFile = getFileByPathSafe(this.projectAnalyzer, targetPath);
|
|
229
234
|
|
|
230
235
|
if (!targetFile && targetPath.includes('/dist/')) {
|
|
231
236
|
const srcPath = targetPath.replace('/dist/', '/src/');
|
|
232
|
-
targetFile = this.projectAnalyzer
|
|
233
|
-
(f) => f.path === srcPath,
|
|
234
|
-
);
|
|
237
|
+
targetFile = getFileByPathSafe(this.projectAnalyzer, srcPath);
|
|
235
238
|
if (targetFile) {
|
|
236
239
|
targetPath = srcPath;
|
|
237
240
|
}
|
|
@@ -239,9 +242,9 @@ export class FileAnalyzer {
|
|
|
239
242
|
// Try with different extensions if still not found
|
|
240
243
|
if (!targetFile) {
|
|
241
244
|
const basePath = srcPath.replace(/\.d\.ts$/, '').replace(/\.js$/, '');
|
|
242
|
-
targetFile =
|
|
243
|
-
(
|
|
244
|
-
|
|
245
|
+
targetFile =
|
|
246
|
+
getFileByPathSafe(this.projectAnalyzer, basePath + '.ts') ??
|
|
247
|
+
getFileByPathSafe(this.projectAnalyzer, basePath + '.tsx');
|
|
245
248
|
if (targetFile) {
|
|
246
249
|
targetPath = targetFile.path;
|
|
247
250
|
}
|
|
@@ -301,24 +304,25 @@ export class FileAnalyzer {
|
|
|
301
304
|
|
|
302
305
|
getLocalEntitiesUsedInFunction(functionName: string) {
|
|
303
306
|
if (!this.sourceFile) return [];
|
|
304
|
-
const entityNodes =
|
|
305
|
-
sourceFile: this.sourceFile,
|
|
306
|
-
});
|
|
307
|
+
const entityNodes = this.getAllEntityNodes();
|
|
307
308
|
|
|
308
309
|
// Defensive check: ensure the function exists in entityNodes
|
|
309
|
-
|
|
310
|
+
const functionNode = entityNodes[functionName];
|
|
311
|
+
if (!functionNode) {
|
|
310
312
|
return [];
|
|
311
313
|
}
|
|
312
314
|
|
|
313
315
|
try {
|
|
314
|
-
const identifiers = this.getIdentifiersInNode(
|
|
316
|
+
const identifiers = this.getIdentifiersInNode(functionNode);
|
|
315
317
|
return identifiers
|
|
316
|
-
.filter(
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
318
|
+
.filter((identifier) => {
|
|
319
|
+
const node = entityNodes[identifier];
|
|
320
|
+
return (
|
|
321
|
+
!!node &&
|
|
322
|
+
node !== functionNode &&
|
|
323
|
+
typeof (node as ts.Node).kind === 'number'
|
|
324
|
+
);
|
|
325
|
+
})
|
|
322
326
|
.map((identifier) => ({
|
|
323
327
|
name: identifier,
|
|
324
328
|
node: entityNodes[identifier],
|
|
@@ -348,14 +352,13 @@ export class FileAnalyzer {
|
|
|
348
352
|
sourceFile: this.sourceFile,
|
|
349
353
|
});
|
|
350
354
|
const identifiersInRelevantNode = this.getIdentifiersInNode(relevantNode);
|
|
355
|
+
const identifiersSet = new Set(identifiersInRelevantNode);
|
|
351
356
|
|
|
352
357
|
const entries = Object.entries(importsAnalysis)
|
|
353
358
|
.map(([importedFilePath, importedExpressions]) => {
|
|
354
359
|
const relevantExpressions = importedExpressions.filter(
|
|
355
360
|
(importedExpression) => {
|
|
356
|
-
return
|
|
357
|
-
importedExpression.importAlias,
|
|
358
|
-
);
|
|
361
|
+
return identifiersSet.has(importedExpression.importAlias);
|
|
359
362
|
},
|
|
360
363
|
);
|
|
361
364
|
|
|
@@ -439,8 +442,9 @@ export class FileAnalyzer {
|
|
|
439
442
|
resolvedImport.resolvedFileName,
|
|
440
443
|
);
|
|
441
444
|
|
|
442
|
-
let importedFile =
|
|
443
|
-
|
|
445
|
+
let importedFile = getFileByPathSafe(
|
|
446
|
+
this.projectAnalyzer,
|
|
447
|
+
projectPath,
|
|
444
448
|
);
|
|
445
449
|
|
|
446
450
|
// Workspace packages often resolve to dist/ paths (from package.json "types" or "main"),
|
|
@@ -448,9 +452,7 @@ export class FileAnalyzer {
|
|
|
448
452
|
if (!importedFile && projectPath.includes('/dist/')) {
|
|
449
453
|
const srcPath = projectPath.replace('/dist/', '/src/');
|
|
450
454
|
// Try exact match first (e.g., dist/index.d.ts -> src/index.ts)
|
|
451
|
-
importedFile = this.projectAnalyzer
|
|
452
|
-
(f) => f.path === srcPath,
|
|
453
|
-
);
|
|
455
|
+
importedFile = getFileByPathSafe(this.projectAnalyzer, srcPath);
|
|
454
456
|
if (importedFile) {
|
|
455
457
|
projectPath = srcPath;
|
|
456
458
|
}
|
|
@@ -460,10 +462,9 @@ export class FileAnalyzer {
|
|
|
460
462
|
const basePath = srcPath
|
|
461
463
|
.replace(/\.d\.ts$/, '')
|
|
462
464
|
.replace(/\.js$/, '');
|
|
463
|
-
importedFile =
|
|
464
|
-
(
|
|
465
|
-
|
|
466
|
-
);
|
|
465
|
+
importedFile =
|
|
466
|
+
getFileByPathSafe(this.projectAnalyzer, basePath + '.ts') ??
|
|
467
|
+
getFileByPathSafe(this.projectAnalyzer, basePath + '.tsx');
|
|
467
468
|
if (importedFile) {
|
|
468
469
|
projectPath = importedFile.path;
|
|
469
470
|
}
|
|
@@ -591,24 +592,35 @@ export class FileAnalyzer {
|
|
|
591
592
|
|
|
592
593
|
getNamespaceIdentifiersInNode(node: ts.Node, namespaceIdentifier: string) {
|
|
593
594
|
const identifiers: string[] = [];
|
|
595
|
+
const seen = new Set<string>();
|
|
594
596
|
|
|
595
597
|
const identifierVisitor = (child: ts.Node) => {
|
|
596
598
|
if (ts.isPropertyAccessExpression(child)) {
|
|
597
599
|
if (child.expression.getText() === namespaceIdentifier) {
|
|
598
|
-
|
|
600
|
+
const name = child.name.getText();
|
|
601
|
+
if (!seen.has(name)) {
|
|
602
|
+
seen.add(name);
|
|
603
|
+
identifiers.push(name);
|
|
604
|
+
}
|
|
599
605
|
}
|
|
600
606
|
}
|
|
601
607
|
ts.forEachChild(child, identifierVisitor);
|
|
602
608
|
};
|
|
603
609
|
|
|
604
610
|
ts.forEachChild(node, identifierVisitor);
|
|
605
|
-
return identifiers
|
|
606
|
-
(identifier, index, self) => self.indexOf(identifier) === index,
|
|
607
|
-
);
|
|
611
|
+
return identifiers;
|
|
608
612
|
}
|
|
609
613
|
|
|
610
614
|
getIdentifiersInNode(node: ts.Node): string[] {
|
|
611
615
|
const identifiers: string[] = [];
|
|
616
|
+
const seen = new Set<string>();
|
|
617
|
+
|
|
618
|
+
const addIdentifier = (text: string, allowDefault = false) => {
|
|
619
|
+
if (!allowDefault && text === 'default') return;
|
|
620
|
+
if (seen.has(text)) return;
|
|
621
|
+
seen.add(text);
|
|
622
|
+
identifiers.push(text);
|
|
623
|
+
};
|
|
612
624
|
|
|
613
625
|
// Helper to safely get text from an identifier or string literal
|
|
614
626
|
const getNodeText = (node: ts.Identifier | ts.StringLiteral): string => {
|
|
@@ -637,63 +649,57 @@ export class FileAnalyzer {
|
|
|
637
649
|
};
|
|
638
650
|
|
|
639
651
|
if (ts.isIdentifier(node)) {
|
|
640
|
-
|
|
652
|
+
addIdentifier(getNodeText(node));
|
|
641
653
|
}
|
|
642
654
|
|
|
643
655
|
const identifierVisitor = (child: ts.Node) => {
|
|
644
656
|
if (ts.isIdentifier(child)) {
|
|
645
|
-
|
|
646
|
-
if (text === 'default') return;
|
|
647
|
-
identifiers.push(text);
|
|
657
|
+
addIdentifier(getNodeText(child));
|
|
648
658
|
} else if (ts.isExportDeclaration(child)) {
|
|
649
659
|
if (child.exportClause && ts.isNamedExports(child.exportClause)) {
|
|
650
660
|
child.exportClause.elements.forEach((element) => {
|
|
651
|
-
|
|
661
|
+
addIdentifier(getNodeText(element.name), true);
|
|
652
662
|
});
|
|
653
663
|
} else if (
|
|
654
664
|
child.exportClause &&
|
|
655
665
|
ts.isNamespaceExport(child.exportClause)
|
|
656
666
|
) {
|
|
657
|
-
|
|
667
|
+
addIdentifier(getNodeText(child.exportClause.name));
|
|
658
668
|
}
|
|
659
669
|
} else if (ts.isExportAssignment(child)) {
|
|
660
670
|
if (ts.isIdentifier(child.expression)) {
|
|
661
|
-
|
|
671
|
+
addIdentifier(getNodeText(child.expression));
|
|
662
672
|
}
|
|
663
673
|
} else if (ts.isExportSpecifier(child)) {
|
|
664
|
-
|
|
674
|
+
addIdentifier(getNodeText(child.name), true);
|
|
665
675
|
return;
|
|
666
676
|
} else if (ts.isFunctionDeclaration(child) && child.name) {
|
|
667
|
-
|
|
677
|
+
addIdentifier(getNodeText(child.name));
|
|
668
678
|
} else if (ts.isVariableStatement(child)) {
|
|
669
679
|
child.declarationList.declarations.forEach((declaration) => {
|
|
670
680
|
if (ts.isIdentifier(declaration.name)) {
|
|
671
|
-
|
|
681
|
+
addIdentifier(getNodeText(declaration.name));
|
|
672
682
|
}
|
|
673
683
|
});
|
|
674
684
|
} else if (ts.isImportDeclaration(child)) {
|
|
675
685
|
if (child.importClause && child.importClause.namedBindings) {
|
|
676
686
|
if (ts.isNamespaceImport(child.importClause.namedBindings)) {
|
|
677
|
-
|
|
678
|
-
getNodeText(child.importClause.namedBindings.name),
|
|
679
|
-
);
|
|
687
|
+
addIdentifier(getNodeText(child.importClause.namedBindings.name));
|
|
680
688
|
} else if (ts.isNamedImports(child.importClause.namedBindings)) {
|
|
681
689
|
child.importClause.namedBindings.elements.forEach((element) => {
|
|
682
|
-
|
|
690
|
+
addIdentifier(getNodeText(element.name));
|
|
683
691
|
});
|
|
684
692
|
}
|
|
685
693
|
}
|
|
686
694
|
} else if (ts.isImportSpecifier(child)) {
|
|
687
|
-
|
|
695
|
+
addIdentifier(getNodeText(child.name), true);
|
|
688
696
|
return;
|
|
689
697
|
}
|
|
690
698
|
ts.forEachChild(child, identifierVisitor);
|
|
691
699
|
};
|
|
692
700
|
|
|
693
701
|
ts.forEachChild(node, identifierVisitor);
|
|
694
|
-
return identifiers
|
|
695
|
-
(identifier, index, self) => self.indexOf(identifier) === index,
|
|
696
|
-
);
|
|
702
|
+
return identifiers;
|
|
697
703
|
}
|
|
698
704
|
|
|
699
705
|
resolveNamespaceImport(
|
|
@@ -13,6 +13,8 @@ export class ProjectAnalyzer {
|
|
|
13
13
|
programs: ts.Program[]; // All programs from all tsconfigs
|
|
14
14
|
typeChecker: ts.TypeChecker;
|
|
15
15
|
private filesByPath: Map<string, File>; // O(1) lookup cache for files
|
|
16
|
+
private sourceFileByPath: Map<string, ts.SourceFile>; // O(1) lookup cache for source files
|
|
17
|
+
private typeCheckerByPath: Map<string, ts.TypeChecker>; // O(1) lookup cache for type checkers by file
|
|
16
18
|
|
|
17
19
|
private constructor({
|
|
18
20
|
project,
|
|
@@ -47,6 +49,11 @@ export class ProjectAnalyzer {
|
|
|
47
49
|
// Primary program is the first one (usually root) for backward compatibility
|
|
48
50
|
this.program = this.programs[0];
|
|
49
51
|
this.typeChecker = this.program.getTypeChecker();
|
|
52
|
+
|
|
53
|
+
// Build source file and type checker indexes for fast lookups
|
|
54
|
+
this.sourceFileByPath = new Map();
|
|
55
|
+
this.typeCheckerByPath = new Map();
|
|
56
|
+
this.buildSourceFileIndex();
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
static from({
|
|
@@ -73,32 +80,7 @@ export class ProjectAnalyzer {
|
|
|
73
80
|
}
|
|
74
81
|
|
|
75
82
|
getFileAnalyzerByPath(filePath: string) {
|
|
76
|
-
|
|
77
|
-
// Rebuild the cache if project.files has changed
|
|
78
|
-
this.filesByPath.clear();
|
|
79
|
-
for (const file of this.project.files) {
|
|
80
|
-
this.filesByPath.set(file.path, file);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Convert absolute path to relative if needed
|
|
85
|
-
let relativePath = filePath;
|
|
86
|
-
if (filePath.startsWith(this.dirPath + '/')) {
|
|
87
|
-
relativePath = this.getRelativePath(filePath);
|
|
88
|
-
} else if (filePath.startsWith('/')) {
|
|
89
|
-
// Might be an absolute path with a different prefix (e.g., symlink)
|
|
90
|
-
// Try to normalize it to match our dirPath
|
|
91
|
-
try {
|
|
92
|
-
const normalizedPath = realpathSync(filePath);
|
|
93
|
-
if (normalizedPath.startsWith(this.dirPath + '/')) {
|
|
94
|
-
relativePath = normalizedPath.replace(this.dirPath + '/', '');
|
|
95
|
-
}
|
|
96
|
-
} catch (error) {
|
|
97
|
-
// If normalization fails, keep the original path
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const file = this.filesByPath.get(relativePath);
|
|
83
|
+
const file = this.getFileByPath(filePath);
|
|
102
84
|
if (!file) {
|
|
103
85
|
// Technically FileAnalyzer was built to accept null file, but most of
|
|
104
86
|
// the code we've written since assumes fileAnalyzer.sourceFile exists,
|
|
@@ -109,6 +91,33 @@ export class ProjectAnalyzer {
|
|
|
109
91
|
return new lib.FileAnalyzer({ projectAnalyzer: this, file });
|
|
110
92
|
}
|
|
111
93
|
|
|
94
|
+
getFileByPath(filePath: string): File | undefined {
|
|
95
|
+
this.ensureFileCache();
|
|
96
|
+
|
|
97
|
+
const candidates = new Set<string>();
|
|
98
|
+
if (filePath) {
|
|
99
|
+
candidates.add(filePath);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (!filePath.startsWith('/')) {
|
|
103
|
+
candidates.add(filePath);
|
|
104
|
+
} else if (filePath.startsWith(this.dirPath + '/')) {
|
|
105
|
+
candidates.add(filePath.slice(this.dirPath.length + 1));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const relativePath = this.toProjectRelativePath(filePath);
|
|
109
|
+
if (relativePath) {
|
|
110
|
+
candidates.add(relativePath);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
for (const candidate of candidates) {
|
|
114
|
+
const file = this.filesByPath.get(candidate);
|
|
115
|
+
if (file) return file;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
|
|
112
121
|
getFileAnalyzer(file: File) {
|
|
113
122
|
this.filesByPath.set(file.path, file);
|
|
114
123
|
return new lib.FileAnalyzer({ projectAnalyzer: this, file });
|
|
@@ -142,6 +151,16 @@ export class ProjectAnalyzer {
|
|
|
142
151
|
|
|
143
152
|
getSourceFile(filePath: string): ts.SourceFile | undefined {
|
|
144
153
|
const absolutePath = this.getAbsolutePath(filePath);
|
|
154
|
+
const relativePath = filePath.startsWith('/')
|
|
155
|
+
? this.toProjectRelativePath(filePath)
|
|
156
|
+
: filePath;
|
|
157
|
+
|
|
158
|
+
if (relativePath) {
|
|
159
|
+
const cached = this.sourceFileByPath.get(relativePath);
|
|
160
|
+
if (cached) {
|
|
161
|
+
return cached;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
145
164
|
|
|
146
165
|
// Search across all programs
|
|
147
166
|
for (const program of this.programs) {
|
|
@@ -241,6 +260,16 @@ export class ProjectAnalyzer {
|
|
|
241
260
|
*/
|
|
242
261
|
getTypeCheckerForFile(filePath: string): ts.TypeChecker {
|
|
243
262
|
const absolutePath = this.getAbsolutePath(filePath);
|
|
263
|
+
const relativePath = filePath.startsWith('/')
|
|
264
|
+
? this.toProjectRelativePath(filePath)
|
|
265
|
+
: filePath;
|
|
266
|
+
|
|
267
|
+
if (relativePath) {
|
|
268
|
+
const cachedChecker = this.typeCheckerByPath.get(relativePath);
|
|
269
|
+
if (cachedChecker) {
|
|
270
|
+
return cachedChecker;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
244
273
|
|
|
245
274
|
// Search for the file in each program and return that program's typeChecker
|
|
246
275
|
for (const program of this.programs) {
|
|
@@ -320,5 +349,63 @@ export class ProjectAnalyzer {
|
|
|
320
349
|
// Update primary program for backward compatibility
|
|
321
350
|
this.program = this.programs[0];
|
|
322
351
|
this.typeChecker = this.program.getTypeChecker();
|
|
352
|
+
|
|
353
|
+
this.buildSourceFileIndex();
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
private ensureFileCache(): void {
|
|
357
|
+
if (this.project.files?.length !== this.filesByPath.size) {
|
|
358
|
+
// Rebuild the cache if project.files has changed
|
|
359
|
+
this.filesByPath.clear();
|
|
360
|
+
for (const file of this.project.files) {
|
|
361
|
+
this.filesByPath.set(file.path, file);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
private toProjectRelativePath(filePath: string): string | null {
|
|
367
|
+
if (!filePath) return null;
|
|
368
|
+
|
|
369
|
+
if (filePath.startsWith(this.dirPath + '/')) {
|
|
370
|
+
return filePath.replace(this.dirPath + '/', '');
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (!filePath.startsWith('/')) {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
try {
|
|
378
|
+
const normalizedPath = realpathSync(filePath);
|
|
379
|
+
if (normalizedPath.startsWith(this.dirPath + '/')) {
|
|
380
|
+
return normalizedPath.replace(this.dirPath + '/', '');
|
|
381
|
+
}
|
|
382
|
+
} catch (error) {
|
|
383
|
+
// If normalization fails, return null
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
private buildSourceFileIndex(): void {
|
|
390
|
+
this.sourceFileByPath.clear();
|
|
391
|
+
this.typeCheckerByPath.clear();
|
|
392
|
+
|
|
393
|
+
for (const program of this.programs) {
|
|
394
|
+
const checker = program.getTypeChecker();
|
|
395
|
+
for (const sf of program.getSourceFiles()) {
|
|
396
|
+
// Skip node_modules files to keep the index small
|
|
397
|
+
if (sf.fileName.includes('node_modules')) {
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const relativePath = this.toProjectRelativePath(sf.fileName);
|
|
402
|
+
if (!relativePath) continue;
|
|
403
|
+
|
|
404
|
+
if (!this.sourceFileByPath.has(relativePath)) {
|
|
405
|
+
this.sourceFileByPath.set(relativePath, sf);
|
|
406
|
+
this.typeCheckerByPath.set(relativePath, checker);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
323
410
|
}
|
|
324
411
|
}
|
package/analyzer-template/packages/analyze/src/lib/asts/sourceFiles/getAllDeclaredEntityNodes.ts
CHANGED
|
@@ -7,6 +7,11 @@ interface GetAllDeclaredEntityNodesArgs {
|
|
|
7
7
|
entities?: { [key: string]: ts.Node };
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
const allDeclaredEntityNodesCache = new WeakMap<
|
|
11
|
+
ts.SourceFile,
|
|
12
|
+
{ [key: string]: ts.Node }
|
|
13
|
+
>();
|
|
14
|
+
|
|
10
15
|
/**
|
|
11
16
|
* Returns all declared entity nodes in a source file.
|
|
12
17
|
*
|
|
@@ -24,6 +29,14 @@ export function getAllDeclaredEntityNodes({
|
|
|
24
29
|
entities = {},
|
|
25
30
|
}: GetAllDeclaredEntityNodesArgs): { [key: string]: ts.Node } {
|
|
26
31
|
try {
|
|
32
|
+
const isRootCall = !possibleIdentifierNode && !entityNode;
|
|
33
|
+
if (isRootCall) {
|
|
34
|
+
const cached = allDeclaredEntityNodesCache.get(sourceFile);
|
|
35
|
+
if (cached) {
|
|
36
|
+
return cached;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
27
40
|
if (!possibleIdentifierNode) {
|
|
28
41
|
possibleIdentifierNode = sourceFile;
|
|
29
42
|
}
|
|
@@ -34,6 +47,9 @@ export function getAllDeclaredEntityNodes({
|
|
|
34
47
|
entities[possibleIdentifierNode.text] =
|
|
35
48
|
entityNode ?? possibleIdentifierNode;
|
|
36
49
|
}
|
|
50
|
+
if (isRootCall) {
|
|
51
|
+
allDeclaredEntityNodesCache.set(sourceFile, entities);
|
|
52
|
+
}
|
|
37
53
|
return entities;
|
|
38
54
|
}
|
|
39
55
|
|
|
@@ -225,6 +241,9 @@ export function getAllDeclaredEntityNodes({
|
|
|
225
241
|
}
|
|
226
242
|
});
|
|
227
243
|
|
|
244
|
+
if (isRootCall) {
|
|
245
|
+
allDeclaredEntityNodesCache.set(sourceFile, entities);
|
|
246
|
+
}
|
|
228
247
|
return entities;
|
|
229
248
|
} catch (e) {
|
|
230
249
|
console.log(
|
|
@@ -7,6 +7,11 @@ interface GetAllEntityNodesArgs {
|
|
|
7
7
|
entities?: { [key: string]: ts.Node };
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
const allEntityNodesCache = new WeakMap<
|
|
11
|
+
ts.SourceFile,
|
|
12
|
+
{ [key: string]: ts.Node }
|
|
13
|
+
>();
|
|
14
|
+
|
|
10
15
|
export function getAllEntityNodes({
|
|
11
16
|
sourceFile,
|
|
12
17
|
possibleIdentifierNode,
|
|
@@ -14,6 +19,14 @@ export function getAllEntityNodes({
|
|
|
14
19
|
entities = {},
|
|
15
20
|
}: GetAllEntityNodesArgs) {
|
|
16
21
|
try {
|
|
22
|
+
const isRootCall = !possibleIdentifierNode && !entityNode;
|
|
23
|
+
if (isRootCall) {
|
|
24
|
+
const cached = allEntityNodesCache.get(sourceFile);
|
|
25
|
+
if (cached) {
|
|
26
|
+
return cached;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
17
30
|
if (!possibleIdentifierNode) {
|
|
18
31
|
possibleIdentifierNode = sourceFile;
|
|
19
32
|
}
|
|
@@ -39,6 +52,9 @@ export function getAllEntityNodes({
|
|
|
39
52
|
}),
|
|
40
53
|
};
|
|
41
54
|
}
|
|
55
|
+
if (isRootCall) {
|
|
56
|
+
allEntityNodesCache.set(sourceFile, entities);
|
|
57
|
+
}
|
|
42
58
|
return entities;
|
|
43
59
|
}
|
|
44
60
|
|
|
@@ -223,6 +239,9 @@ export function getAllEntityNodes({
|
|
|
223
239
|
}
|
|
224
240
|
});
|
|
225
241
|
|
|
242
|
+
if (isRootCall) {
|
|
243
|
+
allEntityNodesCache.set(sourceFile, entities);
|
|
244
|
+
}
|
|
226
245
|
return entities;
|
|
227
246
|
} catch (e) {
|
|
228
247
|
console.log(
|
|
@@ -10,9 +10,19 @@ export interface ExportedFunction {
|
|
|
10
10
|
directImportName?: string;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
const exportsCache = new WeakMap<
|
|
14
|
+
ts.SourceFile,
|
|
15
|
+
Record<string, ExportedFunction>
|
|
16
|
+
>();
|
|
17
|
+
|
|
13
18
|
export function getAllExports(
|
|
14
19
|
sourceFile: ts.SourceFile,
|
|
15
20
|
): Record<string, ExportedFunction> {
|
|
21
|
+
const cached = exportsCache.get(sourceFile);
|
|
22
|
+
if (cached) {
|
|
23
|
+
return cached;
|
|
24
|
+
}
|
|
25
|
+
|
|
16
26
|
const exportsCodeMap: Record<string, ExportedFunction> = {};
|
|
17
27
|
|
|
18
28
|
function addExport(
|
|
@@ -239,5 +249,6 @@ export function getAllExports(
|
|
|
239
249
|
}
|
|
240
250
|
});
|
|
241
251
|
|
|
252
|
+
exportsCache.set(sourceFile, exportsCodeMap);
|
|
242
253
|
return exportsCodeMap;
|
|
243
254
|
}
|