driftdetect-core 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/dist/analyzers/ast-analyzer.d.ts +251 -0
- package/dist/analyzers/ast-analyzer.d.ts.map +1 -0
- package/dist/analyzers/ast-analyzer.js +548 -0
- package/dist/analyzers/ast-analyzer.js.map +1 -0
- package/dist/analyzers/flow-analyzer.d.ts +241 -0
- package/dist/analyzers/flow-analyzer.d.ts.map +1 -0
- package/dist/analyzers/flow-analyzer.js +1219 -0
- package/dist/analyzers/flow-analyzer.js.map +1 -0
- package/dist/analyzers/index.d.ts +18 -0
- package/dist/analyzers/index.d.ts.map +1 -0
- package/dist/analyzers/index.js +19 -0
- package/dist/analyzers/index.js.map +1 -0
- package/dist/analyzers/semantic-analyzer.d.ts +252 -0
- package/dist/analyzers/semantic-analyzer.d.ts.map +1 -0
- package/dist/analyzers/semantic-analyzer.js +1182 -0
- package/dist/analyzers/semantic-analyzer.js.map +1 -0
- package/dist/analyzers/type-analyzer.d.ts +289 -0
- package/dist/analyzers/type-analyzer.d.ts.map +1 -0
- package/dist/analyzers/type-analyzer.js +1269 -0
- package/dist/analyzers/type-analyzer.js.map +1 -0
- package/dist/analyzers/types.d.ts +537 -0
- package/dist/analyzers/types.d.ts.map +1 -0
- package/dist/analyzers/types.js +11 -0
- package/dist/analyzers/types.js.map +1 -0
- package/dist/config/config-loader.d.ts +166 -0
- package/dist/config/config-loader.d.ts.map +1 -0
- package/dist/config/config-loader.js +429 -0
- package/dist/config/config-loader.js.map +1 -0
- package/dist/config/config-validator.d.ts +204 -0
- package/dist/config/config-validator.d.ts.map +1 -0
- package/dist/config/config-validator.js +632 -0
- package/dist/config/config-validator.js.map +1 -0
- package/dist/config/defaults.d.ts +8 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +26 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +10 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +10 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/types.d.ts +47 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +7 -0
- package/dist/config/types.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest/exporter.d.ts +21 -0
- package/dist/manifest/exporter.d.ts.map +1 -0
- package/dist/manifest/exporter.js +339 -0
- package/dist/manifest/exporter.js.map +1 -0
- package/dist/manifest/index.d.ts +14 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +15 -0
- package/dist/manifest/index.js.map +1 -0
- package/dist/manifest/manifest-store.d.ts +111 -0
- package/dist/manifest/manifest-store.d.ts.map +1 -0
- package/dist/manifest/manifest-store.js +418 -0
- package/dist/manifest/manifest-store.js.map +1 -0
- package/dist/manifest/types.d.ts +238 -0
- package/dist/manifest/types.d.ts.map +1 -0
- package/dist/manifest/types.js +11 -0
- package/dist/manifest/types.js.map +1 -0
- package/dist/matcher/confidence-scorer.d.ts +188 -0
- package/dist/matcher/confidence-scorer.d.ts.map +1 -0
- package/dist/matcher/confidence-scorer.js +302 -0
- package/dist/matcher/confidence-scorer.js.map +1 -0
- package/dist/matcher/index.d.ts +24 -0
- package/dist/matcher/index.d.ts.map +1 -0
- package/dist/matcher/index.js +26 -0
- package/dist/matcher/index.js.map +1 -0
- package/dist/matcher/outlier-detector.d.ts +252 -0
- package/dist/matcher/outlier-detector.d.ts.map +1 -0
- package/dist/matcher/outlier-detector.js +544 -0
- package/dist/matcher/outlier-detector.js.map +1 -0
- package/dist/matcher/pattern-matcher.d.ts +169 -0
- package/dist/matcher/pattern-matcher.d.ts.map +1 -0
- package/dist/matcher/pattern-matcher.js +692 -0
- package/dist/matcher/pattern-matcher.js.map +1 -0
- package/dist/matcher/types.d.ts +476 -0
- package/dist/matcher/types.d.ts.map +1 -0
- package/dist/matcher/types.js +36 -0
- package/dist/matcher/types.js.map +1 -0
- package/dist/parsers/base-parser.d.ts +282 -0
- package/dist/parsers/base-parser.d.ts.map +1 -0
- package/dist/parsers/base-parser.js +421 -0
- package/dist/parsers/base-parser.js.map +1 -0
- package/dist/parsers/css-parser.d.ts +225 -0
- package/dist/parsers/css-parser.d.ts.map +1 -0
- package/dist/parsers/css-parser.js +477 -0
- package/dist/parsers/css-parser.js.map +1 -0
- package/dist/parsers/index.d.ts +15 -0
- package/dist/parsers/index.d.ts.map +1 -0
- package/dist/parsers/index.js +15 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/parsers/json-parser.d.ts +219 -0
- package/dist/parsers/json-parser.d.ts.map +1 -0
- package/dist/parsers/json-parser.js +602 -0
- package/dist/parsers/json-parser.js.map +1 -0
- package/dist/parsers/markdown-parser.d.ts +276 -0
- package/dist/parsers/markdown-parser.d.ts.map +1 -0
- package/dist/parsers/markdown-parser.js +731 -0
- package/dist/parsers/markdown-parser.js.map +1 -0
- package/dist/parsers/parser-manager.d.ts +294 -0
- package/dist/parsers/parser-manager.d.ts.map +1 -0
- package/dist/parsers/parser-manager.js +738 -0
- package/dist/parsers/parser-manager.js.map +1 -0
- package/dist/parsers/python-parser.d.ts +204 -0
- package/dist/parsers/python-parser.d.ts.map +1 -0
- package/dist/parsers/python-parser.js +517 -0
- package/dist/parsers/python-parser.js.map +1 -0
- package/dist/parsers/types.d.ts +43 -0
- package/dist/parsers/types.d.ts.map +1 -0
- package/dist/parsers/types.js +7 -0
- package/dist/parsers/types.js.map +1 -0
- package/dist/parsers/typescript-parser.d.ts +264 -0
- package/dist/parsers/typescript-parser.d.ts.map +1 -0
- package/dist/parsers/typescript-parser.js +658 -0
- package/dist/parsers/typescript-parser.js.map +1 -0
- package/dist/rules/evaluator.d.ts +305 -0
- package/dist/rules/evaluator.d.ts.map +1 -0
- package/dist/rules/evaluator.js +579 -0
- package/dist/rules/evaluator.js.map +1 -0
- package/dist/rules/index.d.ts +13 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +13 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/quick-fix-generator.d.ts +334 -0
- package/dist/rules/quick-fix-generator.d.ts.map +1 -0
- package/dist/rules/quick-fix-generator.js +1075 -0
- package/dist/rules/quick-fix-generator.js.map +1 -0
- package/dist/rules/rule-engine.d.ts +241 -0
- package/dist/rules/rule-engine.d.ts.map +1 -0
- package/dist/rules/rule-engine.js +585 -0
- package/dist/rules/rule-engine.js.map +1 -0
- package/dist/rules/severity-manager.d.ts +394 -0
- package/dist/rules/severity-manager.d.ts.map +1 -0
- package/dist/rules/severity-manager.js +619 -0
- package/dist/rules/severity-manager.js.map +1 -0
- package/dist/rules/types.d.ts +370 -0
- package/dist/rules/types.d.ts.map +1 -0
- package/dist/rules/types.js +133 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/rules/variant-manager.d.ts +388 -0
- package/dist/rules/variant-manager.d.ts.map +1 -0
- package/dist/rules/variant-manager.js +777 -0
- package/dist/rules/variant-manager.js.map +1 -0
- package/dist/scanner/change-detector.d.ts +164 -0
- package/dist/scanner/change-detector.d.ts.map +1 -0
- package/dist/scanner/change-detector.js +263 -0
- package/dist/scanner/change-detector.js.map +1 -0
- package/dist/scanner/dependency-graph.d.ts +270 -0
- package/dist/scanner/dependency-graph.d.ts.map +1 -0
- package/dist/scanner/dependency-graph.js +436 -0
- package/dist/scanner/dependency-graph.js.map +1 -0
- package/dist/scanner/file-walker.d.ts +127 -0
- package/dist/scanner/file-walker.d.ts.map +1 -0
- package/dist/scanner/file-walker.js +526 -0
- package/dist/scanner/file-walker.js.map +1 -0
- package/dist/scanner/index.d.ts +12 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +12 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/types.d.ts +218 -0
- package/dist/scanner/types.d.ts.map +1 -0
- package/dist/scanner/types.js +10 -0
- package/dist/scanner/types.js.map +1 -0
- package/dist/scanner/worker-pool.d.ts +317 -0
- package/dist/scanner/worker-pool.d.ts.map +1 -0
- package/dist/scanner/worker-pool.js +571 -0
- package/dist/scanner/worker-pool.js.map +1 -0
- package/dist/store/cache-manager.d.ts +179 -0
- package/dist/store/cache-manager.d.ts.map +1 -0
- package/dist/store/cache-manager.js +391 -0
- package/dist/store/cache-manager.js.map +1 -0
- package/dist/store/history-store.d.ts +314 -0
- package/dist/store/history-store.d.ts.map +1 -0
- package/dist/store/history-store.js +707 -0
- package/dist/store/history-store.js.map +1 -0
- package/dist/store/index.d.ts +20 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +26 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/lock-file-manager.d.ts +202 -0
- package/dist/store/lock-file-manager.d.ts.map +1 -0
- package/dist/store/lock-file-manager.js +475 -0
- package/dist/store/lock-file-manager.js.map +1 -0
- package/dist/store/pattern-store.d.ts +289 -0
- package/dist/store/pattern-store.d.ts.map +1 -0
- package/dist/store/pattern-store.js +936 -0
- package/dist/store/pattern-store.js.map +1 -0
- package/dist/store/schema-validator.d.ts +159 -0
- package/dist/store/schema-validator.d.ts.map +1 -0
- package/dist/store/schema-validator.js +1096 -0
- package/dist/store/schema-validator.js.map +1 -0
- package/dist/store/types.d.ts +585 -0
- package/dist/store/types.d.ts.map +1 -0
- package/dist/store/types.js +82 -0
- package/dist/store/types.js.map +1 -0
- package/dist/types/analysis.d.ts +19 -0
- package/dist/types/analysis.d.ts.map +1 -0
- package/dist/types/analysis.js +5 -0
- package/dist/types/analysis.js.map +1 -0
- package/dist/types/common.d.ts +7 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +5 -0
- package/dist/types/common.js.map +1 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +10 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/patterns.d.ts +40 -0
- package/dist/types/patterns.d.ts.map +1 -0
- package/dist/types/patterns.js +7 -0
- package/dist/types/patterns.js.map +1 -0
- package/dist/types/violations.d.ts +7 -0
- package/dist/types/violations.d.ts.map +1 -0
- package/dist/types/violations.js +7 -0
- package/dist/types/violations.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,1182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic Analyzer - Symbol resolution and scope analysis
|
|
3
|
+
*
|
|
4
|
+
* Provides symbol resolution, scope analysis, symbol table construction,
|
|
5
|
+
* detection of unresolved references, and detection of shadowed variables.
|
|
6
|
+
* Supports TypeScript/JavaScript scope rules.
|
|
7
|
+
*
|
|
8
|
+
* @requirements 3.5 - Parser SHALL provide a unified AST query interface across all languages
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Built-in global symbols for JavaScript/TypeScript
|
|
12
|
+
*/
|
|
13
|
+
const BUILTIN_GLOBALS = new Set([
|
|
14
|
+
// Global objects
|
|
15
|
+
'globalThis', 'window', 'self', 'global',
|
|
16
|
+
// Console
|
|
17
|
+
'console',
|
|
18
|
+
// Timers
|
|
19
|
+
'setTimeout', 'clearTimeout', 'setInterval', 'clearInterval',
|
|
20
|
+
'setImmediate', 'clearImmediate',
|
|
21
|
+
// Encoding
|
|
22
|
+
'atob', 'btoa',
|
|
23
|
+
// Fetch API
|
|
24
|
+
'fetch', 'Request', 'Response', 'Headers',
|
|
25
|
+
// URL
|
|
26
|
+
'URL', 'URLSearchParams',
|
|
27
|
+
// Events
|
|
28
|
+
'Event', 'CustomEvent', 'EventTarget',
|
|
29
|
+
// DOM (browser)
|
|
30
|
+
'document', 'navigator', 'location', 'history',
|
|
31
|
+
// Node.js
|
|
32
|
+
'process', 'Buffer', '__dirname', '__filename', 'module', 'exports', 'require',
|
|
33
|
+
// Built-in constructors
|
|
34
|
+
'Object', 'Array', 'String', 'Number', 'Boolean', 'Symbol', 'BigInt',
|
|
35
|
+
'Function', 'Date', 'RegExp', 'Error', 'TypeError', 'RangeError',
|
|
36
|
+
'SyntaxError', 'ReferenceError', 'EvalError', 'URIError',
|
|
37
|
+
'Map', 'Set', 'WeakMap', 'WeakSet',
|
|
38
|
+
'Promise', 'Proxy', 'Reflect',
|
|
39
|
+
'ArrayBuffer', 'SharedArrayBuffer', 'DataView',
|
|
40
|
+
'Int8Array', 'Uint8Array', 'Uint8ClampedArray',
|
|
41
|
+
'Int16Array', 'Uint16Array', 'Int32Array', 'Uint32Array',
|
|
42
|
+
'Float32Array', 'Float64Array', 'BigInt64Array', 'BigUint64Array',
|
|
43
|
+
// Built-in functions
|
|
44
|
+
'eval', 'isFinite', 'isNaN', 'parseFloat', 'parseInt',
|
|
45
|
+
'decodeURI', 'decodeURIComponent', 'encodeURI', 'encodeURIComponent',
|
|
46
|
+
// Math and JSON
|
|
47
|
+
'Math', 'JSON', 'Intl',
|
|
48
|
+
// TypeScript
|
|
49
|
+
'undefined', 'NaN', 'Infinity',
|
|
50
|
+
]);
|
|
51
|
+
/**
|
|
52
|
+
* Semantic Analyzer class for symbol resolution and scope analysis.
|
|
53
|
+
*
|
|
54
|
+
* Provides a unified interface for analyzing semantic information across
|
|
55
|
+
* TypeScript and JavaScript code.
|
|
56
|
+
*
|
|
57
|
+
* @requirements 3.5 - Unified AST query interface across all languages
|
|
58
|
+
*/
|
|
59
|
+
export class SemanticAnalyzer {
|
|
60
|
+
/** Counter for generating unique scope IDs */
|
|
61
|
+
scopeIdCounter = 0;
|
|
62
|
+
/** All scopes discovered during analysis */
|
|
63
|
+
scopes = new Map();
|
|
64
|
+
/** Global symbol table */
|
|
65
|
+
symbolTable = new Map();
|
|
66
|
+
/** Unresolved references found during analysis */
|
|
67
|
+
unresolvedReferences = [];
|
|
68
|
+
/** Shadowed variables found during analysis */
|
|
69
|
+
shadowedVariables = [];
|
|
70
|
+
/** Current analysis options */
|
|
71
|
+
options = {};
|
|
72
|
+
/**
|
|
73
|
+
* Analyze an AST and produce semantic analysis results.
|
|
74
|
+
*
|
|
75
|
+
* @param ast - The AST to analyze
|
|
76
|
+
* @param options - Analysis options
|
|
77
|
+
* @returns Semantic analysis result
|
|
78
|
+
*/
|
|
79
|
+
analyze(ast, options = {}) {
|
|
80
|
+
// Reset state for fresh analysis
|
|
81
|
+
this.reset();
|
|
82
|
+
this.options = options;
|
|
83
|
+
// Create global scope
|
|
84
|
+
const globalScope = this.createScope('global', null, {
|
|
85
|
+
start: ast.rootNode.startPosition,
|
|
86
|
+
end: ast.rootNode.endPosition,
|
|
87
|
+
});
|
|
88
|
+
// Add built-in symbols if requested
|
|
89
|
+
if (options.includeBuiltins !== false) {
|
|
90
|
+
this.addBuiltinSymbols(globalScope);
|
|
91
|
+
}
|
|
92
|
+
// First pass: collect all declarations and build scope tree
|
|
93
|
+
this.collectDeclarations(ast.rootNode, globalScope.id);
|
|
94
|
+
// Second pass: resolve references
|
|
95
|
+
if (options.trackReferences !== false) {
|
|
96
|
+
this.resolveReferences(ast.rootNode, globalScope.id);
|
|
97
|
+
}
|
|
98
|
+
// Build result
|
|
99
|
+
return this.buildResult();
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Resolve a symbol reference to its definition.
|
|
103
|
+
*
|
|
104
|
+
* @param name - The symbol name to resolve
|
|
105
|
+
* @param scopeId - The scope to start resolution from
|
|
106
|
+
* @returns The resolved symbol info, or null if not found
|
|
107
|
+
*/
|
|
108
|
+
resolveSymbol(name, scopeId) {
|
|
109
|
+
let currentScopeId = scopeId;
|
|
110
|
+
while (currentScopeId !== null) {
|
|
111
|
+
const scope = this.scopes.get(currentScopeId);
|
|
112
|
+
if (!scope)
|
|
113
|
+
break;
|
|
114
|
+
const symbol = scope.symbols.get(name);
|
|
115
|
+
if (symbol) {
|
|
116
|
+
return symbol;
|
|
117
|
+
}
|
|
118
|
+
currentScopeId = scope.parentId;
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Get all symbols visible from a given scope.
|
|
124
|
+
*
|
|
125
|
+
* @param scopeId - The scope to get visible symbols from
|
|
126
|
+
* @returns Map of symbol names to symbol info
|
|
127
|
+
*/
|
|
128
|
+
getVisibleSymbols(scopeId) {
|
|
129
|
+
const visible = new Map();
|
|
130
|
+
let currentScopeId = scopeId;
|
|
131
|
+
while (currentScopeId !== null) {
|
|
132
|
+
const scope = this.scopes.get(currentScopeId);
|
|
133
|
+
if (!scope)
|
|
134
|
+
break;
|
|
135
|
+
// Add symbols from this scope (don't override closer scopes)
|
|
136
|
+
for (const [name, symbol] of scope.symbols) {
|
|
137
|
+
if (!visible.has(name)) {
|
|
138
|
+
visible.set(name, symbol);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
currentScopeId = scope.parentId;
|
|
142
|
+
}
|
|
143
|
+
return visible;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Get the scope containing a specific position.
|
|
147
|
+
*
|
|
148
|
+
* @param position - The position to find scope for
|
|
149
|
+
* @returns The most specific scope at that position, or null
|
|
150
|
+
*/
|
|
151
|
+
getScopeAtPosition(position) {
|
|
152
|
+
let result = null;
|
|
153
|
+
for (const scope of this.scopes.values()) {
|
|
154
|
+
if (this.positionInRange(position, scope.location.start, scope.location.end)) {
|
|
155
|
+
// Keep the most specific (deepest) scope
|
|
156
|
+
if (!result || scope.depth > result.depth) {
|
|
157
|
+
result = scope;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return result ? this.toScopeInfo(result) : null;
|
|
162
|
+
}
|
|
163
|
+
// ============================================
|
|
164
|
+
// Private Helper Methods
|
|
165
|
+
// ============================================
|
|
166
|
+
/**
|
|
167
|
+
* Reset analyzer state for fresh analysis.
|
|
168
|
+
*/
|
|
169
|
+
reset() {
|
|
170
|
+
this.scopeIdCounter = 0;
|
|
171
|
+
this.scopes.clear();
|
|
172
|
+
this.symbolTable.clear();
|
|
173
|
+
this.unresolvedReferences = [];
|
|
174
|
+
this.shadowedVariables = [];
|
|
175
|
+
this.options = {};
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Create a new scope.
|
|
179
|
+
*/
|
|
180
|
+
createScope(kind, parentId, location) {
|
|
181
|
+
const id = `scope_${this.scopeIdCounter++}`;
|
|
182
|
+
const parentScope = parentId ? this.scopes.get(parentId) : null;
|
|
183
|
+
const depth = parentScope ? parentScope.depth + 1 : 0;
|
|
184
|
+
const scope = {
|
|
185
|
+
id,
|
|
186
|
+
kind,
|
|
187
|
+
parentId,
|
|
188
|
+
childIds: [],
|
|
189
|
+
symbols: new Map(),
|
|
190
|
+
location,
|
|
191
|
+
depth,
|
|
192
|
+
};
|
|
193
|
+
this.scopes.set(id, scope);
|
|
194
|
+
// Add to parent's children
|
|
195
|
+
if (parentScope) {
|
|
196
|
+
parentScope.childIds.push(id);
|
|
197
|
+
}
|
|
198
|
+
return scope;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Add built-in global symbols.
|
|
202
|
+
*/
|
|
203
|
+
addBuiltinSymbols(globalScope) {
|
|
204
|
+
for (const name of BUILTIN_GLOBALS) {
|
|
205
|
+
const symbol = this.createSymbol(name, 'variable', globalScope.id, {
|
|
206
|
+
start: { row: 0, column: 0 },
|
|
207
|
+
end: { row: 0, column: 0 },
|
|
208
|
+
});
|
|
209
|
+
symbol.visibility = 'public';
|
|
210
|
+
symbol.isExported = false;
|
|
211
|
+
symbol.isImported = false;
|
|
212
|
+
globalScope.symbols.set(name, symbol);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Create a new symbol.
|
|
217
|
+
*/
|
|
218
|
+
createSymbol(name, kind, scopeId, location) {
|
|
219
|
+
return {
|
|
220
|
+
name,
|
|
221
|
+
kind,
|
|
222
|
+
location,
|
|
223
|
+
scopeId,
|
|
224
|
+
visibility: 'default',
|
|
225
|
+
isExported: false,
|
|
226
|
+
isImported: false,
|
|
227
|
+
references: [],
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Add a symbol to a scope, checking for shadowing.
|
|
232
|
+
*/
|
|
233
|
+
addSymbolToScope(symbol, scopeId) {
|
|
234
|
+
const scope = this.scopes.get(scopeId);
|
|
235
|
+
if (!scope)
|
|
236
|
+
return;
|
|
237
|
+
// Check for shadowing in parent scopes
|
|
238
|
+
if (this.options.detectShadowing !== false) {
|
|
239
|
+
const existingSymbol = this.resolveSymbol(symbol.name, scope.parentId || '');
|
|
240
|
+
if (existingSymbol && existingSymbol.scopeId !== scopeId) {
|
|
241
|
+
this.shadowedVariables.push({
|
|
242
|
+
name: symbol.name,
|
|
243
|
+
shadowLocation: symbol.location,
|
|
244
|
+
originalLocation: existingSymbol.location,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Check for redeclaration in same scope (for let/const)
|
|
249
|
+
const existingInScope = scope.symbols.get(symbol.name);
|
|
250
|
+
if (existingInScope) {
|
|
251
|
+
// This is a redeclaration - could be an error depending on context
|
|
252
|
+
// For now, we just update the symbol
|
|
253
|
+
}
|
|
254
|
+
scope.symbols.set(symbol.name, symbol);
|
|
255
|
+
this.symbolTable.set(`${scopeId}:${symbol.name}`, symbol);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Collect declarations from AST nodes.
|
|
259
|
+
*/
|
|
260
|
+
collectDeclarations(node, scopeId) {
|
|
261
|
+
const nodeType = node.type;
|
|
262
|
+
// Check max depth
|
|
263
|
+
const scope = this.scopes.get(scopeId);
|
|
264
|
+
if (scope && this.options.maxScopeDepth !== undefined &&
|
|
265
|
+
scope.depth >= this.options.maxScopeDepth) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
// Handle different declaration types
|
|
269
|
+
switch (nodeType) {
|
|
270
|
+
case 'program':
|
|
271
|
+
case 'Program':
|
|
272
|
+
// Module scope (treat as global for now)
|
|
273
|
+
this.collectChildDeclarations(node, scopeId);
|
|
274
|
+
break;
|
|
275
|
+
case 'function_declaration':
|
|
276
|
+
case 'FunctionDeclaration':
|
|
277
|
+
this.collectFunctionDeclaration(node, scopeId);
|
|
278
|
+
break;
|
|
279
|
+
case 'arrow_function':
|
|
280
|
+
case 'ArrowFunctionExpression':
|
|
281
|
+
this.collectArrowFunction(node, scopeId);
|
|
282
|
+
break;
|
|
283
|
+
case 'method_definition':
|
|
284
|
+
case 'MethodDefinition':
|
|
285
|
+
this.collectMethodDefinition(node, scopeId);
|
|
286
|
+
break;
|
|
287
|
+
case 'class_declaration':
|
|
288
|
+
case 'ClassDeclaration':
|
|
289
|
+
this.collectClassDeclaration(node, scopeId);
|
|
290
|
+
break;
|
|
291
|
+
case 'variable_declaration':
|
|
292
|
+
case 'VariableDeclaration':
|
|
293
|
+
case 'lexical_declaration':
|
|
294
|
+
this.collectVariableDeclaration(node, scopeId);
|
|
295
|
+
break;
|
|
296
|
+
case 'import_statement':
|
|
297
|
+
case 'ImportDeclaration':
|
|
298
|
+
this.collectImportDeclaration(node, scopeId);
|
|
299
|
+
break;
|
|
300
|
+
case 'export_statement':
|
|
301
|
+
case 'ExportNamedDeclaration':
|
|
302
|
+
case 'ExportDefaultDeclaration':
|
|
303
|
+
this.collectExportDeclaration(node, scopeId);
|
|
304
|
+
break;
|
|
305
|
+
case 'interface_declaration':
|
|
306
|
+
case 'TSInterfaceDeclaration':
|
|
307
|
+
this.collectInterfaceDeclaration(node, scopeId);
|
|
308
|
+
break;
|
|
309
|
+
case 'type_alias_declaration':
|
|
310
|
+
case 'TSTypeAliasDeclaration':
|
|
311
|
+
this.collectTypeAliasDeclaration(node, scopeId);
|
|
312
|
+
break;
|
|
313
|
+
case 'enum_declaration':
|
|
314
|
+
case 'TSEnumDeclaration':
|
|
315
|
+
this.collectEnumDeclaration(node, scopeId);
|
|
316
|
+
break;
|
|
317
|
+
case 'statement_block':
|
|
318
|
+
case 'BlockStatement':
|
|
319
|
+
this.collectBlockStatement(node, scopeId);
|
|
320
|
+
break;
|
|
321
|
+
case 'for_statement':
|
|
322
|
+
case 'ForStatement':
|
|
323
|
+
case 'for_in_statement':
|
|
324
|
+
case 'ForInStatement':
|
|
325
|
+
case 'for_of_statement':
|
|
326
|
+
case 'ForOfStatement':
|
|
327
|
+
this.collectForStatement(node, scopeId);
|
|
328
|
+
break;
|
|
329
|
+
case 'if_statement':
|
|
330
|
+
case 'IfStatement':
|
|
331
|
+
this.collectIfStatement(node, scopeId);
|
|
332
|
+
break;
|
|
333
|
+
case 'switch_statement':
|
|
334
|
+
case 'SwitchStatement':
|
|
335
|
+
this.collectSwitchStatement(node, scopeId);
|
|
336
|
+
break;
|
|
337
|
+
case 'try_statement':
|
|
338
|
+
case 'TryStatement':
|
|
339
|
+
this.collectTryStatement(node, scopeId);
|
|
340
|
+
break;
|
|
341
|
+
case 'catch_clause':
|
|
342
|
+
case 'CatchClause':
|
|
343
|
+
this.collectCatchClause(node, scopeId);
|
|
344
|
+
break;
|
|
345
|
+
default:
|
|
346
|
+
// Recurse into children for other node types
|
|
347
|
+
this.collectChildDeclarations(node, scopeId);
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Collect declarations from child nodes.
|
|
353
|
+
*/
|
|
354
|
+
collectChildDeclarations(node, scopeId) {
|
|
355
|
+
for (const child of node.children) {
|
|
356
|
+
this.collectDeclarations(child, scopeId);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Collect function declaration.
|
|
361
|
+
*/
|
|
362
|
+
collectFunctionDeclaration(node, scopeId) {
|
|
363
|
+
const nameNode = this.findChildByType(node, 'identifier') ||
|
|
364
|
+
this.findChildByType(node, 'Identifier');
|
|
365
|
+
const name = nameNode?.text || '<anonymous>';
|
|
366
|
+
// Add function symbol to current scope
|
|
367
|
+
const symbol = this.createSymbol(name, 'function', scopeId, {
|
|
368
|
+
start: node.startPosition,
|
|
369
|
+
end: node.endPosition,
|
|
370
|
+
});
|
|
371
|
+
symbol.parameters = this.extractParameters(node);
|
|
372
|
+
this.addSymbolToScope(symbol, scopeId);
|
|
373
|
+
// Create function scope
|
|
374
|
+
const funcScope = this.createScope('function', scopeId, {
|
|
375
|
+
start: node.startPosition,
|
|
376
|
+
end: node.endPosition,
|
|
377
|
+
});
|
|
378
|
+
// Add parameters to function scope
|
|
379
|
+
for (const param of symbol.parameters || []) {
|
|
380
|
+
const paramSymbol = this.createSymbol(param.name, 'parameter', funcScope.id, param.location);
|
|
381
|
+
this.addSymbolToScope(paramSymbol, funcScope.id);
|
|
382
|
+
}
|
|
383
|
+
// Process function body
|
|
384
|
+
const body = this.findChildByType(node, 'statement_block') ||
|
|
385
|
+
this.findChildByType(node, 'BlockStatement');
|
|
386
|
+
if (body) {
|
|
387
|
+
this.collectChildDeclarations(body, funcScope.id);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Collect arrow function.
|
|
392
|
+
*/
|
|
393
|
+
collectArrowFunction(node, scopeId) {
|
|
394
|
+
// Create function scope
|
|
395
|
+
const funcScope = this.createScope('function', scopeId, {
|
|
396
|
+
start: node.startPosition,
|
|
397
|
+
end: node.endPosition,
|
|
398
|
+
});
|
|
399
|
+
// Extract and add parameters
|
|
400
|
+
const params = this.extractParameters(node);
|
|
401
|
+
for (const param of params) {
|
|
402
|
+
const paramSymbol = this.createSymbol(param.name, 'parameter', funcScope.id, param.location);
|
|
403
|
+
this.addSymbolToScope(paramSymbol, funcScope.id);
|
|
404
|
+
}
|
|
405
|
+
// Process body
|
|
406
|
+
const body = this.findChildByType(node, 'statement_block') ||
|
|
407
|
+
this.findChildByType(node, 'BlockStatement');
|
|
408
|
+
if (body) {
|
|
409
|
+
this.collectChildDeclarations(body, funcScope.id);
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
// Expression body - still process for nested functions
|
|
413
|
+
this.collectChildDeclarations(node, funcScope.id);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Collect method definition.
|
|
418
|
+
*/
|
|
419
|
+
collectMethodDefinition(node, scopeId) {
|
|
420
|
+
const nameNode = this.findChildByType(node, 'property_identifier') ||
|
|
421
|
+
this.findChildByType(node, 'Identifier');
|
|
422
|
+
const name = nameNode?.text || '<anonymous>';
|
|
423
|
+
// Add method symbol to class scope
|
|
424
|
+
const symbol = this.createSymbol(name, 'method', scopeId, {
|
|
425
|
+
start: node.startPosition,
|
|
426
|
+
end: node.endPosition,
|
|
427
|
+
});
|
|
428
|
+
symbol.visibility = this.extractVisibility(node);
|
|
429
|
+
symbol.parameters = this.extractParameters(node);
|
|
430
|
+
this.addSymbolToScope(symbol, scopeId);
|
|
431
|
+
// Create method scope
|
|
432
|
+
const methodScope = this.createScope('function', scopeId, {
|
|
433
|
+
start: node.startPosition,
|
|
434
|
+
end: node.endPosition,
|
|
435
|
+
});
|
|
436
|
+
// Add 'this' to method scope
|
|
437
|
+
const thisSymbol = this.createSymbol('this', 'variable', methodScope.id, {
|
|
438
|
+
start: node.startPosition,
|
|
439
|
+
end: node.startPosition,
|
|
440
|
+
});
|
|
441
|
+
this.addSymbolToScope(thisSymbol, methodScope.id);
|
|
442
|
+
// Add parameters to method scope
|
|
443
|
+
for (const param of symbol.parameters || []) {
|
|
444
|
+
const paramSymbol = this.createSymbol(param.name, 'parameter', methodScope.id, param.location);
|
|
445
|
+
this.addSymbolToScope(paramSymbol, methodScope.id);
|
|
446
|
+
}
|
|
447
|
+
// Process method body
|
|
448
|
+
const body = this.findChildByType(node, 'statement_block') ||
|
|
449
|
+
this.findChildByType(node, 'BlockStatement');
|
|
450
|
+
if (body) {
|
|
451
|
+
this.collectChildDeclarations(body, methodScope.id);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Collect class declaration.
|
|
456
|
+
*/
|
|
457
|
+
collectClassDeclaration(node, scopeId) {
|
|
458
|
+
const nameNode = this.findChildByType(node, 'type_identifier') ||
|
|
459
|
+
this.findChildByType(node, 'Identifier');
|
|
460
|
+
const name = nameNode?.text || '<anonymous>';
|
|
461
|
+
// Add class symbol to current scope
|
|
462
|
+
const symbol = this.createSymbol(name, 'class', scopeId, {
|
|
463
|
+
start: node.startPosition,
|
|
464
|
+
end: node.endPosition,
|
|
465
|
+
});
|
|
466
|
+
this.addSymbolToScope(symbol, scopeId);
|
|
467
|
+
// Create class scope
|
|
468
|
+
const classScope = this.createScope('class', scopeId, {
|
|
469
|
+
start: node.startPosition,
|
|
470
|
+
end: node.endPosition,
|
|
471
|
+
});
|
|
472
|
+
// Process class body
|
|
473
|
+
const body = this.findChildByType(node, 'class_body') ||
|
|
474
|
+
this.findChildByType(node, 'ClassBody');
|
|
475
|
+
if (body) {
|
|
476
|
+
// Collect class members
|
|
477
|
+
for (const child of body.children) {
|
|
478
|
+
if (child.type === 'method_definition' || child.type === 'MethodDefinition') {
|
|
479
|
+
this.collectMethodDefinition(child, classScope.id);
|
|
480
|
+
}
|
|
481
|
+
else if (child.type === 'public_field_definition' ||
|
|
482
|
+
child.type === 'PropertyDefinition' ||
|
|
483
|
+
child.type === 'field_definition') {
|
|
484
|
+
this.collectFieldDefinition(child, classScope.id);
|
|
485
|
+
}
|
|
486
|
+
else {
|
|
487
|
+
this.collectDeclarations(child, classScope.id);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Collect field definition.
|
|
494
|
+
*/
|
|
495
|
+
collectFieldDefinition(node, scopeId) {
|
|
496
|
+
const nameNode = this.findChildByType(node, 'property_identifier') ||
|
|
497
|
+
this.findChildByType(node, 'Identifier');
|
|
498
|
+
const name = nameNode?.text;
|
|
499
|
+
if (name) {
|
|
500
|
+
const symbol = this.createSymbol(name, 'property', scopeId, {
|
|
501
|
+
start: node.startPosition,
|
|
502
|
+
end: node.endPosition,
|
|
503
|
+
});
|
|
504
|
+
symbol.visibility = this.extractVisibility(node);
|
|
505
|
+
this.addSymbolToScope(symbol, scopeId);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Collect variable declaration.
|
|
510
|
+
*/
|
|
511
|
+
collectVariableDeclaration(node, scopeId) {
|
|
512
|
+
// Find all variable declarators
|
|
513
|
+
for (const child of node.children) {
|
|
514
|
+
if (child.type === 'variable_declarator' || child.type === 'VariableDeclarator') {
|
|
515
|
+
this.collectVariableDeclarator(child, scopeId);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Collect variable declarator.
|
|
521
|
+
*/
|
|
522
|
+
collectVariableDeclarator(node, scopeId) {
|
|
523
|
+
// Handle destructuring patterns
|
|
524
|
+
const pattern = node.children[0];
|
|
525
|
+
if (!pattern)
|
|
526
|
+
return;
|
|
527
|
+
if (pattern.type === 'identifier' || pattern.type === 'Identifier') {
|
|
528
|
+
const symbol = this.createSymbol(pattern.text, 'variable', scopeId, {
|
|
529
|
+
start: pattern.startPosition,
|
|
530
|
+
end: pattern.endPosition,
|
|
531
|
+
});
|
|
532
|
+
this.addSymbolToScope(symbol, scopeId);
|
|
533
|
+
}
|
|
534
|
+
else if (pattern.type === 'object_pattern' || pattern.type === 'ObjectPattern') {
|
|
535
|
+
this.collectObjectPattern(pattern, scopeId);
|
|
536
|
+
}
|
|
537
|
+
else if (pattern.type === 'array_pattern' || pattern.type === 'ArrayPattern') {
|
|
538
|
+
this.collectArrayPattern(pattern, scopeId);
|
|
539
|
+
}
|
|
540
|
+
// Process initializer for nested functions
|
|
541
|
+
const initializer = this.findChildByType(node, 'arrow_function') ||
|
|
542
|
+
this.findChildByType(node, 'ArrowFunctionExpression') ||
|
|
543
|
+
this.findChildByType(node, 'function') ||
|
|
544
|
+
this.findChildByType(node, 'FunctionExpression');
|
|
545
|
+
if (initializer) {
|
|
546
|
+
this.collectDeclarations(initializer, scopeId);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Collect object destructuring pattern.
|
|
551
|
+
*/
|
|
552
|
+
collectObjectPattern(node, scopeId) {
|
|
553
|
+
for (const child of node.children) {
|
|
554
|
+
if (child.type === 'shorthand_property_identifier_pattern' ||
|
|
555
|
+
child.type === 'shorthand_property_identifier') {
|
|
556
|
+
const symbol = this.createSymbol(child.text, 'variable', scopeId, {
|
|
557
|
+
start: child.startPosition,
|
|
558
|
+
end: child.endPosition,
|
|
559
|
+
});
|
|
560
|
+
this.addSymbolToScope(symbol, scopeId);
|
|
561
|
+
}
|
|
562
|
+
else if (child.type === 'pair_pattern' || child.type === 'Property') {
|
|
563
|
+
// { key: value } pattern
|
|
564
|
+
const valueNode = child.children[child.children.length - 1];
|
|
565
|
+
if (valueNode?.type === 'identifier' || valueNode?.type === 'Identifier') {
|
|
566
|
+
const symbol = this.createSymbol(valueNode.text, 'variable', scopeId, {
|
|
567
|
+
start: valueNode.startPosition,
|
|
568
|
+
end: valueNode.endPosition,
|
|
569
|
+
});
|
|
570
|
+
this.addSymbolToScope(symbol, scopeId);
|
|
571
|
+
}
|
|
572
|
+
else if (valueNode) {
|
|
573
|
+
// Nested pattern
|
|
574
|
+
this.collectPattern(valueNode, scopeId);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Collect array destructuring pattern.
|
|
581
|
+
*/
|
|
582
|
+
collectArrayPattern(node, scopeId) {
|
|
583
|
+
for (const child of node.children) {
|
|
584
|
+
if (child.type === 'identifier' || child.type === 'Identifier') {
|
|
585
|
+
const symbol = this.createSymbol(child.text, 'variable', scopeId, {
|
|
586
|
+
start: child.startPosition,
|
|
587
|
+
end: child.endPosition,
|
|
588
|
+
});
|
|
589
|
+
this.addSymbolToScope(symbol, scopeId);
|
|
590
|
+
}
|
|
591
|
+
else if (child.type === 'rest_pattern' || child.type === 'RestElement') {
|
|
592
|
+
const restId = this.findChildByType(child, 'identifier') ||
|
|
593
|
+
this.findChildByType(child, 'Identifier');
|
|
594
|
+
if (restId) {
|
|
595
|
+
const symbol = this.createSymbol(restId.text, 'variable', scopeId, {
|
|
596
|
+
start: restId.startPosition,
|
|
597
|
+
end: restId.endPosition,
|
|
598
|
+
});
|
|
599
|
+
this.addSymbolToScope(symbol, scopeId);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
// Nested pattern
|
|
604
|
+
this.collectPattern(child, scopeId);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Collect any pattern type.
|
|
610
|
+
*/
|
|
611
|
+
collectPattern(node, scopeId) {
|
|
612
|
+
if (node.type === 'identifier' || node.type === 'Identifier') {
|
|
613
|
+
const symbol = this.createSymbol(node.text, 'variable', scopeId, {
|
|
614
|
+
start: node.startPosition,
|
|
615
|
+
end: node.endPosition,
|
|
616
|
+
});
|
|
617
|
+
this.addSymbolToScope(symbol, scopeId);
|
|
618
|
+
}
|
|
619
|
+
else if (node.type === 'object_pattern' || node.type === 'ObjectPattern') {
|
|
620
|
+
this.collectObjectPattern(node, scopeId);
|
|
621
|
+
}
|
|
622
|
+
else if (node.type === 'array_pattern' || node.type === 'ArrayPattern') {
|
|
623
|
+
this.collectArrayPattern(node, scopeId);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Collect import declaration.
|
|
628
|
+
*/
|
|
629
|
+
collectImportDeclaration(node, scopeId) {
|
|
630
|
+
// Find import clause
|
|
631
|
+
const importClause = this.findChildByType(node, 'import_clause');
|
|
632
|
+
if (importClause) {
|
|
633
|
+
for (const child of importClause.children) {
|
|
634
|
+
if (child.type === 'identifier' || child.type === 'Identifier') {
|
|
635
|
+
// Default import
|
|
636
|
+
const symbol = this.createSymbol(child.text, 'variable', scopeId, {
|
|
637
|
+
start: child.startPosition,
|
|
638
|
+
end: child.endPosition,
|
|
639
|
+
});
|
|
640
|
+
symbol.isImported = true;
|
|
641
|
+
this.addSymbolToScope(symbol, scopeId);
|
|
642
|
+
}
|
|
643
|
+
else if (child.type === 'named_imports') {
|
|
644
|
+
// Named imports
|
|
645
|
+
for (const spec of child.children) {
|
|
646
|
+
if (spec.type === 'import_specifier') {
|
|
647
|
+
const localName = this.findChildByType(spec, 'identifier') ||
|
|
648
|
+
spec.children[spec.children.length - 1];
|
|
649
|
+
if (localName && (localName.type === 'identifier' || localName.type === 'Identifier')) {
|
|
650
|
+
const symbol = this.createSymbol(localName.text, 'variable', scopeId, {
|
|
651
|
+
start: localName.startPosition,
|
|
652
|
+
end: localName.endPosition,
|
|
653
|
+
});
|
|
654
|
+
symbol.isImported = true;
|
|
655
|
+
this.addSymbolToScope(symbol, scopeId);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
else if (child.type === 'namespace_import') {
|
|
661
|
+
// Namespace import (import * as name)
|
|
662
|
+
const nameNode = this.findChildByType(child, 'identifier');
|
|
663
|
+
if (nameNode) {
|
|
664
|
+
const symbol = this.createSymbol(nameNode.text, 'namespace', scopeId, {
|
|
665
|
+
start: nameNode.startPosition,
|
|
666
|
+
end: nameNode.endPosition,
|
|
667
|
+
});
|
|
668
|
+
symbol.isImported = true;
|
|
669
|
+
this.addSymbolToScope(symbol, scopeId);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
// Handle direct named imports (ImportDeclaration style)
|
|
675
|
+
for (const child of node.children) {
|
|
676
|
+
if (child.type === 'ImportSpecifier') {
|
|
677
|
+
const localNode = this.findChildByType(child, 'Identifier');
|
|
678
|
+
if (localNode) {
|
|
679
|
+
const symbol = this.createSymbol(localNode.text, 'variable', scopeId, {
|
|
680
|
+
start: localNode.startPosition,
|
|
681
|
+
end: localNode.endPosition,
|
|
682
|
+
});
|
|
683
|
+
symbol.isImported = true;
|
|
684
|
+
this.addSymbolToScope(symbol, scopeId);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Collect export declaration.
|
|
691
|
+
*/
|
|
692
|
+
collectExportDeclaration(node, scopeId) {
|
|
693
|
+
// Process the declaration being exported
|
|
694
|
+
for (const child of node.children) {
|
|
695
|
+
if (child.type === 'function_declaration' || child.type === 'FunctionDeclaration') {
|
|
696
|
+
this.collectFunctionDeclaration(child, scopeId);
|
|
697
|
+
// Mark as exported
|
|
698
|
+
const nameNode = this.findChildByType(child, 'identifier') ||
|
|
699
|
+
this.findChildByType(child, 'Identifier');
|
|
700
|
+
if (nameNode) {
|
|
701
|
+
const scope = this.scopes.get(scopeId);
|
|
702
|
+
const symbol = scope?.symbols.get(nameNode.text);
|
|
703
|
+
if (symbol) {
|
|
704
|
+
symbol.isExported = true;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
else if (child.type === 'class_declaration' || child.type === 'ClassDeclaration') {
|
|
709
|
+
this.collectClassDeclaration(child, scopeId);
|
|
710
|
+
const nameNode = this.findChildByType(child, 'type_identifier') ||
|
|
711
|
+
this.findChildByType(child, 'Identifier');
|
|
712
|
+
if (nameNode) {
|
|
713
|
+
const scope = this.scopes.get(scopeId);
|
|
714
|
+
const symbol = scope?.symbols.get(nameNode.text);
|
|
715
|
+
if (symbol) {
|
|
716
|
+
symbol.isExported = true;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
else if (child.type === 'variable_declaration' || child.type === 'VariableDeclaration' ||
|
|
721
|
+
child.type === 'lexical_declaration') {
|
|
722
|
+
this.collectVariableDeclaration(child, scopeId);
|
|
723
|
+
// Mark all declared variables as exported
|
|
724
|
+
for (const declarator of child.children) {
|
|
725
|
+
if (declarator.type === 'variable_declarator' || declarator.type === 'VariableDeclarator') {
|
|
726
|
+
const idNode = declarator.children[0];
|
|
727
|
+
if (idNode && (idNode.type === 'identifier' || idNode.type === 'Identifier')) {
|
|
728
|
+
const scope = this.scopes.get(scopeId);
|
|
729
|
+
const symbol = scope?.symbols.get(idNode.text);
|
|
730
|
+
if (symbol) {
|
|
731
|
+
symbol.isExported = true;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
else if (child.type === 'interface_declaration' || child.type === 'TSInterfaceDeclaration') {
|
|
738
|
+
this.collectInterfaceDeclaration(child, scopeId);
|
|
739
|
+
}
|
|
740
|
+
else if (child.type === 'type_alias_declaration' || child.type === 'TSTypeAliasDeclaration') {
|
|
741
|
+
this.collectTypeAliasDeclaration(child, scopeId);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
/**
|
|
746
|
+
* Collect interface declaration.
|
|
747
|
+
*/
|
|
748
|
+
collectInterfaceDeclaration(node, scopeId) {
|
|
749
|
+
const nameNode = this.findChildByType(node, 'type_identifier') ||
|
|
750
|
+
this.findChildByType(node, 'Identifier');
|
|
751
|
+
const name = nameNode?.text;
|
|
752
|
+
if (name) {
|
|
753
|
+
const symbol = this.createSymbol(name, 'interface', scopeId, {
|
|
754
|
+
start: node.startPosition,
|
|
755
|
+
end: node.endPosition,
|
|
756
|
+
});
|
|
757
|
+
this.addSymbolToScope(symbol, scopeId);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* Collect type alias declaration.
|
|
762
|
+
*/
|
|
763
|
+
collectTypeAliasDeclaration(node, scopeId) {
|
|
764
|
+
const nameNode = this.findChildByType(node, 'type_identifier') ||
|
|
765
|
+
this.findChildByType(node, 'Identifier');
|
|
766
|
+
const name = nameNode?.text;
|
|
767
|
+
if (name) {
|
|
768
|
+
const symbol = this.createSymbol(name, 'type', scopeId, {
|
|
769
|
+
start: node.startPosition,
|
|
770
|
+
end: node.endPosition,
|
|
771
|
+
});
|
|
772
|
+
this.addSymbolToScope(symbol, scopeId);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Collect enum declaration.
|
|
777
|
+
*/
|
|
778
|
+
collectEnumDeclaration(node, scopeId) {
|
|
779
|
+
const nameNode = this.findChildByType(node, 'identifier') ||
|
|
780
|
+
this.findChildByType(node, 'Identifier');
|
|
781
|
+
const name = nameNode?.text;
|
|
782
|
+
if (name) {
|
|
783
|
+
const symbol = this.createSymbol(name, 'enum', scopeId, {
|
|
784
|
+
start: node.startPosition,
|
|
785
|
+
end: node.endPosition,
|
|
786
|
+
});
|
|
787
|
+
this.addSymbolToScope(symbol, scopeId);
|
|
788
|
+
// Collect enum members
|
|
789
|
+
const body = this.findChildByType(node, 'enum_body');
|
|
790
|
+
if (body) {
|
|
791
|
+
for (const child of body.children) {
|
|
792
|
+
if (child.type === 'enum_assignment' || child.type === 'property_identifier') {
|
|
793
|
+
const memberName = this.findChildByType(child, 'property_identifier') ||
|
|
794
|
+
this.findChildByType(child, 'Identifier');
|
|
795
|
+
if (memberName) {
|
|
796
|
+
// Create enum member symbol (accessible via the enum name)
|
|
797
|
+
const memberSymbol = this.createSymbol(memberName.text, 'enumMember', scopeId, {
|
|
798
|
+
start: memberName.startPosition,
|
|
799
|
+
end: memberName.endPosition,
|
|
800
|
+
});
|
|
801
|
+
this.addSymbolToScope(memberSymbol, scopeId);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
/**
|
|
809
|
+
* Collect block statement.
|
|
810
|
+
*/
|
|
811
|
+
collectBlockStatement(node, scopeId) {
|
|
812
|
+
// Create block scope
|
|
813
|
+
const blockScope = this.createScope('block', scopeId, {
|
|
814
|
+
start: node.startPosition,
|
|
815
|
+
end: node.endPosition,
|
|
816
|
+
});
|
|
817
|
+
this.collectChildDeclarations(node, blockScope.id);
|
|
818
|
+
}
|
|
819
|
+
/**
|
|
820
|
+
* Collect for statement.
|
|
821
|
+
*/
|
|
822
|
+
collectForStatement(node, scopeId) {
|
|
823
|
+
// Create loop scope
|
|
824
|
+
const loopScope = this.createScope('loop', scopeId, {
|
|
825
|
+
start: node.startPosition,
|
|
826
|
+
end: node.endPosition,
|
|
827
|
+
});
|
|
828
|
+
// Collect loop variable declarations
|
|
829
|
+
for (const child of node.children) {
|
|
830
|
+
if (child.type === 'variable_declaration' || child.type === 'VariableDeclaration' ||
|
|
831
|
+
child.type === 'lexical_declaration') {
|
|
832
|
+
this.collectVariableDeclaration(child, loopScope.id);
|
|
833
|
+
}
|
|
834
|
+
else if (child.type === 'statement_block' || child.type === 'BlockStatement') {
|
|
835
|
+
this.collectChildDeclarations(child, loopScope.id);
|
|
836
|
+
}
|
|
837
|
+
else {
|
|
838
|
+
this.collectDeclarations(child, loopScope.id);
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* Collect if statement.
|
|
844
|
+
*/
|
|
845
|
+
collectIfStatement(node, scopeId) {
|
|
846
|
+
for (const child of node.children) {
|
|
847
|
+
if (child.type === 'statement_block' || child.type === 'BlockStatement') {
|
|
848
|
+
// Create conditional scope
|
|
849
|
+
const condScope = this.createScope('conditional', scopeId, {
|
|
850
|
+
start: child.startPosition,
|
|
851
|
+
end: child.endPosition,
|
|
852
|
+
});
|
|
853
|
+
this.collectChildDeclarations(child, condScope.id);
|
|
854
|
+
}
|
|
855
|
+
else if (child.type === 'else_clause') {
|
|
856
|
+
this.collectDeclarations(child, scopeId);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* Collect switch statement.
|
|
862
|
+
*/
|
|
863
|
+
collectSwitchStatement(node, scopeId) {
|
|
864
|
+
// Create switch scope
|
|
865
|
+
const switchScope = this.createScope('switch', scopeId, {
|
|
866
|
+
start: node.startPosition,
|
|
867
|
+
end: node.endPosition,
|
|
868
|
+
});
|
|
869
|
+
const body = this.findChildByType(node, 'switch_body');
|
|
870
|
+
if (body) {
|
|
871
|
+
this.collectChildDeclarations(body, switchScope.id);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* Collect try statement.
|
|
876
|
+
*/
|
|
877
|
+
collectTryStatement(node, scopeId) {
|
|
878
|
+
for (const child of node.children) {
|
|
879
|
+
if (child.type === 'statement_block' || child.type === 'BlockStatement') {
|
|
880
|
+
const tryScope = this.createScope('block', scopeId, {
|
|
881
|
+
start: child.startPosition,
|
|
882
|
+
end: child.endPosition,
|
|
883
|
+
});
|
|
884
|
+
this.collectChildDeclarations(child, tryScope.id);
|
|
885
|
+
}
|
|
886
|
+
else if (child.type === 'catch_clause' || child.type === 'CatchClause') {
|
|
887
|
+
this.collectCatchClause(child, scopeId);
|
|
888
|
+
}
|
|
889
|
+
else if (child.type === 'finally_clause') {
|
|
890
|
+
const finallyBlock = this.findChildByType(child, 'statement_block') ||
|
|
891
|
+
this.findChildByType(child, 'BlockStatement');
|
|
892
|
+
if (finallyBlock) {
|
|
893
|
+
const finallyScope = this.createScope('block', scopeId, {
|
|
894
|
+
start: finallyBlock.startPosition,
|
|
895
|
+
end: finallyBlock.endPosition,
|
|
896
|
+
});
|
|
897
|
+
this.collectChildDeclarations(finallyBlock, finallyScope.id);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
/**
|
|
903
|
+
* Collect catch clause.
|
|
904
|
+
*/
|
|
905
|
+
collectCatchClause(node, scopeId) {
|
|
906
|
+
// Create catch scope
|
|
907
|
+
const catchScope = this.createScope('catch', scopeId, {
|
|
908
|
+
start: node.startPosition,
|
|
909
|
+
end: node.endPosition,
|
|
910
|
+
});
|
|
911
|
+
// Add catch parameter
|
|
912
|
+
const param = this.findChildByType(node, 'identifier') ||
|
|
913
|
+
this.findChildByType(node, 'Identifier');
|
|
914
|
+
if (param) {
|
|
915
|
+
const symbol = this.createSymbol(param.text, 'parameter', catchScope.id, {
|
|
916
|
+
start: param.startPosition,
|
|
917
|
+
end: param.endPosition,
|
|
918
|
+
});
|
|
919
|
+
this.addSymbolToScope(symbol, catchScope.id);
|
|
920
|
+
}
|
|
921
|
+
// Process catch body
|
|
922
|
+
const body = this.findChildByType(node, 'statement_block') ||
|
|
923
|
+
this.findChildByType(node, 'BlockStatement');
|
|
924
|
+
if (body) {
|
|
925
|
+
this.collectChildDeclarations(body, catchScope.id);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Resolve references in AST nodes.
|
|
930
|
+
*/
|
|
931
|
+
resolveReferences(node, scopeId) {
|
|
932
|
+
const nodeType = node.type;
|
|
933
|
+
// Update scope for scope-creating nodes
|
|
934
|
+
let currentScopeId = scopeId;
|
|
935
|
+
if (this.isNewScopeNode(node)) {
|
|
936
|
+
const matchingScope = this.findScopeForNode(node);
|
|
937
|
+
if (matchingScope) {
|
|
938
|
+
currentScopeId = matchingScope.id;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
// Check for identifier references
|
|
942
|
+
if (nodeType === 'identifier' || nodeType === 'Identifier') {
|
|
943
|
+
this.resolveIdentifierReference(node, currentScopeId);
|
|
944
|
+
}
|
|
945
|
+
// Recurse into children
|
|
946
|
+
for (const child of node.children) {
|
|
947
|
+
this.resolveReferences(child, currentScopeId);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* Check if a node creates a new scope.
|
|
952
|
+
*/
|
|
953
|
+
isNewScopeNode(node) {
|
|
954
|
+
const scopeCreatingTypes = new Set([
|
|
955
|
+
'function_declaration', 'FunctionDeclaration',
|
|
956
|
+
'arrow_function', 'ArrowFunctionExpression',
|
|
957
|
+
'method_definition', 'MethodDefinition',
|
|
958
|
+
'class_declaration', 'ClassDeclaration',
|
|
959
|
+
'statement_block', 'BlockStatement',
|
|
960
|
+
'for_statement', 'ForStatement',
|
|
961
|
+
'for_in_statement', 'ForInStatement',
|
|
962
|
+
'for_of_statement', 'ForOfStatement',
|
|
963
|
+
'switch_statement', 'SwitchStatement',
|
|
964
|
+
'catch_clause', 'CatchClause',
|
|
965
|
+
]);
|
|
966
|
+
return scopeCreatingTypes.has(node.type);
|
|
967
|
+
}
|
|
968
|
+
/**
|
|
969
|
+
* Find the scope that matches a node's location.
|
|
970
|
+
*/
|
|
971
|
+
findScopeForNode(node) {
|
|
972
|
+
for (const scope of this.scopes.values()) {
|
|
973
|
+
if (scope.location.start.row === node.startPosition.row &&
|
|
974
|
+
scope.location.start.column === node.startPosition.column &&
|
|
975
|
+
scope.location.end.row === node.endPosition.row &&
|
|
976
|
+
scope.location.end.column === node.endPosition.column) {
|
|
977
|
+
return scope;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
return null;
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* Resolve an identifier reference.
|
|
984
|
+
*/
|
|
985
|
+
resolveIdentifierReference(node, scopeId) {
|
|
986
|
+
const name = node.text;
|
|
987
|
+
// Skip if this is a declaration (handled separately)
|
|
988
|
+
if (this.isDeclarationContext(node)) {
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
// Skip property access (obj.prop - prop is not a reference)
|
|
992
|
+
if (this.isPropertyAccess(node)) {
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
// Try to resolve the symbol
|
|
996
|
+
const symbol = this.resolveSymbol(name, scopeId);
|
|
997
|
+
if (symbol) {
|
|
998
|
+
// Add reference to the symbol
|
|
999
|
+
const reference = {
|
|
1000
|
+
location: {
|
|
1001
|
+
start: node.startPosition,
|
|
1002
|
+
end: node.endPosition,
|
|
1003
|
+
},
|
|
1004
|
+
kind: this.determineReferenceKind(node),
|
|
1005
|
+
isWrite: this.isWriteReference(node),
|
|
1006
|
+
};
|
|
1007
|
+
symbol.references.push(reference);
|
|
1008
|
+
}
|
|
1009
|
+
else {
|
|
1010
|
+
// Unresolved reference
|
|
1011
|
+
this.unresolvedReferences.push({
|
|
1012
|
+
location: {
|
|
1013
|
+
start: node.startPosition,
|
|
1014
|
+
end: node.endPosition,
|
|
1015
|
+
},
|
|
1016
|
+
kind: 'read',
|
|
1017
|
+
isWrite: false,
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* Check if an identifier is in a declaration context.
|
|
1023
|
+
*/
|
|
1024
|
+
isDeclarationContext(_node) {
|
|
1025
|
+
// This is a simplified check - in a real implementation,
|
|
1026
|
+
// we'd need to track parent nodes during traversal
|
|
1027
|
+
return false;
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* Check if an identifier is a property access.
|
|
1031
|
+
*/
|
|
1032
|
+
isPropertyAccess(_node) {
|
|
1033
|
+
// This is a simplified check
|
|
1034
|
+
return false;
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* Determine the kind of reference.
|
|
1038
|
+
*/
|
|
1039
|
+
determineReferenceKind(_node) {
|
|
1040
|
+
// Simplified - would need parent context for accurate determination
|
|
1041
|
+
return 'read';
|
|
1042
|
+
}
|
|
1043
|
+
/**
|
|
1044
|
+
* Check if a reference is a write (assignment).
|
|
1045
|
+
*/
|
|
1046
|
+
isWriteReference(_node) {
|
|
1047
|
+
// Simplified - would need parent context for accurate determination
|
|
1048
|
+
return false;
|
|
1049
|
+
}
|
|
1050
|
+
/**
|
|
1051
|
+
* Extract parameters from a function node.
|
|
1052
|
+
*/
|
|
1053
|
+
extractParameters(node) {
|
|
1054
|
+
const params = [];
|
|
1055
|
+
const paramsNode = this.findChildByType(node, 'formal_parameters') ||
|
|
1056
|
+
this.findChildByType(node, 'parameters');
|
|
1057
|
+
if (!paramsNode)
|
|
1058
|
+
return params;
|
|
1059
|
+
for (const child of paramsNode.children) {
|
|
1060
|
+
if (child.type === 'required_parameter' || child.type === 'optional_parameter' ||
|
|
1061
|
+
child.type === 'identifier' || child.type === 'Identifier') {
|
|
1062
|
+
const nameNode = child.type === 'identifier' || child.type === 'Identifier'
|
|
1063
|
+
? child
|
|
1064
|
+
: this.findChildByType(child, 'identifier') || this.findChildByType(child, 'Identifier');
|
|
1065
|
+
if (nameNode) {
|
|
1066
|
+
params.push({
|
|
1067
|
+
name: nameNode.text,
|
|
1068
|
+
isOptional: child.type === 'optional_parameter',
|
|
1069
|
+
isRest: false,
|
|
1070
|
+
location: {
|
|
1071
|
+
start: nameNode.startPosition,
|
|
1072
|
+
end: nameNode.endPosition,
|
|
1073
|
+
},
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
else if (child.type === 'rest_pattern' || child.type === 'RestElement') {
|
|
1078
|
+
const nameNode = this.findChildByType(child, 'identifier') ||
|
|
1079
|
+
this.findChildByType(child, 'Identifier');
|
|
1080
|
+
if (nameNode) {
|
|
1081
|
+
params.push({
|
|
1082
|
+
name: nameNode.text,
|
|
1083
|
+
isOptional: false,
|
|
1084
|
+
isRest: true,
|
|
1085
|
+
location: {
|
|
1086
|
+
start: nameNode.startPosition,
|
|
1087
|
+
end: nameNode.endPosition,
|
|
1088
|
+
},
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
return params;
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Extract visibility modifier from a node.
|
|
1097
|
+
*/
|
|
1098
|
+
extractVisibility(node) {
|
|
1099
|
+
for (const child of node.children) {
|
|
1100
|
+
if (child.type === 'accessibility_modifier' || child.text === 'public') {
|
|
1101
|
+
return 'public';
|
|
1102
|
+
}
|
|
1103
|
+
else if (child.text === 'private') {
|
|
1104
|
+
return 'private';
|
|
1105
|
+
}
|
|
1106
|
+
else if (child.text === 'protected') {
|
|
1107
|
+
return 'protected';
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
return 'default';
|
|
1111
|
+
}
|
|
1112
|
+
/**
|
|
1113
|
+
* Find a child node by type.
|
|
1114
|
+
*/
|
|
1115
|
+
findChildByType(node, type) {
|
|
1116
|
+
for (const child of node.children) {
|
|
1117
|
+
if (child.type === type) {
|
|
1118
|
+
return child;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
return null;
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* Check if a position is within a range.
|
|
1125
|
+
*/
|
|
1126
|
+
positionInRange(position, start, end) {
|
|
1127
|
+
// Check if position is after start
|
|
1128
|
+
if (position.row < start.row)
|
|
1129
|
+
return false;
|
|
1130
|
+
if (position.row === start.row && position.column < start.column)
|
|
1131
|
+
return false;
|
|
1132
|
+
// Check if position is before end
|
|
1133
|
+
if (position.row > end.row)
|
|
1134
|
+
return false;
|
|
1135
|
+
if (position.row === end.row && position.column > end.column)
|
|
1136
|
+
return false;
|
|
1137
|
+
return true;
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Convert internal scope to ScopeInfo.
|
|
1141
|
+
*/
|
|
1142
|
+
toScopeInfo(scope) {
|
|
1143
|
+
return {
|
|
1144
|
+
id: scope.id,
|
|
1145
|
+
kind: scope.kind,
|
|
1146
|
+
parentId: scope.parentId,
|
|
1147
|
+
childIds: scope.childIds,
|
|
1148
|
+
symbols: Array.from(scope.symbols.keys()),
|
|
1149
|
+
location: scope.location,
|
|
1150
|
+
depth: scope.depth,
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
/**
|
|
1154
|
+
* Build the final analysis result.
|
|
1155
|
+
*/
|
|
1156
|
+
buildResult() {
|
|
1157
|
+
// Build symbol table from all scopes
|
|
1158
|
+
const symbols = new Map();
|
|
1159
|
+
for (const scope of this.scopes.values()) {
|
|
1160
|
+
for (const [name, symbol] of scope.symbols) {
|
|
1161
|
+
// Use scope-qualified key to avoid collisions
|
|
1162
|
+
const key = `${scope.id}:${name}`;
|
|
1163
|
+
symbols.set(key, symbol);
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
// Convert scopes to ScopeInfo array
|
|
1167
|
+
const scopes = Array.from(this.scopes.values()).map((s) => this.toScopeInfo(s));
|
|
1168
|
+
return {
|
|
1169
|
+
symbols,
|
|
1170
|
+
scopes,
|
|
1171
|
+
unresolvedReferences: this.unresolvedReferences,
|
|
1172
|
+
shadowedVariables: this.shadowedVariables,
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
/**
|
|
1176
|
+
* Clear internal state.
|
|
1177
|
+
*/
|
|
1178
|
+
clearCache() {
|
|
1179
|
+
this.reset();
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
//# sourceMappingURL=semantic-analyzer.js.map
|