code-graph-context 0.1.0
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/.env.example +14 -0
- package/LICENSE +21 -0
- package/README.md +870 -0
- package/dist/constants.js +1 -0
- package/dist/core/config/fairsquare-framework-schema.js +832 -0
- package/dist/core/config/graph-v2.js +1595 -0
- package/dist/core/config/nestjs-framework-schema.js +894 -0
- package/dist/core/config/schema.js +799 -0
- package/dist/core/embeddings/embeddings.service.js +26 -0
- package/dist/core/embeddings/natural-language-to-cypher.service.js +148 -0
- package/dist/core/parsers/parser-factory.js +102 -0
- package/dist/core/parsers/typescript-parser-v2.js +590 -0
- package/dist/core/parsers/typescript-parser.js +717 -0
- package/dist/mcp/constants.js +141 -0
- package/dist/mcp/handlers/graph-generator.handler.js +143 -0
- package/dist/mcp/handlers/traversal.handler.js +304 -0
- package/dist/mcp/mcp.server.js +47 -0
- package/dist/mcp/services.js +158 -0
- package/dist/mcp/tools/hello.tool.js +13 -0
- package/dist/mcp/tools/index.js +24 -0
- package/dist/mcp/tools/natural-language-to-cypher.tool.js +59 -0
- package/dist/mcp/tools/parse-typescript-project.tool.js +101 -0
- package/dist/mcp/tools/search-codebase.tool.js +97 -0
- package/dist/mcp/tools/test-neo4j-connection.tool.js +39 -0
- package/dist/mcp/tools/traverse-from-node.tool.js +97 -0
- package/dist/mcp/utils.js +152 -0
- package/dist/parsers/cypher-result.parser.js +44 -0
- package/dist/storage/neo4j/neo4j.service.js +277 -0
- package/dist/utils/test.js +19 -0
- package/package.json +81 -0
|
@@ -0,0 +1,894 @@
|
|
|
1
|
+
/* eslint-disable prefer-arrow/prefer-arrow-functions */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
+
import { CoreNodeType, SemanticNodeType, SemanticEdgeType, } from './schema.js';
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// NESTJS HELPER FUNCTIONS
|
|
6
|
+
// ============================================================================
|
|
7
|
+
function extractMessagePattern(node) {
|
|
8
|
+
// Check for @EventPattern first
|
|
9
|
+
let decorator = node.getDecorator('EventPattern');
|
|
10
|
+
// Check for @MessagePattern
|
|
11
|
+
decorator ??= node.getDecorator('MessagePattern');
|
|
12
|
+
if (!decorator)
|
|
13
|
+
return '';
|
|
14
|
+
const args = decorator.getArguments();
|
|
15
|
+
if (args.length === 0)
|
|
16
|
+
return '';
|
|
17
|
+
// Get the raw text of the first argument
|
|
18
|
+
const rawPattern = args[0].getText();
|
|
19
|
+
return rawPattern;
|
|
20
|
+
}
|
|
21
|
+
function getPatternType(node) {
|
|
22
|
+
if (node.getDecorator('EventPattern'))
|
|
23
|
+
return 'event';
|
|
24
|
+
if (node.getDecorator('MessagePattern'))
|
|
25
|
+
return 'message';
|
|
26
|
+
return 'event'; // default
|
|
27
|
+
}
|
|
28
|
+
function extractControllerPath(node) {
|
|
29
|
+
const decorator = node.getDecorator('Controller');
|
|
30
|
+
if (!decorator)
|
|
31
|
+
return '';
|
|
32
|
+
const args = decorator.getArguments();
|
|
33
|
+
return args.length > 0 ? `/${args[0].getText().replace(/['"]/g, '')}` : '';
|
|
34
|
+
}
|
|
35
|
+
function countHttpEndpoints(node) {
|
|
36
|
+
const methods = node.getMethods();
|
|
37
|
+
const httpDecorators = ['Get', 'Post', 'Put', 'Delete', 'Patch', 'Head', 'Options'];
|
|
38
|
+
return methods.filter((method) => {
|
|
39
|
+
const decorators = method.getDecorators();
|
|
40
|
+
return decorators.some((d) => httpDecorators.includes(d.getName()));
|
|
41
|
+
}).length;
|
|
42
|
+
}
|
|
43
|
+
function hasDecorator(node, decoratorName) {
|
|
44
|
+
const decorators = node.getDecorators();
|
|
45
|
+
return decorators.some((d) => d.getName() === decoratorName);
|
|
46
|
+
}
|
|
47
|
+
function extractVersion(node) {
|
|
48
|
+
const decorator = node.getDecorator('Version');
|
|
49
|
+
if (!decorator)
|
|
50
|
+
return null;
|
|
51
|
+
const args = decorator.getArguments();
|
|
52
|
+
return args.length > 0 ? args[0].getText().replace(/['"]/g, '') : null;
|
|
53
|
+
}
|
|
54
|
+
function extractScope(node) {
|
|
55
|
+
const decorator = node.getDecorator('Injectable');
|
|
56
|
+
if (!decorator)
|
|
57
|
+
return 'DEFAULT';
|
|
58
|
+
const args = decorator.getArguments();
|
|
59
|
+
if (args.length === 0)
|
|
60
|
+
return 'DEFAULT';
|
|
61
|
+
const argText = args[0].getText();
|
|
62
|
+
if (argText.includes('REQUEST'))
|
|
63
|
+
return 'REQUEST';
|
|
64
|
+
if (argText.includes('TRANSIENT'))
|
|
65
|
+
return 'TRANSIENT';
|
|
66
|
+
return 'DEFAULT';
|
|
67
|
+
}
|
|
68
|
+
function hasAsyncMethods(node) {
|
|
69
|
+
const methods = node.getMethods();
|
|
70
|
+
return methods.some((method) => method.isAsync?.());
|
|
71
|
+
}
|
|
72
|
+
function countConstructorParameters(node) {
|
|
73
|
+
const constructors = node.getConstructors();
|
|
74
|
+
return constructors.length > 0 ? constructors[0].getParameters().length : 0;
|
|
75
|
+
}
|
|
76
|
+
function extractInjectionToken(node) {
|
|
77
|
+
const decorator = node.getDecorator('Injectable');
|
|
78
|
+
if (!decorator)
|
|
79
|
+
return null;
|
|
80
|
+
const args = decorator.getArguments();
|
|
81
|
+
if (args.length > 0 && args[0].getText().startsWith("'")) {
|
|
82
|
+
return args[0].getText().replace(/['"]/g, '');
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
function hasDynamicMethods(node) {
|
|
87
|
+
const methods = node.getMethods();
|
|
88
|
+
const dynamicMethods = ['forRoot', 'forFeature', 'forRootAsync', 'forFeatureAsync'];
|
|
89
|
+
return methods.some((method) => {
|
|
90
|
+
return method.isStatic?.() && dynamicMethods.includes(method.getName());
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
function extractModuleImports(node) {
|
|
94
|
+
return extractModuleArrayProperty(node, 'imports');
|
|
95
|
+
}
|
|
96
|
+
function extractModuleProviders(node) {
|
|
97
|
+
return extractModuleArrayProperty(node, 'providers');
|
|
98
|
+
}
|
|
99
|
+
function extractModuleControllers(node) {
|
|
100
|
+
return extractModuleArrayProperty(node, 'controllers');
|
|
101
|
+
}
|
|
102
|
+
function extractModuleExports(node) {
|
|
103
|
+
return extractModuleArrayProperty(node, 'exports');
|
|
104
|
+
}
|
|
105
|
+
function extractModuleArrayProperty(node, propertyName) {
|
|
106
|
+
const decorator = node.getDecorator('Module');
|
|
107
|
+
if (!decorator)
|
|
108
|
+
return [];
|
|
109
|
+
const args = decorator.getArguments();
|
|
110
|
+
if (args.length === 0)
|
|
111
|
+
return [];
|
|
112
|
+
const configText = args[0].getText();
|
|
113
|
+
const regex = new RegExp(`${propertyName}\\s*:\\s*\\[([^\\]]+)\\]`);
|
|
114
|
+
const match = configText.match(regex);
|
|
115
|
+
if (!match)
|
|
116
|
+
return [];
|
|
117
|
+
return match[1]
|
|
118
|
+
.split(',')
|
|
119
|
+
.map((item) => item.trim().replace(/['"]/g, ''))
|
|
120
|
+
.filter((item) => item.length > 0);
|
|
121
|
+
}
|
|
122
|
+
function extractHttpMethod(node) {
|
|
123
|
+
const decorators = node.getDecorators();
|
|
124
|
+
const httpDecorators = ['Get', 'Post', 'Put', 'Delete', 'Patch', 'Head', 'Options'];
|
|
125
|
+
const httpDecorator = decorators.find((d) => httpDecorators.includes(d.getName()));
|
|
126
|
+
return httpDecorator ? httpDecorator.getName().toUpperCase() : '';
|
|
127
|
+
}
|
|
128
|
+
function extractRoutePath(node) {
|
|
129
|
+
const decorators = node.getDecorators();
|
|
130
|
+
const httpDecorators = ['Get', 'Post', 'Put', 'Delete', 'Patch', 'Head', 'Options'];
|
|
131
|
+
const httpDecorator = decorators.find((d) => httpDecorators.includes(d.getName()));
|
|
132
|
+
if (!httpDecorator)
|
|
133
|
+
return '';
|
|
134
|
+
const args = httpDecorator.getArguments();
|
|
135
|
+
return args.length > 0 ? args[0].getText().replace(/['"]/g, '') : '';
|
|
136
|
+
}
|
|
137
|
+
function computeFullPath(node) {
|
|
138
|
+
const methodPath = extractRoutePath(node);
|
|
139
|
+
// Get the parent controller's base path
|
|
140
|
+
const parentClass = node.getParent();
|
|
141
|
+
const controllerPath = extractControllerPath(parentClass);
|
|
142
|
+
// Combine paths properly
|
|
143
|
+
const fullPath = `${controllerPath}/${methodPath}`.replace(/\/+/g, '/').replace(/\/$/, '') || '/';
|
|
144
|
+
return fullPath;
|
|
145
|
+
}
|
|
146
|
+
function extractStatusCode(node) {
|
|
147
|
+
const decorator = node.getDecorator('HttpCode');
|
|
148
|
+
if (!decorator)
|
|
149
|
+
return null;
|
|
150
|
+
const args = decorator.getArguments();
|
|
151
|
+
if (args.length > 0) {
|
|
152
|
+
const status = parseInt(args[0].getText());
|
|
153
|
+
return isNaN(status) ? null : status;
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
function hasAuthDecorators(node) {
|
|
158
|
+
const decorators = node.getDecorators();
|
|
159
|
+
const authDecorators = ['UseGuards', 'Auth', 'Roles', 'Public'];
|
|
160
|
+
return decorators.some((d) => authDecorators.includes(d.getName()));
|
|
161
|
+
}
|
|
162
|
+
function hasValidationDecorators(node) {
|
|
163
|
+
const decorators = node.getDecorators();
|
|
164
|
+
const validationDecorators = ['UsePipes', 'ValidationPipe'];
|
|
165
|
+
return decorators.some((d) => validationDecorators.includes(d.getName()));
|
|
166
|
+
}
|
|
167
|
+
function extractGuardNames(node) {
|
|
168
|
+
return extractDecoratorArguments(node, 'UseGuards');
|
|
169
|
+
}
|
|
170
|
+
function extractPipeNames(node) {
|
|
171
|
+
return extractDecoratorArguments(node, 'UsePipes');
|
|
172
|
+
}
|
|
173
|
+
function extractInterceptorNames(node) {
|
|
174
|
+
return extractDecoratorArguments(node, 'UseInterceptors');
|
|
175
|
+
}
|
|
176
|
+
function extractDecoratorArguments(node, decoratorName) {
|
|
177
|
+
const decorator = node.getDecorator(decoratorName);
|
|
178
|
+
if (!decorator)
|
|
179
|
+
return [];
|
|
180
|
+
const args = decorator.getArguments();
|
|
181
|
+
return args.map((arg) => arg.getText().replace(/[(),]/g, '').trim()).filter((name) => name.length > 0);
|
|
182
|
+
}
|
|
183
|
+
function extractTableName(node) {
|
|
184
|
+
const decorator = node.getDecorator('Entity');
|
|
185
|
+
if (!decorator)
|
|
186
|
+
return null;
|
|
187
|
+
const args = decorator.getArguments();
|
|
188
|
+
return args.length > 0 ? args[0].getText().replace(/['"]/g, '') : null;
|
|
189
|
+
}
|
|
190
|
+
function countColumns(node) {
|
|
191
|
+
const properties = node.getProperties();
|
|
192
|
+
return properties.filter((prop) => {
|
|
193
|
+
const decorators = prop.getDecorators();
|
|
194
|
+
return decorators.some((d) => ['Column', 'PrimaryGeneratedColumn'].includes(d.getName()));
|
|
195
|
+
}).length;
|
|
196
|
+
}
|
|
197
|
+
function hasRelationDecorators(node) {
|
|
198
|
+
const properties = node.getProperties();
|
|
199
|
+
const relationDecorators = ['OneToOne', 'OneToMany', 'ManyToOne', 'ManyToMany'];
|
|
200
|
+
return properties.some((prop) => {
|
|
201
|
+
const decorators = prop.getDecorators();
|
|
202
|
+
return decorators.some((d) => relationDecorators.includes(d.getName()));
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
function extractValidationDecorators(node) {
|
|
206
|
+
const properties = node.getProperties();
|
|
207
|
+
const validationDecorators = [];
|
|
208
|
+
const commonValidators = [
|
|
209
|
+
'IsString',
|
|
210
|
+
'IsNumber',
|
|
211
|
+
'IsEmail',
|
|
212
|
+
'IsOptional',
|
|
213
|
+
'IsNotEmpty',
|
|
214
|
+
'MinLength',
|
|
215
|
+
'MaxLength',
|
|
216
|
+
'IsArray',
|
|
217
|
+
'IsBoolean',
|
|
218
|
+
'IsDate',
|
|
219
|
+
'IsEnum',
|
|
220
|
+
'IsUUID',
|
|
221
|
+
'IsUrl',
|
|
222
|
+
'Min',
|
|
223
|
+
'Max',
|
|
224
|
+
'Matches',
|
|
225
|
+
'IsIn',
|
|
226
|
+
'IsNotIn',
|
|
227
|
+
'IsDefined',
|
|
228
|
+
'ValidateNested',
|
|
229
|
+
];
|
|
230
|
+
properties.forEach((prop) => {
|
|
231
|
+
const decorators = prop.getDecorators();
|
|
232
|
+
decorators.forEach((decorator) => {
|
|
233
|
+
const name = decorator.getName();
|
|
234
|
+
if (commonValidators.includes(name)) {
|
|
235
|
+
validationDecorators.push(name);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
return [...new Set(validationDecorators)];
|
|
240
|
+
}
|
|
241
|
+
function extendsPartialType(node) {
|
|
242
|
+
const baseClass = node.getBaseClass();
|
|
243
|
+
return baseClass ? baseClass.getText().includes('PartialType') : false;
|
|
244
|
+
}
|
|
245
|
+
function extractBaseClass(node) {
|
|
246
|
+
const baseClass = node.getBaseClass();
|
|
247
|
+
return baseClass ? baseClass.getText() : null;
|
|
248
|
+
}
|
|
249
|
+
function detectDependencyInjection(sourceNode, targetNode) {
|
|
250
|
+
if (sourceNode.properties?.coreType !== CoreNodeType.CLASS_DECLARATION)
|
|
251
|
+
return false;
|
|
252
|
+
if (targetNode.properties?.coreType !== CoreNodeType.CLASS_DECLARATION)
|
|
253
|
+
return false;
|
|
254
|
+
const constructors = sourceNode.sourceNode?.getConstructors();
|
|
255
|
+
if (!constructors || constructors.length === 0)
|
|
256
|
+
return false;
|
|
257
|
+
const constructor = constructors[0];
|
|
258
|
+
const parameters = constructor.getParameters();
|
|
259
|
+
const targetName = targetNode.properties?.name;
|
|
260
|
+
return parameters.some((param) => {
|
|
261
|
+
const paramType = param.getTypeNode()?.getText();
|
|
262
|
+
if (paramType === targetName)
|
|
263
|
+
return true;
|
|
264
|
+
const decorators = param.getDecorators();
|
|
265
|
+
return decorators.some((decorator) => {
|
|
266
|
+
if (decorator.getName() === 'Inject') {
|
|
267
|
+
const args = decorator.getArguments();
|
|
268
|
+
if (args.length > 0) {
|
|
269
|
+
const token = args[0].getText().replace(/['"]/g, '');
|
|
270
|
+
return token === targetName;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return false;
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
function extractInjectionTokenFromRelation(sourceNode, targetNode) {
|
|
278
|
+
const constructors = sourceNode.sourceNode?.getConstructors();
|
|
279
|
+
if (!constructors || constructors.length === 0)
|
|
280
|
+
return null;
|
|
281
|
+
const constructor = constructors[0];
|
|
282
|
+
const parameters = constructor.getParameters();
|
|
283
|
+
for (const param of parameters) {
|
|
284
|
+
const decorators = param.getDecorators();
|
|
285
|
+
for (const decorator of decorators) {
|
|
286
|
+
if (decorator.getName() === 'Inject') {
|
|
287
|
+
const args = decorator.getArguments();
|
|
288
|
+
if (args.length > 0) {
|
|
289
|
+
return args[0].getText().replace(/['"]/g, '');
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
function findParameterIndex(sourceNode, targetNode) {
|
|
297
|
+
const constructors = sourceNode.sourceNode?.getConstructors();
|
|
298
|
+
if (!constructors || constructors.length === 0)
|
|
299
|
+
return 0;
|
|
300
|
+
const constructor = constructors[0];
|
|
301
|
+
const parameters = constructor.getParameters();
|
|
302
|
+
const targetName = targetNode.properties?.name;
|
|
303
|
+
return parameters.findIndex((param) => {
|
|
304
|
+
const paramType = param.getTypeNode()?.getText();
|
|
305
|
+
return paramType === targetName;
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
function computeFullPathFromNodes(sourceNode, targetNode) {
|
|
309
|
+
const basePath = sourceNode.properties?.context?.basePath ?? '';
|
|
310
|
+
const methodPath = targetNode.properties?.context?.path ?? '';
|
|
311
|
+
// Properly combine paths
|
|
312
|
+
const fullPath = `${basePath}/${methodPath}`.replace(/\/+/g, '/').replace(/\/$/, '') || '/';
|
|
313
|
+
return fullPath;
|
|
314
|
+
}
|
|
315
|
+
function extractRelativePath(node) {
|
|
316
|
+
const filePath = node.getFilePath();
|
|
317
|
+
const parts = filePath.split('/');
|
|
318
|
+
return parts.slice(-3).join('/');
|
|
319
|
+
}
|
|
320
|
+
function countDeclarations({ node }) {
|
|
321
|
+
return node.getClasses().length + node.getInterfaces().length + node.getFunctions().length + node.getEnums().length;
|
|
322
|
+
}
|
|
323
|
+
function determineImportKind(node) {
|
|
324
|
+
if (node.getDefaultImport())
|
|
325
|
+
return 'default';
|
|
326
|
+
if (node.getNamespaceImport())
|
|
327
|
+
return 'namespace';
|
|
328
|
+
if (node.getNamedImports().length > 0)
|
|
329
|
+
return 'named';
|
|
330
|
+
return 'side-effect';
|
|
331
|
+
}
|
|
332
|
+
function determineDecoratorTarget(node) {
|
|
333
|
+
const parent = node.getParent();
|
|
334
|
+
if (!parent)
|
|
335
|
+
return 'unknown';
|
|
336
|
+
const kind = parent.getKind();
|
|
337
|
+
if (kind === 262)
|
|
338
|
+
return 'class'; // ClassDeclaration
|
|
339
|
+
if (kind === 172)
|
|
340
|
+
return 'method'; // MethodDeclaration
|
|
341
|
+
if (kind === 171)
|
|
342
|
+
return 'property'; // PropertyDeclaration
|
|
343
|
+
if (kind === 169)
|
|
344
|
+
return 'parameter'; // Parameter
|
|
345
|
+
return 'unknown';
|
|
346
|
+
}
|
|
347
|
+
// ============================================================================
|
|
348
|
+
// NESTJS FRAMEWORK SCHEMA
|
|
349
|
+
// ============================================================================
|
|
350
|
+
export const NESTJS_FRAMEWORK_SCHEMA = {
|
|
351
|
+
name: 'NestJS Framework Schema',
|
|
352
|
+
version: '2.0.0',
|
|
353
|
+
description: 'NestJS-specific enhancements with context-based properties',
|
|
354
|
+
enhances: [CoreNodeType.CLASS_DECLARATION, CoreNodeType.METHOD_DECLARATION],
|
|
355
|
+
enhancements: {
|
|
356
|
+
NestController: {
|
|
357
|
+
name: 'NestController',
|
|
358
|
+
targetCoreType: CoreNodeType.CLASS_DECLARATION,
|
|
359
|
+
semanticType: SemanticNodeType.NEST_CONTROLLER,
|
|
360
|
+
detectionPatterns: [
|
|
361
|
+
{
|
|
362
|
+
type: 'decorator',
|
|
363
|
+
pattern: 'Controller',
|
|
364
|
+
confidence: 0.95,
|
|
365
|
+
priority: 10,
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
type: 'filename',
|
|
369
|
+
pattern: /\.controller\.ts$/,
|
|
370
|
+
confidence: 0.7,
|
|
371
|
+
priority: 5,
|
|
372
|
+
},
|
|
373
|
+
],
|
|
374
|
+
contextExtractors: [
|
|
375
|
+
{
|
|
376
|
+
nodeType: CoreNodeType.CLASS_DECLARATION,
|
|
377
|
+
semanticType: SemanticNodeType.NEST_CONTROLLER,
|
|
378
|
+
extractor: (parsedNode) => {
|
|
379
|
+
const node = parsedNode.sourceNode;
|
|
380
|
+
if (!node)
|
|
381
|
+
return {};
|
|
382
|
+
return {
|
|
383
|
+
basePath: extractControllerPath(node),
|
|
384
|
+
endpointCount: countHttpEndpoints(node),
|
|
385
|
+
hasGlobalGuards: hasDecorator(node, 'UseGuards'),
|
|
386
|
+
hasGlobalPipes: hasDecorator(node, 'UsePipes'),
|
|
387
|
+
hasGlobalInterceptors: hasDecorator(node, 'UseInterceptors'),
|
|
388
|
+
version: extractVersion(node),
|
|
389
|
+
};
|
|
390
|
+
},
|
|
391
|
+
priority: 1,
|
|
392
|
+
},
|
|
393
|
+
],
|
|
394
|
+
additionalRelationships: [SemanticEdgeType.EXPOSES, SemanticEdgeType.INJECTS],
|
|
395
|
+
neo4j: {
|
|
396
|
+
additionalLabels: ['Controller', 'NestJS'],
|
|
397
|
+
primaryLabel: 'Controller',
|
|
398
|
+
},
|
|
399
|
+
priority: 90,
|
|
400
|
+
},
|
|
401
|
+
NestService: {
|
|
402
|
+
name: 'NestService',
|
|
403
|
+
targetCoreType: CoreNodeType.CLASS_DECLARATION,
|
|
404
|
+
semanticType: SemanticNodeType.NEST_SERVICE,
|
|
405
|
+
detectionPatterns: [
|
|
406
|
+
{
|
|
407
|
+
type: 'filename',
|
|
408
|
+
pattern: /\.service\.ts$/,
|
|
409
|
+
confidence: 0.9,
|
|
410
|
+
priority: 9,
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
type: 'function',
|
|
414
|
+
pattern: (node) => node.getName()?.endsWith('Service'),
|
|
415
|
+
confidence: 0.7,
|
|
416
|
+
priority: 7,
|
|
417
|
+
},
|
|
418
|
+
],
|
|
419
|
+
contextExtractors: [
|
|
420
|
+
{
|
|
421
|
+
nodeType: CoreNodeType.CLASS_DECLARATION,
|
|
422
|
+
semanticType: SemanticNodeType.NEST_SERVICE,
|
|
423
|
+
extractor: (parsedNode) => {
|
|
424
|
+
const node = parsedNode.sourceNode;
|
|
425
|
+
if (!node)
|
|
426
|
+
return {};
|
|
427
|
+
return {
|
|
428
|
+
scope: extractScope(node),
|
|
429
|
+
isAsync: hasAsyncMethods(node),
|
|
430
|
+
dependencyCount: countConstructorParameters(node),
|
|
431
|
+
injectionToken: extractInjectionToken(node),
|
|
432
|
+
};
|
|
433
|
+
},
|
|
434
|
+
priority: 1,
|
|
435
|
+
},
|
|
436
|
+
],
|
|
437
|
+
additionalRelationships: [SemanticEdgeType.PROVIDED_BY, SemanticEdgeType.MANAGES],
|
|
438
|
+
neo4j: {
|
|
439
|
+
additionalLabels: ['Service', 'NestJS'],
|
|
440
|
+
primaryLabel: 'Service',
|
|
441
|
+
},
|
|
442
|
+
priority: 80,
|
|
443
|
+
},
|
|
444
|
+
NestModule: {
|
|
445
|
+
name: 'NestModule',
|
|
446
|
+
targetCoreType: CoreNodeType.CLASS_DECLARATION,
|
|
447
|
+
semanticType: SemanticNodeType.NEST_MODULE,
|
|
448
|
+
detectionPatterns: [
|
|
449
|
+
{
|
|
450
|
+
type: 'decorator',
|
|
451
|
+
pattern: 'Module',
|
|
452
|
+
confidence: 0.95,
|
|
453
|
+
priority: 10,
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
type: 'filename',
|
|
457
|
+
pattern: /\.module\.ts$/,
|
|
458
|
+
confidence: 0.8,
|
|
459
|
+
priority: 7,
|
|
460
|
+
},
|
|
461
|
+
],
|
|
462
|
+
contextExtractors: [
|
|
463
|
+
{
|
|
464
|
+
nodeType: CoreNodeType.CLASS_DECLARATION,
|
|
465
|
+
semanticType: SemanticNodeType.NEST_MODULE,
|
|
466
|
+
extractor: (parsedNode) => {
|
|
467
|
+
const node = parsedNode.sourceNode;
|
|
468
|
+
if (!node)
|
|
469
|
+
return {};
|
|
470
|
+
return {
|
|
471
|
+
isGlobal: hasDecorator(node, 'Global'),
|
|
472
|
+
isDynamic: hasDynamicMethods(node),
|
|
473
|
+
imports: extractModuleImports(node),
|
|
474
|
+
providers: extractModuleProviders(node),
|
|
475
|
+
controllers: extractModuleControllers(node),
|
|
476
|
+
exports: extractModuleExports(node),
|
|
477
|
+
};
|
|
478
|
+
},
|
|
479
|
+
priority: 1,
|
|
480
|
+
},
|
|
481
|
+
],
|
|
482
|
+
additionalRelationships: [SemanticEdgeType.MODULE_IMPORTS, SemanticEdgeType.MODULE_PROVIDES],
|
|
483
|
+
neo4j: {
|
|
484
|
+
additionalLabels: ['Module', 'NestJS'],
|
|
485
|
+
primaryLabel: 'Module',
|
|
486
|
+
},
|
|
487
|
+
priority: 95,
|
|
488
|
+
},
|
|
489
|
+
MessageHandler: {
|
|
490
|
+
name: 'MessageHandler',
|
|
491
|
+
targetCoreType: CoreNodeType.METHOD_DECLARATION,
|
|
492
|
+
semanticType: SemanticNodeType.MESSAGE_HANDLER,
|
|
493
|
+
detectionPatterns: [
|
|
494
|
+
{
|
|
495
|
+
type: 'function',
|
|
496
|
+
pattern: (node) => {
|
|
497
|
+
const decorators = node.getDecorators?.() ?? [];
|
|
498
|
+
const messageDecorators = ['MessagePattern', 'EventPattern'];
|
|
499
|
+
return decorators.some((d) => messageDecorators.includes(d.getName()));
|
|
500
|
+
},
|
|
501
|
+
confidence: 0.98,
|
|
502
|
+
priority: 15,
|
|
503
|
+
},
|
|
504
|
+
],
|
|
505
|
+
contextExtractors: [
|
|
506
|
+
{
|
|
507
|
+
nodeType: CoreNodeType.METHOD_DECLARATION,
|
|
508
|
+
semanticType: SemanticNodeType.MESSAGE_HANDLER,
|
|
509
|
+
extractor: (parsedNode) => {
|
|
510
|
+
const node = parsedNode.sourceNode;
|
|
511
|
+
if (!node)
|
|
512
|
+
return {};
|
|
513
|
+
return {
|
|
514
|
+
messageQueueName: extractMessagePattern(node),
|
|
515
|
+
isAsync: node.isAsync(),
|
|
516
|
+
returnType: node.getReturnTypeNode()?.getText() ?? 'void',
|
|
517
|
+
pattern: getPatternType(node),
|
|
518
|
+
hasAuth: hasAuthDecorators(node),
|
|
519
|
+
hasValidation: hasValidationDecorators(node),
|
|
520
|
+
guardNames: extractGuardNames(node),
|
|
521
|
+
pipeNames: extractPipeNames(node),
|
|
522
|
+
interceptorNames: extractInterceptorNames(node),
|
|
523
|
+
endpointType: 'RPC',
|
|
524
|
+
};
|
|
525
|
+
},
|
|
526
|
+
priority: 1,
|
|
527
|
+
},
|
|
528
|
+
],
|
|
529
|
+
additionalRelationships: [
|
|
530
|
+
SemanticEdgeType.CONSUMES_MESSAGE,
|
|
531
|
+
SemanticEdgeType.RESPONDS_WITH,
|
|
532
|
+
SemanticEdgeType.GUARDED_BY,
|
|
533
|
+
],
|
|
534
|
+
neo4j: {
|
|
535
|
+
additionalLabels: ['MessageHandler', 'NestJS', 'Microservice'],
|
|
536
|
+
primaryLabel: 'MessageHandler',
|
|
537
|
+
},
|
|
538
|
+
priority: 88,
|
|
539
|
+
},
|
|
540
|
+
HttpEndpoint: {
|
|
541
|
+
name: 'HttpEndpoint',
|
|
542
|
+
targetCoreType: CoreNodeType.METHOD_DECLARATION,
|
|
543
|
+
semanticType: SemanticNodeType.HTTP_ENDPOINT,
|
|
544
|
+
detectionPatterns: [
|
|
545
|
+
{
|
|
546
|
+
type: 'function',
|
|
547
|
+
pattern: (node) => {
|
|
548
|
+
const decorators = node.getDecorators?.() ?? [];
|
|
549
|
+
const httpDecorators = ['Get', 'Post', 'Put', 'Delete', 'Patch', 'Head', 'Options'];
|
|
550
|
+
return decorators.some((d) => httpDecorators.includes(d.getName()));
|
|
551
|
+
},
|
|
552
|
+
confidence: 0.98,
|
|
553
|
+
priority: 15,
|
|
554
|
+
},
|
|
555
|
+
],
|
|
556
|
+
contextExtractors: [
|
|
557
|
+
{
|
|
558
|
+
nodeType: CoreNodeType.METHOD_DECLARATION,
|
|
559
|
+
semanticType: SemanticNodeType.HTTP_ENDPOINT,
|
|
560
|
+
extractor: (parsedNode) => {
|
|
561
|
+
const node = parsedNode.sourceNode;
|
|
562
|
+
if (!node)
|
|
563
|
+
return {};
|
|
564
|
+
return {
|
|
565
|
+
httpMethod: extractHttpMethod(node),
|
|
566
|
+
path: extractRoutePath(node),
|
|
567
|
+
fullPath: computeFullPath(node),
|
|
568
|
+
statusCode: extractStatusCode(node),
|
|
569
|
+
hasAuth: hasAuthDecorators(node),
|
|
570
|
+
hasValidation: hasValidationDecorators(node),
|
|
571
|
+
guardNames: extractGuardNames(node),
|
|
572
|
+
pipeNames: extractPipeNames(node),
|
|
573
|
+
interceptorNames: extractInterceptorNames(node),
|
|
574
|
+
};
|
|
575
|
+
},
|
|
576
|
+
priority: 1,
|
|
577
|
+
},
|
|
578
|
+
],
|
|
579
|
+
additionalRelationships: [SemanticEdgeType.ACCEPTS, SemanticEdgeType.RESPONDS_WITH, SemanticEdgeType.GUARDED_BY],
|
|
580
|
+
neo4j: {
|
|
581
|
+
additionalLabels: ['HttpEndpoint', 'NestJS'],
|
|
582
|
+
primaryLabel: 'HttpEndpoint',
|
|
583
|
+
},
|
|
584
|
+
priority: 85,
|
|
585
|
+
},
|
|
586
|
+
EntityClass: {
|
|
587
|
+
name: 'EntityClass',
|
|
588
|
+
targetCoreType: CoreNodeType.CLASS_DECLARATION,
|
|
589
|
+
semanticType: SemanticNodeType.ENTITY_CLASS,
|
|
590
|
+
detectionPatterns: [
|
|
591
|
+
{
|
|
592
|
+
type: 'decorator',
|
|
593
|
+
pattern: 'Entity',
|
|
594
|
+
confidence: 0.95,
|
|
595
|
+
priority: 10,
|
|
596
|
+
},
|
|
597
|
+
{
|
|
598
|
+
type: 'filename',
|
|
599
|
+
pattern: /\.entity\.ts$/,
|
|
600
|
+
confidence: 0.8,
|
|
601
|
+
priority: 7,
|
|
602
|
+
},
|
|
603
|
+
],
|
|
604
|
+
contextExtractors: [
|
|
605
|
+
{
|
|
606
|
+
nodeType: CoreNodeType.CLASS_DECLARATION,
|
|
607
|
+
semanticType: SemanticNodeType.ENTITY_CLASS,
|
|
608
|
+
extractor: (parsedNode) => {
|
|
609
|
+
const node = parsedNode.sourceNode;
|
|
610
|
+
if (!node)
|
|
611
|
+
return {};
|
|
612
|
+
return {
|
|
613
|
+
tableName: extractTableName(node),
|
|
614
|
+
columnCount: countColumns(node),
|
|
615
|
+
hasRelations: hasRelationDecorators(node),
|
|
616
|
+
};
|
|
617
|
+
},
|
|
618
|
+
priority: 1,
|
|
619
|
+
},
|
|
620
|
+
],
|
|
621
|
+
additionalRelationships: [],
|
|
622
|
+
neo4j: {
|
|
623
|
+
additionalLabels: ['Entity', 'NestJS'],
|
|
624
|
+
primaryLabel: 'Entity',
|
|
625
|
+
},
|
|
626
|
+
priority: 80,
|
|
627
|
+
},
|
|
628
|
+
DTOClass: {
|
|
629
|
+
name: 'DTOClass',
|
|
630
|
+
targetCoreType: CoreNodeType.CLASS_DECLARATION,
|
|
631
|
+
semanticType: SemanticNodeType.DTO_CLASS,
|
|
632
|
+
detectionPatterns: [
|
|
633
|
+
{
|
|
634
|
+
type: 'filename',
|
|
635
|
+
pattern: /\.dto\.ts$/,
|
|
636
|
+
confidence: 0.9,
|
|
637
|
+
priority: 8,
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
type: 'classname',
|
|
641
|
+
pattern: /.*Dto$/,
|
|
642
|
+
confidence: 0.7,
|
|
643
|
+
priority: 6,
|
|
644
|
+
},
|
|
645
|
+
],
|
|
646
|
+
contextExtractors: [
|
|
647
|
+
{
|
|
648
|
+
nodeType: CoreNodeType.CLASS_DECLARATION,
|
|
649
|
+
semanticType: SemanticNodeType.DTO_CLASS,
|
|
650
|
+
extractor: (parsedNode) => {
|
|
651
|
+
const node = parsedNode.sourceNode;
|
|
652
|
+
if (!node)
|
|
653
|
+
return {};
|
|
654
|
+
return {
|
|
655
|
+
validationDecorators: extractValidationDecorators(node),
|
|
656
|
+
isRequestDto: node.getName()?.toLowerCase().includes('request') ?? false,
|
|
657
|
+
isResponseDto: node.getName()?.toLowerCase().includes('response') ?? false,
|
|
658
|
+
isPartialDto: extendsPartialType(node),
|
|
659
|
+
baseClass: extractBaseClass(node),
|
|
660
|
+
};
|
|
661
|
+
},
|
|
662
|
+
priority: 1,
|
|
663
|
+
},
|
|
664
|
+
],
|
|
665
|
+
additionalRelationships: [SemanticEdgeType.VALIDATES],
|
|
666
|
+
neo4j: {
|
|
667
|
+
additionalLabels: ['DTO', 'NestJS'],
|
|
668
|
+
primaryLabel: 'DTO',
|
|
669
|
+
},
|
|
670
|
+
priority: 70,
|
|
671
|
+
},
|
|
672
|
+
},
|
|
673
|
+
edgeEnhancements: {
|
|
674
|
+
DependencyInjection: {
|
|
675
|
+
name: 'DependencyInjection',
|
|
676
|
+
semanticType: SemanticEdgeType.INJECTS,
|
|
677
|
+
relationshipWeight: 0.95, // Critical - core NestJS DI is primary architecture
|
|
678
|
+
detectionPattern: (parsedSourceNode, parsedTargetNode) => {
|
|
679
|
+
return detectDependencyInjection(parsedSourceNode, parsedTargetNode);
|
|
680
|
+
},
|
|
681
|
+
contextExtractor: (parsedSourceNode, parsedTargetNode) => ({
|
|
682
|
+
injectionType: 'constructor',
|
|
683
|
+
injectionToken: extractInjectionTokenFromRelation(parsedSourceNode, parsedTargetNode),
|
|
684
|
+
parameterIndex: findParameterIndex(parsedSourceNode, parsedTargetNode),
|
|
685
|
+
}),
|
|
686
|
+
neo4j: {
|
|
687
|
+
relationshipType: 'INJECTS',
|
|
688
|
+
direction: 'OUTGOING',
|
|
689
|
+
},
|
|
690
|
+
},
|
|
691
|
+
MessageHandlerExposure: {
|
|
692
|
+
name: 'MessageHandlerExposure',
|
|
693
|
+
semanticType: SemanticEdgeType.EXPOSES,
|
|
694
|
+
relationshipWeight: 0.9, // Critical - API surface exposure
|
|
695
|
+
detectionPattern: (parsedSourceNode, parsedTargetNode) => {
|
|
696
|
+
if (parsedSourceNode.properties?.semanticType !== SemanticNodeType.NEST_CONTROLLER ||
|
|
697
|
+
parsedTargetNode.properties?.semanticType !== SemanticNodeType.MESSAGE_HANDLER) {
|
|
698
|
+
return false;
|
|
699
|
+
}
|
|
700
|
+
if (parsedSourceNode.properties?.filePath !== parsedTargetNode.properties?.filePath) {
|
|
701
|
+
return false;
|
|
702
|
+
}
|
|
703
|
+
// Access AST nodes to check parent relationship
|
|
704
|
+
const sourceNode = parsedSourceNode.sourceNode;
|
|
705
|
+
const targetNode = parsedTargetNode.sourceNode;
|
|
706
|
+
if (sourceNode && targetNode) {
|
|
707
|
+
const methodParent = targetNode.getParent();
|
|
708
|
+
if (methodParent === sourceNode) {
|
|
709
|
+
return true;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return false;
|
|
713
|
+
},
|
|
714
|
+
contextExtractor: (parsedSourceNode, parsedTargetNode) => ({
|
|
715
|
+
endpointType: 'RPC',
|
|
716
|
+
}),
|
|
717
|
+
neo4j: {
|
|
718
|
+
relationshipType: 'EXPOSES',
|
|
719
|
+
direction: 'OUTGOING',
|
|
720
|
+
},
|
|
721
|
+
},
|
|
722
|
+
HttpEndpointExposure: {
|
|
723
|
+
name: 'HttpEndpointExposure',
|
|
724
|
+
semanticType: SemanticEdgeType.EXPOSES,
|
|
725
|
+
relationshipWeight: 0.9, // Critical - HTTP API surface
|
|
726
|
+
detectionPattern: (parsedSourceNode, parsedTargetNode) => {
|
|
727
|
+
// Check if source is controller and target is HTTP endpoint
|
|
728
|
+
if (parsedSourceNode.properties?.semanticType !== SemanticNodeType.NEST_CONTROLLER ||
|
|
729
|
+
parsedTargetNode.properties?.semanticType !== SemanticNodeType.HTTP_ENDPOINT) {
|
|
730
|
+
return false;
|
|
731
|
+
}
|
|
732
|
+
if (parsedSourceNode.properties?.filePath !== parsedTargetNode.properties?.filePath) {
|
|
733
|
+
return false;
|
|
734
|
+
}
|
|
735
|
+
// Access AST nodes to check parent relationship
|
|
736
|
+
const sourceNode = parsedSourceNode.sourceNode;
|
|
737
|
+
const targetNode = parsedTargetNode.sourceNode;
|
|
738
|
+
if (sourceNode && targetNode) {
|
|
739
|
+
const methodParent = targetNode.getParent();
|
|
740
|
+
if (methodParent === sourceNode) {
|
|
741
|
+
return true;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
return false;
|
|
745
|
+
},
|
|
746
|
+
contextExtractor: (parsedSourceNode, parsedTargetNode) => ({
|
|
747
|
+
httpMethod: parsedTargetNode.properties?.context?.httpMethod ?? '',
|
|
748
|
+
fullPath: computeFullPathFromNodes(parsedSourceNode, parsedTargetNode),
|
|
749
|
+
statusCode: parsedTargetNode.properties?.context?.statusCode ?? 200,
|
|
750
|
+
}),
|
|
751
|
+
neo4j: {
|
|
752
|
+
relationshipType: 'EXPOSES',
|
|
753
|
+
direction: 'OUTGOING',
|
|
754
|
+
},
|
|
755
|
+
},
|
|
756
|
+
},
|
|
757
|
+
contextExtractors: [
|
|
758
|
+
{
|
|
759
|
+
nodeType: CoreNodeType.SOURCE_FILE,
|
|
760
|
+
extractor: (parsedNode) => {
|
|
761
|
+
const node = parsedNode.sourceNode;
|
|
762
|
+
if (!node)
|
|
763
|
+
return {};
|
|
764
|
+
return {
|
|
765
|
+
extension: node.getFilePath().substring(node.getFilePath().lastIndexOf('.')),
|
|
766
|
+
relativePath: extractRelativePath(node),
|
|
767
|
+
isTestFile: /\.(test|spec)\./.test(node.getFilePath()),
|
|
768
|
+
isDeclarationFile: node.getFilePath().endsWith('.d.ts'),
|
|
769
|
+
moduleKind: 'ES6',
|
|
770
|
+
importCount: node.getImportDeclarations().length,
|
|
771
|
+
exportCount: node.getExportDeclarations().length,
|
|
772
|
+
declarationCount: countDeclarations({ node }),
|
|
773
|
+
};
|
|
774
|
+
},
|
|
775
|
+
priority: 1,
|
|
776
|
+
},
|
|
777
|
+
{
|
|
778
|
+
nodeType: CoreNodeType.CLASS_DECLARATION,
|
|
779
|
+
extractor: (parsedNode) => {
|
|
780
|
+
const node = parsedNode.sourceNode;
|
|
781
|
+
if (!node)
|
|
782
|
+
return {};
|
|
783
|
+
return {
|
|
784
|
+
isAbstract: node.getAbstractKeyword() != null,
|
|
785
|
+
isDefaultExport: node.isDefaultExport(),
|
|
786
|
+
extendsClause: node.getExtends()?.getText(),
|
|
787
|
+
implementsClauses: node.getImplements().map((i) => i.getText()),
|
|
788
|
+
decoratorNames: node.getDecorators().map((d) => d.getName()),
|
|
789
|
+
methodCount: node.getMethods().length,
|
|
790
|
+
propertyCount: node.getProperties().length,
|
|
791
|
+
constructorParameterCount: countConstructorParameters(node),
|
|
792
|
+
};
|
|
793
|
+
},
|
|
794
|
+
priority: 1,
|
|
795
|
+
},
|
|
796
|
+
{
|
|
797
|
+
nodeType: CoreNodeType.METHOD_DECLARATION,
|
|
798
|
+
extractor: (parsedNode) => {
|
|
799
|
+
const node = parsedNode.sourceNode;
|
|
800
|
+
if (!node)
|
|
801
|
+
return {};
|
|
802
|
+
return {
|
|
803
|
+
isStatic: node.isStatic(),
|
|
804
|
+
isAsync: node.isAsync(),
|
|
805
|
+
isAbstract: node.isAbstract(),
|
|
806
|
+
returnType: node.getReturnTypeNode()?.getText() ?? 'void',
|
|
807
|
+
parameterCount: node.getParameters().length,
|
|
808
|
+
decoratorNames: node.getDecorators().map((d) => d.getName()),
|
|
809
|
+
isGetter: node.getKind() === 177,
|
|
810
|
+
isSetter: node.getKind() === 178,
|
|
811
|
+
overloadCount: 1, // Simplified
|
|
812
|
+
};
|
|
813
|
+
},
|
|
814
|
+
priority: 1,
|
|
815
|
+
},
|
|
816
|
+
{
|
|
817
|
+
nodeType: CoreNodeType.PROPERTY_DECLARATION,
|
|
818
|
+
extractor: (parsedNode) => {
|
|
819
|
+
const node = parsedNode.sourceNode;
|
|
820
|
+
if (!node)
|
|
821
|
+
return {};
|
|
822
|
+
return {
|
|
823
|
+
isStatic: node.isStatic(),
|
|
824
|
+
isReadonly: node.isReadonly(),
|
|
825
|
+
type: node.getTypeNode()?.getText() ?? 'any',
|
|
826
|
+
hasInitializer: node.hasInitializer(),
|
|
827
|
+
decoratorNames: node.getDecorators().map((d) => d.getName()),
|
|
828
|
+
isOptional: node.hasQuestionToken(),
|
|
829
|
+
};
|
|
830
|
+
},
|
|
831
|
+
priority: 1,
|
|
832
|
+
},
|
|
833
|
+
{
|
|
834
|
+
nodeType: CoreNodeType.PARAMETER_DECLARATION,
|
|
835
|
+
extractor: (parsedNode) => {
|
|
836
|
+
const node = parsedNode.sourceNode;
|
|
837
|
+
if (!node)
|
|
838
|
+
return {};
|
|
839
|
+
return {
|
|
840
|
+
type: node.getTypeNode()?.getText() ?? 'any',
|
|
841
|
+
isOptional: node.hasQuestionToken(),
|
|
842
|
+
isRestParameter: node.isRestParameter(),
|
|
843
|
+
hasDefaultValue: node.hasInitializer(),
|
|
844
|
+
decoratorNames: node.getDecorators().map((d) => d.getName()),
|
|
845
|
+
parameterIndex: node.getChildIndex(),
|
|
846
|
+
};
|
|
847
|
+
},
|
|
848
|
+
priority: 1,
|
|
849
|
+
},
|
|
850
|
+
{
|
|
851
|
+
nodeType: CoreNodeType.IMPORT_DECLARATION,
|
|
852
|
+
extractor: (parsedNode) => {
|
|
853
|
+
const node = parsedNode.sourceNode;
|
|
854
|
+
if (!node)
|
|
855
|
+
return {};
|
|
856
|
+
return {
|
|
857
|
+
moduleSpecifier: node.getModuleSpecifierValue(),
|
|
858
|
+
isTypeOnly: node.isTypeOnly(),
|
|
859
|
+
importKind: determineImportKind(node),
|
|
860
|
+
namedImports: node.getNamedImports().map((ni) => ni.getName()),
|
|
861
|
+
defaultImport: node.getDefaultImport()?.getText() ?? null,
|
|
862
|
+
namespaceImport: node.getNamespaceImport()?.getText() ?? null,
|
|
863
|
+
};
|
|
864
|
+
},
|
|
865
|
+
priority: 1,
|
|
866
|
+
},
|
|
867
|
+
{
|
|
868
|
+
nodeType: CoreNodeType.DECORATOR,
|
|
869
|
+
extractor: (parsedNode) => {
|
|
870
|
+
const node = parsedNode.sourceNode;
|
|
871
|
+
if (!node)
|
|
872
|
+
return {};
|
|
873
|
+
return {
|
|
874
|
+
arguments: node.getArguments().map((arg) => arg.getText()),
|
|
875
|
+
target: determineDecoratorTarget(node),
|
|
876
|
+
};
|
|
877
|
+
},
|
|
878
|
+
priority: 1,
|
|
879
|
+
},
|
|
880
|
+
],
|
|
881
|
+
metadata: {
|
|
882
|
+
targetLanguages: ['typescript'],
|
|
883
|
+
dependencies: ['@nestjs/core', '@nestjs/common'],
|
|
884
|
+
},
|
|
885
|
+
};
|
|
886
|
+
// ============================================================================
|
|
887
|
+
// PARSE OPTIONS
|
|
888
|
+
// ============================================================================
|
|
889
|
+
export const NESTJS_PARSE_OPTIONS = {
|
|
890
|
+
includePatterns: ['**/*.ts', '**/*.tsx'],
|
|
891
|
+
excludePatterns: ['node_modules/', 'dist/', 'coverage/', '.d.ts', '.spec.ts', '.test.ts'],
|
|
892
|
+
maxFiles: 1000,
|
|
893
|
+
frameworkSchemas: [NESTJS_FRAMEWORK_SCHEMA],
|
|
894
|
+
};
|