@stackguide/mcp-server 3.0.0 → 3.2.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/dist/config/types.d.ts +51 -4
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js.map +1 -1
- package/dist/services/astAnalyzer.d.ts +21 -0
- package/dist/services/astAnalyzer.d.ts.map +1 -0
- package/dist/services/astAnalyzer.js +593 -0
- package/dist/services/astAnalyzer.js.map +1 -0
- package/dist/services/codeAnalyzer.d.ts +54 -14
- package/dist/services/codeAnalyzer.d.ts.map +1 -1
- package/dist/services/codeAnalyzer.js +209 -37
- package/dist/services/codeAnalyzer.js.map +1 -1
- package/dist/services/parsers/baseParser.d.ts +44 -0
- package/dist/services/parsers/baseParser.d.ts.map +1 -0
- package/dist/services/parsers/baseParser.js +177 -0
- package/dist/services/parsers/baseParser.js.map +1 -0
- package/dist/services/parsers/goParser.d.ts +28 -0
- package/dist/services/parsers/goParser.d.ts.map +1 -0
- package/dist/services/parsers/goParser.js +590 -0
- package/dist/services/parsers/goParser.js.map +1 -0
- package/dist/services/parsers/index.d.ts +62 -0
- package/dist/services/parsers/index.d.ts.map +1 -0
- package/dist/services/parsers/index.js +121 -0
- package/dist/services/parsers/index.js.map +1 -0
- package/dist/services/parsers/pythonParser.d.ts +28 -0
- package/dist/services/parsers/pythonParser.d.ts.map +1 -0
- package/dist/services/parsers/pythonParser.js +663 -0
- package/dist/services/parsers/pythonParser.js.map +1 -0
- package/dist/services/parsers/rustParser.d.ts +28 -0
- package/dist/services/parsers/rustParser.d.ts.map +1 -0
- package/dist/services/parsers/rustParser.js +654 -0
- package/dist/services/parsers/rustParser.js.map +1 -0
- package/dist/services/parsers/types.d.ts +241 -0
- package/dist/services/parsers/types.d.ts.map +1 -0
- package/dist/services/parsers/types.js +47 -0
- package/dist/services/parsers/types.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AST Analyzer Service - Phase 2
|
|
3
|
+
* Provides semantic code analysis using ts-morph
|
|
4
|
+
*/
|
|
5
|
+
import { Project, SourceFile, Node, SyntaxKind, ts } from 'ts-morph';
|
|
6
|
+
import { logger } from '../utils/logger.js';
|
|
7
|
+
// =============================================================================
|
|
8
|
+
// AST PROJECT MANAGEMENT
|
|
9
|
+
// =============================================================================
|
|
10
|
+
/**
|
|
11
|
+
* Cached ts-morph project for performance
|
|
12
|
+
* We use in-memory file system to avoid disk I/O
|
|
13
|
+
*/
|
|
14
|
+
let cachedProject = null;
|
|
15
|
+
function getProject() {
|
|
16
|
+
if (!cachedProject) {
|
|
17
|
+
cachedProject = new Project({
|
|
18
|
+
useInMemoryFileSystem: true,
|
|
19
|
+
compilerOptions: {
|
|
20
|
+
target: ts.ScriptTarget.ESNext,
|
|
21
|
+
module: ts.ModuleKind.ESNext,
|
|
22
|
+
strict: false, // Be lenient for analysis
|
|
23
|
+
skipLibCheck: true,
|
|
24
|
+
noEmit: true,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
logger.debug('Created new ts-morph project');
|
|
28
|
+
}
|
|
29
|
+
return cachedProject;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Clear the cached project (useful for testing or memory management)
|
|
33
|
+
*/
|
|
34
|
+
export function clearASTCache() {
|
|
35
|
+
if (cachedProject) {
|
|
36
|
+
cachedProject.getSourceFiles().forEach(sf => cachedProject.removeSourceFile(sf));
|
|
37
|
+
}
|
|
38
|
+
cachedProject = null;
|
|
39
|
+
logger.debug('Cleared AST cache');
|
|
40
|
+
}
|
|
41
|
+
// =============================================================================
|
|
42
|
+
// AST ANALYSIS
|
|
43
|
+
// =============================================================================
|
|
44
|
+
/**
|
|
45
|
+
* Parse source code into a ts-morph SourceFile
|
|
46
|
+
*/
|
|
47
|
+
export function parseCode(filePath, content) {
|
|
48
|
+
try {
|
|
49
|
+
const project = getProject();
|
|
50
|
+
// Check if file already exists and remove it
|
|
51
|
+
const existing = project.getSourceFile(filePath);
|
|
52
|
+
if (existing) {
|
|
53
|
+
project.removeSourceFile(existing);
|
|
54
|
+
}
|
|
55
|
+
// Create the source file
|
|
56
|
+
const sourceFile = project.createSourceFile(filePath, content, { overwrite: true });
|
|
57
|
+
return sourceFile;
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
logger.warn('Failed to parse code for AST analysis', { filePath, error: String(error) });
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Map string node type names to ts-morph SyntaxKind
|
|
66
|
+
*/
|
|
67
|
+
const NODE_TYPE_MAP = {
|
|
68
|
+
// Declarations
|
|
69
|
+
'FunctionDeclaration': SyntaxKind.FunctionDeclaration,
|
|
70
|
+
'ClassDeclaration': SyntaxKind.ClassDeclaration,
|
|
71
|
+
'VariableDeclaration': SyntaxKind.VariableDeclaration,
|
|
72
|
+
'InterfaceDeclaration': SyntaxKind.InterfaceDeclaration,
|
|
73
|
+
'TypeAliasDeclaration': SyntaxKind.TypeAliasDeclaration,
|
|
74
|
+
'EnumDeclaration': SyntaxKind.EnumDeclaration,
|
|
75
|
+
'MethodDeclaration': SyntaxKind.MethodDeclaration,
|
|
76
|
+
'PropertyDeclaration': SyntaxKind.PropertyDeclaration,
|
|
77
|
+
'Constructor': SyntaxKind.Constructor,
|
|
78
|
+
'GetAccessor': SyntaxKind.GetAccessor,
|
|
79
|
+
'SetAccessor': SyntaxKind.SetAccessor,
|
|
80
|
+
// Expressions
|
|
81
|
+
'CallExpression': SyntaxKind.CallExpression,
|
|
82
|
+
'NewExpression': SyntaxKind.NewExpression,
|
|
83
|
+
'ArrowFunction': SyntaxKind.ArrowFunction,
|
|
84
|
+
'FunctionExpression': SyntaxKind.FunctionExpression,
|
|
85
|
+
'BinaryExpression': SyntaxKind.BinaryExpression,
|
|
86
|
+
'ConditionalExpression': SyntaxKind.ConditionalExpression,
|
|
87
|
+
'PropertyAccessExpression': SyntaxKind.PropertyAccessExpression,
|
|
88
|
+
'ElementAccessExpression': SyntaxKind.ElementAccessExpression,
|
|
89
|
+
'AwaitExpression': SyntaxKind.AwaitExpression,
|
|
90
|
+
// Statements
|
|
91
|
+
'IfStatement': SyntaxKind.IfStatement,
|
|
92
|
+
'ForStatement': SyntaxKind.ForStatement,
|
|
93
|
+
'ForInStatement': SyntaxKind.ForInStatement,
|
|
94
|
+
'ForOfStatement': SyntaxKind.ForOfStatement,
|
|
95
|
+
'WhileStatement': SyntaxKind.WhileStatement,
|
|
96
|
+
'DoStatement': SyntaxKind.DoStatement,
|
|
97
|
+
'SwitchStatement': SyntaxKind.SwitchStatement,
|
|
98
|
+
'TryStatement': SyntaxKind.TryStatement,
|
|
99
|
+
'CatchClause': SyntaxKind.CatchClause,
|
|
100
|
+
'ThrowStatement': SyntaxKind.ThrowStatement,
|
|
101
|
+
'ReturnStatement': SyntaxKind.ReturnStatement,
|
|
102
|
+
// Imports/Exports
|
|
103
|
+
'ImportDeclaration': SyntaxKind.ImportDeclaration,
|
|
104
|
+
'ExportDeclaration': SyntaxKind.ExportDeclaration,
|
|
105
|
+
'ExportAssignment': SyntaxKind.ExportAssignment,
|
|
106
|
+
// JSX
|
|
107
|
+
'JsxElement': SyntaxKind.JsxElement,
|
|
108
|
+
'JsxSelfClosingElement': SyntaxKind.JsxSelfClosingElement,
|
|
109
|
+
'JsxFragment': SyntaxKind.JsxFragment,
|
|
110
|
+
// Other
|
|
111
|
+
'Parameter': SyntaxKind.Parameter,
|
|
112
|
+
'TypeReference': SyntaxKind.TypeReference,
|
|
113
|
+
'AsExpression': SyntaxKind.AsExpression,
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Create an ASTCheckContext for a node
|
|
117
|
+
*/
|
|
118
|
+
function createCheckContext(node, sourceFile, filePath) {
|
|
119
|
+
return {
|
|
120
|
+
node,
|
|
121
|
+
sourceFile,
|
|
122
|
+
filePath,
|
|
123
|
+
sourceText: sourceFile.getFullText(),
|
|
124
|
+
getNodeText: () => node.getText(),
|
|
125
|
+
getStartLine: () => node.getStartLineNumber(),
|
|
126
|
+
getTypeText: () => {
|
|
127
|
+
try {
|
|
128
|
+
// Try to get type information if available
|
|
129
|
+
if ('getType' in node && typeof node.getType === 'function') {
|
|
130
|
+
return node.getType().getText();
|
|
131
|
+
}
|
|
132
|
+
return 'unknown';
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return 'unknown';
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Run AST rules against a source file
|
|
142
|
+
*/
|
|
143
|
+
export function analyzeWithAST(filePath, content, rules) {
|
|
144
|
+
const issues = [];
|
|
145
|
+
// Only analyze TS/JS files
|
|
146
|
+
const ext = filePath.split('.').pop()?.toLowerCase();
|
|
147
|
+
if (!['ts', 'tsx', 'js', 'jsx', 'mts', 'mjs', 'cts', 'cjs'].includes(ext || '')) {
|
|
148
|
+
return issues;
|
|
149
|
+
}
|
|
150
|
+
const sourceFile = parseCode(filePath, content);
|
|
151
|
+
if (!sourceFile) {
|
|
152
|
+
return issues;
|
|
153
|
+
}
|
|
154
|
+
logger.debug('Running AST analysis', { filePath, ruleCount: rules.length });
|
|
155
|
+
for (const rule of rules) {
|
|
156
|
+
if (!rule.enabled)
|
|
157
|
+
continue;
|
|
158
|
+
// Get the SyntaxKind values for this rule
|
|
159
|
+
const syntaxKinds = rule.nodeTypes
|
|
160
|
+
.map(nt => NODE_TYPE_MAP[nt])
|
|
161
|
+
.filter((sk) => sk !== undefined);
|
|
162
|
+
if (syntaxKinds.length === 0) {
|
|
163
|
+
logger.warn('No valid node types for AST rule', { ruleId: rule.id, nodeTypes: rule.nodeTypes });
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
// Find all matching nodes
|
|
167
|
+
for (const syntaxKind of syntaxKinds) {
|
|
168
|
+
const nodes = sourceFile.getDescendantsOfKind(syntaxKind);
|
|
169
|
+
for (const node of nodes) {
|
|
170
|
+
try {
|
|
171
|
+
const context = createCheckContext(node, sourceFile, filePath);
|
|
172
|
+
const result = rule.check(context);
|
|
173
|
+
if (result && result.hasIssue) {
|
|
174
|
+
const quickFix = rule.quickFix ? rule.quickFix(context) : undefined;
|
|
175
|
+
issues.push({
|
|
176
|
+
severity: rule.severity,
|
|
177
|
+
rule: rule.id,
|
|
178
|
+
category: rule.category,
|
|
179
|
+
message: result.message || rule.message,
|
|
180
|
+
line: result.line || context.getStartLine(),
|
|
181
|
+
code: result.code || context.getNodeText().substring(0, 100),
|
|
182
|
+
suggestion: rule.suggestion,
|
|
183
|
+
quickFix,
|
|
184
|
+
source: rule.source,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
logger.warn('Error running AST rule check', {
|
|
190
|
+
ruleId: rule.id,
|
|
191
|
+
filePath,
|
|
192
|
+
error: String(error)
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
logger.debug('AST analysis complete', { filePath, issuesFound: issues.length });
|
|
199
|
+
return issues;
|
|
200
|
+
}
|
|
201
|
+
// =============================================================================
|
|
202
|
+
// BUILTIN AST RULES
|
|
203
|
+
// =============================================================================
|
|
204
|
+
export const BUILTIN_AST_RULES = [
|
|
205
|
+
// -------------------------------------------------------------------------
|
|
206
|
+
// UNUSED EXPORTS
|
|
207
|
+
// -------------------------------------------------------------------------
|
|
208
|
+
{
|
|
209
|
+
id: 'AST001',
|
|
210
|
+
type: 'ast',
|
|
211
|
+
category: 'coding-standards',
|
|
212
|
+
nodeTypes: ['FunctionDeclaration', 'ClassDeclaration', 'VariableDeclaration'],
|
|
213
|
+
severity: 'warning',
|
|
214
|
+
message: 'Exported item may be unused within this file',
|
|
215
|
+
suggestion: 'Verify this export is used by other modules or remove it',
|
|
216
|
+
enabled: true,
|
|
217
|
+
priority: 50,
|
|
218
|
+
source: 'builtin',
|
|
219
|
+
check: (ctx) => {
|
|
220
|
+
const node = ctx.node;
|
|
221
|
+
// Check if the node has export modifier
|
|
222
|
+
if (!('getModifiers' in node))
|
|
223
|
+
return null;
|
|
224
|
+
const modifiers = node.getModifiers?.() || [];
|
|
225
|
+
const isExported = modifiers.some((m) => m.getKind() === SyntaxKind.ExportKeyword);
|
|
226
|
+
if (!isExported)
|
|
227
|
+
return null;
|
|
228
|
+
// Get the name
|
|
229
|
+
let name = '';
|
|
230
|
+
if ('getName' in node && typeof node.getName === 'function') {
|
|
231
|
+
name = node.getName() || '';
|
|
232
|
+
}
|
|
233
|
+
if (!name)
|
|
234
|
+
return null;
|
|
235
|
+
// Check if this name is used elsewhere in the file (simple heuristic)
|
|
236
|
+
const sourceText = ctx.sourceText;
|
|
237
|
+
const usagePattern = new RegExp(`\\b${name}\\b`, 'g');
|
|
238
|
+
const matches = sourceText.match(usagePattern);
|
|
239
|
+
// If only 1-2 occurrences, it's likely just the declaration and export
|
|
240
|
+
// This is a heuristic - a proper check would trace references
|
|
241
|
+
if (matches && matches.length <= 2) {
|
|
242
|
+
return {
|
|
243
|
+
hasIssue: true,
|
|
244
|
+
message: `Export '${name}' appears to have no internal usage`,
|
|
245
|
+
code: name,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
return null;
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
// -------------------------------------------------------------------------
|
|
252
|
+
// EMPTY FUNCTION
|
|
253
|
+
// -------------------------------------------------------------------------
|
|
254
|
+
{
|
|
255
|
+
id: 'AST002',
|
|
256
|
+
type: 'ast',
|
|
257
|
+
category: 'coding-standards',
|
|
258
|
+
nodeTypes: ['FunctionDeclaration', 'MethodDeclaration', 'ArrowFunction'],
|
|
259
|
+
severity: 'info',
|
|
260
|
+
message: 'Empty function body detected',
|
|
261
|
+
suggestion: 'Add implementation or a comment explaining why it is empty',
|
|
262
|
+
enabled: true,
|
|
263
|
+
priority: 25,
|
|
264
|
+
source: 'builtin',
|
|
265
|
+
check: (ctx) => {
|
|
266
|
+
const node = ctx.node;
|
|
267
|
+
// Get function body
|
|
268
|
+
if (!('getBody' in node))
|
|
269
|
+
return null;
|
|
270
|
+
const body = node.getBody?.();
|
|
271
|
+
if (!body)
|
|
272
|
+
return null;
|
|
273
|
+
// Check if body is empty (no statements, or only whitespace/comments)
|
|
274
|
+
const bodyText = body.getText?.() || '';
|
|
275
|
+
const cleanBody = bodyText.replace(/[{}\s]/g, '').replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
|
|
276
|
+
if (cleanBody.length === 0) {
|
|
277
|
+
let name = 'anonymous';
|
|
278
|
+
if ('getName' in node && typeof node.getName === 'function') {
|
|
279
|
+
name = node.getName() || 'anonymous';
|
|
280
|
+
}
|
|
281
|
+
return {
|
|
282
|
+
hasIssue: true,
|
|
283
|
+
message: `Function '${name}' has an empty body`,
|
|
284
|
+
code: ctx.getNodeText().substring(0, 50),
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
return null;
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
// -------------------------------------------------------------------------
|
|
291
|
+
// TOO MANY PARAMETERS
|
|
292
|
+
// -------------------------------------------------------------------------
|
|
293
|
+
{
|
|
294
|
+
id: 'AST003',
|
|
295
|
+
type: 'ast',
|
|
296
|
+
category: 'architecture',
|
|
297
|
+
nodeTypes: ['FunctionDeclaration', 'MethodDeclaration', 'ArrowFunction', 'Constructor'],
|
|
298
|
+
severity: 'warning',
|
|
299
|
+
message: 'Function has too many parameters',
|
|
300
|
+
suggestion: 'Consider using an options object or refactoring into smaller functions',
|
|
301
|
+
enabled: true,
|
|
302
|
+
priority: 50,
|
|
303
|
+
source: 'builtin',
|
|
304
|
+
check: (ctx) => {
|
|
305
|
+
const node = ctx.node;
|
|
306
|
+
if (!('getParameters' in node))
|
|
307
|
+
return null;
|
|
308
|
+
const params = node.getParameters?.() || [];
|
|
309
|
+
const MAX_PARAMS = 4;
|
|
310
|
+
if (params.length > MAX_PARAMS) {
|
|
311
|
+
let name = 'function';
|
|
312
|
+
if ('getName' in node && typeof node.getName === 'function') {
|
|
313
|
+
name = node.getName() || 'function';
|
|
314
|
+
}
|
|
315
|
+
return {
|
|
316
|
+
hasIssue: true,
|
|
317
|
+
message: `'${name}' has ${params.length} parameters (max recommended: ${MAX_PARAMS})`,
|
|
318
|
+
code: `${params.length} parameters`,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
return null;
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
// -------------------------------------------------------------------------
|
|
325
|
+
// NESTED CALLBACKS (Callback Hell)
|
|
326
|
+
// -------------------------------------------------------------------------
|
|
327
|
+
{
|
|
328
|
+
id: 'AST004',
|
|
329
|
+
type: 'ast',
|
|
330
|
+
category: 'coding-standards',
|
|
331
|
+
nodeTypes: ['CallExpression'],
|
|
332
|
+
severity: 'warning',
|
|
333
|
+
message: 'Deeply nested callbacks detected (callback hell)',
|
|
334
|
+
suggestion: 'Refactor using async/await or Promise chaining',
|
|
335
|
+
enabled: true,
|
|
336
|
+
priority: 75,
|
|
337
|
+
source: 'builtin',
|
|
338
|
+
check: (ctx) => {
|
|
339
|
+
const node = ctx.node;
|
|
340
|
+
// Count callback nesting depth
|
|
341
|
+
let depth = 0;
|
|
342
|
+
let current = node;
|
|
343
|
+
while (current) {
|
|
344
|
+
if (current.getKind() === SyntaxKind.CallExpression) {
|
|
345
|
+
// Check if this call has a function argument
|
|
346
|
+
const args = current.getArguments?.() || [];
|
|
347
|
+
const hasFunctionArg = args.some((arg) => arg.getKind() === SyntaxKind.ArrowFunction ||
|
|
348
|
+
arg.getKind() === SyntaxKind.FunctionExpression);
|
|
349
|
+
if (hasFunctionArg) {
|
|
350
|
+
depth++;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
current = current.getParent();
|
|
354
|
+
}
|
|
355
|
+
const MAX_CALLBACK_DEPTH = 3;
|
|
356
|
+
if (depth > MAX_CALLBACK_DEPTH) {
|
|
357
|
+
return {
|
|
358
|
+
hasIssue: true,
|
|
359
|
+
message: `Callback nesting depth: ${depth} (max: ${MAX_CALLBACK_DEPTH})`,
|
|
360
|
+
code: ctx.getNodeText().substring(0, 50),
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
return null;
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
// -------------------------------------------------------------------------
|
|
367
|
+
// COMPLEX CONDITIONAL
|
|
368
|
+
// -------------------------------------------------------------------------
|
|
369
|
+
{
|
|
370
|
+
id: 'AST005',
|
|
371
|
+
type: 'ast',
|
|
372
|
+
category: 'coding-standards',
|
|
373
|
+
nodeTypes: ['IfStatement', 'ConditionalExpression'],
|
|
374
|
+
severity: 'info',
|
|
375
|
+
message: 'Complex conditional expression',
|
|
376
|
+
suggestion: 'Consider extracting conditions into named variables for clarity',
|
|
377
|
+
enabled: true,
|
|
378
|
+
priority: 25,
|
|
379
|
+
source: 'builtin',
|
|
380
|
+
check: (ctx) => {
|
|
381
|
+
const node = ctx.node;
|
|
382
|
+
const text = ctx.getNodeText();
|
|
383
|
+
// Count logical operators
|
|
384
|
+
const andCount = (text.match(/&&/g) || []).length;
|
|
385
|
+
const orCount = (text.match(/\|\|/g) || []).length;
|
|
386
|
+
const totalOps = andCount + orCount;
|
|
387
|
+
const MAX_LOGICAL_OPS = 3;
|
|
388
|
+
if (totalOps > MAX_LOGICAL_OPS) {
|
|
389
|
+
return {
|
|
390
|
+
hasIssue: true,
|
|
391
|
+
message: `Conditional has ${totalOps} logical operators (max: ${MAX_LOGICAL_OPS})`,
|
|
392
|
+
code: text.substring(0, 80),
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
return null;
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
// -------------------------------------------------------------------------
|
|
399
|
+
// MISSING RETURN TYPE
|
|
400
|
+
// -------------------------------------------------------------------------
|
|
401
|
+
{
|
|
402
|
+
id: 'AST006',
|
|
403
|
+
type: 'ast',
|
|
404
|
+
category: 'best-practices',
|
|
405
|
+
nodeTypes: ['FunctionDeclaration', 'MethodDeclaration'],
|
|
406
|
+
severity: 'suggestion',
|
|
407
|
+
message: 'Function is missing explicit return type',
|
|
408
|
+
suggestion: 'Add return type annotation for better type safety',
|
|
409
|
+
languages: ['typescript', 'tsx'],
|
|
410
|
+
enabled: true,
|
|
411
|
+
priority: 25,
|
|
412
|
+
source: 'builtin',
|
|
413
|
+
check: (ctx) => {
|
|
414
|
+
// Only check TypeScript files
|
|
415
|
+
if (!ctx.filePath.endsWith('.ts') && !ctx.filePath.endsWith('.tsx')) {
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
const node = ctx.node;
|
|
419
|
+
if (!('getReturnTypeNode' in node))
|
|
420
|
+
return null;
|
|
421
|
+
const returnType = node.getReturnTypeNode?.();
|
|
422
|
+
// Skip if return type is present
|
|
423
|
+
if (returnType)
|
|
424
|
+
return null;
|
|
425
|
+
// Skip constructors
|
|
426
|
+
if (node.getKind() === SyntaxKind.Constructor)
|
|
427
|
+
return null;
|
|
428
|
+
let name = 'function';
|
|
429
|
+
if ('getName' in node && typeof node.getName === 'function') {
|
|
430
|
+
name = node.getName() || 'function';
|
|
431
|
+
}
|
|
432
|
+
// Skip private/protected methods and simple getters
|
|
433
|
+
const text = ctx.getNodeText();
|
|
434
|
+
if (text.startsWith('private ') || text.startsWith('protected ')) {
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
437
|
+
return {
|
|
438
|
+
hasIssue: true,
|
|
439
|
+
message: `Function '${name}' is missing explicit return type`,
|
|
440
|
+
code: name,
|
|
441
|
+
};
|
|
442
|
+
},
|
|
443
|
+
},
|
|
444
|
+
// -------------------------------------------------------------------------
|
|
445
|
+
// ANY TYPE USAGE
|
|
446
|
+
// -------------------------------------------------------------------------
|
|
447
|
+
{
|
|
448
|
+
id: 'AST007',
|
|
449
|
+
type: 'ast',
|
|
450
|
+
category: 'best-practices',
|
|
451
|
+
nodeTypes: ['Parameter', 'VariableDeclaration', 'PropertyDeclaration'],
|
|
452
|
+
severity: 'warning',
|
|
453
|
+
message: 'Explicit "any" type usage detected',
|
|
454
|
+
suggestion: 'Use a more specific type or "unknown" for truly unknown types',
|
|
455
|
+
languages: ['typescript', 'tsx'],
|
|
456
|
+
enabled: true,
|
|
457
|
+
priority: 75,
|
|
458
|
+
source: 'builtin',
|
|
459
|
+
check: (ctx) => {
|
|
460
|
+
// Only check TypeScript files
|
|
461
|
+
if (!ctx.filePath.endsWith('.ts') && !ctx.filePath.endsWith('.tsx')) {
|
|
462
|
+
return null;
|
|
463
|
+
}
|
|
464
|
+
const node = ctx.node;
|
|
465
|
+
// Get the type node
|
|
466
|
+
let typeNode;
|
|
467
|
+
if ('getTypeNode' in node) {
|
|
468
|
+
typeNode = node.getTypeNode?.();
|
|
469
|
+
}
|
|
470
|
+
if (!typeNode)
|
|
471
|
+
return null;
|
|
472
|
+
const typeText = typeNode.getText();
|
|
473
|
+
if (typeText === 'any') {
|
|
474
|
+
return {
|
|
475
|
+
hasIssue: true,
|
|
476
|
+
message: 'Explicit "any" type detected',
|
|
477
|
+
code: ctx.getNodeText().substring(0, 50),
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
return null;
|
|
481
|
+
},
|
|
482
|
+
},
|
|
483
|
+
// -------------------------------------------------------------------------
|
|
484
|
+
// REACT: MISSING KEY IN LIST
|
|
485
|
+
// -------------------------------------------------------------------------
|
|
486
|
+
{
|
|
487
|
+
id: 'AST008',
|
|
488
|
+
type: 'ast',
|
|
489
|
+
category: 'react',
|
|
490
|
+
nodeTypes: ['CallExpression'],
|
|
491
|
+
severity: 'error',
|
|
492
|
+
message: 'Missing "key" prop in list rendering',
|
|
493
|
+
suggestion: 'Add a unique "key" prop to each element in the array',
|
|
494
|
+
languages: ['javascript', 'typescript', 'jsx', 'tsx'],
|
|
495
|
+
enabled: true,
|
|
496
|
+
priority: 100,
|
|
497
|
+
source: 'builtin',
|
|
498
|
+
check: (ctx) => {
|
|
499
|
+
const node = ctx.node;
|
|
500
|
+
// Check if this is a .map() call
|
|
501
|
+
const expression = node.getExpression?.();
|
|
502
|
+
if (!expression)
|
|
503
|
+
return null;
|
|
504
|
+
const expressionText = expression.getText?.() || '';
|
|
505
|
+
if (!expressionText.endsWith('.map'))
|
|
506
|
+
return null;
|
|
507
|
+
// Get the callback argument
|
|
508
|
+
const args = node.getArguments?.() || [];
|
|
509
|
+
if (args.length === 0)
|
|
510
|
+
return null;
|
|
511
|
+
const callback = args[0];
|
|
512
|
+
const callbackText = callback.getText?.() || '';
|
|
513
|
+
// Look for JSX element without key prop
|
|
514
|
+
const hasJsxReturn = callbackText.includes('<') && callbackText.includes('>');
|
|
515
|
+
const hasKeyProp = callbackText.includes('key=') || callbackText.includes('key:');
|
|
516
|
+
if (hasJsxReturn && !hasKeyProp) {
|
|
517
|
+
return {
|
|
518
|
+
hasIssue: true,
|
|
519
|
+
message: 'Array.map() rendering JSX without "key" prop',
|
|
520
|
+
code: expressionText + '(...)',
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
return null;
|
|
524
|
+
},
|
|
525
|
+
},
|
|
526
|
+
// -------------------------------------------------------------------------
|
|
527
|
+
// LONG CLASS
|
|
528
|
+
// -------------------------------------------------------------------------
|
|
529
|
+
{
|
|
530
|
+
id: 'AST009',
|
|
531
|
+
type: 'ast',
|
|
532
|
+
category: 'architecture',
|
|
533
|
+
nodeTypes: ['ClassDeclaration'],
|
|
534
|
+
severity: 'warning',
|
|
535
|
+
message: 'Class has too many members',
|
|
536
|
+
suggestion: 'Consider splitting into smaller, focused classes (SRP)',
|
|
537
|
+
enabled: true,
|
|
538
|
+
priority: 50,
|
|
539
|
+
source: 'builtin',
|
|
540
|
+
check: (ctx) => {
|
|
541
|
+
const node = ctx.node;
|
|
542
|
+
const members = node.getMembers?.() || [];
|
|
543
|
+
const MAX_MEMBERS = 15;
|
|
544
|
+
if (members.length > MAX_MEMBERS) {
|
|
545
|
+
const name = node.getName?.() || 'Class';
|
|
546
|
+
return {
|
|
547
|
+
hasIssue: true,
|
|
548
|
+
message: `Class '${name}' has ${members.length} members (max: ${MAX_MEMBERS})`,
|
|
549
|
+
code: name,
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
return null;
|
|
553
|
+
},
|
|
554
|
+
},
|
|
555
|
+
// -------------------------------------------------------------------------
|
|
556
|
+
// MAGIC NUMBER
|
|
557
|
+
// -------------------------------------------------------------------------
|
|
558
|
+
{
|
|
559
|
+
id: 'AST010',
|
|
560
|
+
type: 'ast',
|
|
561
|
+
category: 'coding-standards',
|
|
562
|
+
nodeTypes: ['BinaryExpression', 'VariableDeclaration'],
|
|
563
|
+
severity: 'info',
|
|
564
|
+
message: 'Magic number detected',
|
|
565
|
+
suggestion: 'Extract to a named constant for clarity',
|
|
566
|
+
enabled: true,
|
|
567
|
+
priority: 25,
|
|
568
|
+
source: 'builtin',
|
|
569
|
+
check: (ctx) => {
|
|
570
|
+
const text = ctx.getNodeText();
|
|
571
|
+
// Look for numeric literals > 1 (skip 0, 1, -1 as common cases)
|
|
572
|
+
const magicNumbers = text.match(/(?<![a-zA-Z_])\b([2-9]|[1-9]\d{2,})\b(?![a-zA-Z_])/g);
|
|
573
|
+
if (magicNumbers && magicNumbers.length > 0) {
|
|
574
|
+
// Filter out common acceptable numbers
|
|
575
|
+
const acceptable = ['100', '1000', '60', '24', '365', '1024', '2048', '4096'];
|
|
576
|
+
const realMagic = magicNumbers.filter(n => !acceptable.includes(n) && parseInt(n) > 10);
|
|
577
|
+
if (realMagic.length > 0) {
|
|
578
|
+
return {
|
|
579
|
+
hasIssue: true,
|
|
580
|
+
message: `Magic number(s) detected: ${realMagic.slice(0, 3).join(', ')}`,
|
|
581
|
+
code: text.substring(0, 50),
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
return null;
|
|
586
|
+
},
|
|
587
|
+
},
|
|
588
|
+
];
|
|
589
|
+
// =============================================================================
|
|
590
|
+
// EXPORTS
|
|
591
|
+
// =============================================================================
|
|
592
|
+
export { SyntaxKind, Node, SourceFile };
|
|
593
|
+
//# sourceMappingURL=astAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"astAnalyzer.js","sourceRoot":"","sources":["../../src/services/astAnalyzer.ts"],"names":[],"mappings":"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"}
|