doc-freshness-checker 2.0.23 → 2.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.
Files changed (98) hide show
  1. package/README.md +19 -0
  2. package/dist/config/defaults.js +9 -3
  3. package/dist/config/defaults.js.map +1 -1
  4. package/dist/index.d.ts +6 -1
  5. package/dist/index.js +5 -0
  6. package/dist/index.js.map +1 -1
  7. package/dist/manifests/manifestInventory.d.ts +28 -0
  8. package/dist/manifests/manifestInventory.js +225 -0
  9. package/dist/manifests/manifestInventory.js.map +1 -0
  10. package/dist/manifests/manifestInventory.test.d.ts +1 -0
  11. package/dist/manifests/manifestInventory.test.js +176 -0
  12. package/dist/manifests/manifestInventory.test.js.map +1 -0
  13. package/dist/manifests/validatorConstructors.test.d.ts +1 -0
  14. package/dist/manifests/validatorConstructors.test.js +17 -0
  15. package/dist/manifests/validatorConstructors.test.js.map +1 -0
  16. package/dist/parsers/documentParser.d.ts +2 -3
  17. package/dist/parsers/documentParser.js.map +1 -1
  18. package/dist/parsers/extractorInterface.test.d.ts +1 -0
  19. package/dist/parsers/extractorInterface.test.js +34 -0
  20. package/dist/parsers/extractorInterface.test.js.map +1 -0
  21. package/dist/parsers/extractors/codeSnippetExtractor.js.map +1 -1
  22. package/dist/plugins/plugin.d.ts +5 -1
  23. package/dist/plugins/plugin.js +5 -1
  24. package/dist/plugins/plugin.js.map +1 -1
  25. package/dist/reporters/consoleReporter.d.ts +5 -11
  26. package/dist/reporters/consoleReporter.js +74 -76
  27. package/dist/reporters/consoleReporter.js.map +1 -1
  28. package/dist/reporters/consoleReporter.test.js +22 -27
  29. package/dist/reporters/consoleReporter.test.js.map +1 -1
  30. package/dist/reporters/enhancedReporter.d.ts +51 -7
  31. package/dist/reporters/enhancedReporter.js +128 -74
  32. package/dist/reporters/enhancedReporter.js.map +1 -1
  33. package/dist/reporters/enhancedReporter.test.js +110 -122
  34. package/dist/reporters/enhancedReporter.test.js.map +1 -1
  35. package/dist/reporters/jsonReporter.d.ts +6 -6
  36. package/dist/reporters/jsonReporter.js +24 -14
  37. package/dist/reporters/jsonReporter.js.map +1 -1
  38. package/dist/reporters/jsonReporter.test.js +26 -11
  39. package/dist/reporters/jsonReporter.test.js.map +1 -1
  40. package/dist/reporters/markdownIssueCells.d.ts +7 -0
  41. package/dist/reporters/markdownIssueCells.js +9 -0
  42. package/dist/reporters/markdownIssueCells.js.map +1 -0
  43. package/dist/reporters/markdownReporter.d.ts +2 -7
  44. package/dist/reporters/markdownReporter.js +57 -56
  45. package/dist/reporters/markdownReporter.js.map +1 -1
  46. package/dist/reporters/markdownReporter.test.js +104 -76
  47. package/dist/reporters/markdownReporter.test.js.map +1 -1
  48. package/dist/reporters/publicReporterApi.test.d.ts +1 -0
  49. package/dist/reporters/publicReporterApi.test.js +28 -0
  50. package/dist/reporters/publicReporterApi.test.js.map +1 -0
  51. package/dist/reporters/reportContext.d.ts +12 -0
  52. package/dist/reporters/reportContext.js +8 -0
  53. package/dist/reporters/reportContext.js.map +1 -0
  54. package/dist/reporters/reportContext.test.d.ts +1 -0
  55. package/dist/reporters/reportContext.test.js +30 -0
  56. package/dist/reporters/reportContext.test.js.map +1 -0
  57. package/dist/reporters/reporters.characterization.test.d.ts +1 -0
  58. package/dist/reporters/reporters.characterization.test.js +208 -0
  59. package/dist/reporters/reporters.characterization.test.js.map +1 -0
  60. package/dist/runner.js +67 -63
  61. package/dist/runner.js.map +1 -1
  62. package/dist/runner.test.js +444 -42
  63. package/dist/runner.test.js.map +1 -1
  64. package/dist/semantic/vectorSearch.js +2 -1
  65. package/dist/semantic/vectorSearch.js.map +1 -1
  66. package/dist/semantic/vectorSearch.test.js +2 -2
  67. package/dist/semantic/vectorSearch.test.js.map +1 -1
  68. package/dist/source/sourceIndex.d.ts +39 -0
  69. package/dist/source/sourceIndex.js +444 -0
  70. package/dist/source/sourceIndex.js.map +1 -0
  71. package/dist/source/sourceIndex.largeGlob.test.d.ts +1 -0
  72. package/dist/source/sourceIndex.largeGlob.test.js +29 -0
  73. package/dist/source/sourceIndex.largeGlob.test.js.map +1 -0
  74. package/dist/source/sourceIndex.test.d.ts +1 -0
  75. package/dist/source/sourceIndex.test.js +263 -0
  76. package/dist/source/sourceIndex.test.js.map +1 -0
  77. package/dist/source/sourceValidators.d.ts +7 -0
  78. package/dist/source/sourceValidators.js +8 -0
  79. package/dist/source/sourceValidators.js.map +1 -0
  80. package/dist/source/sourceValidators.test.d.ts +1 -0
  81. package/dist/source/sourceValidators.test.js +17 -0
  82. package/dist/source/sourceValidators.test.js.map +1 -0
  83. package/dist/types.d.ts +34 -2
  84. package/dist/validators/codePatternValidator.d.ts +5 -11
  85. package/dist/validators/codePatternValidator.js +17 -145
  86. package/dist/validators/codePatternValidator.js.map +1 -1
  87. package/dist/validators/codeSnippetValidator.d.ts +5 -18
  88. package/dist/validators/codeSnippetValidator.js +19 -312
  89. package/dist/validators/codeSnippetValidator.js.map +1 -1
  90. package/dist/validators/dependencyValidator.d.ts +0 -5
  91. package/dist/validators/dependencyValidator.js +7 -64
  92. package/dist/validators/dependencyValidator.js.map +1 -1
  93. package/dist/validators/versionValidator.d.ts +1 -10
  94. package/dist/validators/versionValidator.js +7 -157
  95. package/dist/validators/versionValidator.js.map +1 -1
  96. package/dist/validators/versionValidator.test.js +1 -101
  97. package/dist/validators/versionValidator.test.js.map +1 -1
  98. package/package.json +4 -4
