agent-ide 0.1.10 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -12
- package/dist/application/services/module-coordinator.service.d.ts +0 -1
- package/dist/application/services/module-coordinator.service.d.ts.map +1 -1
- package/dist/application/services/module-coordinator.service.js +2 -8
- package/dist/application/services/module-coordinator.service.js.map +1 -1
- package/dist/core/analysis/index.d.ts +1 -4
- package/dist/core/analysis/index.d.ts.map +1 -1
- package/dist/core/analysis/index.js +1 -7
- package/dist/core/analysis/index.js.map +1 -1
- package/dist/core/dependency/dependency-analyzer.d.ts.map +1 -1
- package/dist/core/dependency/dependency-analyzer.js +10 -0
- package/dist/core/dependency/dependency-analyzer.js.map +1 -1
- package/dist/core/indexing/index-engine.d.ts +4 -0
- package/dist/core/indexing/index-engine.d.ts.map +1 -1
- package/dist/core/indexing/index-engine.js +25 -1
- package/dist/core/indexing/index-engine.js.map +1 -1
- package/dist/core/indexing/symbol-index.d.ts +4 -0
- package/dist/core/indexing/symbol-index.d.ts.map +1 -1
- package/dist/core/indexing/symbol-index.js +17 -0
- package/dist/core/indexing/symbol-index.js.map +1 -1
- package/dist/core/move/import-resolver.d.ts.map +1 -1
- package/dist/core/move/import-resolver.js +8 -0
- package/dist/core/move/import-resolver.js.map +1 -1
- package/dist/core/move/move-service.js +7 -7
- package/dist/core/move/move-service.js.map +1 -1
- package/dist/core/refactor/swift-extractor.d.ts +98 -0
- package/dist/core/refactor/swift-extractor.d.ts.map +1 -0
- package/dist/core/refactor/swift-extractor.js +283 -0
- package/dist/core/refactor/swift-extractor.js.map +1 -0
- package/dist/core/rename/reference-updater.d.ts.map +1 -1
- package/dist/core/rename/reference-updater.js +16 -8
- package/dist/core/rename/reference-updater.js.map +1 -1
- package/dist/core/search/engines/text-engine.js +1 -1
- package/dist/core/search/engines/text-engine.js.map +1 -1
- package/dist/core/shit-score/grading.d.ts +39 -0
- package/dist/core/shit-score/grading.d.ts.map +1 -0
- package/dist/core/shit-score/grading.js +253 -0
- package/dist/core/shit-score/grading.js.map +1 -0
- package/dist/core/shit-score/index.d.ts +9 -0
- package/dist/core/shit-score/index.d.ts.map +1 -0
- package/dist/core/shit-score/index.js +8 -0
- package/dist/core/shit-score/index.js.map +1 -0
- package/dist/core/shit-score/score-calculator.d.ts +75 -0
- package/dist/core/shit-score/score-calculator.d.ts.map +1 -0
- package/dist/core/shit-score/score-calculator.js +240 -0
- package/dist/core/shit-score/score-calculator.js.map +1 -0
- package/dist/core/shit-score/shit-score-analyzer.d.ts +84 -0
- package/dist/core/shit-score/shit-score-analyzer.d.ts.map +1 -0
- package/dist/core/shit-score/shit-score-analyzer.js +595 -0
- package/dist/core/shit-score/shit-score-analyzer.js.map +1 -0
- package/dist/core/shit-score/types.d.ts +231 -0
- package/dist/core/shit-score/types.d.ts.map +1 -0
- package/dist/core/shit-score/types.js +73 -0
- package/dist/core/shit-score/types.js.map +1 -0
- package/dist/core/snapshot/code-compressor.d.ts +39 -0
- package/dist/core/snapshot/code-compressor.d.ts.map +1 -0
- package/dist/core/snapshot/code-compressor.js +211 -0
- package/dist/core/snapshot/code-compressor.js.map +1 -0
- package/dist/core/snapshot/config.d.ts +60 -0
- package/dist/core/snapshot/config.d.ts.map +1 -0
- package/dist/core/snapshot/config.js +136 -0
- package/dist/core/snapshot/config.js.map +1 -0
- package/dist/core/snapshot/index.d.ts +23 -0
- package/dist/core/snapshot/index.d.ts.map +1 -0
- package/dist/core/snapshot/index.js +27 -0
- package/dist/core/snapshot/index.js.map +1 -0
- package/dist/core/snapshot/snapshot-differ.d.ts +54 -0
- package/dist/core/snapshot/snapshot-differ.d.ts.map +1 -0
- package/dist/core/snapshot/snapshot-differ.js +262 -0
- package/dist/core/snapshot/snapshot-differ.js.map +1 -0
- package/dist/core/snapshot/snapshot-engine.d.ts +94 -0
- package/dist/core/snapshot/snapshot-engine.d.ts.map +1 -0
- package/dist/core/snapshot/snapshot-engine.js +492 -0
- package/dist/core/snapshot/snapshot-engine.js.map +1 -0
- package/dist/core/snapshot/types.d.ts +216 -0
- package/dist/core/snapshot/types.d.ts.map +1 -0
- package/dist/core/snapshot/types.js +79 -0
- package/dist/core/snapshot/types.js.map +1 -0
- package/dist/infrastructure/parser/analysis-types.d.ts +198 -0
- package/dist/infrastructure/parser/analysis-types.d.ts.map +1 -0
- package/dist/infrastructure/parser/analysis-types.js +6 -0
- package/dist/infrastructure/parser/analysis-types.js.map +1 -0
- package/dist/infrastructure/parser/base.d.ts +36 -0
- package/dist/infrastructure/parser/base.d.ts.map +1 -1
- package/dist/infrastructure/parser/base.js +72 -0
- package/dist/infrastructure/parser/base.js.map +1 -1
- package/dist/infrastructure/parser/index.d.ts +1 -0
- package/dist/infrastructure/parser/index.d.ts.map +1 -1
- package/dist/infrastructure/parser/index.js.map +1 -1
- package/dist/infrastructure/parser/interface.d.ts +63 -0
- package/dist/infrastructure/parser/interface.d.ts.map +1 -1
- package/dist/infrastructure/parser/interface.js +11 -1
- package/dist/infrastructure/parser/interface.js.map +1 -1
- package/dist/interfaces/cli/cli.d.ts +24 -0
- package/dist/interfaces/cli/cli.d.ts.map +1 -1
- package/dist/interfaces/cli/cli.js +1417 -141
- package/dist/interfaces/cli/cli.js.map +1 -1
- package/dist/plugins/javascript/parser.d.ts +41 -0
- package/dist/plugins/javascript/parser.d.ts.map +1 -1
- package/dist/plugins/javascript/parser.js +284 -0
- package/dist/plugins/javascript/parser.js.map +1 -1
- package/dist/plugins/swift/analyzers/complexity-analyzer.d.ts +41 -0
- package/dist/plugins/swift/analyzers/complexity-analyzer.d.ts.map +1 -0
- package/dist/plugins/swift/analyzers/complexity-analyzer.js +206 -0
- package/dist/plugins/swift/analyzers/complexity-analyzer.js.map +1 -0
- package/dist/plugins/swift/analyzers/duplication-detector.d.ts +89 -0
- package/dist/plugins/swift/analyzers/duplication-detector.d.ts.map +1 -0
- package/dist/plugins/swift/analyzers/duplication-detector.js +271 -0
- package/dist/plugins/swift/analyzers/duplication-detector.js.map +1 -0
- package/dist/plugins/swift/analyzers/error-handling-checker.d.ts +34 -0
- package/dist/plugins/swift/analyzers/error-handling-checker.d.ts.map +1 -0
- package/dist/plugins/swift/analyzers/error-handling-checker.js +135 -0
- package/dist/plugins/swift/analyzers/error-handling-checker.js.map +1 -0
- package/dist/plugins/swift/analyzers/naming-checker.d.ts +47 -0
- package/dist/plugins/swift/analyzers/naming-checker.d.ts.map +1 -0
- package/dist/plugins/swift/analyzers/naming-checker.js +161 -0
- package/dist/plugins/swift/analyzers/naming-checker.js.map +1 -0
- package/dist/plugins/swift/analyzers/pattern-detector.d.ts +78 -0
- package/dist/plugins/swift/analyzers/pattern-detector.d.ts.map +1 -0
- package/dist/plugins/swift/analyzers/pattern-detector.js +247 -0
- package/dist/plugins/swift/analyzers/pattern-detector.js.map +1 -0
- package/dist/plugins/swift/analyzers/security-checker.d.ts +38 -0
- package/dist/plugins/swift/analyzers/security-checker.d.ts.map +1 -0
- package/dist/plugins/swift/analyzers/security-checker.js +135 -0
- package/dist/plugins/swift/analyzers/security-checker.js.map +1 -0
- package/dist/plugins/swift/analyzers/test-coverage-checker.d.ts +26 -0
- package/dist/plugins/swift/analyzers/test-coverage-checker.d.ts.map +1 -0
- package/dist/plugins/swift/analyzers/test-coverage-checker.js +63 -0
- package/dist/plugins/swift/analyzers/test-coverage-checker.js.map +1 -0
- package/dist/plugins/swift/analyzers/type-safety-checker.d.ts +41 -0
- package/dist/plugins/swift/analyzers/type-safety-checker.d.ts.map +1 -0
- package/dist/plugins/swift/analyzers/type-safety-checker.js +121 -0
- package/dist/plugins/swift/analyzers/type-safety-checker.js.map +1 -0
- package/dist/plugins/swift/analyzers/unused-symbol-detector.d.ts +38 -0
- package/dist/plugins/swift/analyzers/unused-symbol-detector.d.ts.map +1 -0
- package/dist/plugins/swift/analyzers/unused-symbol-detector.js +211 -0
- package/dist/plugins/swift/analyzers/unused-symbol-detector.js.map +1 -0
- package/dist/plugins/swift/dependency-analyzer.d.ts +33 -0
- package/dist/plugins/swift/dependency-analyzer.d.ts.map +1 -0
- package/dist/plugins/swift/dependency-analyzer.js +95 -0
- package/dist/plugins/swift/dependency-analyzer.js.map +1 -0
- package/dist/plugins/swift/index.d.ts +14 -0
- package/dist/plugins/swift/index.d.ts.map +1 -0
- package/dist/plugins/swift/index.js +19 -0
- package/dist/plugins/swift/index.js.map +1 -0
- package/dist/plugins/swift/parser.d.ts +160 -0
- package/dist/plugins/swift/parser.d.ts.map +1 -0
- package/dist/plugins/swift/parser.js +670 -0
- package/dist/plugins/swift/parser.js.map +1 -0
- package/dist/plugins/swift/swift-bridge/swift-parser +0 -0
- package/dist/plugins/swift/symbol-extractor.d.ts +46 -0
- package/dist/plugins/swift/symbol-extractor.d.ts.map +1 -0
- package/dist/plugins/swift/symbol-extractor.js +187 -0
- package/dist/plugins/swift/symbol-extractor.js.map +1 -0
- package/dist/plugins/swift/types.d.ts +137 -0
- package/dist/plugins/swift/types.d.ts.map +1 -0
- package/dist/plugins/swift/types.js +212 -0
- package/dist/plugins/swift/types.js.map +1 -0
- package/dist/plugins/typescript/analyzers/complexity-analyzer.d.ts +39 -0
- package/dist/plugins/typescript/analyzers/complexity-analyzer.d.ts.map +1 -0
- package/dist/plugins/typescript/analyzers/complexity-analyzer.js +196 -0
- package/dist/plugins/typescript/analyzers/complexity-analyzer.js.map +1 -0
- package/dist/{core/analysis → plugins/typescript/analyzers}/duplication-detector.d.ts +34 -3
- package/dist/plugins/typescript/analyzers/duplication-detector.d.ts.map +1 -0
- package/dist/plugins/typescript/analyzers/duplication-detector.js +695 -0
- package/dist/plugins/typescript/analyzers/duplication-detector.js.map +1 -0
- package/dist/plugins/typescript/analyzers/error-handling-checker.d.ts +26 -0
- package/dist/plugins/typescript/analyzers/error-handling-checker.d.ts.map +1 -0
- package/dist/plugins/typescript/analyzers/error-handling-checker.js +84 -0
- package/dist/plugins/typescript/analyzers/error-handling-checker.js.map +1 -0
- package/dist/plugins/typescript/analyzers/naming-checker.d.ts +30 -0
- package/dist/plugins/typescript/analyzers/naming-checker.d.ts.map +1 -0
- package/dist/plugins/typescript/analyzers/naming-checker.js +116 -0
- package/dist/plugins/typescript/analyzers/naming-checker.js.map +1 -0
- package/dist/plugins/typescript/analyzers/pattern-detector.d.ts +80 -0
- package/dist/plugins/typescript/analyzers/pattern-detector.d.ts.map +1 -0
- package/dist/plugins/typescript/analyzers/pattern-detector.js +267 -0
- package/dist/plugins/typescript/analyzers/pattern-detector.js.map +1 -0
- package/dist/plugins/typescript/analyzers/security-checker.d.ts +34 -0
- package/dist/plugins/typescript/analyzers/security-checker.d.ts.map +1 -0
- package/dist/plugins/typescript/analyzers/security-checker.js +126 -0
- package/dist/plugins/typescript/analyzers/security-checker.js.map +1 -0
- package/dist/plugins/typescript/analyzers/test-coverage-checker.d.ts +22 -0
- package/dist/plugins/typescript/analyzers/test-coverage-checker.d.ts.map +1 -0
- package/dist/plugins/typescript/analyzers/test-coverage-checker.js +62 -0
- package/dist/plugins/typescript/analyzers/test-coverage-checker.js.map +1 -0
- package/dist/plugins/typescript/analyzers/type-safety-checker.d.ts +32 -0
- package/dist/plugins/typescript/analyzers/type-safety-checker.d.ts.map +1 -0
- package/dist/plugins/typescript/analyzers/type-safety-checker.js +86 -0
- package/dist/plugins/typescript/analyzers/type-safety-checker.js.map +1 -0
- package/dist/plugins/typescript/analyzers/unused-symbol-detector.d.ts +47 -0
- package/dist/plugins/typescript/analyzers/unused-symbol-detector.d.ts.map +1 -0
- package/dist/plugins/typescript/analyzers/unused-symbol-detector.js +152 -0
- package/dist/plugins/typescript/analyzers/unused-symbol-detector.js.map +1 -0
- package/dist/plugins/typescript/parser.d.ts +41 -0
- package/dist/plugins/typescript/parser.d.ts.map +1 -1
- package/dist/plugins/typescript/parser.js +336 -0
- package/dist/plugins/typescript/parser.js.map +1 -1
- package/dist/shared/types/symbol.d.ts +7 -1
- package/dist/shared/types/symbol.d.ts.map +1 -1
- package/dist/shared/types/symbol.js +8 -2
- package/dist/shared/types/symbol.js.map +1 -1
- package/package.json +17 -7
- package/bin/mcp-server.js +0 -20
- package/dist/core/analysis/complexity-analyzer.d.ts +0 -81
- package/dist/core/analysis/complexity-analyzer.d.ts.map +0 -1
- package/dist/core/analysis/complexity-analyzer.js +0 -255
- package/dist/core/analysis/complexity-analyzer.js.map +0 -1
- package/dist/core/analysis/dead-code-detector.d.ts +0 -152
- package/dist/core/analysis/dead-code-detector.d.ts.map +0 -1
- package/dist/core/analysis/dead-code-detector.js +0 -351
- package/dist/core/analysis/dead-code-detector.js.map +0 -1
- package/dist/core/analysis/duplication-detector.d.ts.map +0 -1
- package/dist/core/analysis/duplication-detector.js +0 -433
- package/dist/core/analysis/duplication-detector.js.map +0 -1
- package/dist/interfaces/mcp/index.d.ts +0 -7
- package/dist/interfaces/mcp/index.d.ts.map +0 -1
- package/dist/interfaces/mcp/index.js +0 -6
- package/dist/interfaces/mcp/index.js.map +0 -1
- package/dist/interfaces/mcp/mcp-server.d.ts +0 -34
- package/dist/interfaces/mcp/mcp-server.d.ts.map +0 -1
- package/dist/interfaces/mcp/mcp-server.js +0 -162
- package/dist/interfaces/mcp/mcp-server.js.map +0 -1
- package/dist/interfaces/mcp/mcp.d.ts +0 -52
- package/dist/interfaces/mcp/mcp.d.ts.map +0 -1
- package/dist/interfaces/mcp/mcp.js +0 -853
- package/dist/interfaces/mcp/mcp.js.map +0 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Swift 安全性檢查器
|
|
3
|
+
* 檢測硬編碼密碼、API Key、UserDefaults 儲存敏感資料、非 HTTPS 請求
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Swift 安全性檢查器
|
|
7
|
+
*/
|
|
8
|
+
export class SecurityChecker {
|
|
9
|
+
/**
|
|
10
|
+
* 檢查檔案的安全性問題
|
|
11
|
+
*/
|
|
12
|
+
async check(files, fileContents) {
|
|
13
|
+
let criticalIssues = 0; // 關鍵安全問題
|
|
14
|
+
let highIssues = 0; // 高風險問題
|
|
15
|
+
let mediumIssues = 0; // 中風險問題
|
|
16
|
+
for (const file of files) {
|
|
17
|
+
if (!this.isSwiftFile(file)) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const content = fileContents.get(file);
|
|
21
|
+
if (!content) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
// 關鍵問題:硬編碼密碼和金鑰
|
|
25
|
+
criticalIssues += this.checkHardcodedSecrets(content);
|
|
26
|
+
// 高風險:UserDefaults 儲存敏感資料
|
|
27
|
+
highIssues += this.checkUserDefaultsSecrets(content);
|
|
28
|
+
// 高風險:非 HTTPS 請求
|
|
29
|
+
highIssues += this.checkInsecureHTTP(content);
|
|
30
|
+
// 中風險:print 包含敏感資訊
|
|
31
|
+
mediumIssues += this.checkPrintSecrets(content);
|
|
32
|
+
}
|
|
33
|
+
// 計算總分(關鍵問題權重最高)
|
|
34
|
+
return criticalIssues * 5 + highIssues * 3 + mediumIssues;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 檢測硬編碼的密碼和 API Key
|
|
38
|
+
*/
|
|
39
|
+
checkHardcodedSecrets(content) {
|
|
40
|
+
let count = 0;
|
|
41
|
+
// 硬編碼密碼模式
|
|
42
|
+
const passwordPatterns = [
|
|
43
|
+
/let\s+password\s*=\s*"[^"]+"/gi,
|
|
44
|
+
/var\s+password\s*=\s*"[^"]+"/gi,
|
|
45
|
+
/let\s+apiKey\s*=\s*"[^"]+"/gi,
|
|
46
|
+
/var\s+apiKey\s*=\s*"[^"]+"/gi,
|
|
47
|
+
/let\s+secretKey\s*=\s*"[^"]+"/gi,
|
|
48
|
+
/var\s+secretKey\s*=\s*"[^"]+"/gi
|
|
49
|
+
];
|
|
50
|
+
for (const pattern of passwordPatterns) {
|
|
51
|
+
const matches = content.match(pattern);
|
|
52
|
+
if (matches) {
|
|
53
|
+
// 排除環境變數(ProcessInfo.processInfo.environment)
|
|
54
|
+
for (const match of matches) {
|
|
55
|
+
if (!match.includes('ProcessInfo') && !match.includes('environment')) {
|
|
56
|
+
count++;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return count;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 檢測 UserDefaults 儲存敏感資料
|
|
65
|
+
*/
|
|
66
|
+
checkUserDefaultsSecrets(content) {
|
|
67
|
+
let count = 0;
|
|
68
|
+
// UserDefaults 儲存敏感資料模式
|
|
69
|
+
const userDefaultsPatterns = [
|
|
70
|
+
/UserDefaults\..*\.set\([^)]*password[^)]*\)/gi,
|
|
71
|
+
/UserDefaults\..*\.set\([^)]*token[^)]*\)/gi,
|
|
72
|
+
/UserDefaults\..*\.set\([^)]*apiKey[^)]*\)/gi,
|
|
73
|
+
/UserDefaults\..*\.set\([^)]*secret[^)]*\)/gi
|
|
74
|
+
];
|
|
75
|
+
for (const pattern of userDefaultsPatterns) {
|
|
76
|
+
const matches = content.match(pattern);
|
|
77
|
+
if (matches) {
|
|
78
|
+
count += matches.length;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return count;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 檢測不安全的 HTTP 請求(非 HTTPS)
|
|
85
|
+
*/
|
|
86
|
+
checkInsecureHTTP(content) {
|
|
87
|
+
let count = 0;
|
|
88
|
+
// HTTP URL 模式(不是 HTTPS)
|
|
89
|
+
const httpPattern = /["']http:\/\/[^"']+["']/g;
|
|
90
|
+
const matches = content.match(httpPattern);
|
|
91
|
+
if (matches) {
|
|
92
|
+
// 排除 localhost 和常見測試 URL
|
|
93
|
+
for (const match of matches) {
|
|
94
|
+
if (!match.includes('localhost') && !match.includes('127.0.0.1')) {
|
|
95
|
+
count++;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return count;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* 檢測 print 包含敏感資訊
|
|
103
|
+
*/
|
|
104
|
+
checkPrintSecrets(content) {
|
|
105
|
+
let count = 0;
|
|
106
|
+
// print 包含敏感關鍵字
|
|
107
|
+
const sensitivePatterns = [
|
|
108
|
+
/print\([^)]*password[^)]*\)/gi,
|
|
109
|
+
/print\([^)]*token[^)]*\)/gi,
|
|
110
|
+
/print\([^)]*apiKey[^)]*\)/gi,
|
|
111
|
+
/print\([^)]*secret[^)]*\)/gi
|
|
112
|
+
];
|
|
113
|
+
for (const pattern of sensitivePatterns) {
|
|
114
|
+
const matches = content.match(pattern);
|
|
115
|
+
if (matches) {
|
|
116
|
+
count += matches.length;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return count;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* 判斷是否為 Swift 檔案
|
|
123
|
+
*/
|
|
124
|
+
isSwiftFile(file) {
|
|
125
|
+
return file.endsWith('.swift');
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* 預設導出檢查函式
|
|
130
|
+
*/
|
|
131
|
+
export default async function checkSecurity(files, fileContents) {
|
|
132
|
+
const checker = new SecurityChecker();
|
|
133
|
+
return checker.check(files, fileContents);
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=security-checker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security-checker.js","sourceRoot":"","sources":["../../../../src/plugins/swift/analyzers/security-checker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Swift 測試覆蓋率檢查器
|
|
3
|
+
* 計算測試檔案比例(靜態分析)
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Swift 測試覆蓋率檢查器
|
|
7
|
+
*/
|
|
8
|
+
export declare class TestCoverageChecker {
|
|
9
|
+
/**
|
|
10
|
+
* 計算測試覆蓋率(測試檔案比例)
|
|
11
|
+
*/
|
|
12
|
+
calculate(files: string[]): Promise<number>;
|
|
13
|
+
/**
|
|
14
|
+
* 判斷是否為源碼檔案
|
|
15
|
+
*/
|
|
16
|
+
private isSourceFile;
|
|
17
|
+
/**
|
|
18
|
+
* 判斷是否為測試檔案
|
|
19
|
+
*/
|
|
20
|
+
private isTestFile;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 預設導出計算函式
|
|
24
|
+
*/
|
|
25
|
+
export default function calculateTestCoverage(files: string[]): Promise<number>;
|
|
26
|
+
//# sourceMappingURL=test-coverage-checker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-coverage-checker.d.ts","sourceRoot":"","sources":["../../../../src/plugins/swift/analyzers/test-coverage-checker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,qBAAa,mBAAmB;IAC9B;;OAEG;IACG,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAgBjD;;OAEG;IACH,OAAO,CAAC,YAAY;IAuBpB;;OAEG;IACH,OAAO,CAAC,UAAU;CAWnB;AAED;;GAEG;AACH,wBAA8B,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAGpF"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Swift 測試覆蓋率檢查器
|
|
3
|
+
* 計算測試檔案比例(靜態分析)
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Swift 測試覆蓋率檢查器
|
|
7
|
+
*/
|
|
8
|
+
export class TestCoverageChecker {
|
|
9
|
+
/**
|
|
10
|
+
* 計算測試覆蓋率(測試檔案比例)
|
|
11
|
+
*/
|
|
12
|
+
async calculate(files) {
|
|
13
|
+
// 過濾出源碼檔案和測試檔案
|
|
14
|
+
const sourceFiles = files.filter(file => this.isSourceFile(file));
|
|
15
|
+
const testFiles = files.filter(file => this.isTestFile(file));
|
|
16
|
+
if (sourceFiles.length === 0) {
|
|
17
|
+
return 0;
|
|
18
|
+
}
|
|
19
|
+
// 計算測試覆蓋率(測試檔案數 / 源碼檔案數)
|
|
20
|
+
const coverageRatio = testFiles.length / sourceFiles.length;
|
|
21
|
+
// 回傳 0-1 的比例
|
|
22
|
+
return Math.min(coverageRatio, 1);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 判斷是否為源碼檔案
|
|
26
|
+
*/
|
|
27
|
+
isSourceFile(file) {
|
|
28
|
+
// Swift 檔案
|
|
29
|
+
if (!file.endsWith('.swift')) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
// 排除測試檔案
|
|
33
|
+
if (this.isTestFile(file)) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
// 排除測試目錄
|
|
37
|
+
if (file.includes('/Tests/') ||
|
|
38
|
+
file.includes('/Test/') ||
|
|
39
|
+
file.includes('Tests.swift')) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 判斷是否為測試檔案
|
|
46
|
+
*/
|
|
47
|
+
isTestFile(file) {
|
|
48
|
+
const filename = file.split('/').pop() || '';
|
|
49
|
+
// Swift 測試檔案命名模式
|
|
50
|
+
return (filename.endsWith('Tests.swift') ||
|
|
51
|
+
filename.endsWith('Test.swift') ||
|
|
52
|
+
file.includes('/Tests/') ||
|
|
53
|
+
file.includes('/Test/'));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 預設導出計算函式
|
|
58
|
+
*/
|
|
59
|
+
export default async function calculateTestCoverage(files) {
|
|
60
|
+
const checker = new TestCoverageChecker();
|
|
61
|
+
return checker.calculate(files);
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=test-coverage-checker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-coverage-checker.js","sourceRoot":"","sources":["../../../../src/plugins/swift/analyzers/test-coverage-checker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,OAAO,mBAAmB;IAC9B;;OAEG;IACH,KAAK,CAAC,SAAS,CAAC,KAAe;QAC7B,eAAe;QACf,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;QAClE,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QAE9D,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,CAAC;QACX,CAAC;QAED,yBAAyB;QACzB,MAAM,aAAa,GAAG,SAAS,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;QAE5D,aAAa;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;IACpC,CAAC;IAED;;OAEG;IACK,YAAY,CAAC,IAAY;QAC/B,WAAW;QACX,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,OAAO,KAAK,CAAC;QACf,CAAC;QAED,SAAS;QACT,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,OAAO,KAAK,CAAC;QACf,CAAC;QAED,SAAS;QACT,IACE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;YACxB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACvB,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAC5B,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACK,UAAU,CAAC,IAAY;QAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;QAE7C,iBAAiB;QACjB,OAAO,CACL,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC;YAChC,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC;YAC/B,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;YACxB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CACxB,CAAC;IACJ,CAAC;CACF;AAED;;GAEG;AACH,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,qBAAqB,CAAC,KAAe;IACjE,MAAM,OAAO,GAAG,IAAI,mBAAmB,EAAE,CAAC;IAC1C,OAAO,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Swift 型別安全檢查器
|
|
3
|
+
* 檢測 Any、as?、as!、try!、implicitly unwrapped optionals
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* 型別安全檢查結果
|
|
7
|
+
*/
|
|
8
|
+
export interface TypeSafetyResult {
|
|
9
|
+
readonly anyTypeCount: number;
|
|
10
|
+
readonly forceCastCount: number;
|
|
11
|
+
readonly optionalCastCount: number;
|
|
12
|
+
readonly forceUnwrapCount: number;
|
|
13
|
+
readonly forceTryCount: number;
|
|
14
|
+
readonly implicitlyUnwrappedCount: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Swift 型別安全檢查器
|
|
18
|
+
*/
|
|
19
|
+
export declare class TypeSafetyChecker {
|
|
20
|
+
/**
|
|
21
|
+
* 檢查檔案的型別安全問題
|
|
22
|
+
*/
|
|
23
|
+
check(files: string[], fileContents: Map<string, string>): Promise<TypeSafetyResult>;
|
|
24
|
+
/**
|
|
25
|
+
* 檢測強制 unwrap(排除型別宣告)
|
|
26
|
+
*/
|
|
27
|
+
private detectForceUnwrap;
|
|
28
|
+
/**
|
|
29
|
+
* 判斷是否為 Swift 檔案
|
|
30
|
+
*/
|
|
31
|
+
private isSwiftFile;
|
|
32
|
+
/**
|
|
33
|
+
* 計算總風險分數(加權計算)
|
|
34
|
+
*/
|
|
35
|
+
calculateRiskScore(result: TypeSafetyResult): number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 預設導出檢查函式
|
|
39
|
+
*/
|
|
40
|
+
export default function checkTypeSafety(files: string[], fileContents: Map<string, string>): Promise<TypeSafetyResult>;
|
|
41
|
+
//# sourceMappingURL=type-safety-checker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-safety-checker.d.ts","sourceRoot":"","sources":["../../../../src/plugins/swift/analyzers/type-safety-checker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,wBAAwB,EAAE,MAAM,CAAC;CAC3C;AAED;;GAEG;AACH,qBAAa,iBAAiB;IAC5B;;OAEG;IACG,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA+D1F;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAgCzB;;OAEG;IACH,OAAO,CAAC,WAAW;IAInB;;OAEG;IACH,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM;CAUrD;AAED;;GAEG;AACH,wBAA8B,eAAe,CAC3C,KAAK,EAAE,MAAM,EAAE,EACf,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,OAAO,CAAC,gBAAgB,CAAC,CAG3B"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Swift 型別安全檢查器
|
|
3
|
+
* 檢測 Any、as?、as!、try!、implicitly unwrapped optionals
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Swift 型別安全檢查器
|
|
7
|
+
*/
|
|
8
|
+
export class TypeSafetyChecker {
|
|
9
|
+
/**
|
|
10
|
+
* 檢查檔案的型別安全問題
|
|
11
|
+
*/
|
|
12
|
+
async check(files, fileContents) {
|
|
13
|
+
let anyTypeCount = 0;
|
|
14
|
+
let forceCastCount = 0;
|
|
15
|
+
let optionalCastCount = 0;
|
|
16
|
+
let forceUnwrapCount = 0;
|
|
17
|
+
let forceTryCount = 0;
|
|
18
|
+
let implicitlyUnwrappedCount = 0;
|
|
19
|
+
for (const file of files) {
|
|
20
|
+
if (!this.isSwiftFile(file)) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const content = fileContents.get(file);
|
|
24
|
+
if (!content) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
// 檢測 Any 型別使用
|
|
28
|
+
const anyMatches = content.match(/:\s*Any\b/g);
|
|
29
|
+
if (anyMatches) {
|
|
30
|
+
anyTypeCount += anyMatches.length;
|
|
31
|
+
}
|
|
32
|
+
// 檢測強制轉型 as!
|
|
33
|
+
const forceCastMatches = content.match(/\bas!\s+\w+/g);
|
|
34
|
+
if (forceCastMatches) {
|
|
35
|
+
forceCastCount += forceCastMatches.length;
|
|
36
|
+
}
|
|
37
|
+
// 檢測可選轉型 as?
|
|
38
|
+
const optionalCastMatches = content.match(/\bas\?\s+\w+/g);
|
|
39
|
+
if (optionalCastMatches) {
|
|
40
|
+
optionalCastCount += optionalCastMatches.length;
|
|
41
|
+
}
|
|
42
|
+
// 檢測強制 unwrap !(排除宣告)
|
|
43
|
+
const forceUnwrapMatches = this.detectForceUnwrap(content);
|
|
44
|
+
forceUnwrapCount += forceUnwrapMatches;
|
|
45
|
+
// 檢測 try! 強制執行
|
|
46
|
+
const forceTryMatches = content.match(/\btry!\s+/g);
|
|
47
|
+
if (forceTryMatches) {
|
|
48
|
+
forceTryCount += forceTryMatches.length;
|
|
49
|
+
}
|
|
50
|
+
// 檢測 implicitly unwrapped optionals(Type!)
|
|
51
|
+
const implicitlyUnwrappedMatches = content.match(/:\s*\w+!/g);
|
|
52
|
+
if (implicitlyUnwrappedMatches) {
|
|
53
|
+
implicitlyUnwrappedCount += implicitlyUnwrappedMatches.length;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
anyTypeCount,
|
|
58
|
+
forceCastCount,
|
|
59
|
+
optionalCastCount,
|
|
60
|
+
forceUnwrapCount,
|
|
61
|
+
forceTryCount,
|
|
62
|
+
implicitlyUnwrappedCount
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 檢測強制 unwrap(排除型別宣告)
|
|
67
|
+
*/
|
|
68
|
+
detectForceUnwrap(content) {
|
|
69
|
+
let count = 0;
|
|
70
|
+
const lines = content.split('\n');
|
|
71
|
+
for (const line of lines) {
|
|
72
|
+
// 跳過型別宣告行(包含 : Type!)
|
|
73
|
+
if (/:\s*\w+!/.test(line)) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// 跳過註解
|
|
77
|
+
if (line.trim().startsWith('//')) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
// 檢測 variable! 使用
|
|
81
|
+
const matches = line.match(/\w+!/g);
|
|
82
|
+
if (matches) {
|
|
83
|
+
// 過濾掉型別宣告
|
|
84
|
+
for (const match of matches) {
|
|
85
|
+
// 檢查前面是否有冒號(型別宣告)
|
|
86
|
+
const index = line.indexOf(match);
|
|
87
|
+
if (index > 0 && line[index - 1] !== ':') {
|
|
88
|
+
count++;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return count;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 判斷是否為 Swift 檔案
|
|
97
|
+
*/
|
|
98
|
+
isSwiftFile(file) {
|
|
99
|
+
return file.endsWith('.swift');
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* 計算總風險分數(加權計算)
|
|
103
|
+
*/
|
|
104
|
+
calculateRiskScore(result) {
|
|
105
|
+
return (result.anyTypeCount * 2 + // Any 型別權重 2
|
|
106
|
+
result.forceCastCount * 5 + // 強制轉型權重 5(高風險)
|
|
107
|
+
result.optionalCastCount * 1 + // 可選轉型權重 1(較安全)
|
|
108
|
+
result.forceUnwrapCount * 4 + // 強制 unwrap 權重 4
|
|
109
|
+
result.forceTryCount * 5 + // try! 權重 5(高風險)
|
|
110
|
+
result.implicitlyUnwrappedCount * 3 // IUO 權重 3
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 預設導出檢查函式
|
|
116
|
+
*/
|
|
117
|
+
export default async function checkTypeSafety(files, fileContents) {
|
|
118
|
+
const checker = new TypeSafetyChecker();
|
|
119
|
+
return checker.check(files, fileContents);
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=type-safety-checker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-safety-checker.js","sourceRoot":"","sources":["../../../../src/plugins/swift/analyzers/type-safety-checker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Swift 未使用符號檢測器
|
|
3
|
+
* 檢測未使用的 class、struct、protocol、function、variable
|
|
4
|
+
*/
|
|
5
|
+
import type { UnusedCode } from '../../../infrastructure/parser/analysis-types.js';
|
|
6
|
+
/**
|
|
7
|
+
* 未使用符號檢測器
|
|
8
|
+
*/
|
|
9
|
+
export declare class UnusedSymbolDetector {
|
|
10
|
+
/**
|
|
11
|
+
* 檢測未使用的符號
|
|
12
|
+
* @param code Swift 原始程式碼
|
|
13
|
+
* @param filePath 檔案路徑
|
|
14
|
+
* @returns 未使用的符號列表
|
|
15
|
+
*/
|
|
16
|
+
detect(code: string, filePath: string): Promise<UnusedCode[]>;
|
|
17
|
+
/**
|
|
18
|
+
* 提取所有符號定義
|
|
19
|
+
*/
|
|
20
|
+
private extractSymbols;
|
|
21
|
+
/**
|
|
22
|
+
* 檢查是否有特殊屬性(@main, @Published, @State 等)
|
|
23
|
+
*/
|
|
24
|
+
private hasSpecialAttribute;
|
|
25
|
+
/**
|
|
26
|
+
* 查找符號引用次數(不包括定義本身)
|
|
27
|
+
*/
|
|
28
|
+
private findReferences;
|
|
29
|
+
/**
|
|
30
|
+
* 映射符號類型到 UnusedCode 類型
|
|
31
|
+
*/
|
|
32
|
+
private mapSymbolType;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 預設導出檢測函式
|
|
36
|
+
*/
|
|
37
|
+
export default function detectUnusedSymbols(code: string, filePath: string): Promise<UnusedCode[]>;
|
|
38
|
+
//# sourceMappingURL=unused-symbol-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unused-symbol-detector.d.ts","sourceRoot":"","sources":["../../../../src/plugins/swift/analyzers/unused-symbol-detector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kDAAkD,CAAC;AAwBnF;;GAEG;AACH,qBAAa,oBAAoB;IAC/B;;;;;OAKG;IACG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAoCnE;;OAEG;IACH,OAAO,CAAC,cAAc;IA0FtB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA2B3B;;OAEG;IACH,OAAO,CAAC,cAAc;IAwBtB;;OAEG;IACH,OAAO,CAAC,aAAa;CActB;AAED;;GAEG;AACH,wBAA8B,mBAAmB,CAC/C,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,EAAE,CAAC,CAGvB"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Swift 未使用符號檢測器
|
|
3
|
+
* 檢測未使用的 class、struct、protocol、function、variable
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Swift 符號類型
|
|
7
|
+
*/
|
|
8
|
+
var SwiftSymbolType;
|
|
9
|
+
(function (SwiftSymbolType) {
|
|
10
|
+
SwiftSymbolType["Class"] = "class";
|
|
11
|
+
SwiftSymbolType["Struct"] = "struct";
|
|
12
|
+
SwiftSymbolType["Protocol"] = "protocol";
|
|
13
|
+
SwiftSymbolType["Function"] = "function";
|
|
14
|
+
SwiftSymbolType["Variable"] = "variable";
|
|
15
|
+
})(SwiftSymbolType || (SwiftSymbolType = {}));
|
|
16
|
+
/**
|
|
17
|
+
* 未使用符號檢測器
|
|
18
|
+
*/
|
|
19
|
+
export class UnusedSymbolDetector {
|
|
20
|
+
/**
|
|
21
|
+
* 檢測未使用的符號
|
|
22
|
+
* @param code Swift 原始程式碼
|
|
23
|
+
* @param filePath 檔案路徑
|
|
24
|
+
* @returns 未使用的符號列表
|
|
25
|
+
*/
|
|
26
|
+
async detect(code, filePath) {
|
|
27
|
+
const symbols = this.extractSymbols(code);
|
|
28
|
+
const unused = [];
|
|
29
|
+
for (const symbol of symbols) {
|
|
30
|
+
// 跳過 public 符號(可能被外部使用)
|
|
31
|
+
if (symbol.isPublic) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
// 跳過特殊符號
|
|
35
|
+
if (symbol.isSpecial) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
// 檢查是否有引用
|
|
39
|
+
const references = this.findReferences(code, symbol.name, symbol.line);
|
|
40
|
+
if (references === 0) {
|
|
41
|
+
unused.push({
|
|
42
|
+
type: this.mapSymbolType(symbol.type),
|
|
43
|
+
name: symbol.name,
|
|
44
|
+
location: {
|
|
45
|
+
filePath,
|
|
46
|
+
line: symbol.line,
|
|
47
|
+
column: 0
|
|
48
|
+
},
|
|
49
|
+
confidence: 0.9,
|
|
50
|
+
reason: `${symbol.type} '${symbol.name}' 已宣告但從未使用`
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return unused;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 提取所有符號定義
|
|
58
|
+
*/
|
|
59
|
+
extractSymbols(code) {
|
|
60
|
+
const symbols = [];
|
|
61
|
+
const lines = code.split('\n');
|
|
62
|
+
for (let i = 0; i < lines.length; i++) {
|
|
63
|
+
const line = lines[i].trim();
|
|
64
|
+
const lineNumber = i + 1;
|
|
65
|
+
// 檢測特殊屬性
|
|
66
|
+
const isSpecial = this.hasSpecialAttribute(lines, i);
|
|
67
|
+
// Class
|
|
68
|
+
if (/^\s*(public|internal|private|fileprivate)?\s*class\s+([a-zA-Z_][a-zA-Z0-9_]*)/.test(line)) {
|
|
69
|
+
const match = line.match(/class\s+([a-zA-Z_][a-zA-Z0-9_]*)/);
|
|
70
|
+
if (match) {
|
|
71
|
+
symbols.push({
|
|
72
|
+
type: SwiftSymbolType.Class,
|
|
73
|
+
name: match[1],
|
|
74
|
+
line: lineNumber,
|
|
75
|
+
isPublic: /\bpublic\b/.test(line),
|
|
76
|
+
isSpecial
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Struct
|
|
81
|
+
if (/^\s*(public|internal|private|fileprivate)?\s*struct\s+([a-zA-Z_][a-zA-Z0-9_]*)/.test(line)) {
|
|
82
|
+
const match = line.match(/struct\s+([a-zA-Z_][a-zA-Z0-9_]*)/);
|
|
83
|
+
if (match) {
|
|
84
|
+
symbols.push({
|
|
85
|
+
type: SwiftSymbolType.Struct,
|
|
86
|
+
name: match[1],
|
|
87
|
+
line: lineNumber,
|
|
88
|
+
isPublic: /\bpublic\b/.test(line),
|
|
89
|
+
isSpecial
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Protocol
|
|
94
|
+
if (/^\s*(public|internal|private)?\s*protocol\s+([a-zA-Z_][a-zA-Z0-9_]*)/.test(line)) {
|
|
95
|
+
const match = line.match(/protocol\s+([a-zA-Z_][a-zA-Z0-9_]*)/);
|
|
96
|
+
if (match) {
|
|
97
|
+
symbols.push({
|
|
98
|
+
type: SwiftSymbolType.Protocol,
|
|
99
|
+
name: match[1],
|
|
100
|
+
line: lineNumber,
|
|
101
|
+
isPublic: /\bpublic\b/.test(line),
|
|
102
|
+
isSpecial
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Function
|
|
107
|
+
if (/^\s*(public|private|fileprivate|internal)?\s*func\s+([a-zA-Z_][a-zA-Z0-9_]*)/.test(line)) {
|
|
108
|
+
const match = line.match(/func\s+([a-zA-Z_][a-zA-Z0-9_]*)/);
|
|
109
|
+
if (match) {
|
|
110
|
+
// 跳過 SwiftUI body
|
|
111
|
+
if (match[1] === 'body') {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
symbols.push({
|
|
115
|
+
type: SwiftSymbolType.Function,
|
|
116
|
+
name: match[1],
|
|
117
|
+
line: lineNumber,
|
|
118
|
+
isPublic: /\bpublic\b/.test(line),
|
|
119
|
+
isSpecial
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Variable/Constant
|
|
124
|
+
if (/^\s*(public|private|fileprivate|internal)?\s*(let|var)\s+([a-zA-Z_][a-zA-Z0-9_]*)/.test(line)) {
|
|
125
|
+
const match = line.match(/(let|var)\s+([a-zA-Z_][a-zA-Z0-9_]*)/);
|
|
126
|
+
if (match) {
|
|
127
|
+
symbols.push({
|
|
128
|
+
type: SwiftSymbolType.Variable,
|
|
129
|
+
name: match[2],
|
|
130
|
+
line: lineNumber,
|
|
131
|
+
isPublic: /\bpublic\b/.test(line),
|
|
132
|
+
isSpecial
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return symbols;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* 檢查是否有特殊屬性(@main, @Published, @State 等)
|
|
141
|
+
*/
|
|
142
|
+
hasSpecialAttribute(lines, currentIndex) {
|
|
143
|
+
// 檢查當前行和上一行
|
|
144
|
+
const currentLine = lines[currentIndex];
|
|
145
|
+
const previousLine = currentIndex > 0 ? lines[currentIndex - 1] : '';
|
|
146
|
+
const specialAttributes = [
|
|
147
|
+
'@main',
|
|
148
|
+
'@Published',
|
|
149
|
+
'@State',
|
|
150
|
+
'@Binding',
|
|
151
|
+
'@ObservedObject',
|
|
152
|
+
'@StateObject',
|
|
153
|
+
'@EnvironmentObject',
|
|
154
|
+
'@Environment',
|
|
155
|
+
'@AppStorage',
|
|
156
|
+
'@SceneStorage'
|
|
157
|
+
];
|
|
158
|
+
for (const attr of specialAttributes) {
|
|
159
|
+
if (currentLine.includes(attr) || previousLine.includes(attr)) {
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* 查找符號引用次數(不包括定義本身)
|
|
167
|
+
*/
|
|
168
|
+
findReferences(code, symbolName, definitionLine) {
|
|
169
|
+
const lines = code.split('\n');
|
|
170
|
+
let count = 0;
|
|
171
|
+
for (let i = 0; i < lines.length; i++) {
|
|
172
|
+
// 跳過定義行
|
|
173
|
+
if (i + 1 === definitionLine) {
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const line = lines[i];
|
|
177
|
+
// 使用單詞邊界匹配符號名稱
|
|
178
|
+
const regex = new RegExp(`\\b${symbolName}\\b`, 'g');
|
|
179
|
+
const matches = line.match(regex);
|
|
180
|
+
if (matches) {
|
|
181
|
+
count += matches.length;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return count;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* 映射符號類型到 UnusedCode 類型
|
|
188
|
+
*/
|
|
189
|
+
mapSymbolType(symbolType) {
|
|
190
|
+
switch (symbolType) {
|
|
191
|
+
case SwiftSymbolType.Function:
|
|
192
|
+
return 'function';
|
|
193
|
+
case SwiftSymbolType.Class:
|
|
194
|
+
case SwiftSymbolType.Struct:
|
|
195
|
+
case SwiftSymbolType.Protocol:
|
|
196
|
+
return 'class';
|
|
197
|
+
case SwiftSymbolType.Variable:
|
|
198
|
+
return 'variable';
|
|
199
|
+
default:
|
|
200
|
+
return 'variable';
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* 預設導出檢測函式
|
|
206
|
+
*/
|
|
207
|
+
export default async function detectUnusedSymbols(code, filePath) {
|
|
208
|
+
const detector = new UnusedSymbolDetector();
|
|
209
|
+
return detector.detect(code, filePath);
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=unused-symbol-detector.js.map
|