agent-ide 0.7.5 → 0.8.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/core/deadcode/dead-code-remover.d.ts +27 -9
- package/dist/core/deadcode/dead-code-remover.d.ts.map +1 -1
- package/dist/core/deadcode/dead-code-remover.js +100 -26
- package/dist/core/deadcode/dead-code-remover.js.map +1 -1
- package/dist/core/move/import-resolver.d.ts +0 -3
- package/dist/core/move/import-resolver.d.ts.map +1 -1
- package/dist/core/move/import-resolver.js +0 -10
- package/dist/core/move/import-resolver.js.map +1 -1
- package/dist/core/move-member/index.d.ts +1 -1
- package/dist/core/move-member/index.d.ts.map +1 -1
- package/dist/core/move-member/index.js.map +1 -1
- package/dist/core/move-member/move-member-service.d.ts +2 -0
- package/dist/core/move-member/move-member-service.d.ts.map +1 -1
- package/dist/core/move-member/move-member-service.js +24 -31
- package/dist/core/move-member/move-member-service.js.map +1 -1
- package/dist/core/move-member/types.d.ts +48 -23
- package/dist/core/move-member/types.d.ts.map +1 -1
- package/dist/core/move-member/types.js.map +1 -1
- package/dist/core/rename/reference-updater.d.ts.map +1 -1
- package/dist/core/rename/reference-updater.js +3 -1
- package/dist/core/rename/reference-updater.js.map +1 -1
- package/dist/core/shared/symbol-finder.d.ts +39 -11
- package/dist/core/shared/symbol-finder.d.ts.map +1 -1
- package/dist/core/shared/symbol-finder.js +109 -75
- package/dist/core/shared/symbol-finder.js.map +1 -1
- package/dist/core/snapshot/snapshot-generator.d.ts +11 -0
- package/dist/core/snapshot/snapshot-generator.d.ts.map +1 -1
- package/dist/core/snapshot/snapshot-generator.js +117 -5
- package/dist/core/snapshot/snapshot-generator.js.map +1 -1
- package/dist/infrastructure/formatters/diff-generator.js +93 -26
- package/dist/infrastructure/formatters/diff-generator.js.map +1 -1
- package/dist/infrastructure/formatters/diff-utils.d.ts +24 -0
- package/dist/infrastructure/formatters/diff-utils.d.ts.map +1 -0
- package/dist/infrastructure/formatters/diff-utils.js +104 -0
- package/dist/infrastructure/formatters/diff-utils.js.map +1 -0
- package/dist/infrastructure/formatters/preview-converter.d.ts +2 -0
- package/dist/infrastructure/formatters/preview-converter.d.ts.map +1 -1
- package/dist/infrastructure/formatters/preview-converter.js +43 -5
- package/dist/infrastructure/formatters/preview-converter.js.map +1 -1
- package/dist/infrastructure/parser/base.d.ts +2 -6
- package/dist/infrastructure/parser/base.d.ts.map +1 -1
- package/dist/infrastructure/parser/base.js +1 -16
- package/dist/infrastructure/parser/base.js.map +1 -1
- package/dist/infrastructure/parser/index.d.ts +2 -0
- package/dist/infrastructure/parser/index.d.ts.map +1 -1
- package/dist/infrastructure/parser/index.js +1 -0
- package/dist/infrastructure/parser/index.js.map +1 -1
- package/dist/infrastructure/parser/interface.d.ts +197 -0
- package/dist/infrastructure/parser/interface.d.ts.map +1 -1
- package/dist/infrastructure/parser/interface.js +13 -0
- package/dist/infrastructure/parser/interface.js.map +1 -1
- package/dist/interfaces/cli/commands/cycles.command.js +8 -1
- package/dist/interfaces/cli/commands/cycles.command.js.map +1 -1
- package/dist/interfaces/cli/commands/deadcode.command.js +7 -1
- package/dist/interfaces/cli/commands/deadcode.command.js.map +1 -1
- package/dist/interfaces/cli/commands/impact.command.js +19 -5
- package/dist/interfaces/cli/commands/impact.command.js.map +1 -1
- package/dist/interfaces/cli/commands/move-member.command.d.ts.map +1 -1
- package/dist/interfaces/cli/commands/move-member.command.js +55 -29
- package/dist/interfaces/cli/commands/move-member.command.js.map +1 -1
- package/dist/plugins/javascript/code-analyzer.d.ts +68 -0
- package/dist/plugins/javascript/code-analyzer.d.ts.map +1 -0
- package/dist/plugins/javascript/code-analyzer.js +302 -0
- package/dist/plugins/javascript/code-analyzer.js.map +1 -0
- package/dist/plugins/javascript/declaration-analyzer.d.ts +58 -0
- package/dist/plugins/javascript/declaration-analyzer.d.ts.map +1 -0
- package/dist/plugins/javascript/declaration-analyzer.js +367 -0
- package/dist/plugins/javascript/declaration-analyzer.js.map +1 -0
- package/dist/plugins/javascript/parser.d.ts +21 -36
- package/dist/plugins/javascript/parser.d.ts.map +1 -1
- package/dist/plugins/javascript/parser.js +55 -321
- package/dist/plugins/javascript/parser.js.map +1 -1
- package/dist/plugins/javascript/pattern-analyzer.d.ts +33 -0
- package/dist/plugins/javascript/pattern-analyzer.d.ts.map +1 -0
- package/dist/plugins/javascript/pattern-analyzer.js +142 -0
- package/dist/plugins/javascript/pattern-analyzer.js.map +1 -0
- package/dist/plugins/javascript/reference-finder.d.ts +38 -0
- package/dist/plugins/javascript/reference-finder.d.ts.map +1 -0
- package/dist/plugins/javascript/reference-finder.js +210 -0
- package/dist/plugins/javascript/reference-finder.js.map +1 -0
- package/dist/plugins/javascript/types.d.ts +2 -4
- package/dist/plugins/javascript/types.d.ts.map +1 -1
- package/dist/plugins/javascript/types.js +4 -12
- package/dist/plugins/javascript/types.js.map +1 -1
- package/dist/plugins/shared/constants.d.ts +32 -0
- package/dist/plugins/shared/constants.d.ts.map +1 -0
- package/dist/plugins/shared/constants.js +78 -0
- package/dist/plugins/shared/constants.js.map +1 -0
- package/dist/plugins/shared/index.d.ts +7 -0
- package/dist/plugins/shared/index.d.ts.map +1 -0
- package/dist/plugins/shared/index.js +9 -0
- package/dist/plugins/shared/index.js.map +1 -0
- package/dist/plugins/shared/parser-helpers.d.ts +109 -0
- package/dist/plugins/shared/parser-helpers.d.ts.map +1 -0
- package/dist/plugins/shared/parser-helpers.js +223 -0
- package/dist/plugins/shared/parser-helpers.js.map +1 -0
- package/dist/plugins/typescript/declaration-analyzer.d.ts +123 -0
- package/dist/plugins/typescript/declaration-analyzer.d.ts.map +1 -0
- package/dist/plugins/typescript/declaration-analyzer.js +474 -0
- package/dist/plugins/typescript/declaration-analyzer.js.map +1 -0
- package/dist/plugins/typescript/dependency-analyzer.d.ts +0 -6
- package/dist/plugins/typescript/dependency-analyzer.d.ts.map +1 -1
- package/dist/plugins/typescript/dependency-analyzer.js +0 -34
- package/dist/plugins/typescript/dependency-analyzer.js.map +1 -1
- package/dist/plugins/typescript/index.d.ts +5 -0
- package/dist/plugins/typescript/index.d.ts.map +1 -1
- package/dist/plugins/typescript/index.js +5 -0
- package/dist/plugins/typescript/index.js.map +1 -1
- package/dist/plugins/typescript/language-service.d.ts +93 -0
- package/dist/plugins/typescript/language-service.d.ts.map +1 -0
- package/dist/plugins/typescript/language-service.js +159 -0
- package/dist/plugins/typescript/language-service.js.map +1 -0
- package/dist/plugins/typescript/parser.d.ts +27 -34
- package/dist/plugins/typescript/parser.d.ts.map +1 -1
- package/dist/plugins/typescript/parser.js +74 -429
- package/dist/plugins/typescript/parser.js.map +1 -1
- package/dist/plugins/typescript/pattern-analyzer.d.ts +59 -0
- package/dist/plugins/typescript/pattern-analyzer.d.ts.map +1 -0
- package/dist/plugins/typescript/pattern-analyzer.js +179 -0
- package/dist/plugins/typescript/pattern-analyzer.js.map +1 -0
- package/dist/plugins/typescript/reference-finder.d.ts +51 -0
- package/dist/plugins/typescript/reference-finder.d.ts.map +1 -0
- package/dist/plugins/typescript/reference-finder.js +214 -0
- package/dist/plugins/typescript/reference-finder.js.map +1 -0
- package/dist/plugins/typescript/scope-analyzer.d.ts +61 -0
- package/dist/plugins/typescript/scope-analyzer.d.ts.map +1 -0
- package/dist/plugins/typescript/scope-analyzer.js +300 -0
- package/dist/plugins/typescript/scope-analyzer.js.map +1 -0
- package/dist/plugins/typescript/symbol-extractor.d.ts +5 -0
- package/dist/plugins/typescript/symbol-extractor.d.ts.map +1 -1
- package/dist/plugins/typescript/symbol-extractor.js +25 -0
- package/dist/plugins/typescript/symbol-extractor.js.map +1 -1
- package/dist/plugins/typescript/types.d.ts +2 -4
- package/dist/plugins/typescript/types.d.ts.map +1 -1
- package/dist/plugins/typescript/types.js +4 -12
- package/dist/plugins/typescript/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -9,6 +9,12 @@ import { DEFAULT_COMPILER_OPTIONS, TypeScriptParseError, createTypeScriptASTNode
|
|
|
9
9
|
import { createSymbolExtractor } from '../typescript/symbol-extractor.js';
|
|
10
10
|
import { createDependencyAnalyzer } from '../typescript/dependency-analyzer.js';
|
|
11
11
|
import { MemoryMonitor } from '../../shared/utils/memory-monitor.js';
|
|
12
|
+
import { TYPESCRIPT_EXCLUDE_PATTERNS, matchesAnyPattern } from '../shared/index.js';
|
|
13
|
+
import { createLanguageServiceManager } from './language-service.js';
|
|
14
|
+
import { createScopeAnalyzer } from './scope-analyzer.js';
|
|
15
|
+
import { createDeclarationAnalyzer } from './declaration-analyzer.js';
|
|
16
|
+
import { createPatternAnalyzer } from './pattern-analyzer.js';
|
|
17
|
+
import { createReferenceFinder } from './reference-finder.js';
|
|
12
18
|
/**
|
|
13
19
|
* TypeScript Parser 實作
|
|
14
20
|
*/
|
|
@@ -20,13 +26,20 @@ export class TypeScriptParser {
|
|
|
20
26
|
symbolExtractor;
|
|
21
27
|
dependencyAnalyzer;
|
|
22
28
|
compilerOptions;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
languageServiceManager;
|
|
30
|
+
scopeAnalyzer;
|
|
31
|
+
declarationAnalyzer;
|
|
32
|
+
patternAnalyzer;
|
|
33
|
+
referenceFinder;
|
|
26
34
|
constructor(compilerOptions) {
|
|
35
|
+
this.compilerOptions = { ...DEFAULT_COMPILER_OPTIONS, ...compilerOptions };
|
|
27
36
|
this.symbolExtractor = createSymbolExtractor();
|
|
28
37
|
this.dependencyAnalyzer = createDependencyAnalyzer();
|
|
29
|
-
this.
|
|
38
|
+
this.languageServiceManager = createLanguageServiceManager(this.compilerOptions);
|
|
39
|
+
this.scopeAnalyzer = createScopeAnalyzer();
|
|
40
|
+
this.declarationAnalyzer = createDeclarationAnalyzer(this.compilerOptions);
|
|
41
|
+
this.patternAnalyzer = createPatternAnalyzer(this.compilerOptions);
|
|
42
|
+
this.referenceFinder = createReferenceFinder(this.compilerOptions);
|
|
30
43
|
// 註冊到記憶體監控器
|
|
31
44
|
MemoryMonitor.getInstance().register(this);
|
|
32
45
|
}
|
|
@@ -103,26 +116,26 @@ export class TypeScriptParser {
|
|
|
103
116
|
const typedAst = ast;
|
|
104
117
|
const typedSymbol = symbol;
|
|
105
118
|
// 確保 Language Service 已初始化
|
|
106
|
-
this.
|
|
107
|
-
if (!this.languageService) {
|
|
119
|
+
this.languageServiceManager.ensureInitialized(typedAst.tsSourceFile);
|
|
120
|
+
if (!this.languageServiceManager.languageService) {
|
|
108
121
|
// 如果無法使用 Language Service,回退到原始方法
|
|
109
122
|
return this.findReferencesBasic(ast, symbol);
|
|
110
123
|
}
|
|
111
124
|
const fileName = typedAst.tsSourceFile.fileName;
|
|
112
125
|
// 取得符號位置
|
|
113
|
-
const symbolPosition = this.getSymbolPosition(typedSymbol, typedAst.tsSourceFile);
|
|
126
|
+
const symbolPosition = this.languageServiceManager.getSymbolPosition(typedSymbol, typedAst.tsSourceFile, (node) => this.scopeAnalyzer.getIdentifierFromSymbolNode(node) ?? undefined);
|
|
114
127
|
if (symbolPosition === undefined) {
|
|
115
128
|
return [];
|
|
116
129
|
}
|
|
117
130
|
// 使用 Language Service 查找引用
|
|
118
|
-
const referencesResult = this.languageService.findReferences(fileName, symbolPosition);
|
|
131
|
+
const referencesResult = this.languageServiceManager.languageService.findReferences(fileName, symbolPosition);
|
|
119
132
|
if (!referencesResult) {
|
|
120
133
|
return [];
|
|
121
134
|
}
|
|
122
135
|
const references = [];
|
|
123
136
|
for (const refSymbol of referencesResult) {
|
|
124
137
|
for (const ref of refSymbol.references) {
|
|
125
|
-
const sourceFile = this.getSourceFileFromFileName(ref.fileName);
|
|
138
|
+
const sourceFile = this.languageServiceManager.getSourceFileFromFileName(ref.fileName);
|
|
126
139
|
if (!sourceFile) {
|
|
127
140
|
continue;
|
|
128
141
|
}
|
|
@@ -155,17 +168,17 @@ export class TypeScriptParser {
|
|
|
155
168
|
const references = [];
|
|
156
169
|
const symbolName = typedSymbol.name;
|
|
157
170
|
// 獲取符號的標識符節點
|
|
158
|
-
const symbolIdentifier = this.getIdentifierFromSymbolNode(typedSymbol.tsNode);
|
|
171
|
+
const symbolIdentifier = this.scopeAnalyzer.getIdentifierFromSymbolNode(typedSymbol.tsNode);
|
|
159
172
|
if (!symbolIdentifier) {
|
|
160
173
|
return references;
|
|
161
174
|
}
|
|
162
175
|
// 使用 TypeScript 原生的節點遍歷,收集所有標識符
|
|
163
176
|
const collectIdentifiers = (node) => {
|
|
164
|
-
//
|
|
177
|
+
// 過濾:跳過字串字面值
|
|
165
178
|
if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
|
|
166
179
|
return; // 不處理子節點
|
|
167
180
|
}
|
|
168
|
-
//
|
|
181
|
+
// 過濾:跳過模板字串
|
|
169
182
|
if (ts.isTemplateExpression(node)) {
|
|
170
183
|
// 只處理模板表達式中的插值部分,跳過字串部分
|
|
171
184
|
node.templateSpans.forEach(span => {
|
|
@@ -175,12 +188,12 @@ export class TypeScriptParser {
|
|
|
175
188
|
}
|
|
176
189
|
if (ts.isIdentifier(node) && node.text === symbolName) {
|
|
177
190
|
// 檢查這個標識符是否真的引用了我們的符號
|
|
178
|
-
if (this.isReferenceToSymbol(node, typedSymbol)) {
|
|
191
|
+
if (this.scopeAnalyzer.isReferenceToSymbol(node, typedSymbol)) {
|
|
179
192
|
const location = {
|
|
180
193
|
filePath: typedAst.tsSourceFile.fileName,
|
|
181
194
|
range: tsNodeToRange(node, typedAst.tsSourceFile)
|
|
182
195
|
};
|
|
183
|
-
const referenceType = this.getReferenceType(node, typedSymbol);
|
|
196
|
+
const referenceType = this.scopeAnalyzer.getReferenceType(node, typedSymbol, this.isDeclarationNode.bind(this));
|
|
184
197
|
references.push({
|
|
185
198
|
symbol,
|
|
186
199
|
location,
|
|
@@ -220,7 +233,7 @@ export class TypeScriptParser {
|
|
|
220
233
|
targetIdentifier = node;
|
|
221
234
|
}
|
|
222
235
|
else if (this.isRenameableNode(node)) {
|
|
223
|
-
targetIdentifier = this.getIdentifierFromSymbolNode(node);
|
|
236
|
+
targetIdentifier = this.scopeAnalyzer.getIdentifierFromSymbolNode(node);
|
|
224
237
|
}
|
|
225
238
|
if (!targetIdentifier) {
|
|
226
239
|
throw new Error('該位置的符號不支援重新命名');
|
|
@@ -248,7 +261,7 @@ export class TypeScriptParser {
|
|
|
248
261
|
/**
|
|
249
262
|
* 提取函式重構
|
|
250
263
|
*/
|
|
251
|
-
async extractFunction(
|
|
264
|
+
async extractFunction(_ast, _selection) {
|
|
252
265
|
// 這是一個複雜的重構操作,目前提供基本實作
|
|
253
266
|
throw new Error('提取函式重構尚未實作');
|
|
254
267
|
}
|
|
@@ -345,16 +358,17 @@ export class TypeScriptParser {
|
|
|
345
358
|
async dispose() {
|
|
346
359
|
// 從記憶體監控器取消註冊
|
|
347
360
|
MemoryMonitor.getInstance().unregister(this);
|
|
348
|
-
// 清理 Language Service
|
|
349
|
-
if (this.
|
|
350
|
-
this.
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
//
|
|
354
|
-
this.
|
|
355
|
-
|
|
356
|
-
this.
|
|
357
|
-
|
|
361
|
+
// 清理 Language Service Manager
|
|
362
|
+
if (this.languageServiceManager && 'dispose' in this.languageServiceManager) {
|
|
363
|
+
this.languageServiceManager.dispose();
|
|
364
|
+
}
|
|
365
|
+
this.languageServiceManager = null;
|
|
366
|
+
// 清理新模組
|
|
367
|
+
this.scopeAnalyzer = null;
|
|
368
|
+
this.declarationAnalyzer = null;
|
|
369
|
+
this.patternAnalyzer = null;
|
|
370
|
+
this.referenceFinder = null;
|
|
371
|
+
// 清理編譯器選項參考
|
|
358
372
|
this.compilerOptions = null;
|
|
359
373
|
// 清理符號提取器和依賴分析器(如果有 dispose 方法)
|
|
360
374
|
if (this.symbolExtractor && 'dispose' in this.symbolExtractor && typeof this.symbolExtractor.dispose === 'function') {
|
|
@@ -379,59 +393,14 @@ export class TypeScriptParser {
|
|
|
379
393
|
* 包含基礎排除模式 + TypeScript 測試檔案和型別定義
|
|
380
394
|
*/
|
|
381
395
|
getDefaultExcludePatterns() {
|
|
382
|
-
return [
|
|
383
|
-
// 通用排除模式
|
|
384
|
-
'node_modules/**',
|
|
385
|
-
'.git/**',
|
|
386
|
-
'dist/**',
|
|
387
|
-
'build/**',
|
|
388
|
-
'coverage/**',
|
|
389
|
-
'.next/**',
|
|
390
|
-
'.nuxt/**',
|
|
391
|
-
'out/**',
|
|
392
|
-
'.cache/**',
|
|
393
|
-
'.turbo/**',
|
|
394
|
-
// TypeScript 特定排除模式
|
|
395
|
-
'**/*.test.ts',
|
|
396
|
-
'**/*.spec.ts',
|
|
397
|
-
'**/*.test.tsx',
|
|
398
|
-
'**/*.spec.tsx',
|
|
399
|
-
'**/__tests__/**',
|
|
400
|
-
'**/__mocks__/**',
|
|
401
|
-
'**/*.d.ts' // 型別定義檔案通常不需要分析
|
|
402
|
-
];
|
|
396
|
+
return [...TYPESCRIPT_EXCLUDE_PATTERNS];
|
|
403
397
|
}
|
|
404
398
|
/**
|
|
405
399
|
* 判斷是否應該忽略特定檔案
|
|
406
400
|
* TypeScript parser 會忽略測試檔案和型別定義檔案
|
|
407
401
|
*/
|
|
408
402
|
shouldIgnoreFile(filePath) {
|
|
409
|
-
|
|
410
|
-
const normalizedPath = filePath.replace(/^\.?\//, '');
|
|
411
|
-
// 使用 minimatch 進行模式匹配
|
|
412
|
-
return patterns.some(pattern => {
|
|
413
|
-
try {
|
|
414
|
-
// 直接使用字串包含檢查來提高效能
|
|
415
|
-
if (pattern.includes('**')) {
|
|
416
|
-
// 對於包含 ** 的模式,進行簡單的子字串匹配
|
|
417
|
-
const simplePattern = pattern.replace(/\*\*/g, '').replace(/\//g, '');
|
|
418
|
-
if (normalizedPath.includes(simplePattern)) {
|
|
419
|
-
return true;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
// 檢查檔案路徑是否匹配模式
|
|
423
|
-
if (pattern.startsWith('**/')) {
|
|
424
|
-
const suffix = pattern.substring(3);
|
|
425
|
-
if (normalizedPath.endsWith(suffix) || normalizedPath.includes('/' + suffix)) {
|
|
426
|
-
return true;
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
return false;
|
|
430
|
-
}
|
|
431
|
-
catch (error) {
|
|
432
|
-
return false;
|
|
433
|
-
}
|
|
434
|
-
});
|
|
403
|
+
return matchesAnyPattern(filePath, TYPESCRIPT_EXCLUDE_PATTERNS);
|
|
435
404
|
}
|
|
436
405
|
/**
|
|
437
406
|
* 判斷符號是否為抽象宣告
|
|
@@ -483,11 +452,6 @@ export class TypeScriptParser {
|
|
|
483
452
|
const ext = filePath.substring(filePath.lastIndexOf('.'));
|
|
484
453
|
return ext === '.tsx' ? 'tsx' : 'typescript';
|
|
485
454
|
}
|
|
486
|
-
getSyntacticDiagnostics(sourceFile) {
|
|
487
|
-
// 對於獨立的 SourceFile,我們跳過語法診斷檢查
|
|
488
|
-
// 在實際專案中,這通常由 Program 提供
|
|
489
|
-
return [];
|
|
490
|
-
}
|
|
491
455
|
findNodeAtPosition(sourceFile, position) {
|
|
492
456
|
function findNode(node) {
|
|
493
457
|
if (position >= node.getStart(sourceFile) && position < node.getEnd()) {
|
|
@@ -505,192 +469,6 @@ export class TypeScriptParser {
|
|
|
505
469
|
}
|
|
506
470
|
return findNode(sourceFile);
|
|
507
471
|
}
|
|
508
|
-
isReferenceToSymbol(node, symbol) {
|
|
509
|
-
if (!ts.isIdentifier(node)) {
|
|
510
|
-
return false;
|
|
511
|
-
}
|
|
512
|
-
const name = node.text;
|
|
513
|
-
if (name !== symbol.name) {
|
|
514
|
-
return false;
|
|
515
|
-
}
|
|
516
|
-
// 找到符號的標識符節點
|
|
517
|
-
const symbolIdentifier = this.getIdentifierFromSymbolNode(symbol.tsNode);
|
|
518
|
-
if (!symbolIdentifier) {
|
|
519
|
-
return false;
|
|
520
|
-
}
|
|
521
|
-
// 檢查是否為相同符號的引用
|
|
522
|
-
// 1. 如果是符號的定義位置本身
|
|
523
|
-
if (node === symbolIdentifier) {
|
|
524
|
-
return true;
|
|
525
|
-
}
|
|
526
|
-
// 2. 對於型別宣告(類別、介面、型別別名等),檢查是否在型別位置使用
|
|
527
|
-
if (ts.isClassDeclaration(symbol.tsNode) ||
|
|
528
|
-
ts.isInterfaceDeclaration(symbol.tsNode) ||
|
|
529
|
-
ts.isTypeAliasDeclaration(symbol.tsNode) ||
|
|
530
|
-
ts.isEnumDeclaration(symbol.tsNode)) {
|
|
531
|
-
// 對於型別,只要名稱相同就是引用(在同一個檔案中)
|
|
532
|
-
if (node.getSourceFile() === symbolIdentifier.getSourceFile()) {
|
|
533
|
-
return true;
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
// 3. 檢查是否在同一個檔案中
|
|
537
|
-
if (node.getSourceFile() !== symbolIdentifier.getSourceFile()) {
|
|
538
|
-
return false;
|
|
539
|
-
}
|
|
540
|
-
// 4. 對於變數、函式和方法,使用作用域檢查
|
|
541
|
-
const symbolScope = this.getScopeContainer(symbolIdentifier);
|
|
542
|
-
const nodeScope = this.getScopeContainer(node);
|
|
543
|
-
// 檢查是否在相同作用域或符號的子作用域內
|
|
544
|
-
if (nodeScope === symbolScope || this.isInScopeChain(node, symbolScope)) {
|
|
545
|
-
// 檢查是否被遮蔽(同名變數在更內層作用域)
|
|
546
|
-
if (!this.isShadowed(node, symbolIdentifier)) {
|
|
547
|
-
return true;
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
// 5. 對於頂層函式和變數,放寬檢查條件
|
|
551
|
-
// 如果符號在頂層作用域(SourceFile),則同一檔案中所有同名標識符都可能是引用
|
|
552
|
-
if (ts.isSourceFile(symbolScope) && !this.isShadowed(node, symbolIdentifier)) {
|
|
553
|
-
return true;
|
|
554
|
-
}
|
|
555
|
-
return false;
|
|
556
|
-
}
|
|
557
|
-
getIdentifierFromSymbolNode(node) {
|
|
558
|
-
// 如果本身就是 Identifier,直接返回
|
|
559
|
-
if (ts.isIdentifier(node)) {
|
|
560
|
-
return node;
|
|
561
|
-
}
|
|
562
|
-
// 對於變數宣告,標識符在 name 屬性中
|
|
563
|
-
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
564
|
-
return node.name;
|
|
565
|
-
}
|
|
566
|
-
// 對於函式宣告,標識符在 name 屬性中
|
|
567
|
-
if (ts.isFunctionDeclaration(node) && node.name && ts.isIdentifier(node.name)) {
|
|
568
|
-
return node.name;
|
|
569
|
-
}
|
|
570
|
-
// 對於類別宣告
|
|
571
|
-
if (ts.isClassDeclaration(node) && node.name && ts.isIdentifier(node.name)) {
|
|
572
|
-
return node.name;
|
|
573
|
-
}
|
|
574
|
-
// 對於方法宣告
|
|
575
|
-
if (ts.isMethodDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
576
|
-
return node.name;
|
|
577
|
-
}
|
|
578
|
-
// 對於屬性宣告
|
|
579
|
-
if (ts.isPropertyDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
580
|
-
return node.name;
|
|
581
|
-
}
|
|
582
|
-
// 對於參數
|
|
583
|
-
if (ts.isParameter(node) && ts.isIdentifier(node.name)) {
|
|
584
|
-
return node.name;
|
|
585
|
-
}
|
|
586
|
-
// 對於介面宣告
|
|
587
|
-
if (ts.isInterfaceDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
588
|
-
return node.name;
|
|
589
|
-
}
|
|
590
|
-
// 對於型別別名宣告
|
|
591
|
-
if (ts.isTypeAliasDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
592
|
-
return node.name;
|
|
593
|
-
}
|
|
594
|
-
// 對於列舉宣告
|
|
595
|
-
if (ts.isEnumDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
596
|
-
return node.name;
|
|
597
|
-
}
|
|
598
|
-
// 對於命名空間宣告
|
|
599
|
-
if (ts.isModuleDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
600
|
-
return node.name;
|
|
601
|
-
}
|
|
602
|
-
// 對於 Get/Set 存取器
|
|
603
|
-
if ((ts.isGetAccessor(node) || ts.isSetAccessor(node)) && ts.isIdentifier(node.name)) {
|
|
604
|
-
return node.name;
|
|
605
|
-
}
|
|
606
|
-
// 對於型別參數(泛型)
|
|
607
|
-
if (ts.isTypeParameterDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
608
|
-
return node.name;
|
|
609
|
-
}
|
|
610
|
-
// 對於介面/型別的屬性簽名
|
|
611
|
-
if (ts.isPropertySignature(node) && ts.isIdentifier(node.name)) {
|
|
612
|
-
return node.name;
|
|
613
|
-
}
|
|
614
|
-
// 對於方法簽名
|
|
615
|
-
if (ts.isMethodSignature(node) && ts.isIdentifier(node.name)) {
|
|
616
|
-
return node.name;
|
|
617
|
-
}
|
|
618
|
-
return null;
|
|
619
|
-
}
|
|
620
|
-
getNodeScope(node) {
|
|
621
|
-
let current = node.parent;
|
|
622
|
-
while (current) {
|
|
623
|
-
if (ts.isFunctionDeclaration(current) ||
|
|
624
|
-
ts.isMethodDeclaration(current) ||
|
|
625
|
-
ts.isArrowFunction(current) ||
|
|
626
|
-
ts.isFunctionExpression(current)) {
|
|
627
|
-
return `function_${current.pos}_${current.end}`;
|
|
628
|
-
}
|
|
629
|
-
if (ts.isBlock(current) && current.parent &&
|
|
630
|
-
(ts.isIfStatement(current.parent) ||
|
|
631
|
-
ts.isForStatement(current.parent) ||
|
|
632
|
-
ts.isWhileStatement(current.parent))) {
|
|
633
|
-
return `block_${current.pos}_${current.end}`;
|
|
634
|
-
}
|
|
635
|
-
current = current.parent;
|
|
636
|
-
}
|
|
637
|
-
return 'global';
|
|
638
|
-
}
|
|
639
|
-
isInSameScope(node, symbolNode) {
|
|
640
|
-
// 找到符號定義所在的作用域
|
|
641
|
-
let symbolScope = symbolNode.parent;
|
|
642
|
-
while (symbolScope && !this.isScopeNode(symbolScope)) {
|
|
643
|
-
symbolScope = symbolScope.parent;
|
|
644
|
-
}
|
|
645
|
-
// 檢查節點是否在該作用域內
|
|
646
|
-
let currentScope = node.parent;
|
|
647
|
-
while (currentScope) {
|
|
648
|
-
if (currentScope === symbolScope) {
|
|
649
|
-
return true;
|
|
650
|
-
}
|
|
651
|
-
currentScope = currentScope.parent;
|
|
652
|
-
}
|
|
653
|
-
return false;
|
|
654
|
-
}
|
|
655
|
-
isScopeNode(node) {
|
|
656
|
-
return ts.isFunctionDeclaration(node) ||
|
|
657
|
-
ts.isMethodDeclaration(node) ||
|
|
658
|
-
ts.isArrowFunction(node) ||
|
|
659
|
-
ts.isFunctionExpression(node) ||
|
|
660
|
-
ts.isBlock(node) ||
|
|
661
|
-
ts.isSourceFile(node);
|
|
662
|
-
}
|
|
663
|
-
getReferenceType(node, symbol) {
|
|
664
|
-
// 找到符號的標識符節點
|
|
665
|
-
const symbolIdentifier = this.getIdentifierFromSymbolNode(symbol.tsNode);
|
|
666
|
-
// 如果是符號的原始定義位置
|
|
667
|
-
if (node === symbolIdentifier) {
|
|
668
|
-
return ReferenceType.Definition;
|
|
669
|
-
}
|
|
670
|
-
// 檢查是否為宣告(例如函式參數、變數宣告等)
|
|
671
|
-
if (this.isDeclarationNode(node.parent)) {
|
|
672
|
-
return ReferenceType.Declaration;
|
|
673
|
-
}
|
|
674
|
-
// 檢查是否在 import 語句內
|
|
675
|
-
if (this.isInImportStatement(node)) {
|
|
676
|
-
return ReferenceType.Import;
|
|
677
|
-
}
|
|
678
|
-
// 否則為使用
|
|
679
|
-
return ReferenceType.Usage;
|
|
680
|
-
}
|
|
681
|
-
/**
|
|
682
|
-
* 檢查節點是否位於 import 語句內
|
|
683
|
-
*/
|
|
684
|
-
isInImportStatement(node) {
|
|
685
|
-
let current = node.parent;
|
|
686
|
-
while (current) {
|
|
687
|
-
if (ts.isImportDeclaration(current) || ts.isImportEqualsDeclaration(current)) {
|
|
688
|
-
return true;
|
|
689
|
-
}
|
|
690
|
-
current = current.parent;
|
|
691
|
-
}
|
|
692
|
-
return false;
|
|
693
|
-
}
|
|
694
472
|
isRenameableNode(node) {
|
|
695
473
|
return (ts.isIdentifier(node) ||
|
|
696
474
|
ts.isClassDeclaration(node) ||
|
|
@@ -792,7 +570,7 @@ export class TypeScriptParser {
|
|
|
792
570
|
for (const symbol of symbols) {
|
|
793
571
|
const typedSymbol = symbol;
|
|
794
572
|
// 獲取符號的標識符節點
|
|
795
|
-
const identifier = this.getIdentifierFromSymbolNode(typedSymbol.tsNode);
|
|
573
|
+
const identifier = this.scopeAnalyzer.getIdentifierFromSymbolNode(typedSymbol.tsNode);
|
|
796
574
|
if (!identifier) {
|
|
797
575
|
continue;
|
|
798
576
|
}
|
|
@@ -823,189 +601,56 @@ export class TypeScriptParser {
|
|
|
823
601
|
return true;
|
|
824
602
|
}
|
|
825
603
|
/**
|
|
826
|
-
*
|
|
827
|
-
*/
|
|
828
|
-
ensureLanguageServiceInitialized(sourceFile) {
|
|
829
|
-
if (this.languageService) {
|
|
830
|
-
// 更新檔案內容
|
|
831
|
-
this.updateFile(sourceFile.fileName, sourceFile.text);
|
|
832
|
-
return;
|
|
833
|
-
}
|
|
834
|
-
// 添加當前檔案到檔案列表
|
|
835
|
-
this.updateFile(sourceFile.fileName, sourceFile.text);
|
|
836
|
-
// 建立 Language Service Host
|
|
837
|
-
this.languageServiceHost = {
|
|
838
|
-
getScriptFileNames: () => {
|
|
839
|
-
const fileNames = Array.from(this.files.keys());
|
|
840
|
-
// 確保包含當前檔案
|
|
841
|
-
if (!fileNames.includes(sourceFile.fileName)) {
|
|
842
|
-
fileNames.push(sourceFile.fileName);
|
|
843
|
-
}
|
|
844
|
-
return fileNames;
|
|
845
|
-
},
|
|
846
|
-
getScriptVersion: (fileName) => {
|
|
847
|
-
const file = this.files.get(fileName);
|
|
848
|
-
return file ? String(file.version) : '0';
|
|
849
|
-
},
|
|
850
|
-
getScriptSnapshot: (fileName) => {
|
|
851
|
-
const file = this.files.get(fileName);
|
|
852
|
-
if (file) {
|
|
853
|
-
return ts.ScriptSnapshot.fromString(file.content);
|
|
854
|
-
}
|
|
855
|
-
// 嘗試讀取實際檔案
|
|
856
|
-
try {
|
|
857
|
-
const content = ts.sys.readFile(fileName);
|
|
858
|
-
if (content) {
|
|
859
|
-
return ts.ScriptSnapshot.fromString(content);
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
catch {
|
|
863
|
-
// 忽略錯誤
|
|
864
|
-
}
|
|
865
|
-
return undefined;
|
|
866
|
-
},
|
|
867
|
-
getCurrentDirectory: () => process.cwd(),
|
|
868
|
-
getCompilationSettings: () => ({
|
|
869
|
-
...this.compilerOptions,
|
|
870
|
-
// 確保啟用必要的選項
|
|
871
|
-
allowNonTsExtensions: true,
|
|
872
|
-
noResolve: false,
|
|
873
|
-
noLib: false,
|
|
874
|
-
lib: this.compilerOptions.lib || ['lib.es2020.d.ts']
|
|
875
|
-
}),
|
|
876
|
-
getDefaultLibFileName: (options) => ts.getDefaultLibFilePath(options),
|
|
877
|
-
fileExists: (fileName) => {
|
|
878
|
-
return this.files.has(fileName) || (ts.sys.fileExists ? ts.sys.fileExists(fileName) : false);
|
|
879
|
-
},
|
|
880
|
-
readFile: (fileName) => {
|
|
881
|
-
const file = this.files.get(fileName);
|
|
882
|
-
if (file) {
|
|
883
|
-
return file.content;
|
|
884
|
-
}
|
|
885
|
-
return ts.sys.readFile ? ts.sys.readFile(fileName) : undefined;
|
|
886
|
-
},
|
|
887
|
-
readDirectory: ts.sys.readDirectory ? ts.sys.readDirectory : () => [],
|
|
888
|
-
getDirectories: ts.sys.getDirectories ? ts.sys.getDirectories : () => [],
|
|
889
|
-
directoryExists: ts.sys.directoryExists ? ts.sys.directoryExists : () => false,
|
|
890
|
-
realpath: ts.sys.realpath ? ts.sys.realpath : (path) => path,
|
|
891
|
-
getNewLine: () => '\n'
|
|
892
|
-
};
|
|
893
|
-
// 建立 Language Service
|
|
894
|
-
this.languageService = ts.createLanguageService(this.languageServiceHost, ts.createDocumentRegistry());
|
|
895
|
-
}
|
|
896
|
-
/**
|
|
897
|
-
* 更新檔案內容
|
|
604
|
+
* 判斷檔案是否為測試檔案
|
|
898
605
|
*/
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
}
|
|
904
|
-
this.files.set(fileName, {
|
|
905
|
-
version: existing ? existing.version + 1 : 0,
|
|
906
|
-
content
|
|
907
|
-
});
|
|
606
|
+
isTestFile(filePath) {
|
|
607
|
+
return /\.(test|spec)\.(ts|tsx)$/.test(filePath) ||
|
|
608
|
+
filePath.includes('/__tests__/') ||
|
|
609
|
+
filePath.includes('/__mocks__/');
|
|
908
610
|
}
|
|
909
611
|
/**
|
|
910
|
-
*
|
|
612
|
+
* 取得符號的完整宣告範圍(包含 JSDoc、裝飾器)
|
|
613
|
+
* 委託給 DeclarationAnalyzer
|
|
911
614
|
*/
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
if (!identifier) {
|
|
915
|
-
return undefined;
|
|
916
|
-
}
|
|
917
|
-
return identifier.getStart(sourceFile);
|
|
615
|
+
getFullDeclarationRange(code, symbolName, symbolType, startLine) {
|
|
616
|
+
return this.declarationAnalyzer.getFullDeclarationRange(code, symbolName, symbolType, startLine);
|
|
918
617
|
}
|
|
919
618
|
/**
|
|
920
|
-
*
|
|
619
|
+
* 解析程式碼中的所有 import 宣告
|
|
620
|
+
* 委託給 DeclarationAnalyzer
|
|
921
621
|
*/
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
return undefined;
|
|
925
|
-
}
|
|
926
|
-
const program = this.languageService.getProgram();
|
|
927
|
-
return program?.getSourceFile(fileName);
|
|
622
|
+
getImportDeclarations(code) {
|
|
623
|
+
return this.declarationAnalyzer.getImportDeclarations(code);
|
|
928
624
|
}
|
|
929
625
|
/**
|
|
930
|
-
*
|
|
626
|
+
* 格式化函數簽章
|
|
627
|
+
* 委託給 DeclarationAnalyzer
|
|
931
628
|
*/
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
while (current) {
|
|
935
|
-
if (ts.isFunctionDeclaration(current) ||
|
|
936
|
-
ts.isFunctionExpression(current) ||
|
|
937
|
-
ts.isArrowFunction(current) ||
|
|
938
|
-
ts.isMethodDeclaration(current) ||
|
|
939
|
-
ts.isConstructorDeclaration(current) ||
|
|
940
|
-
ts.isBlock(current) ||
|
|
941
|
-
ts.isSourceFile(current)) {
|
|
942
|
-
return current;
|
|
943
|
-
}
|
|
944
|
-
current = current.parent;
|
|
945
|
-
}
|
|
946
|
-
return node.getSourceFile();
|
|
629
|
+
formatSignature(code, functionName, line) {
|
|
630
|
+
return this.declarationAnalyzer.formatSignature(code, functionName, line);
|
|
947
631
|
}
|
|
948
632
|
/**
|
|
949
|
-
*
|
|
633
|
+
* 提取符號的 JSDoc 文件註解
|
|
634
|
+
* 委託給 DeclarationAnalyzer
|
|
950
635
|
*/
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
while (current) {
|
|
954
|
-
if (current === scopeContainer) {
|
|
955
|
-
return true;
|
|
956
|
-
}
|
|
957
|
-
current = current.parent;
|
|
958
|
-
}
|
|
959
|
-
return false;
|
|
636
|
+
getDocumentation(code, symbolName, symbolType, line) {
|
|
637
|
+
return this.declarationAnalyzer.getDocumentation(code, symbolName, symbolType, line);
|
|
960
638
|
}
|
|
639
|
+
// ===== 設計模式識別支援 =====
|
|
961
640
|
/**
|
|
962
|
-
*
|
|
641
|
+
* 識別程式碼中的設計模式
|
|
642
|
+
* 委託給 PatternAnalyzer
|
|
963
643
|
*/
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
let current = node.parent;
|
|
967
|
-
// 從 node 向上遍歷到 originalIdentifier 的作用域
|
|
968
|
-
while (current && current !== originalIdentifier.parent) {
|
|
969
|
-
// 檢查當前作用域是否有同名的宣告
|
|
970
|
-
if (ts.isFunctionDeclaration(current) ||
|
|
971
|
-
ts.isFunctionExpression(current) ||
|
|
972
|
-
ts.isArrowFunction(current) ||
|
|
973
|
-
ts.isMethodDeclaration(current)) {
|
|
974
|
-
// 檢查參數
|
|
975
|
-
if (current.parameters) {
|
|
976
|
-
for (const param of current.parameters) {
|
|
977
|
-
if (ts.isIdentifier(param.name) && param.name.text === name) {
|
|
978
|
-
return true; // 被參數遮蔽
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
// 檢查區塊作用域中的宣告
|
|
984
|
-
if (ts.isBlock(current)) {
|
|
985
|
-
for (const statement of current.statements) {
|
|
986
|
-
if (ts.isVariableStatement(statement)) {
|
|
987
|
-
for (const decl of statement.declarationList.declarations) {
|
|
988
|
-
if (ts.isIdentifier(decl.name) && decl.name.text === name) {
|
|
989
|
-
// 確認這個宣告在 node 之前
|
|
990
|
-
if (decl.pos < node.pos) {
|
|
991
|
-
return true; // 被區域變數遮蔽
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
current = current.parent;
|
|
999
|
-
}
|
|
1000
|
-
return false;
|
|
644
|
+
identifyPatterns(code) {
|
|
645
|
+
return this.patternAnalyzer.identifyPatterns(code);
|
|
1001
646
|
}
|
|
647
|
+
// ===== 作用域感知符號查找支援 =====
|
|
1002
648
|
/**
|
|
1003
|
-
*
|
|
649
|
+
* 作用域感知的符號引用查找
|
|
650
|
+
* 委託給 ReferenceFinder
|
|
1004
651
|
*/
|
|
1005
|
-
|
|
1006
|
-
return
|
|
1007
|
-
filePath.includes('/__tests__/') ||
|
|
1008
|
-
filePath.includes('/__mocks__/');
|
|
652
|
+
findScopedReferences(code, symbolName, options) {
|
|
653
|
+
return this.referenceFinder.findScopedReferences(code, symbolName, options);
|
|
1009
654
|
}
|
|
1010
655
|
}
|
|
1011
656
|
//# sourceMappingURL=parser.js.map
|