@@ -1,175 +1,47 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { glob } from 'glob';
4
1
  import { findSimilar } from '../utils/similarity.js';
5
- /**
6
- * Language-specific source file patterns and code symbol extractors
7
- */
8
- const languageConfigs = {
9
- javascript: {
10
- extensions: ['js', 'jsx', 'mjs', 'cjs'],
11
- patterns: [
12
- { regex: /\bclass\s+([A-Z][a-zA-Z0-9]+)/g, kind: 'class' },
13
- { regex: /\bexport\s+(?:async\s+)?function\s+([a-zA-Z][a-zA-Z0-9]+)/g, kind: 'function' },
14
- { regex: /\bexport\s+const\s+([A-Z][a-zA-Z0-9]+)/g, kind: 'const' },
15
- { regex: /\bfunction\s+([a-zA-Z][a-zA-Z0-9]+)/g, kind: 'function' },
16
- ],
17
- },
18
- typescript: {
19
- extensions: ['ts', 'tsx'],
20
- patterns: [
21
- { regex: /\bclass\s+([A-Z][a-zA-Z0-9]+)/g, kind: 'class' },
22
- { regex: /\binterface\s+([A-Z][a-zA-Z0-9]+)/g, kind: 'interface' },
23
- { regex: /\btype\s+([A-Z][a-zA-Z0-9]+)\s*=/g, kind: 'type' },
24
- { regex: /\bexport\s+(?:async\s+)?function\s+([a-zA-Z][a-zA-Z0-9]+)/g, kind: 'function' },
25
- { regex: /\bexport\s+const\s+([A-Z][a-zA-Z0-9]+)/g, kind: 'const' },
26
- { regex: /\bfunction\s+([a-zA-Z][a-zA-Z0-9]+)/g, kind: 'function' },
27
- ],
28
- },
29
- python: {
30
- extensions: ['py'],
31
- patterns: [
32
- { regex: /\bclass\s+([A-Z][a-zA-Z0-9]+)/g, kind: 'class' },
33
- { regex: /\bdef\s+([a-z_][a-zA-Z0-9_]*)/g, kind: 'function' },
34
- ],
35
- },
36
- go: {
37
- extensions: ['go'],
38
- patterns: [
39
- { regex: /\btype\s+([A-Z][a-zA-Z0-9]+)\s+struct/g, kind: 'struct' },
40
- { regex: /\btype\s+([A-Z][a-zA-Z0-9]+)\s+interface/g, kind: 'interface' },
41
- { regex: /\bfunc\s+(?:\([^)]+\)\s+)?([A-Z][a-zA-Z0-9]+)/g, kind: 'function' },
42
- ],
43
- },
44
- rust: {
45
- extensions: ['rs'],
46
- patterns: [
47
- { regex: /\bstruct\s+([A-Z][a-zA-Z0-9]+)/g, kind: 'struct' },
48
- { regex: /\benum\s+([A-Z][a-zA-Z0-9]+)/g, kind: 'enum' },
49
- { regex: /\btrait\s+([A-Z][a-zA-Z0-9]+)/g, kind: 'trait' },
50
- { regex: /\bpub\s+fn\s+([a-z_][a-zA-Z0-9_]*)/g, kind: 'function' },
51
- { regex: /\bfn\s+([a-z_][a-zA-Z0-9_]*)/g, kind: 'function' },
52
- ],
53
- },
54
- java: {
55
- extensions: ['java'],
56
- patterns: [
57
- { regex: /\bclass\s+([A-Z][a-zA-Z0-9]+)/g, kind: 'class' },
58
- { regex: /\binterface\s+([A-Z][a-zA-Z0-9]+)/g, kind: 'interface' },
59
- { regex: /\benum\s+([A-Z][a-zA-Z0-9]+)/g, kind: 'enum' },
60
- ],
61
- },
62
- };
2
+ import { SourceIndex, languageConfigs as sourceLanguageConfigs } from '../source/sourceIndex.js';
63
3
  import { isIllustrativeSymbol } from '../utils/illustrativePatterns.js';
