neuronlayer 0.1.9 → 0.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.

Potentially problematic release.


This version of neuronlayer might be problematic. Click here for more details.

Files changed (81) hide show
  1. package/README.md +3 -2
  2. package/dist/index.js +172 -90
  3. package/dist/index.js.map +7 -0
  4. package/package.json +6 -1
  5. package/esbuild.config.js +0 -26
  6. package/src/cli/commands.ts +0 -573
  7. package/src/core/adr-exporter.ts +0 -253
  8. package/src/core/architecture/architecture-enforcement.ts +0 -228
  9. package/src/core/architecture/duplicate-detector.ts +0 -288
  10. package/src/core/architecture/index.ts +0 -6
  11. package/src/core/architecture/pattern-learner.ts +0 -306
  12. package/src/core/architecture/pattern-library.ts +0 -403
  13. package/src/core/architecture/pattern-validator.ts +0 -324
  14. package/src/core/change-intelligence/bug-correlator.ts +0 -544
  15. package/src/core/change-intelligence/change-intelligence.ts +0 -264
  16. package/src/core/change-intelligence/change-tracker.ts +0 -334
  17. package/src/core/change-intelligence/fix-suggester.ts +0 -340
  18. package/src/core/change-intelligence/index.ts +0 -5
  19. package/src/core/code-verifier.ts +0 -843
  20. package/src/core/confidence/confidence-scorer.ts +0 -251
  21. package/src/core/confidence/conflict-checker.ts +0 -289
  22. package/src/core/confidence/index.ts +0 -5
  23. package/src/core/confidence/source-tracker.ts +0 -263
  24. package/src/core/confidence/warning-detector.ts +0 -241
  25. package/src/core/context-rot/compaction.ts +0 -284
  26. package/src/core/context-rot/context-health.ts +0 -243
  27. package/src/core/context-rot/context-rot-prevention.ts +0 -213
  28. package/src/core/context-rot/critical-context.ts +0 -221
  29. package/src/core/context-rot/drift-detector.ts +0 -255
  30. package/src/core/context-rot/index.ts +0 -7
  31. package/src/core/context.ts +0 -263
  32. package/src/core/decision-extractor.ts +0 -339
  33. package/src/core/decisions.ts +0 -69
  34. package/src/core/deja-vu.ts +0 -421
  35. package/src/core/engine.ts +0 -1646
  36. package/src/core/feature-context.ts +0 -726
  37. package/src/core/ghost-mode.ts +0 -465
  38. package/src/core/learning.ts +0 -519
  39. package/src/core/living-docs/activity-tracker.ts +0 -296
  40. package/src/core/living-docs/architecture-generator.ts +0 -428
  41. package/src/core/living-docs/changelog-generator.ts +0 -348
  42. package/src/core/living-docs/component-generator.ts +0 -230
  43. package/src/core/living-docs/doc-engine.ts +0 -134
  44. package/src/core/living-docs/doc-validator.ts +0 -282
  45. package/src/core/living-docs/index.ts +0 -8
  46. package/src/core/project-manager.ts +0 -301
  47. package/src/core/refresh/activity-gate.ts +0 -256
  48. package/src/core/refresh/git-staleness-checker.ts +0 -108
  49. package/src/core/refresh/index.ts +0 -27
  50. package/src/core/summarizer.ts +0 -290
  51. package/src/core/test-awareness/change-validator.ts +0 -499
  52. package/src/core/test-awareness/index.ts +0 -5
  53. package/src/index.ts +0 -90
  54. package/src/indexing/ast.ts +0 -868
  55. package/src/indexing/embeddings.ts +0 -85
  56. package/src/indexing/indexer.ts +0 -270
  57. package/src/indexing/watcher.ts +0 -78
  58. package/src/server/gateways/aggregator.ts +0 -374
  59. package/src/server/gateways/index.ts +0 -473
  60. package/src/server/gateways/memory-ghost.ts +0 -343
  61. package/src/server/gateways/memory-query.ts +0 -452
  62. package/src/server/gateways/memory-record.ts +0 -346
  63. package/src/server/gateways/memory-review.ts +0 -410
  64. package/src/server/gateways/memory-status.ts +0 -517
  65. package/src/server/gateways/memory-verify.ts +0 -392
  66. package/src/server/gateways/router.ts +0 -434
  67. package/src/server/gateways/types.ts +0 -610
  68. package/src/server/http.ts +0 -228
  69. package/src/server/mcp.ts +0 -154
  70. package/src/server/resources.ts +0 -85
  71. package/src/server/tools.ts +0 -2460
  72. package/src/storage/database.ts +0 -271
  73. package/src/storage/tier1.ts +0 -135
  74. package/src/storage/tier2.ts +0 -972
  75. package/src/storage/tier3.ts +0 -123
  76. package/src/types/documentation.ts +0 -619
  77. package/src/types/index.ts +0 -222
  78. package/src/utils/config.ts +0 -194
  79. package/src/utils/files.ts +0 -117
  80. package/src/utils/time.ts +0 -37
  81. package/src/utils/tokens.ts +0 -52
