codesearch-mcp 0.3.0-alpha → 0.4.0-alpha
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/CHANGELOG.md +59 -6
- package/LICENSE +661 -21
- package/README.md +33 -17
- package/dist/app.js +13 -20
- package/dist/src/ast/CallExtractor.d.ts +8 -0
- package/dist/src/ast/CallExtractor.js +68 -0
- package/dist/src/ast/GraphqlNameExtractor.d.ts +22 -0
- package/dist/src/ast/GraphqlNameExtractor.js +240 -0
- package/dist/src/ast/ImportEdgeExtractor.d.ts +11 -0
- package/dist/src/ast/ImportEdgeExtractor.js +129 -0
- package/dist/src/ast/IndexedNodeResolver.d.ts +14 -0
- package/dist/src/ast/IndexedNodeResolver.js +217 -0
- package/dist/src/ast/MemberExtractor.d.ts +8 -0
- package/dist/src/ast/MemberExtractor.js +129 -0
- package/dist/src/ast/TopLevelSymbolExtractor.d.ts +5 -0
- package/dist/src/ast/TopLevelSymbolExtractor.js +86 -0
- package/dist/src/ast/graphql-grammar.d.ts +24 -0
- package/dist/src/ast/graphql-grammar.js +93 -0
- package/dist/src/ast/node-helpers.d.ts +11 -0
- package/dist/src/ast/node-helpers.js +55 -0
- package/dist/src/commands/EvalCommand.d.ts +7 -3
- package/dist/src/commands/EvalCommand.js +36 -158
- package/dist/src/commands/IndexCommand.d.ts +10 -4
- package/dist/src/commands/IndexCommand.js +52 -124
- package/dist/src/commands/McpCommand.d.ts +6 -3
- package/dist/src/commands/McpCommand.js +19 -14
- package/dist/src/commands/WebCommand.d.ts +9 -3
- package/dist/src/commands/WebCommand.js +17 -8
- package/dist/src/commands/eval/baseline-comparison.d.ts +6 -0
- package/dist/src/commands/eval/baseline-comparison.js +54 -0
- package/dist/src/commands/eval/eval-args.d.ts +6 -0
- package/dist/src/commands/eval/eval-args.js +71 -0
- package/dist/src/commands/eval/eval-corpora.d.ts +6 -0
- package/dist/src/commands/eval/eval-corpora.js +76 -0
- package/dist/src/commands/eval/eval-metadata.d.ts +17 -0
- package/dist/src/commands/eval/eval-metadata.js +75 -0
- package/dist/src/commands/eval/index-inspector.d.ts +3 -0
- package/dist/src/commands/eval/index-inspector.js +21 -0
- package/dist/src/commands/eval/staged-search.d.ts +3 -0
- package/dist/src/commands/eval/staged-search.js +20 -0
- package/dist/src/commands/eval/suite-loader.d.ts +8 -0
- package/dist/src/commands/eval/suite-loader.js +52 -0
- package/dist/src/commands/index/backend-probe.d.ts +2 -0
- package/dist/src/commands/index/backend-probe.js +15 -0
- package/dist/src/commands/index/embedding-setup.d.ts +3 -0
- package/dist/src/commands/index/embedding-setup.js +16 -0
- package/dist/src/commands/index/index-summary.d.ts +2 -0
- package/dist/src/commands/index/index-summary.js +22 -0
- package/dist/src/commands/index/legacy-ollama-guard.d.ts +3 -0
- package/dist/src/commands/index/legacy-ollama-guard.js +23 -0
- package/dist/src/commands/index/prune-step.d.ts +3 -0
- package/dist/src/commands/index/prune-step.js +22 -0
- package/dist/src/commands/index/scan-targets.d.ts +8 -0
- package/dist/src/commands/index/scan-targets.js +107 -0
- package/dist/src/config-store.d.ts +0 -1
- package/dist/src/config-store.js +3 -4
- package/dist/src/config.d.ts +1 -1
- package/dist/src/config.js +1 -1
- package/dist/src/constants.d.ts +15 -0
- package/dist/src/constants.js +34 -6
- package/dist/src/container.d.ts +4 -2
- package/dist/src/container.js +7 -5
- package/dist/src/db/drizzle-types.d.ts +7 -0
- package/dist/src/db/index.d.ts +1 -0
- package/dist/src/db/schema-steps.d.ts +8 -0
- package/dist/src/db/schema-steps.js +105 -0
- package/dist/src/declarations/DeclarationTree.d.ts +1 -1
- package/dist/src/eval-results.js +16 -2
- package/dist/src/eval-vector-index.d.ts +5 -0
- package/dist/src/eval-vector-index.js +60 -0
- package/dist/src/help.js +9 -1
- package/dist/src/index-args.d.ts +13 -0
- package/dist/src/index-args.js +48 -0
- package/dist/src/indexing/AnalysisBatcher.d.ts +12 -0
- package/dist/src/indexing/AnalysisBatcher.js +28 -0
- package/dist/src/indexing/ChunkEmbedder.d.ts +24 -0
- package/dist/src/indexing/ChunkEmbedder.js +37 -0
- package/dist/src/indexing/ConsoleScanReporter.d.ts +10 -0
- package/dist/src/indexing/ConsoleScanReporter.js +73 -0
- package/dist/src/indexing/EmbeddingSchemaPreparer.d.ts +14 -0
- package/dist/src/indexing/EmbeddingSchemaPreparer.js +66 -0
- package/dist/src/indexing/FileIngestor.d.ts +22 -0
- package/dist/src/indexing/FileIngestor.js +116 -0
- package/dist/src/indexing/IndexStore.d.ts +24 -0
- package/dist/src/indexing/IndexStore.js +69 -0
- package/dist/src/indexing/StaleFilePruner.d.ts +8 -0
- package/dist/src/indexing/StaleFilePruner.js +55 -0
- package/dist/src/indexing/analysis-rows.d.ts +4 -0
- package/dist/src/indexing/analysis-rows.js +65 -0
- package/dist/src/indexing/project-notices.d.ts +2 -0
- package/dist/src/indexing/project-notices.js +63 -0
- package/dist/src/interfaces/IAstParser.d.ts +2 -1
- package/dist/src/interfaces/ICallGraph.d.ts +28 -0
- package/dist/src/interfaces/ICallGraph.js +2 -0
- package/dist/src/interfaces/IChunkSearch.d.ts +42 -0
- package/dist/src/interfaces/IChunkSearch.js +2 -0
- package/dist/src/interfaces/IDatabase.d.ts +6 -2
- package/dist/src/interfaces/IDependencyGraph.d.ts +24 -0
- package/dist/src/interfaces/IDependencyGraph.js +2 -0
- package/dist/src/interfaces/IIndexIdentityGuard.d.ts +3 -0
- package/dist/src/interfaces/IIndexIdentityGuard.js +2 -0
- package/dist/src/interfaces/IIndexedNodeResolver.d.ts +10 -0
- package/dist/src/interfaces/IIndexedNodeResolver.js +2 -0
- package/dist/src/interfaces/IMcpReadiness.d.ts +12 -0
- package/dist/src/interfaces/IMcpReadiness.js +2 -0
- package/dist/src/interfaces/IProjectCatalog.d.ts +13 -0
- package/dist/src/interfaces/IProjectCatalog.js +2 -0
- package/dist/src/interfaces/IProjectRoots.d.ts +3 -0
- package/dist/src/interfaces/IProjectRoots.js +2 -0
- package/dist/src/interfaces/IRetrievalEvaluator.d.ts +21 -2
- package/dist/src/interfaces/IScanReporter.d.ts +13 -0
- package/dist/src/interfaces/IScanReporter.js +2 -0
- package/dist/src/interfaces/ISymbolLookup.d.ts +49 -0
- package/dist/src/interfaces/ISymbolLookup.js +2 -0
- package/dist/src/interfaces/IToolPaths.d.ts +62 -0
- package/dist/src/interfaces/IToolPaths.js +2 -0
- package/dist/src/interfaces/IWorkspaceFiles.d.ts +28 -0
- package/dist/src/interfaces/IWorkspaceFiles.js +2 -0
- package/dist/src/interfaces/SymbolKind.d.ts +1 -0
- package/dist/src/interfaces/SymbolKind.js +2 -0
- package/dist/src/interfaces/index.d.ts +12 -1
- package/dist/src/project-scope.d.ts +1 -0
- package/dist/src/project-scope.js +5 -0
- package/dist/src/retrieval-eval.d.ts +2 -1
- package/dist/src/retrieval-eval.js +45 -2
- package/dist/src/search/CallGraph.d.ts +9 -0
- package/dist/src/search/CallGraph.js +84 -0
- package/dist/src/search/ChunkSearch.d.ts +23 -0
- package/dist/src/search/ChunkSearch.js +115 -0
- package/dist/src/search/DependencyGraph.d.ts +19 -0
- package/dist/src/search/DependencyGraph.js +180 -0
- package/dist/src/search/IndexIdentityGuard.d.ts +11 -0
- package/dist/src/search/IndexIdentityGuard.js +37 -0
- package/dist/src/search/ProjectCatalog.d.ts +11 -0
- package/dist/src/search/ProjectCatalog.js +38 -0
- package/dist/src/search/SymbolLookup.d.ts +24 -0
- package/dist/src/search/SymbolLookup.js +97 -0
- package/dist/src/search/chunks/CandidateFetcher.d.ts +19 -0
- package/dist/src/search/chunks/CandidateFetcher.js +40 -0
- package/dist/src/search/chunks/IterativeScanGate.d.ts +10 -0
- package/dist/src/search/chunks/IterativeScanGate.js +42 -0
- package/dist/src/search/chunks/RerankStage.d.ts +15 -0
- package/dist/src/search/chunks/RerankStage.js +42 -0
- package/dist/src/search/chunks/search-metrics.d.ts +18 -0
- package/dist/src/search/chunks/search-metrics.js +32 -0
- package/dist/src/search/chunks/search-plan.d.ts +18 -0
- package/dist/src/search/chunks/search-plan.js +19 -0
- package/dist/src/search/create-search-services.d.ts +26 -0
- package/dist/src/search/create-search-services.js +29 -0
- package/dist/src/search/index-paths.d.ts +1 -0
- package/dist/src/search/index-paths.js +5 -0
- package/dist/src/search/symbol-sql.d.ts +13 -0
- package/dist/src/search/symbol-sql.js +66 -0
- package/dist/src/search/symbols/SymbolGrepFallback.d.ts +19 -0
- package/dist/src/search/symbols/SymbolGrepFallback.js +106 -0
- package/dist/src/search/symbols/SymbolIndexQuery.d.ts +14 -0
- package/dist/src/search/symbols/SymbolIndexQuery.js +52 -0
- package/dist/src/search/symbols/SymbolTextSearch.d.ts +13 -0
- package/dist/src/search/symbols/SymbolTextSearch.js +84 -0
- package/dist/src/search/symbols/TargetColumnGate.d.ts +7 -0
- package/dist/src/search/symbols/TargetColumnGate.js +23 -0
- package/dist/src/search/symbols/find-symbol-constants.d.ts +4 -0
- package/dist/src/search/symbols/find-symbol-constants.js +8 -0
- package/dist/src/search/symbols/grep-args.d.ts +3 -0
- package/dist/src/search/symbols/grep-args.js +7 -0
- package/dist/src/search/symbols/grep-patterns.d.ts +4 -0
- package/dist/src/search/symbols/grep-patterns.js +60 -0
- package/dist/src/services/AstParserService.d.ts +8 -44
- package/dist/src/services/AstParserService.js +19 -938
- package/dist/src/services/DatabaseService.d.ts +8 -10
- package/dist/src/services/DatabaseService.js +29 -86
- package/dist/src/services/IndexerService.d.ts +7 -10
- package/dist/src/services/IndexerService.js +36 -255
- package/dist/src/services/McpReadiness.d.ts +18 -0
- package/dist/src/services/McpReadiness.js +73 -0
- package/dist/src/services/McpServer.d.ts +32 -9
- package/dist/src/services/McpServer.js +78 -41
- package/dist/src/services/WebServerService.d.ts +4 -3
- package/dist/src/services/WebServerService.js +16 -8
- package/dist/src/setup.d.ts +16 -4
- package/dist/src/setup.js +115 -40
- package/dist/src/symbol-name.d.ts +1 -0
- package/dist/src/symbol-name.js +16 -12
- package/dist/src/tools/FindSymbolTool.d.ts +17 -7
- package/dist/src/tools/FindSymbolTool.js +54 -35
- package/dist/src/tools/GetCallersTool.d.ts +16 -8
- package/dist/src/tools/GetCallersTool.js +65 -35
- package/dist/src/tools/GetDependenciesTool.d.ts +16 -8
- package/dist/src/tools/GetDependenciesTool.js +35 -28
- package/dist/src/tools/GetDependentsTool.d.ts +20 -8
- package/dist/src/tools/GetDependentsTool.js +47 -33
- package/dist/src/tools/ListFilesTool.d.ts +16 -8
- package/dist/src/tools/ListFilesTool.js +20 -26
- package/dist/src/tools/ListProjectsTool.d.ts +11 -7
- package/dist/src/tools/ListProjectsTool.js +13 -11
- package/dist/src/tools/McpTool.d.ts +17 -0
- package/dist/src/tools/McpTool.js +28 -0
- package/dist/src/tools/ReadFileRangeTool.d.ts +16 -8
- package/dist/src/tools/ReadFileRangeTool.js +23 -25
- package/dist/src/tools/ReadFileTool.d.ts +15 -8
- package/dist/src/tools/ReadFileTool.js +19 -24
- package/dist/src/tools/SearchCodebaseTool.d.ts +22 -10
- package/dist/src/tools/SearchCodebaseTool.js +69 -51
- package/dist/src/tools/format-helpers.d.ts +9 -3
- package/dist/src/tools/format-helpers.js +59 -14
- package/dist/src/tools/tool-args.d.ts +38 -0
- package/dist/src/tools/tool-args.js +95 -0
- package/dist/src/workspace/GrepRunner.d.ts +15 -0
- package/dist/src/workspace/GrepRunner.js +104 -0
- package/dist/src/workspace/ProjectRoots.d.ts +22 -0
- package/dist/src/workspace/ProjectRoots.js +102 -0
- package/dist/src/workspace/ToolPaths.d.ts +31 -0
- package/dist/src/workspace/ToolPaths.js +312 -0
- package/dist/src/workspace/WorkspaceFiles.d.ts +19 -0
- package/dist/src/workspace/WorkspaceFiles.js +285 -0
- package/dist/src/workspace/fs-access.d.ts +9 -0
- package/dist/src/workspace/fs-access.js +47 -0
- package/dist/src/workspace/path-helpers.d.ts +3 -0
- package/dist/src/workspace/path-helpers.js +43 -0
- package/package.json +4 -3
- package/dist/src/interfaces/ISearcher.d.ts +0 -46
- package/dist/src/services/SearcherService.d.ts +0 -235
- package/dist/src/services/SearcherService.js +0 -1118
- /package/dist/src/{interfaces/ISearcher.js → db/drizzle-types.js} +0 -0
|
@@ -40,27 +40,32 @@ const ts_morph_1 = require("ts-morph");
|
|
|
40
40
|
const DeclarationTreeBuilder_1 = require("../declarations/DeclarationTreeBuilder");
|
|
41
41
|
const DeclarationTree_1 = require("../declarations/DeclarationTree");
|
|
42
42
|
const LoggerService_1 = require("./LoggerService");
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const
|
|
43
|
+
const IndexedNodeResolver_1 = require("../ast/IndexedNodeResolver");
|
|
44
|
+
const ImportEdgeExtractor_1 = require("../ast/ImportEdgeExtractor");
|
|
45
|
+
const TopLevelSymbolExtractor_1 = require("../ast/TopLevelSymbolExtractor");
|
|
46
|
+
const MemberExtractor_1 = require("../ast/MemberExtractor");
|
|
47
|
+
const CallExtractor_1 = require("../ast/CallExtractor");
|
|
48
|
+
const GraphqlNameExtractor_1 = require("../ast/GraphqlNameExtractor");
|
|
49
49
|
const FALLBACK_OPTS = {
|
|
50
50
|
skipAddingFilesFromTsConfig: true,
|
|
51
51
|
skipFileDependencyResolution: false,
|
|
52
52
|
compilerOptions: { allowJs: true, noEmit: true },
|
|
53
53
|
};
|
|
54
54
|
const MORPH_CACHE_MAX = 10;
|
|
55
|
-
const VALID_SEGMENT = /^#?[\w$]+$/;
|
|
56
55
|
class AstParserService {
|
|
57
56
|
logger;
|
|
58
|
-
deps;
|
|
59
57
|
morphProjects = new Map();
|
|
60
58
|
declarationBuilder = new DeclarationTreeBuilder_1.DeclarationTreeBuilder();
|
|
59
|
+
resolver = new IndexedNodeResolver_1.IndexedNodeResolver();
|
|
60
|
+
edges;
|
|
61
|
+
topLevel = new TopLevelSymbolExtractor_1.TopLevelSymbolExtractor();
|
|
62
|
+
members = new MemberExtractor_1.MemberExtractor(this.resolver);
|
|
63
|
+
calls = new CallExtractor_1.CallExtractor(this.resolver);
|
|
64
|
+
graphql;
|
|
61
65
|
constructor(logger = LoggerService_1.LoggerService.silent(), deps = {}) {
|
|
62
66
|
this.logger = logger;
|
|
63
|
-
this.
|
|
67
|
+
this.edges = new ImportEdgeExtractor_1.ImportEdgeExtractor(logger);
|
|
68
|
+
this.graphql = new GraphqlNameExtractor_1.GraphqlNameExtractor(this.resolver, logger, deps.resolveDeclaration);
|
|
64
69
|
}
|
|
65
70
|
async analyzeProject(filePaths, serviceName, projectRoot = process.cwd(), opts = {}) {
|
|
66
71
|
const t0 = Date.now();
|
|
@@ -137,23 +142,23 @@ class AstParserService {
|
|
|
137
142
|
}
|
|
138
143
|
analyzeSourceFile(sourceFile, filePath, serviceName) {
|
|
139
144
|
try {
|
|
140
|
-
const edges = this.extractEdges(sourceFile, filePath, serviceName);
|
|
141
|
-
const symbolCandidates = this.extractSymbols(sourceFile, filePath, serviceName);
|
|
145
|
+
const edges = this.edges.extractEdges(sourceFile, filePath, serviceName);
|
|
146
|
+
const symbolCandidates = this.topLevel.extractSymbols(sourceFile, filePath, serviceName);
|
|
142
147
|
const symbols = symbolCandidates.map(c => c.entry);
|
|
143
148
|
let memberCandidates = [];
|
|
144
149
|
try {
|
|
145
|
-
memberCandidates = this.extractMembers(sourceFile, filePath, serviceName);
|
|
150
|
+
memberCandidates = this.members.extractMembers(sourceFile, filePath, serviceName);
|
|
146
151
|
}
|
|
147
152
|
catch (err) {
|
|
148
153
|
this.logger.warn('AstParser: member extraction failed', { filePath, err });
|
|
149
154
|
memberCandidates = [];
|
|
150
155
|
}
|
|
151
156
|
const members = memberCandidates.map(c => c.entry);
|
|
152
|
-
const calls = this.extractCalls(sourceFile, filePath, serviceName);
|
|
157
|
+
const calls = this.calls.extractCalls(sourceFile, filePath, serviceName);
|
|
153
158
|
const declarations = this.buildDeclarations(sourceFile, filePath, symbolCandidates, memberCandidates);
|
|
154
159
|
let graphqlNames = [];
|
|
155
160
|
try {
|
|
156
|
-
graphqlNames = this.extractGraphqlNames(sourceFile, filePath, serviceName, [...symbolCandidates, ...memberCandidates]);
|
|
161
|
+
graphqlNames = this.graphql.extractGraphqlNames(sourceFile, filePath, serviceName, [...symbolCandidates, ...memberCandidates]);
|
|
157
162
|
}
|
|
158
163
|
catch (err) {
|
|
159
164
|
this.logger.warn('AstParser: GraphQL extraction failed', { filePath, err });
|
|
@@ -227,329 +232,6 @@ class AstParserService {
|
|
|
227
232
|
this.morphProjects.set(projectRoot, project);
|
|
228
233
|
return project;
|
|
229
234
|
}
|
|
230
|
-
extractEdges(sourceFile, filePath, serviceName) {
|
|
231
|
-
const edges = [];
|
|
232
|
-
const usageMap = this.buildUsageMap(sourceFile);
|
|
233
|
-
for (const decl of sourceFile.getImportDeclarations()) {
|
|
234
|
-
const namedImports = decl.getNamedImports();
|
|
235
|
-
const defaultImport = decl.getDefaultImport();
|
|
236
|
-
const namespaceImport = decl.getNamespaceImport();
|
|
237
|
-
const hasClause = Boolean(defaultImport || namespaceImport || namedImports.length > 0);
|
|
238
|
-
const resolved = decl.getModuleSpecifierSourceFile();
|
|
239
|
-
let toFile = resolved ? resolved.getFilePath() : null;
|
|
240
|
-
if (!toFile && !hasClause) {
|
|
241
|
-
toFile = this.resolveSideEffectModuleSpecifier(decl, sourceFile, filePath);
|
|
242
|
-
}
|
|
243
|
-
if (!toFile) {
|
|
244
|
-
const specifier = decl.getModuleSpecifierValue();
|
|
245
|
-
const isCodeImport = !/\.(json|css|scss|less|svg|png|jpg|gif|ico|woff2?|ttf|eot)(\?.*)?$/.test(specifier);
|
|
246
|
-
if (specifier.startsWith('.') && isCodeImport) {
|
|
247
|
-
this.logger.debug('AstParser: unresolved import', { specifier, file: filePath });
|
|
248
|
-
}
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
if (toFile.includes('/node_modules/'))
|
|
252
|
-
continue;
|
|
253
|
-
if (!hasClause) {
|
|
254
|
-
edges.push({
|
|
255
|
-
project: serviceName, fromFile: filePath, fromSymbol: null,
|
|
256
|
-
toFile, toSymbol: null, depType: 'import-side-effect',
|
|
257
|
-
});
|
|
258
|
-
continue;
|
|
259
|
-
}
|
|
260
|
-
if (defaultImport) {
|
|
261
|
-
const fromSymbol = this.resolveFromSymbol(defaultImport.getText(), usageMap);
|
|
262
|
-
edges.push({
|
|
263
|
-
project: serviceName, fromFile: filePath, fromSymbol,
|
|
264
|
-
toFile, toSymbol: null, depType: 'import-default',
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
if (namespaceImport) {
|
|
268
|
-
const fromSymbol = this.resolveFromSymbol(namespaceImport.getText(), usageMap);
|
|
269
|
-
edges.push({
|
|
270
|
-
project: serviceName, fromFile: filePath, fromSymbol,
|
|
271
|
-
toFile, toSymbol: null, depType: 'import-namespace',
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
for (const named of namedImports) {
|
|
275
|
-
const localName = named.getAliasNode()?.getText() ?? named.getName();
|
|
276
|
-
const fromSymbol = this.resolveFromSymbol(localName, usageMap);
|
|
277
|
-
edges.push({
|
|
278
|
-
project: serviceName, fromFile: filePath, fromSymbol,
|
|
279
|
-
toFile, toSymbol: named.getName(), depType: 'import',
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
for (const decl of sourceFile.getExportDeclarations()) {
|
|
284
|
-
const resolved = decl.getModuleSpecifierSourceFile();
|
|
285
|
-
if (!resolved)
|
|
286
|
-
continue;
|
|
287
|
-
const toFile = resolved.getFilePath();
|
|
288
|
-
if (toFile.includes('/node_modules/'))
|
|
289
|
-
continue;
|
|
290
|
-
const namedExports = decl.getNamedExports();
|
|
291
|
-
if (namedExports.length > 0) {
|
|
292
|
-
for (const named of namedExports) {
|
|
293
|
-
edges.push({
|
|
294
|
-
project: serviceName, fromFile: filePath, fromSymbol: null,
|
|
295
|
-
toFile, toSymbol: named.getName(), depType: 'reexport',
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
else {
|
|
300
|
-
edges.push({
|
|
301
|
-
project: serviceName, fromFile: filePath, fromSymbol: null,
|
|
302
|
-
toFile, toSymbol: null, depType: 'reexport-namespace',
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
return edges;
|
|
307
|
-
}
|
|
308
|
-
resolveSideEffectModuleSpecifier(decl, sourceFile, filePath) {
|
|
309
|
-
const specifier = decl.getModuleSpecifierValue();
|
|
310
|
-
const compilerOptions = sourceFile.getProject().getCompilerOptions();
|
|
311
|
-
const result = ts_morph_1.ts.resolveModuleName(specifier, filePath, compilerOptions, ts_morph_1.ts.sys);
|
|
312
|
-
const resolvedFileName = result.resolvedModule?.resolvedFileName;
|
|
313
|
-
if (!resolvedFileName)
|
|
314
|
-
return null;
|
|
315
|
-
return sourceFile.getProject().getSourceFile(resolvedFileName)?.getFilePath() ?? null;
|
|
316
|
-
}
|
|
317
|
-
resolveFromSymbol(localName, usageMap) {
|
|
318
|
-
const users = usageMap.get(localName);
|
|
319
|
-
return users?.length === 1 ? users[0] : null;
|
|
320
|
-
}
|
|
321
|
-
buildUsageMap(sourceFile) {
|
|
322
|
-
const map = new Map();
|
|
323
|
-
const containers = [
|
|
324
|
-
...sourceFile.getClasses().flatMap(n => n.getName() ? [{ name: n.getName(), node: n }] : []),
|
|
325
|
-
...sourceFile.getFunctions().flatMap(n => n.getName() ? [{ name: n.getName(), node: n }] : []),
|
|
326
|
-
...sourceFile.getVariableStatements()
|
|
327
|
-
.flatMap(stmt => stmt.getDeclarations())
|
|
328
|
-
.flatMap(n => {
|
|
329
|
-
const name = n.getName();
|
|
330
|
-
return name ? [{ name, node: n }] : [];
|
|
331
|
-
}),
|
|
332
|
-
];
|
|
333
|
-
for (const { name, node } of containers) {
|
|
334
|
-
for (const id of node.getDescendantsOfKind(ts_morph_1.SyntaxKind.Identifier)) {
|
|
335
|
-
const text = id.getText();
|
|
336
|
-
const existing = map.get(text);
|
|
337
|
-
if (existing) {
|
|
338
|
-
if (!existing.includes(name))
|
|
339
|
-
existing.push(name);
|
|
340
|
-
}
|
|
341
|
-
else {
|
|
342
|
-
map.set(text, [name]);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
return map;
|
|
347
|
-
}
|
|
348
|
-
getPos(sourceFile, node) {
|
|
349
|
-
const { line, character } = sourceFile.compilerNode
|
|
350
|
-
.getLineAndCharacterOfPosition(node.getStart());
|
|
351
|
-
return { line: line + 1, col: character + 1 };
|
|
352
|
-
}
|
|
353
|
-
lineTextAt(sourceLines, sourceFile, node) {
|
|
354
|
-
const { line } = this.getPos(sourceFile, node);
|
|
355
|
-
return (sourceLines[line - 1] ?? node.getText().split('\n')[0]).trim();
|
|
356
|
-
}
|
|
357
|
-
extractSymbols(sourceFile, filePath, serviceName) {
|
|
358
|
-
const candidates = [];
|
|
359
|
-
const sourceLines = sourceFile.getFullText().split('\n');
|
|
360
|
-
const lineAt = (node) => this.lineTextAt(sourceLines, sourceFile, node);
|
|
361
|
-
for (const cls of sourceFile.getClasses()) {
|
|
362
|
-
const name = cls.getName();
|
|
363
|
-
if (!name)
|
|
364
|
-
continue;
|
|
365
|
-
const nameNode = cls.getNameNode() ?? cls;
|
|
366
|
-
const { line, col } = this.getPos(sourceFile, nameNode);
|
|
367
|
-
candidates.push({
|
|
368
|
-
declNode: cls,
|
|
369
|
-
entry: {
|
|
370
|
-
project: serviceName, filePath, name, kind: 'class',
|
|
371
|
-
signature: lineAt(nameNode),
|
|
372
|
-
line, endLine: cls.getEndLineNumber(), col,
|
|
373
|
-
container: null, isStatic: false,
|
|
374
|
-
},
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
for (const fn of sourceFile.getFunctions()) {
|
|
378
|
-
const name = fn.getName();
|
|
379
|
-
if (!name)
|
|
380
|
-
continue;
|
|
381
|
-
const nameNode = fn.getNameNode() ?? fn;
|
|
382
|
-
const { line, col } = this.getPos(sourceFile, nameNode);
|
|
383
|
-
candidates.push({
|
|
384
|
-
declNode: fn,
|
|
385
|
-
entry: {
|
|
386
|
-
project: serviceName, filePath, name, kind: 'function',
|
|
387
|
-
signature: lineAt(nameNode),
|
|
388
|
-
line, endLine: fn.getEndLineNumber(), col,
|
|
389
|
-
container: null, isStatic: false, hasBody: fn.getBody() !== undefined,
|
|
390
|
-
},
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
|
-
for (const iface of sourceFile.getInterfaces()) {
|
|
394
|
-
const nameNode = iface.getNameNode();
|
|
395
|
-
const { line, col } = this.getPos(sourceFile, nameNode);
|
|
396
|
-
candidates.push({
|
|
397
|
-
declNode: iface,
|
|
398
|
-
entry: {
|
|
399
|
-
project: serviceName, filePath, name: iface.getName(), kind: 'interface',
|
|
400
|
-
signature: lineAt(nameNode),
|
|
401
|
-
line, endLine: iface.getEndLineNumber(), col,
|
|
402
|
-
container: null, isStatic: false,
|
|
403
|
-
},
|
|
404
|
-
});
|
|
405
|
-
}
|
|
406
|
-
for (const ta of sourceFile.getTypeAliases()) {
|
|
407
|
-
const nameNode = ta.getNameNode();
|
|
408
|
-
const { line, col } = this.getPos(sourceFile, nameNode);
|
|
409
|
-
candidates.push({
|
|
410
|
-
declNode: ta,
|
|
411
|
-
entry: {
|
|
412
|
-
project: serviceName, filePath, name: ta.getName(), kind: 'type',
|
|
413
|
-
signature: lineAt(nameNode),
|
|
414
|
-
line, endLine: ta.getEndLineNumber(), col,
|
|
415
|
-
container: null, isStatic: false,
|
|
416
|
-
},
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
for (const stmt of sourceFile.getVariableStatements()) {
|
|
420
|
-
for (const decl of stmt.getDeclarations()) {
|
|
421
|
-
const nameNode = decl.getNameNode();
|
|
422
|
-
const { line, col } = this.getPos(sourceFile, nameNode);
|
|
423
|
-
candidates.push({
|
|
424
|
-
declNode: decl,
|
|
425
|
-
entry: {
|
|
426
|
-
project: serviceName, filePath, name: decl.getName(), kind: 'variable',
|
|
427
|
-
signature: lineAt(nameNode),
|
|
428
|
-
line, endLine: stmt.getEndLineNumber(), col,
|
|
429
|
-
container: null, isStatic: false,
|
|
430
|
-
},
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
return candidates;
|
|
435
|
-
}
|
|
436
|
-
extractMembers(sourceFile, filePath, serviceName) {
|
|
437
|
-
const candidates = [];
|
|
438
|
-
const sourceLines = sourceFile.getFullText().split('\n');
|
|
439
|
-
const lineAt = (node) => this.lineTextAt(sourceLines, sourceFile, node);
|
|
440
|
-
const push = (declNode, posNode, name, kind, container, isStatic, hasBody) => {
|
|
441
|
-
const { line, col } = this.getPos(sourceFile, posNode);
|
|
442
|
-
candidates.push({
|
|
443
|
-
declNode,
|
|
444
|
-
entry: {
|
|
445
|
-
project: serviceName, filePath, name, kind,
|
|
446
|
-
signature: lineAt(posNode),
|
|
447
|
-
line, endLine: declNode.getEndLineNumber(), col,
|
|
448
|
-
container: container.length ? container.join('.') : null,
|
|
449
|
-
isStatic, hasBody,
|
|
450
|
-
},
|
|
451
|
-
});
|
|
452
|
-
};
|
|
453
|
-
for (const cls of [
|
|
454
|
-
...sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.ClassDeclaration),
|
|
455
|
-
...sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.ClassExpression),
|
|
456
|
-
]) {
|
|
457
|
-
if (ts_morph_1.Node.isClassDeclaration(cls) && cls.getName() && ts_morph_1.Node.isSourceFile(cls.getParent()))
|
|
458
|
-
continue;
|
|
459
|
-
const described = this.describeIndexedNode(cls);
|
|
460
|
-
if (!described)
|
|
461
|
-
continue;
|
|
462
|
-
const posNode = (ts_morph_1.Node.isClassDeclaration(cls) ? cls.getNameNode() : undefined) ?? cls;
|
|
463
|
-
push(cls, posNode, described.name, 'class', described.container, false, true);
|
|
464
|
-
}
|
|
465
|
-
for (const m of sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.MethodDeclaration)) {
|
|
466
|
-
const described = this.describeIndexedNode(m);
|
|
467
|
-
if (!described)
|
|
468
|
-
continue;
|
|
469
|
-
push(m, m.getNameNode(), described.name, 'method', described.container, m.isStatic(), m.getBody() !== undefined);
|
|
470
|
-
}
|
|
471
|
-
for (const a of sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.GetAccessor)) {
|
|
472
|
-
const described = this.describeIndexedNode(a);
|
|
473
|
-
if (!described)
|
|
474
|
-
continue;
|
|
475
|
-
push(a, a.getNameNode(), described.name, 'get_accessor', described.container, a.isStatic(), true);
|
|
476
|
-
}
|
|
477
|
-
for (const a of sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.SetAccessor)) {
|
|
478
|
-
const described = this.describeIndexedNode(a);
|
|
479
|
-
if (!described)
|
|
480
|
-
continue;
|
|
481
|
-
push(a, a.getNameNode(), described.name, 'set_accessor', described.container, a.isStatic(), true);
|
|
482
|
-
}
|
|
483
|
-
for (const c of sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.Constructor)) {
|
|
484
|
-
const described = this.describeIndexedNode(c);
|
|
485
|
-
if (!described)
|
|
486
|
-
continue;
|
|
487
|
-
const kw = c.getFirstChildByKind(ts_morph_1.SyntaxKind.ConstructorKeyword) ?? c;
|
|
488
|
-
push(c, kw, described.name, 'constructor', described.container, false, c.getBody() !== undefined);
|
|
489
|
-
}
|
|
490
|
-
for (const p of sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.PropertyDeclaration)) {
|
|
491
|
-
const described = this.describeIndexedNode(p);
|
|
492
|
-
if (!described)
|
|
493
|
-
continue;
|
|
494
|
-
push(p, p.getNameNode(), described.name, 'function_property', described.container, p.isStatic(), true);
|
|
495
|
-
}
|
|
496
|
-
for (const p of sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.PropertyAssignment)) {
|
|
497
|
-
const described = this.describeIndexedNode(p);
|
|
498
|
-
if (!described)
|
|
499
|
-
continue;
|
|
500
|
-
push(p, p.getNameNode(), described.name, 'function_property', described.container, false, true);
|
|
501
|
-
}
|
|
502
|
-
for (const s of sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.MethodSignature)) {
|
|
503
|
-
const described = this.describeIndexedNode(s);
|
|
504
|
-
if (!described)
|
|
505
|
-
continue;
|
|
506
|
-
push(s, s.getNameNode(), described.name, 'method_signature', described.container, false, false);
|
|
507
|
-
}
|
|
508
|
-
for (const s of sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.PropertySignature)) {
|
|
509
|
-
const described = this.describeIndexedNode(s);
|
|
510
|
-
if (!described)
|
|
511
|
-
continue;
|
|
512
|
-
push(s, s.getNameNode(), described.name, 'method_signature', described.container, false, false);
|
|
513
|
-
}
|
|
514
|
-
for (const fn of sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.FunctionDeclaration)) {
|
|
515
|
-
if (!ts_morph_1.Node.isModuleBlock(fn.getParent()))
|
|
516
|
-
continue;
|
|
517
|
-
const described = this.describeIndexedNode(fn);
|
|
518
|
-
if (!described)
|
|
519
|
-
continue;
|
|
520
|
-
const nameNode = fn.getNameNode();
|
|
521
|
-
if (!nameNode)
|
|
522
|
-
continue;
|
|
523
|
-
push(fn, nameNode, described.name, 'function', described.container, false, fn.getBody() !== undefined);
|
|
524
|
-
}
|
|
525
|
-
for (const iface of sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.InterfaceDeclaration)) {
|
|
526
|
-
if (!ts_morph_1.Node.isModuleBlock(iface.getParent()))
|
|
527
|
-
continue;
|
|
528
|
-
const described = this.describeIndexedNode(iface);
|
|
529
|
-
if (!described)
|
|
530
|
-
continue;
|
|
531
|
-
push(iface, iface.getNameNode(), described.name, 'interface', described.container, false, true);
|
|
532
|
-
}
|
|
533
|
-
for (const ta of sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.TypeAliasDeclaration)) {
|
|
534
|
-
if (!ts_morph_1.Node.isModuleBlock(ta.getParent()))
|
|
535
|
-
continue;
|
|
536
|
-
const described = this.describeIndexedNode(ta);
|
|
537
|
-
if (!described)
|
|
538
|
-
continue;
|
|
539
|
-
push(ta, ta.getNameNode(), described.name, 'type', described.container, false, true);
|
|
540
|
-
}
|
|
541
|
-
for (const stmt of sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.VariableStatement)) {
|
|
542
|
-
if (!ts_morph_1.Node.isModuleBlock(stmt.getParent()))
|
|
543
|
-
continue;
|
|
544
|
-
for (const decl of stmt.getDeclarations()) {
|
|
545
|
-
const described = this.describeIndexedNode(decl);
|
|
546
|
-
if (!described)
|
|
547
|
-
continue;
|
|
548
|
-
push(decl, decl.getNameNode(), described.name, 'variable', described.container, false, true);
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
return candidates;
|
|
552
|
-
}
|
|
553
235
|
buildDeclarations(sourceFile, filePath, symbolCandidates, memberCandidates) {
|
|
554
236
|
try {
|
|
555
237
|
return this.declarationBuilder.build(sourceFile, [...symbolCandidates, ...memberCandidates]);
|
|
@@ -564,606 +246,5 @@ class AstParserService {
|
|
|
564
246
|
}
|
|
565
247
|
}
|
|
566
248
|
}
|
|
567
|
-
buildGraphqlImportMap(sourceFile) {
|
|
568
|
-
const map = new Map();
|
|
569
|
-
for (const decl of sourceFile.getImportDeclarations()) {
|
|
570
|
-
if (decl.getModuleSpecifierValue() !== GRAPHQL_MODULE)
|
|
571
|
-
continue;
|
|
572
|
-
for (const named of decl.getNamedImports()) {
|
|
573
|
-
const exportedName = named.getName();
|
|
574
|
-
const localName = named.getAliasNode()?.getText() ?? exportedName;
|
|
575
|
-
map.set(localName, exportedName);
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
return map;
|
|
579
|
-
}
|
|
580
|
-
static decoratorIdentifier(dec) {
|
|
581
|
-
const expr = dec.getExpression();
|
|
582
|
-
if (ts_morph_1.Node.isCallExpression(expr)) {
|
|
583
|
-
const callee = expr.getExpression();
|
|
584
|
-
return ts_morph_1.Node.isIdentifier(callee) ? callee : undefined;
|
|
585
|
-
}
|
|
586
|
-
return ts_morph_1.Node.isIdentifier(expr) ? expr : undefined;
|
|
587
|
-
}
|
|
588
|
-
recognizedDecorator(dec, importMap) {
|
|
589
|
-
const idNode = AstParserService.decoratorIdentifier(dec);
|
|
590
|
-
if (!idNode)
|
|
591
|
-
return null;
|
|
592
|
-
const exported = importMap.get(idNode.getText());
|
|
593
|
-
if (!exported)
|
|
594
|
-
return null;
|
|
595
|
-
const expr = dec.getExpression();
|
|
596
|
-
const args = ts_morph_1.Node.isCallExpression(expr) ? expr.getArguments() : [];
|
|
597
|
-
return { name: exported, args };
|
|
598
|
-
}
|
|
599
|
-
static literalStringValue(node) {
|
|
600
|
-
if (ts_morph_1.Node.isStringLiteral(node) || ts_morph_1.Node.isNoSubstitutionTemplateLiteral(node))
|
|
601
|
-
return node.getLiteralValue();
|
|
602
|
-
return null;
|
|
603
|
-
}
|
|
604
|
-
static checkGraphqlGrammar(name) {
|
|
605
|
-
return GRAPHQL_NAME_RE.test(name) ? { ok: true, name } : { ok: false, reason: 'invalid-name', value: name };
|
|
606
|
-
}
|
|
607
|
-
static isAbstractGraphqlType(args) {
|
|
608
|
-
return args.some((arg) => {
|
|
609
|
-
if (!ts_morph_1.Node.isObjectLiteralExpression(arg))
|
|
610
|
-
return false;
|
|
611
|
-
const prop = arg.getProperties().find((p) => {
|
|
612
|
-
if (!ts_morph_1.Node.isPropertyAssignment(p))
|
|
613
|
-
return false;
|
|
614
|
-
const nameNode = p.getNameNode();
|
|
615
|
-
if (ts_morph_1.Node.isIdentifier(nameNode))
|
|
616
|
-
return nameNode.getText() === 'isAbstract';
|
|
617
|
-
if (ts_morph_1.Node.isStringLiteral(nameNode))
|
|
618
|
-
return nameNode.getLiteralValue() === 'isAbstract';
|
|
619
|
-
return false;
|
|
620
|
-
});
|
|
621
|
-
const init = prop?.getInitializer();
|
|
622
|
-
return init !== undefined && ts_morph_1.Node.isTrueLiteral(init);
|
|
623
|
-
});
|
|
624
|
-
}
|
|
625
|
-
static findNameProperty(obj) {
|
|
626
|
-
return obj.getProperties().find((p) => {
|
|
627
|
-
if (!ts_morph_1.Node.isPropertyAssignment(p) && !ts_morph_1.Node.isShorthandPropertyAssignment(p))
|
|
628
|
-
return false;
|
|
629
|
-
const nameNode = p.getNameNode();
|
|
630
|
-
if (ts_morph_1.Node.isIdentifier(nameNode))
|
|
631
|
-
return nameNode.getText() === 'name';
|
|
632
|
-
if (ts_morph_1.Node.isStringLiteral(nameNode))
|
|
633
|
-
return nameNode.getLiteralValue() === 'name';
|
|
634
|
-
return false;
|
|
635
|
-
});
|
|
636
|
-
}
|
|
637
|
-
static peekThroughWrapper(node) {
|
|
638
|
-
let current = node;
|
|
639
|
-
let wrapped = false;
|
|
640
|
-
while (true) {
|
|
641
|
-
if (ts_morph_1.Node.isParenthesizedExpression(current) || ts_morph_1.Node.isAsExpression(current) || ts_morph_1.Node.isSatisfiesExpression(current) || ts_morph_1.Node.isNonNullExpression(current)) {
|
|
642
|
-
current = current.getExpression();
|
|
643
|
-
wrapped = true;
|
|
644
|
-
continue;
|
|
645
|
-
}
|
|
646
|
-
break;
|
|
647
|
-
}
|
|
648
|
-
return { inner: current, wrapped };
|
|
649
|
-
}
|
|
650
|
-
deriveGraphqlName(args, allowOptionsName, fallbackName) {
|
|
651
|
-
if (args.length > 0) {
|
|
652
|
-
const first = args[0];
|
|
653
|
-
const { inner, wrapped } = AstParserService.peekThroughWrapper(first);
|
|
654
|
-
const literal = AstParserService.literalStringValue(inner);
|
|
655
|
-
if (literal !== null) {
|
|
656
|
-
if (wrapped)
|
|
657
|
-
return { ok: false, reason: 'non-literal-name' };
|
|
658
|
-
return AstParserService.checkGraphqlGrammar(literal);
|
|
659
|
-
}
|
|
660
|
-
const isTypeFnOrOptions = ts_morph_1.Node.isArrowFunction(inner) || ts_morph_1.Node.isFunctionExpression(inner) || ts_morph_1.Node.isObjectLiteralExpression(inner);
|
|
661
|
-
if (!isTypeFnOrOptions)
|
|
662
|
-
return { ok: false, reason: 'non-literal-name' };
|
|
663
|
-
}
|
|
664
|
-
if (allowOptionsName) {
|
|
665
|
-
for (const arg of args) {
|
|
666
|
-
const { inner, wrapped } = AstParserService.peekThroughWrapper(arg);
|
|
667
|
-
if (!ts_morph_1.Node.isObjectLiteralExpression(inner))
|
|
668
|
-
continue;
|
|
669
|
-
if (wrapped)
|
|
670
|
-
return { ok: false, reason: 'non-literal-name' };
|
|
671
|
-
const nameProp = AstParserService.findNameProperty(inner);
|
|
672
|
-
if (!nameProp)
|
|
673
|
-
continue;
|
|
674
|
-
if (ts_morph_1.Node.isShorthandPropertyAssignment(nameProp))
|
|
675
|
-
return { ok: false, reason: 'non-literal-name' };
|
|
676
|
-
const init = nameProp.getInitializer();
|
|
677
|
-
const value = init ? AstParserService.literalStringValue(init) : null;
|
|
678
|
-
if (value !== null)
|
|
679
|
-
return AstParserService.checkGraphqlGrammar(value);
|
|
680
|
-
return { ok: false, reason: 'non-literal-name' };
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
return AstParserService.checkGraphqlGrammar(fallbackName);
|
|
684
|
-
}
|
|
685
|
-
logGraphqlSkip(filePath, declaration, decorator, reason, value) {
|
|
686
|
-
const fields = { filePath, declaration, decorator, reason };
|
|
687
|
-
if (value !== undefined)
|
|
688
|
-
fields.value = value;
|
|
689
|
-
this.logger.debug('AstParser: graphql row skipped', fields);
|
|
690
|
-
}
|
|
691
|
-
declarationNameFor(node, fallback) {
|
|
692
|
-
const described = this.describeIndexedNode(node);
|
|
693
|
-
return described ? this.qualifiedName(described) : fallback;
|
|
694
|
-
}
|
|
695
|
-
static extractResolverIdentifier(argNode) {
|
|
696
|
-
let target = argNode;
|
|
697
|
-
if (ts_morph_1.Node.isArrowFunction(target)) {
|
|
698
|
-
const body = target.getBody();
|
|
699
|
-
if (ts_morph_1.Node.isBlock(body))
|
|
700
|
-
return null;
|
|
701
|
-
target = body;
|
|
702
|
-
}
|
|
703
|
-
if (ts_morph_1.Node.isIdentifier(target))
|
|
704
|
-
return target;
|
|
705
|
-
if (ts_morph_1.Node.isArrayLiteralExpression(target)) {
|
|
706
|
-
const elements = target.getElements();
|
|
707
|
-
if (elements.length === 1 && ts_morph_1.Node.isIdentifier(elements[0]))
|
|
708
|
-
return elements[0];
|
|
709
|
-
}
|
|
710
|
-
return null;
|
|
711
|
-
}
|
|
712
|
-
defaultResolveDeclaration(identifier) {
|
|
713
|
-
const sym = identifier.getSymbol();
|
|
714
|
-
if (!sym)
|
|
715
|
-
return undefined;
|
|
716
|
-
const firstDecl = sym.getDeclarations()?.[0];
|
|
717
|
-
const resolved = firstDecl && ts_morph_1.Node.isImportSpecifier(firstDecl) ? (sym.getAliasedSymbol() ?? sym) : sym;
|
|
718
|
-
return resolved.getDeclarations()?.[0];
|
|
719
|
-
}
|
|
720
|
-
classGraphqlTypeName(declClass) {
|
|
721
|
-
const declImportMap = this.buildGraphqlImportMap(declClass.getSourceFile());
|
|
722
|
-
const decorators = declClass.getDecorators();
|
|
723
|
-
const hasAnyTypeSpelledDecorator = decorators.some((d) => {
|
|
724
|
-
const idNode = AstParserService.decoratorIdentifier(d);
|
|
725
|
-
const text = idNode?.getText();
|
|
726
|
-
return text === 'ObjectType' || text === 'InterfaceType';
|
|
727
|
-
});
|
|
728
|
-
const recognized = decorators
|
|
729
|
-
.map(d => this.recognizedDecorator(d, declImportMap))
|
|
730
|
-
.find(r => r?.name === 'ObjectType')
|
|
731
|
-
?? decorators.map(d => this.recognizedDecorator(d, declImportMap)).find(r => r?.name === 'InterfaceType');
|
|
732
|
-
if (recognized) {
|
|
733
|
-
const fallbackName = declClass.getName() ?? (declClass.isDefaultExport() ? 'default' : '');
|
|
734
|
-
const nameResult = this.deriveGraphqlName(recognized.args, false, fallbackName);
|
|
735
|
-
return nameResult.ok ? { ok: true, name: nameResult.name } : { ok: false };
|
|
736
|
-
}
|
|
737
|
-
if (hasAnyTypeSpelledDecorator)
|
|
738
|
-
return { ok: false };
|
|
739
|
-
const name = declClass.getName();
|
|
740
|
-
if (!name)
|
|
741
|
-
return { ok: false };
|
|
742
|
-
return GRAPHQL_NAME_RE.test(name) ? { ok: true, name } : { ok: false, value: name };
|
|
743
|
-
}
|
|
744
|
-
resolveResolverParentType(cls, importMap) {
|
|
745
|
-
const resolverDec = cls.getDecorators()
|
|
746
|
-
.map(d => this.recognizedDecorator(d, importMap))
|
|
747
|
-
.find(r => r?.name === 'Resolver');
|
|
748
|
-
if (!resolverDec || resolverDec.args.length === 0)
|
|
749
|
-
return { ok: false };
|
|
750
|
-
const argNode = resolverDec.args[0];
|
|
751
|
-
const literal = AstParserService.literalStringValue(argNode);
|
|
752
|
-
if (literal !== null) {
|
|
753
|
-
return GRAPHQL_NAME_RE.test(literal) ? { ok: true, name: literal } : { ok: false, value: literal };
|
|
754
|
-
}
|
|
755
|
-
const identifier = AstParserService.extractResolverIdentifier(argNode);
|
|
756
|
-
if (!identifier)
|
|
757
|
-
return { ok: false };
|
|
758
|
-
const resolve = this.deps.resolveDeclaration ?? this.defaultResolveDeclaration.bind(this);
|
|
759
|
-
const declaration = resolve(identifier);
|
|
760
|
-
if (!declaration || !ts_morph_1.Node.isClassDeclaration(declaration))
|
|
761
|
-
return { ok: false };
|
|
762
|
-
return this.classGraphqlTypeName(declaration);
|
|
763
|
-
}
|
|
764
|
-
extractClassTypeRows(cls, importMap, ownByDeclNode, filePath, serviceName, entries) {
|
|
765
|
-
const own = ownByDeclNode.get(cls);
|
|
766
|
-
const declaration = this.declarationNameFor(cls, own?.entry.name ?? cls.getName() ?? 'default');
|
|
767
|
-
const seenNames = new Set();
|
|
768
|
-
for (const dec of cls.getDecorators()) {
|
|
769
|
-
const rec = this.recognizedDecorator(dec, importMap);
|
|
770
|
-
if (!rec || !GRAPHQL_TYPE_DECORATORS.has(rec.name))
|
|
771
|
-
continue;
|
|
772
|
-
if (AstParserService.isAbstractGraphqlType(rec.args)) {
|
|
773
|
-
this.logGraphqlSkip(filePath, declaration, rec.name, 'abstract-type');
|
|
774
|
-
continue;
|
|
775
|
-
}
|
|
776
|
-
if (!own) {
|
|
777
|
-
this.logGraphqlSkip(filePath, declaration, rec.name, 'no-symbol-row');
|
|
778
|
-
continue;
|
|
779
|
-
}
|
|
780
|
-
const nameResult = this.deriveGraphqlName(rec.args, false, own.entry.name);
|
|
781
|
-
if (!nameResult.ok) {
|
|
782
|
-
this.logGraphqlSkip(filePath, declaration, rec.name, nameResult.reason, nameResult.reason === 'invalid-name' ? nameResult.value : undefined);
|
|
783
|
-
continue;
|
|
784
|
-
}
|
|
785
|
-
if (seenNames.has(nameResult.name)) {
|
|
786
|
-
this.logGraphqlSkip(filePath, declaration, rec.name, 'duplicate', own.entry.name);
|
|
787
|
-
continue;
|
|
788
|
-
}
|
|
789
|
-
seenNames.add(nameResult.name);
|
|
790
|
-
entries.push({
|
|
791
|
-
project: serviceName, filePath, name: nameResult.name, kind: 'graphql_type',
|
|
792
|
-
signature: own.entry.signature, line: own.entry.line, endLine: own.entry.endLine, col: own.entry.col,
|
|
793
|
-
container: null, isStatic: false, target: declaration,
|
|
794
|
-
});
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
extractResolveFieldRow(method, rec, own, declaration, importMap, filePath, serviceName, entries) {
|
|
798
|
-
if (!own) {
|
|
799
|
-
this.logGraphqlSkip(filePath, declaration, 'ResolveField', 'no-symbol-row');
|
|
800
|
-
return;
|
|
801
|
-
}
|
|
802
|
-
const cls = method.getParent();
|
|
803
|
-
if (!cls || !ts_morph_1.Node.isClassDeclaration(cls)) {
|
|
804
|
-
this.logGraphqlSkip(filePath, declaration, 'ResolveField', 'unresolvable-parent');
|
|
805
|
-
return;
|
|
806
|
-
}
|
|
807
|
-
const parent = this.resolveResolverParentType(cls, importMap);
|
|
808
|
-
if (!parent.ok) {
|
|
809
|
-
this.logGraphqlSkip(filePath, declaration, 'ResolveField', 'unresolvable-parent', parent.value);
|
|
810
|
-
return;
|
|
811
|
-
}
|
|
812
|
-
const nameResult = this.deriveGraphqlName(rec.args, true, own.entry.name);
|
|
813
|
-
if (!nameResult.ok) {
|
|
814
|
-
this.logGraphqlSkip(filePath, declaration, 'ResolveField', nameResult.reason, nameResult.reason === 'invalid-name' ? nameResult.value : undefined);
|
|
815
|
-
return;
|
|
816
|
-
}
|
|
817
|
-
entries.push({
|
|
818
|
-
project: serviceName, filePath, name: nameResult.name, kind: 'graphql_field',
|
|
819
|
-
signature: own.entry.signature, line: own.entry.line, endLine: own.entry.endLine, col: own.entry.col,
|
|
820
|
-
container: parent.name, isStatic: own.entry.isStatic, target: declaration,
|
|
821
|
-
});
|
|
822
|
-
}
|
|
823
|
-
extractMethodOperationRows(method, importMap, ownByDeclNode, filePath, serviceName, entries) {
|
|
824
|
-
const own = ownByDeclNode.get(method);
|
|
825
|
-
const declaration = this.declarationNameFor(method, own?.entry.name ?? AstParserService.memberName(method.getNameNode()) ?? '<anonymous>');
|
|
826
|
-
for (const dec of method.getDecorators()) {
|
|
827
|
-
const rec = this.recognizedDecorator(dec, importMap);
|
|
828
|
-
if (!rec)
|
|
829
|
-
continue;
|
|
830
|
-
if (rec.name === 'ResolveField') {
|
|
831
|
-
try {
|
|
832
|
-
this.extractResolveFieldRow(method, rec, own, declaration, importMap, filePath, serviceName, entries);
|
|
833
|
-
}
|
|
834
|
-
catch (err) {
|
|
835
|
-
this.logGraphqlSkip(filePath, declaration, 'ResolveField', 'unresolvable-parent');
|
|
836
|
-
}
|
|
837
|
-
continue;
|
|
838
|
-
}
|
|
839
|
-
const kind = GRAPHQL_OPERATION_KIND[rec.name];
|
|
840
|
-
if (!kind)
|
|
841
|
-
continue;
|
|
842
|
-
if (!own) {
|
|
843
|
-
this.logGraphqlSkip(filePath, declaration, rec.name, 'no-symbol-row');
|
|
844
|
-
continue;
|
|
845
|
-
}
|
|
846
|
-
const nameResult = this.deriveGraphqlName(rec.args, true, own.entry.name);
|
|
847
|
-
if (!nameResult.ok) {
|
|
848
|
-
this.logGraphqlSkip(filePath, declaration, rec.name, nameResult.reason, nameResult.reason === 'invalid-name' ? nameResult.value : undefined);
|
|
849
|
-
continue;
|
|
850
|
-
}
|
|
851
|
-
entries.push({
|
|
852
|
-
project: serviceName, filePath, name: nameResult.name, kind,
|
|
853
|
-
signature: own.entry.signature, line: own.entry.line, endLine: own.entry.endLine, col: own.entry.col,
|
|
854
|
-
container: rec.name, isStatic: own.entry.isStatic, target: declaration,
|
|
855
|
-
});
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
extractGraphqlNames(sourceFile, filePath, serviceName, ownRows) {
|
|
859
|
-
const importMap = this.buildGraphqlImportMap(sourceFile);
|
|
860
|
-
if (importMap.size === 0)
|
|
861
|
-
return [];
|
|
862
|
-
const ownByDeclNode = new Map();
|
|
863
|
-
for (const c of ownRows)
|
|
864
|
-
ownByDeclNode.set(c.declNode, c);
|
|
865
|
-
const entries = [];
|
|
866
|
-
for (const cls of sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.ClassDeclaration)) {
|
|
867
|
-
this.extractClassTypeRows(cls, importMap, ownByDeclNode, filePath, serviceName, entries);
|
|
868
|
-
}
|
|
869
|
-
for (const method of sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.MethodDeclaration)) {
|
|
870
|
-
this.extractMethodOperationRows(method, importMap, ownByDeclNode, filePath, serviceName, entries);
|
|
871
|
-
}
|
|
872
|
-
return entries;
|
|
873
|
-
}
|
|
874
|
-
static isValidSegment(s) {
|
|
875
|
-
return VALID_SEGMENT.test(s);
|
|
876
|
-
}
|
|
877
|
-
static memberName(nameNode) {
|
|
878
|
-
if (!nameNode)
|
|
879
|
-
return null;
|
|
880
|
-
if (ts_morph_1.Node.isPrivateIdentifier(nameNode))
|
|
881
|
-
return nameNode.getText();
|
|
882
|
-
if (ts_morph_1.Node.isIdentifier(nameNode))
|
|
883
|
-
return nameNode.getText();
|
|
884
|
-
if (ts_morph_1.Node.isStringLiteral(nameNode))
|
|
885
|
-
return nameNode.getLiteralValue();
|
|
886
|
-
if (ts_morph_1.Node.isNumericLiteral(nameNode))
|
|
887
|
-
return nameNode.getText();
|
|
888
|
-
if (ts_morph_1.Node.isComputedPropertyName(nameNode))
|
|
889
|
-
return nameNode.getText().replace(/\s+/g, '');
|
|
890
|
-
return null;
|
|
891
|
-
}
|
|
892
|
-
static unwrapExpr(node) {
|
|
893
|
-
let current = node;
|
|
894
|
-
while (ts_morph_1.Node.isParenthesizedExpression(current) || ts_morph_1.Node.isAsExpression(current) || ts_morph_1.Node.isSatisfiesExpression(current)) {
|
|
895
|
-
current = current.getExpression();
|
|
896
|
-
}
|
|
897
|
-
return current;
|
|
898
|
-
}
|
|
899
|
-
static unwrapParent(node) {
|
|
900
|
-
let current = node.getParent();
|
|
901
|
-
while (current && (ts_morph_1.Node.isParenthesizedExpression(current) || ts_morph_1.Node.isAsExpression(current) || ts_morph_1.Node.isSatisfiesExpression(current))) {
|
|
902
|
-
current = current.getParent();
|
|
903
|
-
}
|
|
904
|
-
return current;
|
|
905
|
-
}
|
|
906
|
-
isModuleOrNamespaceLevelVariable(varDecl) {
|
|
907
|
-
const stmt = varDecl.getParent()?.getParent();
|
|
908
|
-
const stmtParent = stmt?.getParent();
|
|
909
|
-
return ts_morph_1.Node.isSourceFile(stmtParent) || ts_morph_1.Node.isModuleBlock(stmtParent);
|
|
910
|
-
}
|
|
911
|
-
classExpressionRoot(classExpr) {
|
|
912
|
-
const parent = AstParserService.unwrapParent(classExpr);
|
|
913
|
-
if (!parent)
|
|
914
|
-
return null;
|
|
915
|
-
if (ts_morph_1.Node.isVariableDeclaration(parent)) {
|
|
916
|
-
const name = parent.getName();
|
|
917
|
-
return name ? { name, namingParent: parent } : null;
|
|
918
|
-
}
|
|
919
|
-
if (ts_morph_1.Node.isExportAssignment(parent) && !parent.isExportEquals()) {
|
|
920
|
-
return { name: 'default', namingParent: parent };
|
|
921
|
-
}
|
|
922
|
-
return null;
|
|
923
|
-
}
|
|
924
|
-
objectLiteralRootValid(obj) {
|
|
925
|
-
const parent = AstParserService.unwrapParent(obj);
|
|
926
|
-
if (!parent)
|
|
927
|
-
return false;
|
|
928
|
-
if (ts_morph_1.Node.isPropertyAssignment(parent))
|
|
929
|
-
return true;
|
|
930
|
-
if (ts_morph_1.Node.isVariableDeclaration(parent))
|
|
931
|
-
return this.isModuleOrNamespaceLevelVariable(parent);
|
|
932
|
-
if (ts_morph_1.Node.isExportAssignment(parent) && !parent.isExportEquals())
|
|
933
|
-
return true;
|
|
934
|
-
return false;
|
|
935
|
-
}
|
|
936
|
-
isTopLevelOrNamespaceDirect(node) {
|
|
937
|
-
return ts_morph_1.Node.isSourceFile(node) || ts_morph_1.Node.isModuleBlock(node);
|
|
938
|
-
}
|
|
939
|
-
walkStep(node) {
|
|
940
|
-
if (ts_morph_1.Node.isModuleDeclaration(node)) {
|
|
941
|
-
if (node.compilerNode.flags & ts_morph_1.NodeFlags.GlobalAugmentation)
|
|
942
|
-
return { kind: 'exclude' };
|
|
943
|
-
const nameNode = node.getNameNode();
|
|
944
|
-
if (ts_morph_1.Node.isStringLiteral(nameNode))
|
|
945
|
-
return { kind: 'exclude' };
|
|
946
|
-
return { kind: 'segment', text: nameNode.getText() };
|
|
947
|
-
}
|
|
948
|
-
if (ts_morph_1.Node.isClassDeclaration(node)) {
|
|
949
|
-
const name = node.getName();
|
|
950
|
-
if (name)
|
|
951
|
-
return { kind: 'segment', text: name };
|
|
952
|
-
if (node.isDefaultExport())
|
|
953
|
-
return { kind: 'segment', text: 'default' };
|
|
954
|
-
return { kind: 'exclude' };
|
|
955
|
-
}
|
|
956
|
-
if (ts_morph_1.Node.isClassExpression(node)) {
|
|
957
|
-
const root = this.classExpressionRoot(node);
|
|
958
|
-
if (!root)
|
|
959
|
-
return { kind: 'exclude' };
|
|
960
|
-
return { kind: 'segment', text: root.name, skipTo: root.namingParent };
|
|
961
|
-
}
|
|
962
|
-
if (ts_morph_1.Node.isFunctionDeclaration(node)) {
|
|
963
|
-
const name = node.getName();
|
|
964
|
-
return name ? { kind: 'segment', text: name } : { kind: 'transparent' };
|
|
965
|
-
}
|
|
966
|
-
if (ts_morph_1.Node.isMethodDeclaration(node) || ts_morph_1.Node.isGetAccessorDeclaration(node) || ts_morph_1.Node.isSetAccessorDeclaration(node)) {
|
|
967
|
-
const name = AstParserService.memberName(node.getNameNode());
|
|
968
|
-
return name !== null ? { kind: 'segment', text: name } : { kind: 'exclude' };
|
|
969
|
-
}
|
|
970
|
-
if (ts_morph_1.Node.isConstructorDeclaration(node)) {
|
|
971
|
-
return { kind: 'segment', text: 'constructor' };
|
|
972
|
-
}
|
|
973
|
-
if (ts_morph_1.Node.isPropertyDeclaration(node) || ts_morph_1.Node.isPropertyAssignment(node)) {
|
|
974
|
-
const name = AstParserService.memberName(node.getNameNode());
|
|
975
|
-
return name !== null ? { kind: 'segment', text: name } : { kind: 'exclude' };
|
|
976
|
-
}
|
|
977
|
-
if (ts_morph_1.Node.isInterfaceDeclaration(node)) {
|
|
978
|
-
return { kind: 'segment', text: node.getName() };
|
|
979
|
-
}
|
|
980
|
-
if (ts_morph_1.Node.isTypeAliasDeclaration(node)) {
|
|
981
|
-
return { kind: 'segment', text: node.getName() };
|
|
982
|
-
}
|
|
983
|
-
if (ts_morph_1.Node.isVariableDeclaration(node)) {
|
|
984
|
-
return { kind: 'segment', text: node.getName() };
|
|
985
|
-
}
|
|
986
|
-
if (ts_morph_1.Node.isObjectLiteralExpression(node)) {
|
|
987
|
-
return this.objectLiteralRootValid(node) ? { kind: 'transparent' } : { kind: 'exclude' };
|
|
988
|
-
}
|
|
989
|
-
return { kind: 'transparent' };
|
|
990
|
-
}
|
|
991
|
-
containerSegments(node) {
|
|
992
|
-
const segments = [];
|
|
993
|
-
let current = node.getParent();
|
|
994
|
-
while (current) {
|
|
995
|
-
const step = this.walkStep(current);
|
|
996
|
-
if (step.kind === 'exclude')
|
|
997
|
-
return null;
|
|
998
|
-
if (step.kind === 'segment') {
|
|
999
|
-
if (!AstParserService.isValidSegment(step.text))
|
|
1000
|
-
return null;
|
|
1001
|
-
segments.unshift(step.text);
|
|
1002
|
-
current = step.skipTo ? step.skipTo.getParent() : current.getParent();
|
|
1003
|
-
continue;
|
|
1004
|
-
}
|
|
1005
|
-
current = current.getParent();
|
|
1006
|
-
}
|
|
1007
|
-
return segments;
|
|
1008
|
-
}
|
|
1009
|
-
describeIndexedNode(node) {
|
|
1010
|
-
if (ts_morph_1.Node.isClassDeclaration(node)) {
|
|
1011
|
-
const name = node.getName() ?? (node.isDefaultExport() ? 'default' : null);
|
|
1012
|
-
if (name === null)
|
|
1013
|
-
return null;
|
|
1014
|
-
const container = this.containerSegments(node);
|
|
1015
|
-
return container === null ? null : { name, container };
|
|
1016
|
-
}
|
|
1017
|
-
if (ts_morph_1.Node.isClassExpression(node)) {
|
|
1018
|
-
const root = this.classExpressionRoot(node);
|
|
1019
|
-
if (!root)
|
|
1020
|
-
return null;
|
|
1021
|
-
const container = this.containerSegments(root.namingParent);
|
|
1022
|
-
return container === null ? null : { name: root.name, container };
|
|
1023
|
-
}
|
|
1024
|
-
if (ts_morph_1.Node.isFunctionDeclaration(node)) {
|
|
1025
|
-
const name = node.getName();
|
|
1026
|
-
if (!name || !this.isTopLevelOrNamespaceDirect(node.getParent()))
|
|
1027
|
-
return null;
|
|
1028
|
-
const container = this.containerSegments(node);
|
|
1029
|
-
return container === null ? null : { name, container };
|
|
1030
|
-
}
|
|
1031
|
-
if (ts_morph_1.Node.isMethodDeclaration(node) || ts_morph_1.Node.isGetAccessorDeclaration(node) || ts_morph_1.Node.isSetAccessorDeclaration(node)) {
|
|
1032
|
-
const name = AstParserService.memberName(node.getNameNode());
|
|
1033
|
-
if (name === null)
|
|
1034
|
-
return null;
|
|
1035
|
-
const container = this.containerSegments(node);
|
|
1036
|
-
return container === null ? null : { name, container };
|
|
1037
|
-
}
|
|
1038
|
-
if (ts_morph_1.Node.isConstructorDeclaration(node)) {
|
|
1039
|
-
const container = this.containerSegments(node);
|
|
1040
|
-
return container === null ? null : { name: 'constructor', container };
|
|
1041
|
-
}
|
|
1042
|
-
if (ts_morph_1.Node.isPropertyDeclaration(node) || ts_morph_1.Node.isPropertyAssignment(node)) {
|
|
1043
|
-
const init = node.getInitializer();
|
|
1044
|
-
if (!init)
|
|
1045
|
-
return null;
|
|
1046
|
-
const unwrapped = AstParserService.unwrapExpr(init);
|
|
1047
|
-
if (!(ts_morph_1.Node.isArrowFunction(unwrapped) || ts_morph_1.Node.isFunctionExpression(unwrapped)))
|
|
1048
|
-
return null;
|
|
1049
|
-
const name = AstParserService.memberName(node.getNameNode());
|
|
1050
|
-
if (name === null)
|
|
1051
|
-
return null;
|
|
1052
|
-
const container = this.containerSegments(node);
|
|
1053
|
-
return container === null ? null : { name, container };
|
|
1054
|
-
}
|
|
1055
|
-
if (ts_morph_1.Node.isInterfaceDeclaration(node)) {
|
|
1056
|
-
if (!this.isTopLevelOrNamespaceDirect(node.getParent()))
|
|
1057
|
-
return null;
|
|
1058
|
-
const container = this.containerSegments(node);
|
|
1059
|
-
return container === null ? null : { name: node.getName(), container };
|
|
1060
|
-
}
|
|
1061
|
-
if (ts_morph_1.Node.isTypeAliasDeclaration(node)) {
|
|
1062
|
-
if (!this.isTopLevelOrNamespaceDirect(node.getParent()))
|
|
1063
|
-
return null;
|
|
1064
|
-
const container = this.containerSegments(node);
|
|
1065
|
-
return container === null ? null : { name: node.getName(), container };
|
|
1066
|
-
}
|
|
1067
|
-
if (ts_morph_1.Node.isVariableDeclaration(node)) {
|
|
1068
|
-
if (!this.isModuleOrNamespaceLevelVariable(node))
|
|
1069
|
-
return null;
|
|
1070
|
-
const container = this.containerSegments(node);
|
|
1071
|
-
return container === null ? null : { name: node.getName(), container };
|
|
1072
|
-
}
|
|
1073
|
-
if (ts_morph_1.Node.isMethodSignature(node) || ts_morph_1.Node.isPropertySignature(node)) {
|
|
1074
|
-
if (ts_morph_1.Node.isPropertySignature(node)) {
|
|
1075
|
-
const typeNode = node.getTypeNode();
|
|
1076
|
-
if (!typeNode || !ts_morph_1.Node.isFunctionTypeNode(typeNode))
|
|
1077
|
-
return null;
|
|
1078
|
-
}
|
|
1079
|
-
const parent = node.getParent();
|
|
1080
|
-
let validParent = false;
|
|
1081
|
-
if (ts_morph_1.Node.isInterfaceDeclaration(parent)) {
|
|
1082
|
-
validParent = true;
|
|
1083
|
-
}
|
|
1084
|
-
else if (ts_morph_1.Node.isTypeLiteral(parent)) {
|
|
1085
|
-
const aliasParent = parent.getParent();
|
|
1086
|
-
validParent = ts_morph_1.Node.isTypeAliasDeclaration(aliasParent) && aliasParent.getTypeNode() === parent;
|
|
1087
|
-
}
|
|
1088
|
-
if (!validParent)
|
|
1089
|
-
return null;
|
|
1090
|
-
const name = AstParserService.memberName(node.getNameNode());
|
|
1091
|
-
if (name === null)
|
|
1092
|
-
return null;
|
|
1093
|
-
const container = this.containerSegments(node);
|
|
1094
|
-
return container === null ? null : { name, container };
|
|
1095
|
-
}
|
|
1096
|
-
return null;
|
|
1097
|
-
}
|
|
1098
|
-
qualifiedName(described) {
|
|
1099
|
-
return described.container.length ? `${described.container.join('.')}.${described.name}` : described.name;
|
|
1100
|
-
}
|
|
1101
|
-
findFromSymbol(node) {
|
|
1102
|
-
let current = node.getParent();
|
|
1103
|
-
while (current) {
|
|
1104
|
-
const described = this.describeIndexedNode(current);
|
|
1105
|
-
if (described)
|
|
1106
|
-
return this.qualifiedName(described);
|
|
1107
|
-
current = current.getParent();
|
|
1108
|
-
}
|
|
1109
|
-
return null;
|
|
1110
|
-
}
|
|
1111
|
-
extractCalls(sourceFile, filePath, serviceName) {
|
|
1112
|
-
const calls = [];
|
|
1113
|
-
for (const callExpr of sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.CallExpression)) {
|
|
1114
|
-
const expr = callExpr.getExpression();
|
|
1115
|
-
let calleeName = null;
|
|
1116
|
-
let calleeFile = null;
|
|
1117
|
-
let calleeDecl;
|
|
1118
|
-
try {
|
|
1119
|
-
if (ts_morph_1.Node.isPropertyAccessExpression(expr)) {
|
|
1120
|
-
calleeName = expr.getName();
|
|
1121
|
-
const sym = expr.getNameNode().getSymbol();
|
|
1122
|
-
const decl = sym?.getDeclarations()?.[0];
|
|
1123
|
-
const declPath = decl?.getSourceFile().getFilePath();
|
|
1124
|
-
if (declPath && !declPath.includes('/node_modules/')) {
|
|
1125
|
-
calleeFile = declPath;
|
|
1126
|
-
calleeDecl = decl;
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
else if (ts_morph_1.Node.isIdentifier(expr)) {
|
|
1130
|
-
calleeName = expr.getText();
|
|
1131
|
-
const sym = expr.getSymbol();
|
|
1132
|
-
if (sym) {
|
|
1133
|
-
const firstDecl = sym.getDeclarations()?.[0];
|
|
1134
|
-
const resolved = firstDecl && ts_morph_1.Node.isImportSpecifier(firstDecl)
|
|
1135
|
-
? (sym.getAliasedSymbol() ?? sym)
|
|
1136
|
-
: sym;
|
|
1137
|
-
const decl = resolved.getDeclarations()?.[0];
|
|
1138
|
-
const declPath = decl?.getSourceFile().getFilePath();
|
|
1139
|
-
if (declPath && !declPath.includes('/node_modules/')) {
|
|
1140
|
-
calleeFile = declPath;
|
|
1141
|
-
calleeDecl = decl;
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
catch {
|
|
1147
|
-
}
|
|
1148
|
-
if (!calleeName || !calleeFile)
|
|
1149
|
-
continue;
|
|
1150
|
-
const described = calleeDecl ? this.describeIndexedNode(calleeDecl) : null;
|
|
1151
|
-
const calleeSymbol = described ? this.qualifiedName(described) : null;
|
|
1152
|
-
const fromSymbol = this.findFromSymbol(callExpr);
|
|
1153
|
-
const pos = sourceFile.compilerNode
|
|
1154
|
-
.getLineAndCharacterOfPosition(callExpr.getStart());
|
|
1155
|
-
calls.push({
|
|
1156
|
-
project: serviceName,
|
|
1157
|
-
fromFile: filePath,
|
|
1158
|
-
fromSymbol,
|
|
1159
|
-
calleeName,
|
|
1160
|
-
calleeFile,
|
|
1161
|
-
calleeSymbol,
|
|
1162
|
-
line: pos.line + 1,
|
|
1163
|
-
col: pos.character + 1,
|
|
1164
|
-
});
|
|
1165
|
-
}
|
|
1166
|
-
return calls;
|
|
1167
|
-
}
|
|
1168
249
|
}
|
|
1169
250
|
exports.AstParserService = AstParserService;
|