64
4
  import { createIllustrativeSkippedResult, getRuleSeverity, severityForIllustrative } from '../utils/validation.js';
5
+ const languageConfigs = sourceLanguageConfigs;
65
6
  /**
66
7
  * Validates code patterns exist in source files
67
8
  */
68
9
  export class CodePatternValidator {
10
+ index;
69
11
  /** @internal */
70
12
  incrementalCaptureScope = 'project';
71
13
  /** @internal */
72
14
  incrementalInputsRequiredForGraph = true;
73
15
  sourceIndex;
74
16
  sourceFiles; // Stores file content for vector search
75
- sourceInputs;
76
- sourceInputsAvailable;
77
- capturedInputs;
78
- constructor() {
17
+ incrementalInputs;
18
+ constructor(index = new SourceIndex()) {
19
+ this.index = index;
79
20
  this.sourceIndex = null;
80
21
  this.sourceFiles = null;
81
- this.sourceInputs = null;
82
- this.sourceInputsAvailable = false;
83
- this.capturedInputs = null;
22
+ this.incrementalInputs = null;
84
23
  }
85
24
  async buildSourceIndex(config) {
86
25
  if (this.sourceIndex) {
87
26
  return;
88
27
  }
89
- this.sourceIndex = new Map();
90
- this.sourceFiles = new Map();
91
- this.sourceInputs = new Map();
92
- this.sourceInputsAvailable = true;
93
- // Use configured source patterns or detect automatically
94
- const sourcePatterns = config.sourcePatterns || this.detectSourcePatterns();
95
- for (const pattern of sourcePatterns) {
96
- try {
97
- const files = await glob(pattern, {
98
- cwd: config.rootDir,
99
- absolute: true,
100
- nodir: true,
101
- ignore: ['**/*.test.*', '**/*.spec.*', '**/*.d.ts', '**/node_modules/**', '**/vendor/**'],
102
- });
103
- for (const file of files) {
104
- const absolutePath = path.resolve(file);
105
- if (this.sourceInputs.has(absolutePath)) {
106
- continue;
107
- }
108
- try {
109
- const content = await fs.promises.readFile(absolutePath, 'utf-8');
110
- const relativePath = path.relative(config.rootDir || process.cwd(), absolutePath);
111
- const lang = this.detectLanguage(absolutePath);
112
- this.indexContent(content, relativePath, lang);
113
- // Store file content for vector search
114
- this.sourceFiles.set(relativePath, { content, language: lang });
115
- this.sourceInputs.set(absolutePath, content);
116
- }
117
- catch {
118
- // Skip unreadable files
119
- this.sourceInputsAvailable = false;
120
- }
121
- }
122
- }
123
- catch {
124
- // Skip invalid patterns
125
- this.sourceInputsAvailable = false;
126
- }
28
+ try {
29
+ this.useSnapshot(await this.index.load(config, 'pattern'));
127
30
  }
128
- this.capturedInputs = this.sourceInputsAvailable
129
- ? [...this.sourceInputs].map(([sourcePath, content]) => ({ path: sourcePath, content }))
130
- : null;
131
- }
132
- detectSourcePatterns() {
133
- // Auto-detect based on what files exist
134
- const patterns = [];
135
- for (const conf of Object.values(languageConfigs)) {
136
- for (const ext of conf.extensions) {
137
- patterns.push(`**/*.${ext}`);
138
- }
31
+ catch (error) {
32
+ this.useSnapshot(await this.index.load(config, 'pattern'));
33
+ throw error;
139
34
  }
140
- return patterns;
141
35
  }
142
- detectLanguage(filePath) {
143
- const ext = path.extname(filePath).slice(1).toLowerCase();
144
- for (const [lang, conf] of Object.entries(languageConfigs)) {
145
- if (conf.extensions.includes(ext)) {
146
- return lang;
147
- }
148
- }
149
- return 'javascript';
36
+ useSnapshot(snapshot) {
37
+ this.sourceIndex = snapshot.symbols;
38
+ this.sourceFiles = snapshot.patternFiles;
39
+ this.incrementalInputs = snapshot.patternInputs;
150
40
  }
151
41
  /** @internal */
152
42
  async getIncrementalInputs(_references, _document, config) {
153
43
  await this.buildSourceIndex(config);
154
- return this.capturedInputs;
155
- }
156
- indexContent(content, filePath, language) {
157
- const langConfig = languageConfigs[language];
158
- if (!langConfig) {
159
- return;
160
- }
161
- for (const { regex, kind } of langConfig.patterns) {
162
- let match;
163
- // Clone regex to avoid state issues
164
- const re = new RegExp(regex.source, regex.flags);
165
- while ((match = re.exec(content)) !== null) {
166
- const name = match[1];
167
- if (!this.sourceIndex.has(name)) {
168
- this.sourceIndex.set(name, []);
169
- }
170
- this.sourceIndex.get(name).push({ filePath, kind, language });
171
- }
172
- }
44
+ return this.incrementalInputs;
173
45
  }
174
46
  async validateBatch(references, _document, config) {
175
47
  await this.buildSourceIndex(config);
@@ -1 +1 @@
1
- {"version":3,"file":"codePatternValidator.js","sourceRoot":"","sources":["../../src/validators/codePatternValidator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"codePatternValidator.js","sourceRoot":"","sources":["../../src/validators/codePatternValidator.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,4 @@
1
- import type { DocFreshnessConfig, Document, Reference, ValidationResult } from '../types.js';
2
- interface FunctionSignature {
3
- params: string[];
4
- requiredParams: number;
5
- filePath: string;
6
- }
1
+ import type { DocFreshnessConfig, Document, FunctionSignature, Reference, ValidationResult } from '../types.js';
7
2
  /**
8
3
  * Validates code-snippet references extracted from documentation code blocks.
9
4
  *
@@ -13,15 +8,17 @@ interface FunctionSignature {
13
8
  * 3. Config keys — keys exist in the referenced type/interface
14
9
  */
15
10
  export declare class CodeSnippetValidator {
11
+ private readonly index;
16
12
  private sourceFiles;
17
13
  private functionSignatures;
18
14
  private interfaceKeys;
15
+ private exportsByFile;
19
16
  private customPatterns;
20
- private indexBuilt;
17
+ constructor();
21
18
  validateBatch(references: Reference[], _document: Document, config: DocFreshnessConfig): Promise<ValidationResult[]>;
22
19
  private initCustomPatterns;
23
20
  private buildIndex;
24
- private detectLanguage;
21
+ private useSnapshot;
25
22
  private validateImport;
26
23
  private resolveImportPath;
27
24
  private resolvePythonImportPath;
@@ -29,20 +26,10 @@ export declare class CodeSnippetValidator {
29
26
  private getExportedSymbols;
30
27
  private validateFunctionCall;
31
28
  private validateConfigKeys;
32
- private indexFunctionSignatures;
33
- private addSignature;
34
- private parseParameters;
35
- private extractParamName;
36
- private isOptionalParam;
37
29
  private legacyImportSpecifiers;
38
30
  private extractSpecifiersByPrefix;
39
31
  private validateFunctionParameterNames;
40
32
  private parameterNamesMatch;
41
- private indexInterfaceDefinitions;
42
- private addInterfaceKeys;
43
- private extractBraceContent;
44
- private extractPropertyKeys;
45
33
  getFunctionSignatures(): Map<string, FunctionSignature[]> | null;
46
34
  getInterfaceKeys(): Map<string, Set<string>> | null;
47
35
  }
48
- export {};
@@ -1,19 +1,9 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
- import { glob } from 'glob';
3
+ import { SourceIndex } from '../source/sourceIndex.js';
4
4
  import { isIllustrativePath, isIllustrativeSymbol, compilePatterns } from '../utils/illustrativePatterns.js';
5
5
  import { findSimilar } from '../utils/similarity.js';
6
6
  import { createIllustrativeSkippedResult, getRuleSeverity, severityForIllustrative } from '../utils/validation.js';
7
- const LANG_EXTENSIONS = {
8
- ts: 'typescript',
9
- tsx: 'typescript',
10
- js: 'javascript',
11
- jsx: 'javascript',
12
- mjs: 'javascript',
13
- cjs: 'javascript',
14
- py: 'python',
15
- go: 'go',
16
- };
17
7
  /**
18
8
  * Validates code-snippet references extracted from documentation code blocks.
19
9
  *
@@ -23,11 +13,15 @@ const LANG_EXTENSIONS = {
23
13
  * 3. Config keys — keys exist in the referenced type/interface
24
14
  */
25
15
  export class CodeSnippetValidator {
16
+ index;
26
17
  sourceFiles = null;
27
18
  functionSignatures = null;
28
19
  interfaceKeys = null;
20
+ exportsByFile = null;
29
21
  customPatterns = [];
30
- indexBuilt = false;
22
+ constructor(index = new SourceIndex()) {
23
+ this.index = index;
24
+ }
31
25
  async validateBatch(references, _document, config) {
32
26
  await this.buildIndex(config);
33
27
  const ruleConfig = config.rules?.['code-snippet'];
@@ -59,44 +53,22 @@ export class CodeSnippetValidator {
59
53
  // Index building
60
54
  // ---------------------------------------------------------------------------
61
55
  async buildIndex(config) {
62
- if (this.indexBuilt) {
56
+ if (this.sourceFiles) {
63
57
  return;
64
58
  }
65
- this.indexBuilt = true;
66
- this.sourceFiles = new Map();
67
- this.functionSignatures = new Map();
68
- this.interfaceKeys = new Map();
69
- const rootDir = config.rootDir || process.cwd();
70
- const sourcePatterns = config.sourcePatterns || ['**/*.{ts,tsx,js,jsx,py,go}'];
71
- for (const pattern of sourcePatterns) {
72
- try {
73
- const files = await glob(pattern, {
74
- cwd: rootDir,
75
- absolute: true,
76
- ignore: ['**/*.test.*', '**/*.spec.*', '**/*.d.ts', '**/node_modules/**', '**/vendor/**', '**/dist/**', '**/build/**'],
77
- });
78
- for (const file of files) {
79
- try {
80
- const content = await fs.promises.readFile(file, 'utf-8');
81
- const relativePath = path.relative(rootDir, file);
82
- const lang = this.detectLanguage(file);
83
- this.sourceFiles.set(relativePath, { content, language: lang });
84
- this.indexFunctionSignatures(content, relativePath, lang);
85
- this.indexInterfaceDefinitions(content, relativePath, lang);
86
- }
87
- catch {
88
- /* skip unreadable files */
89
- }
90
- }
91
- }
92
- catch {
93
- /* skip invalid patterns */
94
- }
59
+ try {
60
+ this.useSnapshot(await this.index.load(config, 'snippet'));
61
+ }
62
+ catch (error) {
63
+ this.useSnapshot(await this.index.load(config, 'snippet'));
64
+ throw error;
95
65
  }
96
66
  }
97
- detectLanguage(filePath) {
98
- const ext = path.extname(filePath).slice(1).toLowerCase();
99
- return LANG_EXTENSIONS[ext] || 'javascript';
67
+ useSnapshot(snapshot) {
68
+ this.sourceFiles = snapshot.snippetFiles;
69
+ this.functionSignatures = snapshot.functionSignatures;
70
+ this.interfaceKeys = snapshot.interfaceKeys;
71
+ this.exportsByFile = snapshot.exportsByFile;
100
72
  }
101
73
  // ---------------------------------------------------------------------------
102
74
  // Import validation
@@ -228,77 +200,7 @@ export class CodeSnippetValidator {
228
200
  return null;
229
201
  }
230
202
  getExportedSymbols(filePath) {
231
- const fileData = this.sourceFiles?.get(filePath);
232
- if (!fileData) {
233
- return new Set();
234
- }
235
- const exports = new Set();
236
- const content = fileData.content;
237
- if (fileData.language === 'python') {
238
- const defPattern = /^(?:async\s+)?def\s+([A-Za-z_]\w*)\s*\(/gm;
239
- let pythonMatch;
240
- while ((pythonMatch = defPattern.exec(content)) !== null) {
241
- if (!pythonMatch[1].startsWith('_')) {
242
- exports.add(pythonMatch[1]);
243
- }
244
- }
245
- const classPattern = /^class\s+([A-Za-z_]\w*)\b/gm;
246
- while ((pythonMatch = classPattern.exec(content)) !== null) {
247
- if (!pythonMatch[1].startsWith('_')) {
248
- exports.add(pythonMatch[1]);
249
- }
250
- }
251
- const assignmentPattern = /^([A-Za-z_]\w*)\s*=/gm;
252
- while ((pythonMatch = assignmentPattern.exec(content)) !== null) {
253
- if (!pythonMatch[1].startsWith('_')) {
254
- exports.add(pythonMatch[1]);
255
- }
256
- }
257
- return exports;
258
- }
259
- // export [async] function|class|const|let|var|interface|type|enum Name
260
- const directPattern = /export\s+(?:default\s+)?(?:async\s+)?(?:function|class|const|let|var|interface|type|enum)\s+(\w+)/g;
261
- let match;
262
- while ((match = directPattern.exec(content)) !== null) {
263
- exports.add(match[1]);
264
- }
265
- // export { Name1, Name2 as Alias }
266
- const namedPattern = /export\s*\{([^}]+)\}/g;
267
- while ((match = namedPattern.exec(content)) !== null) {
268
- for (const item of match[1].split(',')) {
269
- const original = item
270
- .trim()
271
- .split(/\s+as\s+/)[0]
272
- .trim();
273
- if (original) {
274
- exports.add(original);
275
- }
276
- }
277
- }
278
- // export default identifier;
279
- const defaultPattern = /export\s+default\s+(\w+)\s*[;\n]/g;
280
- while ((match = defaultPattern.exec(content)) !== null) {
281
- exports.add(match[1]);
282
- exports.add('default');
283
- }
284
- const defaultDeclarationPattern = /export\s+default\s+(?:async\s+)?(?:function|class)\b(?:\s+(\w+))?/g;
285
- while ((match = defaultDeclarationPattern.exec(content)) !== null) {
286
- if (match[1]) {
287
- exports.add(match[1]);
288
- }
289
- exports.add('default');
290
- }
291
- // module.exports = { name1, name2: value }
292
- const cjsPattern = /module\.exports\s*=\s*\{([^}]+)\}/g;
293
- while ((match = cjsPattern.exec(content)) !== null) {
294
- for (const item of match[1].split(',')) {
295
- const name = item.trim().split(/\s*:/)[0].trim();
296
- if (name) {
297
- exports.add(name);
298
- }
299
- }
300
- }
301
- return exports;
203
+ return this.exportsByFile?.get(filePath) || new Set();
302
204
  }
303
205
  // ---------------------------------------------------------------------------
304
206
  // Function call validation
@@ -393,129 +295,6 @@ export class CodeSnippetValidator {
393
295
  suggestion: suggestions.some((s) => s.includes('→')) ? `Did you mean: ${suggestions.join(', ')}?` : null,
394
296
  };
395
297
  }
396
- // ---------------------------------------------------------------------------
397
- // Signature & interface indexing
398
- // ---------------------------------------------------------------------------
399
- indexFunctionSignatures(content, filePath, lang) {
400
- if (lang === 'javascript' || lang === 'typescript') {
401
- const funcPattern = /(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/g;
402
- let match;
403
- while ((match = funcPattern.exec(content)) !== null) {
404
- this.addSignature(match[1], match[2], filePath, lang);
405
- }
406
- // Arrow / const functions
407
- const arrowPattern = /(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\(([^)]*)\)[^{;]*=>/g;
408
- while ((match = arrowPattern.exec(content)) !== null) {
409
- this.addSignature(match[1], match[2], filePath, lang);
410
- }
411
- }
412
- if (lang === 'python') {
413
- const defPattern = /def\s+(\w+)\s*\(([^)]*)\)/g;
414
- let match;
415
- while ((match = defPattern.exec(content)) !== null) {
416
- this.addSignature(match[1], match[2], filePath, lang);
417
- }
418
- }
419
- }
420
- addSignature(name, paramsStr, filePath, lang) {
421
- const { names, requiredCount } = this.parseParameters(paramsStr, lang);
422
- let params = names;
423
- let required = requiredCount;
424
- // Strip Python self/cls
425
- if (lang === 'python' && params.length > 0 && (params[0] === 'self' || params[0] === 'cls')) {
426
- params = params.slice(1);
427
- required = Math.max(0, required - 1);
428
- }
429
- const signatures = this.functionSignatures.get(name) || [];
430
- if (signatures.length === 0) {
431
- this.functionSignatures.set(name, signatures);
432
- }
433
- signatures.push({ params, requiredParams: required, filePath });
434
- }
435
- parseParameters(paramsStr, lang) {
436
- if (!paramsStr.trim()) {
437
- return { names: [], requiredCount: 0 };
438
- }
439
- const rawParams = [];
440
- let depth = 0;
441
- let current = '';
442
- for (const ch of paramsStr) {
443
- if ('(<[{'.includes(ch)) {
444
- depth++;
445
- }
446
- else if (')>]}'.includes(ch)) {
447
- depth--;
448
- }
449
- if (ch === ',' && depth === 0) {
450
- rawParams.push(current.trim());
451
- current = '';
452
- }
453
- else {
454
- current += ch;
455
- }
456
- }
457
- if (current.trim()) {
458
- rawParams.push(current.trim());
459
- }
460
- const names = [];
461
- let requiredCount = 0;
462
- let seenOptional = false;
463
- for (const raw of rawParams) {
464
- const name = this.extractParamName(raw, lang);
465
- if (!name) {
466
- continue;
467
- }
468
- names.push(name);
469
- const isOptional = this.isOptionalParam(raw, lang);
470
- const isRest = raw.trim().startsWith('...') || raw.trim().startsWith('*');
471
- if (!isOptional && !isRest && !seenOptional) {
472
- requiredCount++;
473
- }
474
- else {
475
- seenOptional = true;
476
- }
477
- }
478
- return { names, requiredCount };
479
- }
480
- extractParamName(raw, lang) {
481
- if (!raw) {
482
- return null;
483
- }
484
- if (lang === 'typescript' || lang === 'javascript') {
485
- const match = raw.match(/^(?:\.\.\.)?(\w+)/);
486
- return match ? match[1] : null;
487
- }
488
- if (lang === 'python') {
489
- const match = raw.match(/^\*{0,2}(\w+)/);
490
- return match ? match[1] : null;
491
- }
492
- return null;
493
- }
494
- isOptionalParam(raw, lang) {
495
- if (raw.trim().startsWith('...') || raw.trim().startsWith('*')) {
496
- return true;
497
- }
498
- if (lang === 'typescript' || lang === 'javascript') {
499
- // name? (TS optional marker right after identifier)
500
- if (/^\w+\s*\?/.test(raw.trim())) {
501
- return true;
502
- }
503
- }
504
- // Default value at top level (= but not =>)
505
- let depth = 0;
506
- for (let i = 0; i < raw.length; i++) {
507
- if ('({[<'.includes(raw[i])) {
508
- depth++;
509
- }
510
- else if (')}]>'.includes(raw[i])) {
511
- depth--;
512
- }
513
- if (depth === 0 && raw[i] === '=' && raw[i + 1] !== '>') {
514
- return true;
515
- }
516
- }
517
- return false;
518
- }
519
298
  legacyImportSpecifiers(linkText) {
520
299
  return linkText
521
300
  ? linkText
@@ -560,78 +339,6 @@ export class CodeSnippetValidator {
560
339
  }
561
340
  return argumentNames.every((name, index) => name === parameterNames[index]);
562
341
  }
563
- indexInterfaceDefinitions(content, _filePath, lang) {
564
- if (lang !== 'typescript') {
565
- return;
566
- }
567
- // interface Name { ... }
568
- const ifacePattern = /(?:export\s+)?interface\s+(\w+)(?:\s+extends\s+[\w,\s<>]+)?\s*\{/g;
569
- let match;
570
- while ((match = ifacePattern.exec(content)) !== null) {
571
- this.addInterfaceKeys(match[1], content, match.index + match[0].length - 1);
572
- }
573
- // type Name = { ... }
574
- const typeObjPattern = /(?:export\s+)?type\s+(\w+)\s*=\s*\{/g;
575
- while ((match = typeObjPattern.exec(content)) !== null) {
576
- this.addInterfaceKeys(match[1], content, match.index + match[0].length - 1);
577
- }
578
- }
579
- addInterfaceKeys(name, content, braceStart) {
580
- const body = this.extractBraceContent(content, braceStart);
581
- if (!body) {
582
- return;
583
- }
584
- const keys = this.extractPropertyKeys(body);
585
- if (keys.size === 0) {
586
- return;
587
- }
588
- if (!this.interfaceKeys.has(name)) {
589
- this.interfaceKeys.set(name, new Set());
590
- }
591
- for (const key of keys) {
592
- this.interfaceKeys.get(name).add(key);
593
- }
594
- }
595
- extractBraceContent(content, braceStart) {
596
- let depth = 0;
597
- for (let i = braceStart; i < content.length; i++) {
598
- if (content[i] === '{') {
599
- depth++;
600
- }
601
- else if (content[i] === '}') {
602
- depth--;
603
- if (depth === 0) {
604
- return content.substring(braceStart + 1, i);
605
- }
606
- }
607
- }
608
- return null;
609
- }
610
- extractPropertyKeys(body) {
611
- const keys = new Set();
612
- let depth = 0;
613
- for (const line of body.split('\n')) {
614
- const trimmed = line.trim();
615
- if (!trimmed) {
616
- continue;
617
- }
618
- if (depth === 0) {
619
- const keyMatch = trimmed.match(/^(?:readonly\s+)?(\w+)\??\s*:/);
620
- if (keyMatch) {
621
- keys.add(keyMatch[1]);
622
- }
623
- }
624
- for (const ch of trimmed) {
625
- if (ch === '{') {
626
- depth++;
627
- }
628
- else if (ch === '}') {
629
- depth--;
630
- }
631
- }
632
- }
633
- return keys;
634
- }
635
342
  // Exposed for testing / integration
636
343
  getFunctionSignatures() {
637
344
  return this.functionSignatures;