@@ -1,868 +0,0 @@
1
- import Parser from 'web-tree-sitter';
2
- import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'fs';
3
- import { join, dirname } from 'path';
4
- import { fileURLToPath } from 'url';
5
- import type { CodeSymbol, Import, Export, SymbolKind } from '../types/index.js';
6
-
7
- // Language configurations for parsing
8
- interface LanguageConfig {
9
- wasmFile: string;
10
- extensions: string[];
11
- queries: {
12
- functions?: string;
13
- classes?: string;
14
- interfaces?: string;
15
- types?: string;
16
- imports?: string;
17
- exports?: string;
18
- };
19
- }
20
-
21
- const LANGUAGE_CONFIGS: Record<string, LanguageConfig> = {
22
- typescript: {
23
- wasmFile: 'tree-sitter-typescript.wasm',
24
- extensions: ['.ts', '.tsx'],
25
- queries: {
26
- functions: `
27
- (function_declaration name: (identifier) @name) @func
28
- (arrow_function) @func
29
- (method_definition name: (property_identifier) @name) @func
30
- `,
31
- classes: `
32
- (class_declaration name: (type_identifier) @name) @class
33
- `,
34
- interfaces: `
35
- (interface_declaration name: (type_identifier) @name) @interface
36
- `,
37
- types: `
38
- (type_alias_declaration name: (type_identifier) @name) @type
39
- `,
40
- imports: `
41
- (import_statement) @import
42
- `,
43
- exports: `
44
- (export_statement) @export
45
- `
46
- }
47
- },
48
- javascript: {
49
- wasmFile: 'tree-sitter-javascript.wasm',
50
- extensions: ['.js', '.jsx', '.mjs', '.cjs'],
51
- queries: {
52
- functions: `
53
- (function_declaration name: (identifier) @name) @func
54
- (arrow_function) @func
55
- (method_definition name: (property_identifier) @name) @func
56
- `,
57
- classes: `
58
- (class_declaration name: (identifier) @name) @class
59
- `,
60
- imports: `
61
- (import_statement) @import
62
- `,
63
- exports: `
64
- (export_statement) @export
65
- `
66
- }
67
- },
68
- python: {
69
- wasmFile: 'tree-sitter-python.wasm',
70
- extensions: ['.py'],
71
- queries: {
72
- functions: `
73
- (function_definition name: (identifier) @name) @func
74
- `,
75
- classes: `
76
- (class_definition name: (identifier) @name) @class
77
- `,
78
- imports: `
79
- (import_statement) @import
80
- (import_from_statement) @import
81
- `
82
- }
83
- },
84
- go: {
85
- wasmFile: 'tree-sitter-go.wasm',
86
- extensions: ['.go'],
87
- queries: {
88
- functions: `(function_declaration name: (identifier) @name) @func`,
89
- classes: `(type_declaration (type_spec name: (type_identifier) @name type: (struct_type))) @class`
90
- }
91
- },
92
- rust: {
93
- wasmFile: 'tree-sitter-rust.wasm',
94
- extensions: ['.rs'],
95
- queries: {
96
- functions: `(function_item name: (identifier) @name) @func`,
97
- classes: `(struct_item name: (type_identifier) @name) @class`
98
- }
99
- },
100
- java: {
101
- wasmFile: 'tree-sitter-java.wasm',
102
- extensions: ['.java'],
103
- queries: {
104
- functions: `(method_declaration name: (identifier) @name) @func`,
105
- classes: `(class_declaration name: (identifier) @name) @class`
106
- }
107
- }
108
- };
109
-
110
- export class ASTParser {
111
- private parser: Parser | null = null;
112
- private languages: Map<string, Parser.Language> = new Map();
113
- private initialized = false;
114
- private dataDir: string;
115
-
116
- constructor(dataDir: string) {
117
- this.dataDir = dataDir;
118
- }
119
-
120
- async initialize(): Promise<void> {
121
- if (this.initialized) return;
122
- // Using regex-based parsing for reliable cross-platform support
123
- // Tree-sitter WASM support reserved for future enhancement
124
- this.initialized = true;
125
- }
126
-
127
- private async loadLanguage(_langName: string): Promise<Parser.Language | null> {
128
- // Tree-sitter WASM loading not implemented - using regex fallback
129
- // Language configs are retained for future tree-sitter support
130
- return null;
131
- }
132
-
133
- getLanguageForFile(filePath: string): string | null {
134
- const ext = filePath.slice(filePath.lastIndexOf('.')).toLowerCase();
135
-
136
- for (const [lang, config] of Object.entries(LANGUAGE_CONFIGS)) {
137
- if (config.extensions.includes(ext)) {
138
- return lang;
139
- }
140
- }
141
- return null;
142
- }
143
-
144
- async parseFile(filePath: string, content: string): Promise<{
145
- symbols: CodeSymbol[];
146
- imports: Import[];
147
- exports: Export[];
148
- } | null> {
149
- if (!this.initialized) {
150
- await this.initialize();
151
- }
152
-
153
- // Regex-based parsing - reliable cross-platform symbol extraction
154
- return this.parseWithRegex(filePath, content);
155
- }
156
-
157
- // Regex-based parsing for symbol extraction
158
- // Handles: functions, classes, interfaces, types, imports, exports
159
- // Supports: TypeScript, JavaScript, Python, Go, Rust, Java
160
- private parseWithRegex(filePath: string, content: string): {
161
- symbols: CodeSymbol[];
162
- imports: Import[];
163
- exports: Export[];
164
- } {
165
- const symbols: CodeSymbol[] = [];
166
- const imports: Import[] = [];
167
- const exports: Export[] = [];
168
- const lines = content.split('\n');
169
- const lang = this.getLanguageForFile(filePath);
170
-
171
- if (lang === 'typescript' || lang === 'javascript') {
172
- this.parseTypeScriptJS(filePath, content, lines, symbols, imports, exports);
173
- } else if (lang === 'python') {
174
- this.parsePython(filePath, content, lines, symbols, imports, exports);
175
- } else if (lang === 'go') {
176
- this.parseGo(filePath, content, lines, symbols, imports, exports);
177
- } else if (lang === 'rust') {
178
- this.parseRust(filePath, content, lines, symbols, imports, exports);
179
- } else if (lang === 'java') {
180
- this.parseJava(filePath, content, lines, symbols, imports, exports);
181
- }
182
-
183
- return { symbols, imports, exports };
184
- }
185
-
186
- private parseTypeScriptJS(
187
- filePath: string,
188
- content: string,
189
- lines: string[],
190
- symbols: CodeSymbol[],
191
- imports: Import[],
192
- exports: Export[]
193
- ): void {
194
- // Patterns for TypeScript/JavaScript
195
- const patterns = {
196
- // Functions: function name(), export default function name(), const name = () =>
197
- function: /^(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s+(\w+)/,
198
- // Arrow functions: handles type annotations and destructured params
199
- arrowFunc: /^(?:export\s+)?(?:const|let|var)\s+(\w+)\s*(?::\s*[^=]+)?\s*=\s*(?:async\s+)?(?:\([^)]*\)|[a-zA-Z_]\w*)\s*(?::\s*[^=]+)?\s*=>/,
200
- // Classes
201
- class: /^(?:export\s+)?(?:default\s+)?(?:abstract\s+)?class\s+(\w+)/,
202
- // Interfaces (TS only)
203
- interface: /^(?:export\s+)?interface\s+(\w+)/,
204
- // Types (TS only)
205
- type: /^(?:export\s+)?type\s+(\w+)\s*(?:<[^>]*>)?\s*=/,
206
- // Imports - supports 'import type'
207
- import: /^import\s+(?:type\s+)?(?:(\w+)(?:\s*,\s*)?)?(?:\{([^}]+)\})?\s*from\s*['"]([^'"]+)['"]/,
208
- importAll: /^import\s+(?:type\s+)?\*\s+as\s+(\w+)\s+from\s*['"]([^'"]+)['"]/,
209
- importSideEffect: /^import\s*['"]([^'"]+)['"]/,
210
- // Exports
211
- exportNamed: /^export\s+(?:type\s+)?\{([^}]+)\}/,
212
- exportDefault: /^export\s+default\s+(?:class|function|const|let|var)?\s*(\w+)?/,
213
- exportDirect: /^export\s+(?:const|let|var|function|class|interface|type|enum|async\s+function)\s+(\w+)/,
214
- // Enums (TS)
215
- enum: /^(?:export\s+)?(?:const\s+)?enum\s+(\w+)/,
216
- // Methods inside classes - handles generics, readonly, and all modifiers
217
- method: /^\s+(?:async\s+)?(?:static\s+)?(?:readonly\s+)?(?:private\s+|public\s+|protected\s+)?(?:get\s+|set\s+)?(\w+)\s*(?:<[^>]+>)?\s*\(/,
218
- };
219
-
220
- let currentClass: { name: string; startLine: number } | null = null;
221
- let braceDepth = 0;
222
- let inBlockComment = false;
223
-
224
- for (let i = 0; i < lines.length; i++) {
225
- const line = lines[i] || '';
226
- const trimmed = line.trim();
227
- const lineNum = i + 1;
228
-
229
- // Track block comments properly
230
- if (inBlockComment) {
231
- if (trimmed.includes('*/')) {
232
- inBlockComment = false;
233
- }
234
- continue;
235
- }
236
-
237
- // Skip single-line comments
238
- if (trimmed.startsWith('//')) {
239
- continue;
240
- }
241
-
242
- // Handle block comment start
243
- if (trimmed.startsWith('/*')) {
244
- if (!trimmed.includes('*/')) {
245
- inBlockComment = true;
246
- }
247
- continue;
248
- }
249
-
250
- // Track brace depth for class scope
251
- braceDepth += (line.match(/\{/g) || []).length;
252
- braceDepth -= (line.match(/\}/g) || []).length;
253
-
254
- if (currentClass && braceDepth === 0) {
255
- // Class ended
256
- const existingSymbol = symbols.find(s => s.name === currentClass!.name && s.kind === 'class');
257
- if (existingSymbol) {
258
- existingSymbol.lineEnd = lineNum;
259
- }
260
- currentClass = null;
261
- }
262
-
263
- // Functions
264
- let match = trimmed.match(patterns.function);
265
- if (match && match[1]) {
266
- symbols.push({
267
- fileId: 0,
268
- filePath,
269
- kind: 'function',
270
- name: match[1],
271
- lineStart: lineNum,
272
- lineEnd: this.findBlockEnd(lines, i),
273
- exported: trimmed.startsWith('export'),
274
- signature: this.extractSignature(trimmed)
275
- });
276
- continue;
277
- }
278
-
279
- // Arrow functions
280
- match = trimmed.match(patterns.arrowFunc);
281
- if (match && match[1]) {
282
- symbols.push({
283
- fileId: 0,
284
- filePath,
285
- kind: 'function',
286
- name: match[1],
287
- lineStart: lineNum,
288
- lineEnd: this.findBlockEnd(lines, i),
289
- exported: trimmed.startsWith('export'),
290
- signature: this.extractSignature(trimmed)
291
- });
292
- continue;
293
- }
294
-
295
- // Classes
296
- match = trimmed.match(patterns.class);
297
- if (match && match[1]) {
298
- currentClass = { name: match[1], startLine: lineNum };
299
- braceDepth = 1; // Reset for class tracking
300
- symbols.push({
301
- fileId: 0,
302
- filePath,
303
- kind: 'class',
304
- name: match[1],
305
- lineStart: lineNum,
306
- lineEnd: lineNum, // Will be updated when class ends
307
- exported: trimmed.startsWith('export')
308
- });
309
- continue;
310
- }
311
-
312
- // Interfaces
313
- match = trimmed.match(patterns.interface);
314
- if (match && match[1]) {
315
- symbols.push({
316
- fileId: 0,
317
- filePath,
318
- kind: 'interface',
319
- name: match[1],
320
- lineStart: lineNum,
321
- lineEnd: this.findBlockEnd(lines, i),
322
- exported: trimmed.startsWith('export')
323
- });
324
- continue;
325
- }
326
-
327
- // Types
328
- match = trimmed.match(patterns.type);
329
- if (match && match[1]) {
330
- symbols.push({
331
- fileId: 0,
332
- filePath,
333
- kind: 'type',
334
- name: match[1],
335
- lineStart: lineNum,
336
- lineEnd: this.findStatementEnd(lines, i),
337
- exported: trimmed.startsWith('export')
338
- });
339
- continue;
340
- }
341
-
342
- // Enums
343
- match = trimmed.match(patterns.enum);
344
- if (match && match[1]) {
345
- symbols.push({
346
- fileId: 0,
347
- filePath,
348
- kind: 'enum',
349
- name: match[1],
350
- lineStart: lineNum,
351
- lineEnd: this.findBlockEnd(lines, i),
352
- exported: trimmed.startsWith('export')
353
- });
354
- continue;
355
- }
356
-
357
- // Methods (when inside a class)
358
- if (currentClass) {
359
- match = trimmed.match(patterns.method);
360
- if (match && match[1] && !['if', 'for', 'while', 'switch', 'catch', 'constructor'].includes(match[1])) {
361
- symbols.push({
362
- fileId: 0,
363
- filePath,
364
- kind: 'method',
365
- name: `${currentClass.name}.${match[1]}`,
366
- lineStart: lineNum,
367
- lineEnd: this.findBlockEnd(lines, i),
368
- exported: false // Methods inherit class export status
369
- });
370
- }
371
- }
372
-
373
- // Imports
374
- match = trimmed.match(patterns.import);
375
- if (match) {
376
- const defaultImport = match[1];
377
- const namedImports = match[2]?.split(',').map(s => s.trim().split(/\s+as\s+/)[0]?.trim()).filter((s): s is string => !!s) || [];
378
- const from = match[3] || '';
379
-
380
- imports.push({
381
- fileId: 0,
382
- filePath,
383
- importedFrom: from,
384
- importedSymbols: defaultImport ? [defaultImport, ...namedImports] : namedImports,
385
- isDefault: !!defaultImport,
386
- isNamespace: false,
387
- lineNumber: lineNum
388
- });
389
- continue;
390
- }
391
-
392
- match = trimmed.match(patterns.importAll);
393
- if (match) {
394
- imports.push({
395
- fileId: 0,
396
- filePath,
397
- importedFrom: match[2] || '',
398
- importedSymbols: ['*'],
399
- isDefault: false,
400
- isNamespace: true,
401
- lineNumber: lineNum
402
- });
403
- continue;
404
- }
405
-
406
- // Exports
407
- match = trimmed.match(patterns.exportDirect);
408
- if (match && match[1]) {
409
- exports.push({
410
- fileId: 0,
411
- filePath,
412
- exportedName: match[1],
413
- isDefault: false,
414
- lineNumber: lineNum
415
- });
416
- continue;
417
- }
418
-
419
- match = trimmed.match(patterns.exportDefault);
420
- if (match) {
421
- exports.push({
422
- fileId: 0,
423
- filePath,
424
- exportedName: match[1] || 'default',
425
- isDefault: true,
426
- lineNumber: lineNum
427
- });
428
- continue;
429
- }
430
-
431
- match = trimmed.match(patterns.exportNamed);
432
- if (match && match[1]) {
433
- const names = match[1].split(',').map(s => {
434
- const parts = s.trim().split(/\s+as\s+/);
435
- return parts[parts.length - 1]?.trim();
436
- }).filter((n): n is string => !!n);
437
-
438
- for (const name of names) {
439
- exports.push({
440
- fileId: 0,
441
- filePath,
442
- exportedName: name,
443
- isDefault: false,
444
- lineNumber: lineNum
445
- });
446
- }
447
- }
448
- }
449
- }
450
-
451
- private parsePython(
452
- filePath: string,
453
- content: string,
454
- lines: string[],
455
- symbols: CodeSymbol[],
456
- imports: Import[],
457
- exports: Export[]
458
- ): void {
459
- const patterns = {
460
- function: /^(?:async\s+)?def\s+(\w+)\s*\(/,
461
- class: /^class\s+(\w+)/,
462
- import: /^import\s+(\w+(?:\.\w+)*)/,
463
- fromImport: /^from\s+(\w+(?:\.\w+)*)\s+import\s+(.+)/,
464
- };
465
-
466
- for (let i = 0; i < lines.length; i++) {
467
- const line = lines[i] || '';
468
- const trimmed = line.trim();
469
- const lineNum = i + 1;
470
- const indent = line.length - line.trimStart().length;
471
-
472
- // Skip comments
473
- if (trimmed.startsWith('#')) continue;
474
-
475
- // Functions
476
- let match = trimmed.match(patterns.function);
477
- if (match && match[1]) {
478
- symbols.push({
479
- fileId: 0,
480
- filePath,
481
- kind: 'function',
482
- name: match[1],
483
- lineStart: lineNum,
484
- lineEnd: this.findPythonBlockEnd(lines, i, indent),
485
- exported: !match[1].startsWith('_'),
486
- signature: trimmed.split(':')[0]
487
- });
488
- continue;
489
- }
490
-
491
- // Classes
492
- match = trimmed.match(patterns.class);
493
- if (match && match[1]) {
494
- symbols.push({
495
- fileId: 0,
496
- filePath,
497
- kind: 'class',
498
- name: match[1],
499
- lineStart: lineNum,
500
- lineEnd: this.findPythonBlockEnd(lines, i, indent),
501
- exported: !match[1].startsWith('_')
502
- });
503
- continue;
504
- }
505
-
506
- // Imports
507
- match = trimmed.match(patterns.import);
508
- if (match && match[1]) {
509
- imports.push({
510
- fileId: 0,
511
- filePath,
512
- importedFrom: match[1],
513
- importedSymbols: [match[1].split('.').pop() || match[1]],
514
- isDefault: false,
515
- isNamespace: true,
516
- lineNumber: lineNum
517
- });
518
- continue;
519
- }
520
-
521
- match = trimmed.match(patterns.fromImport);
522
- if (match) {
523
- const from = match[1] || '';
524
- const imported = match[2]?.split(',').map(s => s.trim().split(/\s+as\s+/)[0]?.trim()).filter((s): s is string => !!s) || [];
525
- imports.push({
526
- fileId: 0,
527
- filePath,
528
- importedFrom: from,
529
- importedSymbols: imported,
530
- isDefault: false,
531
- isNamespace: imported.includes('*'),
532
- lineNumber: lineNum
533
- });
534
- }
535
- }
536
- }
537
-
538
- private parseGo(
539
- filePath: string,
540
- content: string,
541
- lines: string[],
542
- symbols: CodeSymbol[],
543
- imports: Import[],
544
- exports: Export[]
545
- ): void {
546
- let inImportBlock = false;
547
-
548
- for (let i = 0; i < lines.length; i++) {
549
- const line = lines[i] || '';
550
- const trimmed = line.trim();
551
- const lineNum = i + 1;
552
-
553
- // Skip comments
554
- if (trimmed.startsWith('//')) continue;
555
-
556
- // Handle import blocks
557
- if (trimmed === 'import (') {
558
- inImportBlock = true;
559
- continue;
560
- }
561
- if (inImportBlock && trimmed === ')') {
562
- inImportBlock = false;
563
- continue;
564
- }
565
-
566
- // Single import or import block item
567
- const importMatch = inImportBlock
568
- ? trimmed.match(/^(?:(\w+)\s+)?"([^"]+)"/)
569
- : trimmed.match(/^import\s+(?:(\w+)\s+)?"([^"]+)"/);
570
- if (importMatch) {
571
- const alias = importMatch[1];
572
- const path = importMatch[2] || '';
573
- const pkg = alias || path.split('/').pop() || '';
574
- imports.push({
575
- fileId: 0,
576
- filePath,
577
- importedFrom: path,
578
- importedSymbols: [pkg],
579
- isDefault: false,
580
- isNamespace: false,
581
- lineNumber: lineNum
582
- });
583
- continue;
584
- }
585
-
586
- // Functions and methods
587
- const funcMatch = trimmed.match(/^func\s+(?:\((\w+)\s+\*?(\w+)\)\s+)?(\w+)\s*\(/);
588
- if (funcMatch) {
589
- const receiver = funcMatch[2];
590
- const name = receiver ? `${receiver}.${funcMatch[3]}` : (funcMatch[3] || '');
591
- symbols.push({
592
- fileId: 0,
593
- filePath,
594
- kind: receiver ? 'method' : 'function',
595
- name,
596
- lineStart: lineNum,
597
- lineEnd: this.findBlockEnd(lines, i),
598
- exported: /^[A-Z]/.test(funcMatch[3] || ''),
599
- signature: trimmed.split('{')[0]?.trim()
600
- });
601
- continue;
602
- }
603
-
604
- // Structs
605
- const structMatch = trimmed.match(/^type\s+(\w+)\s+struct\s*\{?/);
606
- if (structMatch) {
607
- symbols.push({
608
- fileId: 0,
609
- filePath,
610
- kind: 'class',
611
- name: structMatch[1] || '',
612
- lineStart: lineNum,
613
- lineEnd: this.findBlockEnd(lines, i),
614
- exported: /^[A-Z]/.test(structMatch[1] || '')
615
- });
616
- continue;
617
- }
618
-
619
- // Interfaces
620
- const ifaceMatch = trimmed.match(/^type\s+(\w+)\s+interface\s*\{?/);
621
- if (ifaceMatch) {
622
- symbols.push({
623
- fileId: 0,
624
- filePath,
625
- kind: 'interface',
626
- name: ifaceMatch[1] || '',
627
- lineStart: lineNum,
628
- lineEnd: this.findBlockEnd(lines, i),
629
- exported: /^[A-Z]/.test(ifaceMatch[1] || '')
630
- });
631
- }
632
- }
633
- }
634
-
635
- private parseRust(
636
- filePath: string,
637
- content: string,
638
- lines: string[],
639
- symbols: CodeSymbol[],
640
- imports: Import[],
641
- exports: Export[]
642
- ): void {
643
- for (let i = 0; i < lines.length; i++) {
644
- const line = lines[i] || '';
645
- const trimmed = line.trim();
646
- const lineNum = i + 1;
647
-
648
- // Skip comments
649
- if (trimmed.startsWith('//')) continue;
650
-
651
- // Functions
652
- const fnMatch = trimmed.match(/^(?:pub\s+)?(?:async\s+)?fn\s+(\w+)/);
653
- if (fnMatch) {
654
- symbols.push({
655
- fileId: 0,
656
- filePath,
657
- kind: 'function',
658
- name: fnMatch[1] || '',
659
- lineStart: lineNum,
660
- lineEnd: this.findBlockEnd(lines, i),
661
- exported: trimmed.startsWith('pub'),
662
- signature: trimmed.split('{')[0]?.trim()
663
- });
664
- continue;
665
- }
666
-
667
- // Structs
668
- const structMatch = trimmed.match(/^(?:pub\s+)?struct\s+(\w+)/);
669
- if (structMatch) {
670
- symbols.push({
671
- fileId: 0,
672
- filePath,
673
- kind: 'class',
674
- name: structMatch[1] || '',
675
- lineStart: lineNum,
676
- lineEnd: this.findBlockEnd(lines, i),
677
- exported: trimmed.startsWith('pub')
678
- });
679
- continue;
680
- }
681
-
682
- // Enums
683
- const enumMatch = trimmed.match(/^(?:pub\s+)?enum\s+(\w+)/);
684
- if (enumMatch) {
685
- symbols.push({
686
- fileId: 0,
687
- filePath,
688
- kind: 'enum',
689
- name: enumMatch[1] || '',
690
- lineStart: lineNum,
691
- lineEnd: this.findBlockEnd(lines, i),
692
- exported: trimmed.startsWith('pub')
693
- });
694
- continue;
695
- }
696
-
697
- // Traits (similar to interfaces)
698
- const traitMatch = trimmed.match(/^(?:pub\s+)?trait\s+(\w+)/);
699
- if (traitMatch) {
700
- symbols.push({
701
- fileId: 0,
702
- filePath,
703
- kind: 'interface',
704
- name: traitMatch[1] || '',
705
- lineStart: lineNum,
706
- lineEnd: this.findBlockEnd(lines, i),
707
- exported: trimmed.startsWith('pub')
708
- });
709
- continue;
710
- }
711
-
712
- // Impl blocks
713
- const implMatch = trimmed.match(/^impl\s+(?:<[^>]+>\s+)?(?:(\w+)\s+for\s+)?(\w+)/);
714
- if (implMatch) {
715
- const traitName = implMatch[1];
716
- const typeName = implMatch[2] || '';
717
- const name = traitName ? `${traitName} for ${typeName}` : typeName;
718
- symbols.push({
719
- fileId: 0,
720
- filePath,
721
- kind: 'class',
722
- name: `impl ${name}`,
723
- lineStart: lineNum,
724
- lineEnd: this.findBlockEnd(lines, i),
725
- exported: false
726
- });
727
- continue;
728
- }
729
-
730
- // use statements
731
- const useMatch = trimmed.match(/^(?:pub\s+)?use\s+(.+);/);
732
- if (useMatch) {
733
- const path = (useMatch[1] || '').replace(/::/g, '/');
734
- imports.push({
735
- fileId: 0,
736
- filePath,
737
- importedFrom: path,
738
- importedSymbols: [path.split('/').pop()?.replace(/[{}]/g, '') || ''],
739
- isDefault: false,
740
- isNamespace: path.includes('*'),
741
- lineNumber: lineNum
742
- });
743
- }
744
- }
745
- }
746
-
747
- private parseJava(
748
- filePath: string,
749
- content: string,
750
- lines: string[],
751
- symbols: CodeSymbol[],
752
- imports: Import[],
753
- exports: Export[]
754
- ): void {
755
- let currentClass: string | null = null;
756
-
757
- for (let i = 0; i < lines.length; i++) {
758
- const line = lines[i] || '';
759
- const trimmed = line.trim();
760
- const lineNum = i + 1;
761
-
762
- // Skip comments
763
- if (trimmed.startsWith('//') || trimmed.startsWith('*') || trimmed.startsWith('/*')) continue;
764
-
765
- // Imports
766
- const importMatch = trimmed.match(/^import\s+(?:static\s+)?([^;]+);/);
767
- if (importMatch) {
768
- const path = importMatch[1] || '';
769
- imports.push({
770
- fileId: 0,
771
- filePath,
772
- importedFrom: path,
773
- importedSymbols: [path.split('.').pop() || ''],
774
- isDefault: false,
775
- isNamespace: path.endsWith('*'),
776
- lineNumber: lineNum
777
- });
778
- continue;
779
- }
780
-
781
- // Classes and interfaces
782
- const classMatch = trimmed.match(/^(?:public\s+|private\s+|protected\s+)?(?:abstract\s+)?(?:final\s+)?(class|interface|enum)\s+(\w+)/);
783
- if (classMatch) {
784
- currentClass = classMatch[2] || '';
785
- symbols.push({
786
- fileId: 0,
787
- filePath,
788
- kind: classMatch[1] === 'interface' ? 'interface' : classMatch[1] === 'enum' ? 'enum' : 'class',
789
- name: currentClass,
790
- lineStart: lineNum,
791
- lineEnd: this.findBlockEnd(lines, i),
792
- exported: trimmed.includes('public')
793
- });
794
- continue;
795
- }
796
-
797
- // Methods
798
- const methodMatch = trimmed.match(/^(?:public\s+|private\s+|protected\s+)?(?:static\s+)?(?:final\s+)?(?:synchronized\s+)?(?:abstract\s+)?(?:<[^>]+>\s+)?(\w+(?:<[^>]+>)?)\s+(\w+)\s*\(/);
799
- if (methodMatch && currentClass && !['if', 'for', 'while', 'switch', 'catch', 'class', 'interface', 'enum'].includes(methodMatch[2] || '')) {
800
- const returnType = methodMatch[1];
801
- const methodName = methodMatch[2] || '';
802
- // Skip constructors (name matches class name)
803
- if (methodName !== currentClass) {
804
- symbols.push({
805
- fileId: 0,
806
- filePath,
807
- kind: 'method',
808
- name: `${currentClass}.${methodName}`,
809
- lineStart: lineNum,
810
- lineEnd: this.findBlockEnd(lines, i),
811
- exported: trimmed.includes('public'),
812
- signature: `${returnType} ${methodName}(...)`
813
- });
814
- }
815
- }
816
- }
817
- }
818
-
819
- private findBlockEnd(lines: string[], startIndex: number): number {
820
- let braceCount = 0;
821
- let started = false;
822
-
823
- for (let i = startIndex; i < lines.length; i++) {
824
- const line = lines[i] || '';
825
- for (const char of line) {
826
- if (char === '{') {
827
- braceCount++;
828
- started = true;
829
- } else if (char === '}') {
830
- braceCount--;
831
- if (started && braceCount === 0) {
832
- return i + 1;
833
- }
834
- }
835
- }
836
- }
837
- return startIndex + 1;
838
- }
839
-
840
- private findStatementEnd(lines: string[], startIndex: number): number {
841
- for (let i = startIndex; i < lines.length; i++) {
842
- const line = lines[i] || '';
843
- if (line.includes(';') || (i > startIndex && !line.trim().startsWith('|') && !line.trim().startsWith('&'))) {
844
- return i + 1;
845
- }
846
- }
847
- return startIndex + 1;
848
- }
849
-
850
- private findPythonBlockEnd(lines: string[], startIndex: number, baseIndent: number): number {
851
- for (let i = startIndex + 1; i < lines.length; i++) {
852
- const line = lines[i] || '';
853
- if (line.trim() === '') continue;
854
-
855
- const indent = line.length - line.trimStart().length;
856
- if (indent <= baseIndent) {
857
- return i;
858
- }
859
- }
860
- return lines.length;
861
- }
862
-
863
- private extractSignature(line: string): string {
864
- // Extract function signature from line
865
- const match = line.match(/(?:function\s+\w+|const\s+\w+\s*=\s*(?:async\s+)?)\s*(\([^)]*\))/);
866
- return match?.[1] || '';
867
- }
868
- }