agent-ide 0.1.9 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/README.md +103 -17
  2. package/dist/application/services/module-coordinator.service.d.ts +0 -1
  3. package/dist/application/services/module-coordinator.service.d.ts.map +1 -1
  4. package/dist/application/services/module-coordinator.service.js +2 -8
  5. package/dist/application/services/module-coordinator.service.js.map +1 -1
  6. package/dist/core/analysis/index.d.ts +1 -4
  7. package/dist/core/analysis/index.d.ts.map +1 -1
  8. package/dist/core/analysis/index.js +1 -7
  9. package/dist/core/analysis/index.js.map +1 -1
  10. package/dist/core/dependency/dependency-analyzer.d.ts.map +1 -1
  11. package/dist/core/dependency/dependency-analyzer.js +10 -0
  12. package/dist/core/dependency/dependency-analyzer.js.map +1 -1
  13. package/dist/core/indexing/index-engine.d.ts +4 -0
  14. package/dist/core/indexing/index-engine.d.ts.map +1 -1
  15. package/dist/core/indexing/index-engine.js +25 -1
  16. package/dist/core/indexing/index-engine.js.map +1 -1
  17. package/dist/core/indexing/symbol-index.d.ts +4 -0
  18. package/dist/core/indexing/symbol-index.d.ts.map +1 -1
  19. package/dist/core/indexing/symbol-index.js +17 -0
  20. package/dist/core/indexing/symbol-index.js.map +1 -1
  21. package/dist/core/move/import-resolver.d.ts.map +1 -1
  22. package/dist/core/move/import-resolver.js +8 -0
  23. package/dist/core/move/import-resolver.js.map +1 -1
  24. package/dist/core/move/move-service.js +7 -7
  25. package/dist/core/move/move-service.js.map +1 -1
  26. package/dist/core/refactor/swift-extractor.d.ts +98 -0
  27. package/dist/core/refactor/swift-extractor.d.ts.map +1 -0
  28. package/dist/core/refactor/swift-extractor.js +283 -0
  29. package/dist/core/refactor/swift-extractor.js.map +1 -0
  30. package/dist/core/rename/reference-updater.d.ts.map +1 -1
  31. package/dist/core/rename/reference-updater.js +16 -8
  32. package/dist/core/rename/reference-updater.js.map +1 -1
  33. package/dist/core/search/engines/text-engine.js +1 -1
  34. package/dist/core/search/engines/text-engine.js.map +1 -1
  35. package/dist/core/shit-score/grading.d.ts +39 -0
  36. package/dist/core/shit-score/grading.d.ts.map +1 -0
  37. package/dist/core/shit-score/grading.js +253 -0
  38. package/dist/core/shit-score/grading.js.map +1 -0
  39. package/dist/core/shit-score/index.d.ts +9 -0
  40. package/dist/core/shit-score/index.d.ts.map +1 -0
  41. package/dist/core/shit-score/index.js +8 -0
  42. package/dist/core/shit-score/index.js.map +1 -0
  43. package/dist/core/shit-score/score-calculator.d.ts +75 -0
  44. package/dist/core/shit-score/score-calculator.d.ts.map +1 -0
  45. package/dist/core/shit-score/score-calculator.js +240 -0
  46. package/dist/core/shit-score/score-calculator.js.map +1 -0
  47. package/dist/core/shit-score/shit-score-analyzer.d.ts +84 -0
  48. package/dist/core/shit-score/shit-score-analyzer.d.ts.map +1 -0
  49. package/dist/core/shit-score/shit-score-analyzer.js +595 -0
  50. package/dist/core/shit-score/shit-score-analyzer.js.map +1 -0
  51. package/dist/core/shit-score/types.d.ts +231 -0
  52. package/dist/core/shit-score/types.d.ts.map +1 -0
  53. package/dist/core/shit-score/types.js +73 -0
  54. package/dist/core/shit-score/types.js.map +1 -0
  55. package/dist/core/snapshot/code-compressor.d.ts +39 -0
  56. package/dist/core/snapshot/code-compressor.d.ts.map +1 -0
  57. package/dist/core/snapshot/code-compressor.js +211 -0
  58. package/dist/core/snapshot/code-compressor.js.map +1 -0
  59. package/dist/core/snapshot/config.d.ts +60 -0
  60. package/dist/core/snapshot/config.d.ts.map +1 -0
  61. package/dist/core/snapshot/config.js +136 -0
  62. package/dist/core/snapshot/config.js.map +1 -0
  63. package/dist/core/snapshot/index.d.ts +23 -0
  64. package/dist/core/snapshot/index.d.ts.map +1 -0
  65. package/dist/core/snapshot/index.js +27 -0
  66. package/dist/core/snapshot/index.js.map +1 -0
  67. package/dist/core/snapshot/snapshot-differ.d.ts +54 -0
  68. package/dist/core/snapshot/snapshot-differ.d.ts.map +1 -0
  69. package/dist/core/snapshot/snapshot-differ.js +262 -0
  70. package/dist/core/snapshot/snapshot-differ.js.map +1 -0
  71. package/dist/core/snapshot/snapshot-engine.d.ts +94 -0
  72. package/dist/core/snapshot/snapshot-engine.d.ts.map +1 -0
  73. package/dist/core/snapshot/snapshot-engine.js +492 -0
  74. package/dist/core/snapshot/snapshot-engine.js.map +1 -0
  75. package/dist/core/snapshot/types.d.ts +216 -0
  76. package/dist/core/snapshot/types.d.ts.map +1 -0
  77. package/dist/core/snapshot/types.js +79 -0
  78. package/dist/core/snapshot/types.js.map +1 -0
  79. package/dist/infrastructure/parser/analysis-types.d.ts +198 -0
  80. package/dist/infrastructure/parser/analysis-types.d.ts.map +1 -0
  81. package/dist/infrastructure/parser/analysis-types.js +6 -0
  82. package/dist/infrastructure/parser/analysis-types.js.map +1 -0
  83. package/dist/infrastructure/parser/base.d.ts +36 -0
  84. package/dist/infrastructure/parser/base.d.ts.map +1 -1
  85. package/dist/infrastructure/parser/base.js +72 -0
  86. package/dist/infrastructure/parser/base.js.map +1 -1
  87. package/dist/infrastructure/parser/index.d.ts +1 -0
  88. package/dist/infrastructure/parser/index.d.ts.map +1 -1
  89. package/dist/infrastructure/parser/index.js.map +1 -1
  90. package/dist/infrastructure/parser/interface.d.ts +63 -0
  91. package/dist/infrastructure/parser/interface.d.ts.map +1 -1
  92. package/dist/infrastructure/parser/interface.js +11 -1
  93. package/dist/infrastructure/parser/interface.js.map +1 -1
  94. package/dist/interfaces/cli/cli.d.ts +24 -0
  95. package/dist/interfaces/cli/cli.d.ts.map +1 -1
  96. package/dist/interfaces/cli/cli.js +1483 -157
  97. package/dist/interfaces/cli/cli.js.map +1 -1
  98. package/dist/plugins/javascript/parser.d.ts +41 -0
  99. package/dist/plugins/javascript/parser.d.ts.map +1 -1
  100. package/dist/plugins/javascript/parser.js +284 -0
  101. package/dist/plugins/javascript/parser.js.map +1 -1
  102. package/dist/plugins/swift/analyzers/complexity-analyzer.d.ts +41 -0
  103. package/dist/plugins/swift/analyzers/complexity-analyzer.d.ts.map +1 -0
  104. package/dist/plugins/swift/analyzers/complexity-analyzer.js +206 -0
  105. package/dist/plugins/swift/analyzers/complexity-analyzer.js.map +1 -0
  106. package/dist/plugins/swift/analyzers/duplication-detector.d.ts +89 -0
  107. package/dist/plugins/swift/analyzers/duplication-detector.d.ts.map +1 -0
  108. package/dist/plugins/swift/analyzers/duplication-detector.js +271 -0
  109. package/dist/plugins/swift/analyzers/duplication-detector.js.map +1 -0
  110. package/dist/plugins/swift/analyzers/error-handling-checker.d.ts +34 -0
  111. package/dist/plugins/swift/analyzers/error-handling-checker.d.ts.map +1 -0
  112. package/dist/plugins/swift/analyzers/error-handling-checker.js +135 -0
  113. package/dist/plugins/swift/analyzers/error-handling-checker.js.map +1 -0
  114. package/dist/plugins/swift/analyzers/naming-checker.d.ts +47 -0
  115. package/dist/plugins/swift/analyzers/naming-checker.d.ts.map +1 -0
  116. package/dist/plugins/swift/analyzers/naming-checker.js +161 -0
  117. package/dist/plugins/swift/analyzers/naming-checker.js.map +1 -0
  118. package/dist/plugins/swift/analyzers/pattern-detector.d.ts +78 -0
  119. package/dist/plugins/swift/analyzers/pattern-detector.d.ts.map +1 -0
  120. package/dist/plugins/swift/analyzers/pattern-detector.js +247 -0
  121. package/dist/plugins/swift/analyzers/pattern-detector.js.map +1 -0
  122. package/dist/plugins/swift/analyzers/security-checker.d.ts +38 -0
  123. package/dist/plugins/swift/analyzers/security-checker.d.ts.map +1 -0
  124. package/dist/plugins/swift/analyzers/security-checker.js +135 -0
  125. package/dist/plugins/swift/analyzers/security-checker.js.map +1 -0
  126. package/dist/plugins/swift/analyzers/test-coverage-checker.d.ts +26 -0
  127. package/dist/plugins/swift/analyzers/test-coverage-checker.d.ts.map +1 -0
  128. package/dist/plugins/swift/analyzers/test-coverage-checker.js +63 -0
  129. package/dist/plugins/swift/analyzers/test-coverage-checker.js.map +1 -0
  130. package/dist/plugins/swift/analyzers/type-safety-checker.d.ts +41 -0
  131. package/dist/plugins/swift/analyzers/type-safety-checker.d.ts.map +1 -0
  132. package/dist/plugins/swift/analyzers/type-safety-checker.js +121 -0
  133. package/dist/plugins/swift/analyzers/type-safety-checker.js.map +1 -0
  134. package/dist/plugins/swift/analyzers/unused-symbol-detector.d.ts +38 -0
  135. package/dist/plugins/swift/analyzers/unused-symbol-detector.d.ts.map +1 -0
  136. package/dist/plugins/swift/analyzers/unused-symbol-detector.js +211 -0
  137. package/dist/plugins/swift/analyzers/unused-symbol-detector.js.map +1 -0
  138. package/dist/plugins/swift/dependency-analyzer.d.ts +33 -0
  139. package/dist/plugins/swift/dependency-analyzer.d.ts.map +1 -0
  140. package/dist/plugins/swift/dependency-analyzer.js +95 -0
  141. package/dist/plugins/swift/dependency-analyzer.js.map +1 -0
  142. package/dist/plugins/swift/index.d.ts +14 -0
  143. package/dist/plugins/swift/index.d.ts.map +1 -0
  144. package/dist/plugins/swift/index.js +19 -0
  145. package/dist/plugins/swift/index.js.map +1 -0
  146. package/dist/plugins/swift/parser.d.ts +160 -0
  147. package/dist/plugins/swift/parser.d.ts.map +1 -0
  148. package/dist/plugins/swift/parser.js +670 -0
  149. package/dist/plugins/swift/parser.js.map +1 -0
  150. package/dist/plugins/swift/swift-bridge/swift-parser +0 -0
  151. package/dist/plugins/swift/symbol-extractor.d.ts +46 -0
  152. package/dist/plugins/swift/symbol-extractor.d.ts.map +1 -0
  153. package/dist/plugins/swift/symbol-extractor.js +187 -0
  154. package/dist/plugins/swift/symbol-extractor.js.map +1 -0
  155. package/dist/plugins/swift/types.d.ts +137 -0
  156. package/dist/plugins/swift/types.d.ts.map +1 -0
  157. package/dist/plugins/swift/types.js +212 -0
  158. package/dist/plugins/swift/types.js.map +1 -0
  159. package/dist/plugins/typescript/analyzers/complexity-analyzer.d.ts +39 -0
  160. package/dist/plugins/typescript/analyzers/complexity-analyzer.d.ts.map +1 -0
  161. package/dist/plugins/typescript/analyzers/complexity-analyzer.js +196 -0
  162. package/dist/plugins/typescript/analyzers/complexity-analyzer.js.map +1 -0
  163. package/dist/{core/analysis → plugins/typescript/analyzers}/duplication-detector.d.ts +34 -3
  164. package/dist/plugins/typescript/analyzers/duplication-detector.d.ts.map +1 -0
  165. package/dist/plugins/typescript/analyzers/duplication-detector.js +695 -0
  166. package/dist/plugins/typescript/analyzers/duplication-detector.js.map +1 -0
  167. package/dist/plugins/typescript/analyzers/error-handling-checker.d.ts +26 -0
  168. package/dist/plugins/typescript/analyzers/error-handling-checker.d.ts.map +1 -0
  169. package/dist/plugins/typescript/analyzers/error-handling-checker.js +84 -0
  170. package/dist/plugins/typescript/analyzers/error-handling-checker.js.map +1 -0
  171. package/dist/plugins/typescript/analyzers/naming-checker.d.ts +30 -0
  172. package/dist/plugins/typescript/analyzers/naming-checker.d.ts.map +1 -0
  173. package/dist/plugins/typescript/analyzers/naming-checker.js +116 -0
  174. package/dist/plugins/typescript/analyzers/naming-checker.js.map +1 -0
  175. package/dist/plugins/typescript/analyzers/pattern-detector.d.ts +80 -0
  176. package/dist/plugins/typescript/analyzers/pattern-detector.d.ts.map +1 -0
  177. package/dist/plugins/typescript/analyzers/pattern-detector.js +267 -0
  178. package/dist/plugins/typescript/analyzers/pattern-detector.js.map +1 -0
  179. package/dist/plugins/typescript/analyzers/security-checker.d.ts +34 -0
  180. package/dist/plugins/typescript/analyzers/security-checker.d.ts.map +1 -0
  181. package/dist/plugins/typescript/analyzers/security-checker.js +126 -0
  182. package/dist/plugins/typescript/analyzers/security-checker.js.map +1 -0
  183. package/dist/plugins/typescript/analyzers/test-coverage-checker.d.ts +22 -0
  184. package/dist/plugins/typescript/analyzers/test-coverage-checker.d.ts.map +1 -0
  185. package/dist/plugins/typescript/analyzers/test-coverage-checker.js +62 -0
  186. package/dist/plugins/typescript/analyzers/test-coverage-checker.js.map +1 -0
  187. package/dist/plugins/typescript/analyzers/type-safety-checker.d.ts +32 -0
  188. package/dist/plugins/typescript/analyzers/type-safety-checker.d.ts.map +1 -0
  189. package/dist/plugins/typescript/analyzers/type-safety-checker.js +86 -0
  190. package/dist/plugins/typescript/analyzers/type-safety-checker.js.map +1 -0
  191. package/dist/plugins/typescript/analyzers/unused-symbol-detector.d.ts +47 -0
  192. package/dist/plugins/typescript/analyzers/unused-symbol-detector.d.ts.map +1 -0
  193. package/dist/plugins/typescript/analyzers/unused-symbol-detector.js +152 -0
  194. package/dist/plugins/typescript/analyzers/unused-symbol-detector.js.map +1 -0
  195. package/dist/plugins/typescript/parser.d.ts +41 -0
  196. package/dist/plugins/typescript/parser.d.ts.map +1 -1
  197. package/dist/plugins/typescript/parser.js +336 -0
  198. package/dist/plugins/typescript/parser.js.map +1 -1
  199. package/dist/shared/types/symbol.d.ts +7 -1
  200. package/dist/shared/types/symbol.d.ts.map +1 -1
  201. package/dist/shared/types/symbol.js +8 -2
  202. package/dist/shared/types/symbol.js.map +1 -1
  203. package/package.json +17 -7
  204. package/bin/mcp-server.js +0 -20
  205. package/dist/core/analysis/complexity-analyzer.d.ts +0 -81
  206. package/dist/core/analysis/complexity-analyzer.d.ts.map +0 -1
  207. package/dist/core/analysis/complexity-analyzer.js +0 -255
  208. package/dist/core/analysis/complexity-analyzer.js.map +0 -1
  209. package/dist/core/analysis/dead-code-detector.d.ts +0 -152
  210. package/dist/core/analysis/dead-code-detector.d.ts.map +0 -1
  211. package/dist/core/analysis/dead-code-detector.js +0 -351
  212. package/dist/core/analysis/dead-code-detector.js.map +0 -1
  213. package/dist/core/analysis/duplication-detector.d.ts.map +0 -1
  214. package/dist/core/analysis/duplication-detector.js +0 -433
  215. package/dist/core/analysis/duplication-detector.js.map +0 -1
  216. package/dist/interfaces/mcp/index.d.ts +0 -7
  217. package/dist/interfaces/mcp/index.d.ts.map +0 -1
  218. package/dist/interfaces/mcp/index.js +0 -6
  219. package/dist/interfaces/mcp/index.js.map +0 -1
  220. package/dist/interfaces/mcp/mcp-server.d.ts +0 -34
  221. package/dist/interfaces/mcp/mcp-server.d.ts.map +0 -1
  222. package/dist/interfaces/mcp/mcp-server.js +0 -162
  223. package/dist/interfaces/mcp/mcp-server.js.map +0 -1
  224. package/dist/interfaces/mcp/mcp.d.ts +0 -52
  225. package/dist/interfaces/mcp/mcp.d.ts.map +0 -1
  226. package/dist/interfaces/mcp/mcp.js +0 -843
  227. package/dist/interfaces/mcp/mcp.js.map +0 -1
@@ -0,0 +1,267 @@
1
+ /**
2
+ * 模式檢測器
3
+ * 檢測常見的樣板代碼模式(try-catch、logger、constructor DI 等)
4
+ */
5
+ import { readFile } from 'fs/promises';
6
+ /**
7
+ * 模式類型
8
+ */
9
+ export var PatternType;
10
+ (function (PatternType) {
11
+ PatternType["TryCatch"] = "try-catch";
12
+ PatternType["LoggerInit"] = "logger-init";
13
+ PatternType["ConstructorDI"] = "constructor-di";
14
+ PatternType["EnvVar"] = "env-var";
15
+ PatternType["ConfigObject"] = "config-object";
16
+ })(PatternType || (PatternType = {}));
17
+ /**
18
+ * 模式檢測器主類
19
+ */
20
+ export class PatternDetector {
21
+ /**
22
+ * 檢測所有模式
23
+ */
24
+ async detectAll(files) {
25
+ const results = new Map();
26
+ const tryCatchMatches = await this.detectTryCatchBoilerplate(files);
27
+ if (tryCatchMatches.length > 0) {
28
+ results.set(PatternType.TryCatch, {
29
+ type: PatternType.TryCatch,
30
+ instances: tryCatchMatches,
31
+ count: tryCatchMatches.length,
32
+ recommendation: '建議使用裝飾器 @HandleError() 或 Interceptor 統一處理錯誤'
33
+ });
34
+ }
35
+ const loggerMatches = await this.detectLoggerInit(files);
36
+ if (loggerMatches.length > 0) {
37
+ results.set(PatternType.LoggerInit, {
38
+ type: PatternType.LoggerInit,
39
+ instances: loggerMatches,
40
+ count: loggerMatches.length,
41
+ recommendation: '建議使用依賴注入或 @InjectLogger() 裝飾器統一注入 logger'
42
+ });
43
+ }
44
+ const constructorMatches = await this.detectConstructorDI(files);
45
+ if (constructorMatches.length > 0) {
46
+ results.set(PatternType.ConstructorDI, {
47
+ type: PatternType.ConstructorDI,
48
+ instances: constructorMatches,
49
+ count: constructorMatches.length,
50
+ recommendation: '建構函式依賴注入是標準模式,保持現狀即可'
51
+ });
52
+ }
53
+ const envVarMatches = await this.detectEnvVarAccess(files);
54
+ if (envVarMatches.length > 0) {
55
+ results.set(PatternType.EnvVar, {
56
+ type: PatternType.EnvVar,
57
+ instances: envVarMatches,
58
+ count: envVarMatches.length,
59
+ recommendation: '建議使用 ConfigService 統一管理環境變數,避免直接存取 process.env'
60
+ });
61
+ }
62
+ const configMatches = await this.detectConfigObject(files);
63
+ if (configMatches.length > 0) {
64
+ results.set(PatternType.ConfigObject, {
65
+ type: PatternType.ConfigObject,
66
+ instances: configMatches,
67
+ count: configMatches.length,
68
+ recommendation: '建議提取配置物件到獨立的 config 檔案,遵循單一真實來源原則'
69
+ });
70
+ }
71
+ return results;
72
+ }
73
+ /**
74
+ * 檢測 try-catch 樣板代碼
75
+ */
76
+ async detectTryCatchBoilerplate(files) {
77
+ const matches = [];
78
+ const tryCatchRegex = /try\s*\{[\s\S]*?\}\s*catch\s*\([^)]*\)\s*\{[\s\S]*?\}/g;
79
+ for (const file of files) {
80
+ try {
81
+ const content = await readFile(file, 'utf-8');
82
+ let match;
83
+ while ((match = tryCatchRegex.exec(content)) !== null) {
84
+ const startLine = this.getLineNumber(content, match.index);
85
+ const endLine = this.getLineNumber(content, match.index + match[0].length);
86
+ matches.push({
87
+ type: PatternType.TryCatch,
88
+ file,
89
+ startLine,
90
+ endLine,
91
+ code: match[0],
92
+ similarity: 0.8
93
+ });
94
+ }
95
+ }
96
+ catch {
97
+ continue;
98
+ }
99
+ }
100
+ // 分組相似的 try-catch 區塊
101
+ return this.groupSimilarPatterns(matches);
102
+ }
103
+ /**
104
+ * 檢測 Logger 初始化模式
105
+ */
106
+ async detectLoggerInit(files) {
107
+ const matches = [];
108
+ const loggerRegex = /(private|protected|public)?\s*(readonly)?\s*logger\s*=\s*new\s+Logger\([^)]*\)/g;
109
+ for (const file of files) {
110
+ try {
111
+ const content = await readFile(file, 'utf-8');
112
+ let match;
113
+ while ((match = loggerRegex.exec(content)) !== null) {
114
+ const lineNumber = this.getLineNumber(content, match.index);
115
+ matches.push({
116
+ type: PatternType.LoggerInit,
117
+ file,
118
+ startLine: lineNumber,
119
+ endLine: lineNumber,
120
+ code: match[0],
121
+ similarity: 0.9
122
+ });
123
+ }
124
+ }
125
+ catch {
126
+ continue;
127
+ }
128
+ }
129
+ return this.groupSimilarPatterns(matches);
130
+ }
131
+ /**
132
+ * 檢測建構函式依賴注入模式
133
+ */
134
+ async detectConstructorDI(files) {
135
+ const matches = [];
136
+ const constructorRegex = /constructor\s*\([^)]*\)\s*\{/g;
137
+ for (const file of files) {
138
+ try {
139
+ const content = await readFile(file, 'utf-8');
140
+ let match;
141
+ while ((match = constructorRegex.exec(content)) !== null) {
142
+ const lineNumber = this.getLineNumber(content, match.index);
143
+ // 檢查是否有 private/protected/public 參數(DI 模式)
144
+ const constructorParams = match[0];
145
+ if (/(private|protected|public)\s+(readonly\s+)?\w+/.test(constructorParams)) {
146
+ matches.push({
147
+ type: PatternType.ConstructorDI,
148
+ file,
149
+ startLine: lineNumber,
150
+ endLine: lineNumber,
151
+ code: match[0],
152
+ similarity: 0.85
153
+ });
154
+ }
155
+ }
156
+ }
157
+ catch {
158
+ continue;
159
+ }
160
+ }
161
+ return this.groupSimilarPatterns(matches);
162
+ }
163
+ /**
164
+ * 檢測環境變數存取模式
165
+ */
166
+ async detectEnvVarAccess(files) {
167
+ const matches = [];
168
+ const envVarRegex = /process\.env\.\w+(\s*\|\|\s*['"][^'"]*['"])?/g;
169
+ for (const file of files) {
170
+ try {
171
+ const content = await readFile(file, 'utf-8');
172
+ let match;
173
+ while ((match = envVarRegex.exec(content)) !== null) {
174
+ const lineNumber = this.getLineNumber(content, match.index);
175
+ matches.push({
176
+ type: PatternType.EnvVar,
177
+ file,
178
+ startLine: lineNumber,
179
+ endLine: lineNumber,
180
+ code: match[0],
181
+ similarity: 0.8
182
+ });
183
+ }
184
+ }
185
+ catch {
186
+ continue;
187
+ }
188
+ }
189
+ return this.groupSimilarPatterns(matches);
190
+ }
191
+ /**
192
+ * 檢測配置物件模式
193
+ */
194
+ async detectConfigObject(files) {
195
+ const matches = [];
196
+ const configKeywords = ['host', 'port', 'database', 'uri', 'url', 'connection'];
197
+ for (const file of files) {
198
+ try {
199
+ const content = await readFile(file, 'utf-8');
200
+ const lines = content.split('\n');
201
+ for (let i = 0; i < lines.length; i++) {
202
+ const line = lines[i];
203
+ // 檢查是否包含多個配置關鍵字
204
+ const keywordCount = configKeywords.filter(keyword => line.includes(`${keyword}:`) || line.includes(`${keyword} =`)).length;
205
+ if (keywordCount >= 2 && line.includes('{')) {
206
+ const startPos = content.indexOf(lines.slice(0, i + 1).join('\n'));
207
+ const braceIndex = line.indexOf('{');
208
+ matches.push({
209
+ type: PatternType.ConfigObject,
210
+ file,
211
+ startLine: i + 1,
212
+ endLine: i + 1,
213
+ code: line,
214
+ similarity: 0.75
215
+ });
216
+ }
217
+ }
218
+ }
219
+ catch {
220
+ continue;
221
+ }
222
+ }
223
+ return this.groupSimilarPatterns(matches);
224
+ }
225
+ /**
226
+ * 分組相似的模式(過濾重複、計算相似度)
227
+ */
228
+ groupSimilarPatterns(matches) {
229
+ const seen = new Set();
230
+ const grouped = [];
231
+ for (const match of matches) {
232
+ const key = `${match.file}:${match.startLine}`;
233
+ if (!seen.has(key)) {
234
+ seen.add(key);
235
+ grouped.push(match);
236
+ }
237
+ }
238
+ return grouped;
239
+ }
240
+ /**
241
+ * 取得字串在內容中的行號
242
+ */
243
+ getLineNumber(content, index) {
244
+ return content.substring(0, index).split('\n').length;
245
+ }
246
+ /**
247
+ * 取得模式檢測統計
248
+ */
249
+ async getStatistics(patterns) {
250
+ const byType = {};
251
+ const recommendations = [];
252
+ let totalPatterns = 0;
253
+ for (const [type, group] of patterns.entries()) {
254
+ byType[type] = group.count;
255
+ totalPatterns += group.count;
256
+ if (group.count > 1) {
257
+ recommendations.push(`${type}: ${group.recommendation}`);
258
+ }
259
+ }
260
+ return {
261
+ totalPatterns,
262
+ byType,
263
+ recommendations
264
+ };
265
+ }
266
+ }
267
+ //# sourceMappingURL=pattern-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pattern-detector.js","sourceRoot":"","sources":["../../../../src/plugins/typescript/analyzers/pattern-detector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC;;GAEG;AACH,MAAM,CAAN,IAAY,WAMX;AAND,WAAY,WAAW;IACrB,qCAAsB,CAAA;IACtB,yCAA0B,CAAA;IAC1B,+CAAgC,CAAA;IAChC,iCAAkB,CAAA;IAClB,6CAA8B,CAAA;AAChC,CAAC,EANW,WAAW,KAAX,WAAW,QAMtB;AAwBD;;GAEG;AACH,MAAM,OAAO,eAAe;IAC1B;;OAEG;IACH,KAAK,CAAC,SAAS,CAAC,KAAe;QAC7B,MAAM,OAAO,GAAG,IAAI,GAAG,EAA6B,CAAC;QAErD,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC;QACpE,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/B,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ,EAAE;gBAChC,IAAI,EAAE,WAAW,CAAC,QAAQ;gBAC1B,SAAS,EAAE,eAAe;gBAC1B,KAAK,EAAE,eAAe,CAAC,MAAM;gBAC7B,cAAc,EAAE,6CAA6C;aAC9D,CAAC,CAAC;QACL,CAAC;QAED,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACzD,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,UAAU,EAAE;gBAClC,IAAI,EAAE,WAAW,CAAC,UAAU;gBAC5B,SAAS,EAAE,aAAa;gBACxB,KAAK,EAAE,aAAa,CAAC,MAAM;gBAC3B,cAAc,EAAE,0CAA0C;aAC3D,CAAC,CAAC;QACL,CAAC;QAED,MAAM,kBAAkB,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;QACjE,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,aAAa,EAAE;gBACrC,IAAI,EAAE,WAAW,CAAC,aAAa;gBAC/B,SAAS,EAAE,kBAAkB;gBAC7B,KAAK,EAAE,kBAAkB,CAAC,MAAM;gBAChC,cAAc,EAAE,sBAAsB;aACvC,CAAC,CAAC;QACL,CAAC;QAED,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAC3D,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,EAAE;gBAC9B,IAAI,EAAE,WAAW,CAAC,MAAM;gBACxB,SAAS,EAAE,aAAa;gBACxB,KAAK,EAAE,aAAa,CAAC,MAAM;gBAC3B,cAAc,EAAE,gDAAgD;aACjE,CAAC,CAAC;QACL,CAAC;QAED,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAC3D,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,YAAY,EAAE;gBACpC,IAAI,EAAE,WAAW,CAAC,YAAY;gBAC9B,SAAS,EAAE,aAAa;gBACxB,KAAK,EAAE,aAAa,CAAC,MAAM;gBAC3B,cAAc,EAAE,mCAAmC;aACpD,CAAC,CAAC;QACL,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,yBAAyB,CAAC,KAAe;QAC7C,MAAM,OAAO,GAAmB,EAAE,CAAC;QACnC,MAAM,aAAa,GAAG,wDAAwD,CAAC;QAE/E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBAC9C,IAAI,KAA6B,CAAC;gBAElC,OAAO,CAAC,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;oBACtD,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;oBAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;oBAE3E,OAAO,CAAC,IAAI,CAAC;wBACX,IAAI,EAAE,WAAW,CAAC,QAAQ;wBAC1B,IAAI;wBACJ,SAAS;wBACT,OAAO;wBACP,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;wBACd,UAAU,EAAE,GAAG;qBAChB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;QAED,qBAAqB;QACrB,OAAO,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB,CAAC,KAAe;QACpC,MAAM,OAAO,GAAmB,EAAE,CAAC;QACnC,MAAM,WAAW,GAAG,iFAAiF,CAAC;QAEtG,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBAC9C,IAAI,KAA6B,CAAC;gBAElC,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;oBACpD,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;oBAE5D,OAAO,CAAC,IAAI,CAAC;wBACX,IAAI,EAAE,WAAW,CAAC,UAAU;wBAC5B,IAAI;wBACJ,SAAS,EAAE,UAAU;wBACrB,OAAO,EAAE,UAAU;wBACnB,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;wBACd,UAAU,EAAE,GAAG;qBAChB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,mBAAmB,CAAC,KAAe;QACvC,MAAM,OAAO,GAAmB,EAAE,CAAC;QACnC,MAAM,gBAAgB,GAAG,+BAA+B,CAAC;QAEzD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBAC9C,IAAI,KAA6B,CAAC;gBAElC,OAAO,CAAC,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;oBACzD,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;oBAE5D,2CAA2C;oBAC3C,MAAM,iBAAiB,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;oBACnC,IAAI,gDAAgD,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC;wBAC7E,OAAO,CAAC,IAAI,CAAC;4BACX,IAAI,EAAE,WAAW,CAAC,aAAa;4BAC/B,IAAI;4BACJ,SAAS,EAAE,UAAU;4BACrB,OAAO,EAAE,UAAU;4BACnB,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;4BACd,UAAU,EAAE,IAAI;yBACjB,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,kBAAkB,CAAC,KAAe;QACtC,MAAM,OAAO,GAAmB,EAAE,CAAC;QACnC,MAAM,WAAW,GAAG,+CAA+C,CAAC;QAEpE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBAC9C,IAAI,KAA6B,CAAC;gBAElC,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;oBACpD,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;oBAE5D,OAAO,CAAC,IAAI,CAAC;wBACX,IAAI,EAAE,WAAW,CAAC,MAAM;wBACxB,IAAI;wBACJ,SAAS,EAAE,UAAU;wBACrB,OAAO,EAAE,UAAU;wBACnB,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;wBACd,UAAU,EAAE,GAAG;qBAChB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,kBAAkB,CAAC,KAAe;QACtC,MAAM,OAAO,GAAmB,EAAE,CAAC;QACnC,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;QAEhF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAElC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;oBAEtB,gBAAgB;oBAChB,MAAM,YAAY,GAAG,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CACnD,IAAI,CAAC,QAAQ,CAAC,GAAG,OAAO,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,OAAO,IAAI,CAAC,CAC9D,CAAC,MAAM,CAAC;oBAET,IAAI,YAAY,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;wBAC5C,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;wBACnE,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;wBAErC,OAAO,CAAC,IAAI,CAAC;4BACX,IAAI,EAAE,WAAW,CAAC,YAAY;4BAC9B,IAAI;4BACJ,SAAS,EAAE,CAAC,GAAG,CAAC;4BAChB,OAAO,EAAE,CAAC,GAAG,CAAC;4BACd,IAAI,EAAE,IAAI;4BACV,UAAU,EAAE,IAAI;yBACjB,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACK,oBAAoB,CAAC,OAAuB;QAClD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,MAAM,OAAO,GAAmB,EAAE,CAAC;QAEnC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YAC/C,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACnB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACd,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACK,aAAa,CAAC,OAAe,EAAE,KAAa;QAClD,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;IACxD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,QAAwC;QAK1D,MAAM,MAAM,GAA2B,EAAE,CAAC;QAC1C,MAAM,eAAe,GAAa,EAAE,CAAC;QACrC,IAAI,aAAa,GAAG,CAAC,CAAC;QAEtB,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;YAC/C,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;YAC3B,aAAa,IAAI,KAAK,CAAC,KAAK,CAAC;YAC7B,IAAI,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;gBACpB,eAAe,CAAC,IAAI,CAAC,GAAG,IAAI,KAAK,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;QAED,OAAO;YACL,aAAa;YACb,MAAM;YACN,eAAe;SAChB,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * 安全性檢查器
3
+ * 檢測硬編碼密碼、API Key、eval、innerHTML 等安全風險
4
+ */
5
+ /**
6
+ * 安全性檢查器
7
+ */
8
+ export declare class SecurityChecker {
9
+ /**
10
+ * 檢查檔案的安全性問題
11
+ */
12
+ check(files: string[]): Promise<number>;
13
+ /**
14
+ * 檢測硬編碼的密碼和 API Key
15
+ */
16
+ private checkHardcodedSecrets;
17
+ /**
18
+ * 檢測 eval 使用
19
+ */
20
+ private checkEvalUsage;
21
+ /**
22
+ * 檢測 innerHTML 使用(XSS 風險)
23
+ */
24
+ private checkInnerHTMLUsage;
25
+ /**
26
+ * 檢測 console.log 包含敏感資訊
27
+ */
28
+ private checkConsoleLogSecrets;
29
+ /**
30
+ * 判斷是否為 JavaScript 或 TypeScript 檔案
31
+ */
32
+ private isJavaScriptOrTypeScript;
33
+ }
34
+ //# sourceMappingURL=security-checker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-checker.d.ts","sourceRoot":"","sources":["../../../../src/plugins/typescript/analyzers/security-checker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;GAEG;AACH,qBAAa,eAAe;IAC1B;;OAEG;IACG,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAiC7C;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA8C7B;;OAEG;IACH,OAAO,CAAC,cAAc;IAKtB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAK3B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAqB9B;;OAEG;IACH,OAAO,CAAC,wBAAwB;CAQjC"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * 安全性檢查器
3
+ * 檢測硬編碼密碼、API Key、eval、innerHTML 等安全風險
4
+ */
5
+ import * as fs from 'fs/promises';
6
+ /**
7
+ * 安全性檢查器
8
+ */
9
+ export class SecurityChecker {
10
+ /**
11
+ * 檢查檔案的安全性問題
12
+ */
13
+ async check(files) {
14
+ let criticalIssues = 0; // 關鍵安全問題
15
+ let highIssues = 0; // 高風險問題
16
+ let mediumIssues = 0; // 中風險問題
17
+ for (const file of files) {
18
+ if (!this.isJavaScriptOrTypeScript(file)) {
19
+ continue;
20
+ }
21
+ try {
22
+ const content = await fs.readFile(file, 'utf-8');
23
+ // 關鍵問題:硬編碼密碼和金鑰
24
+ criticalIssues += this.checkHardcodedSecrets(content);
25
+ // 關鍵問題:eval 使用
26
+ criticalIssues += this.checkEvalUsage(content);
27
+ // 高風險:innerHTML 使用
28
+ highIssues += this.checkInnerHTMLUsage(content);
29
+ // 中風險:console.log 包含敏感資訊
30
+ mediumIssues += this.checkConsoleLogSecrets(content);
31
+ }
32
+ catch {
33
+ // 忽略無法讀取的檔案
34
+ }
35
+ }
36
+ // 計算總分(關鍵問題權重最高)
37
+ return criticalIssues * 5 + highIssues * 3 + mediumIssues;
38
+ }
39
+ /**
40
+ * 檢測硬編碼的密碼和 API Key
41
+ */
42
+ checkHardcodedSecrets(content) {
43
+ let count = 0;
44
+ // 硬編碼密碼模式
45
+ const passwordPatterns = [
46
+ /password\s*=\s*['"][^'"]+['"]/gi,
47
+ /dbPassword\s*=\s*['"][^'"]+['"]/gi,
48
+ /userPassword\s*=\s*['"][^'"]+['"]/gi,
49
+ ];
50
+ // API Key 模式
51
+ const apiKeyPatterns = [
52
+ /apiKey\s*=\s*['"][^'"]+['"]/gi,
53
+ /secretKey\s*=\s*['"][^'"]+['"]/gi,
54
+ /api_key\s*=\s*['"][^'"]+['"]/gi,
55
+ ];
56
+ // 檢測密碼
57
+ for (const pattern of passwordPatterns) {
58
+ const matches = content.match(pattern);
59
+ if (matches) {
60
+ // 排除環境變數(process.env.PASSWORD)
61
+ for (const match of matches) {
62
+ if (!match.includes('process.env') && !match.includes('env.')) {
63
+ count++;
64
+ }
65
+ }
66
+ }
67
+ }
68
+ // 檢測 API Key
69
+ for (const pattern of apiKeyPatterns) {
70
+ const matches = content.match(pattern);
71
+ if (matches) {
72
+ // 排除環境變數
73
+ for (const match of matches) {
74
+ if (!match.includes('process.env') && !match.includes('env.')) {
75
+ count++;
76
+ }
77
+ }
78
+ }
79
+ }
80
+ return count;
81
+ }
82
+ /**
83
+ * 檢測 eval 使用
84
+ */
85
+ checkEvalUsage(content) {
86
+ const evalMatches = content.match(/\beval\s*\(/g);
87
+ return evalMatches ? evalMatches.length : 0;
88
+ }
89
+ /**
90
+ * 檢測 innerHTML 使用(XSS 風險)
91
+ */
92
+ checkInnerHTMLUsage(content) {
93
+ const innerHTMLMatches = content.match(/\.innerHTML\s*=/g);
94
+ return innerHTMLMatches ? innerHTMLMatches.length : 0;
95
+ }
96
+ /**
97
+ * 檢測 console.log 包含敏感資訊
98
+ */
99
+ checkConsoleLogSecrets(content) {
100
+ let count = 0;
101
+ // 檢測 console.log 包含 password、token、secret 等關鍵字
102
+ const sensitivePatterns = [
103
+ /console\.log\([^)]*password[^)]*\)/gi,
104
+ /console\.log\([^)]*token[^)]*\)/gi,
105
+ /console\.log\([^)]*secret[^)]*\)/gi,
106
+ /console\.log\([^)]*apiKey[^)]*\)/gi,
107
+ ];
108
+ for (const pattern of sensitivePatterns) {
109
+ const matches = content.match(pattern);
110
+ if (matches) {
111
+ count += matches.length;
112
+ }
113
+ }
114
+ return count;
115
+ }
116
+ /**
117
+ * 判斷是否為 JavaScript 或 TypeScript 檔案
118
+ */
119
+ isJavaScriptOrTypeScript(file) {
120
+ return (file.endsWith('.ts') ||
121
+ file.endsWith('.tsx') ||
122
+ file.endsWith('.js') ||
123
+ file.endsWith('.jsx'));
124
+ }
125
+ }
126
+ //# sourceMappingURL=security-checker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-checker.js","sourceRoot":"","sources":["../../../../src/plugins/typescript/analyzers/security-checker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAElC;;GAEG;AACH,MAAM,OAAO,eAAe;IAC1B;;OAEG;IACH,KAAK,CAAC,KAAK,CAAC,KAAe;QACzB,IAAI,cAAc,GAAG,CAAC,CAAC,CAAC,SAAS;QACjC,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC,QAAQ;QAC5B,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC,QAAQ;QAE9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzC,SAAS;YACX,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBAEjD,gBAAgB;gBAChB,cAAc,IAAI,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC;gBAEtD,eAAe;gBACf,cAAc,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;gBAE/C,mBAAmB;gBACnB,UAAU,IAAI,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;gBAEhD,yBAAyB;gBACzB,YAAY,IAAI,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;YACvD,CAAC;YAAC,MAAM,CAAC;gBACP,YAAY;YACd,CAAC;QACH,CAAC;QAED,iBAAiB;QACjB,OAAO,cAAc,GAAG,CAAC,GAAG,UAAU,GAAG,CAAC,GAAG,YAAY,CAAC;IAC5D,CAAC;IAED;;OAEG;IACK,qBAAqB,CAAC,OAAe;QAC3C,IAAI,KAAK,GAAG,CAAC,CAAC;QAEd,UAAU;QACV,MAAM,gBAAgB,GAAG;YACvB,iCAAiC;YACjC,mCAAmC;YACnC,qCAAqC;SACtC,CAAC;QAEF,aAAa;QACb,MAAM,cAAc,GAAG;YACrB,+BAA+B;YAC/B,kCAAkC;YAClC,gCAAgC;SACjC,CAAC;QAEF,OAAO;QACP,KAAK,MAAM,OAAO,IAAI,gBAAgB,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACvC,IAAI,OAAO,EAAE,CAAC;gBACZ,+BAA+B;gBAC/B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;oBAC5B,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC9D,KAAK,EAAE,CAAC;oBACV,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,aAAa;QACb,KAAK,MAAM,OAAO,IAAI,cAAc,EAAE,CAAC;YACrC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACvC,IAAI,OAAO,EAAE,CAAC;gBACZ,SAAS;gBACT,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;oBAC5B,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC9D,KAAK,EAAE,CAAC;oBACV,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACK,cAAc,CAAC,OAAe;QACpC,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAClD,OAAO,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED;;OAEG;IACK,mBAAmB,CAAC,OAAe;QACzC,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAC3D,OAAO,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC;IAED;;OAEG;IACK,sBAAsB,CAAC,OAAe;QAC5C,IAAI,KAAK,GAAG,CAAC,CAAC;QAEd,+CAA+C;QAC/C,MAAM,iBAAiB,GAAG;YACxB,sCAAsC;YACtC,mCAAmC;YACnC,oCAAoC;YACpC,oCAAoC;SACrC,CAAC;QAEF,KAAK,MAAM,OAAO,IAAI,iBAAiB,EAAE,CAAC;YACxC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACvC,IAAI,OAAO,EAAE,CAAC;gBACZ,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;YAC1B,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACK,wBAAwB,CAAC,IAAY;QAC3C,OAAO,CACL,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YACpB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YACrB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YACpB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CACtB,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * 測試覆蓋率檢查器
3
+ * 計算測試檔案比例(靜態分析)
4
+ */
5
+ /**
6
+ * 測試覆蓋率檢查器
7
+ */
8
+ export declare class TestCoverageChecker {
9
+ /**
10
+ * 計算測試覆蓋率(測試檔案比例)
11
+ */
12
+ calculate(files: string[], _projectRoot: string): Promise<number>;
13
+ /**
14
+ * 判斷是否為源碼檔案
15
+ */
16
+ private isSourceFile;
17
+ /**
18
+ * 判斷是否為測試檔案
19
+ */
20
+ private isTestFile;
21
+ }
22
+ //# sourceMappingURL=test-coverage-checker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-coverage-checker.d.ts","sourceRoot":"","sources":["../../../../src/plugins/typescript/analyzers/test-coverage-checker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;GAEG;AACH,qBAAa,mBAAmB;IAC9B;;OAEG;IACG,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAgBvE;;OAEG;IACH,OAAO,CAAC,YAAY;IAoBpB;;OAEG;IACH,OAAO,CAAC,UAAU;CAiBnB"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * 測試覆蓋率檢查器
3
+ * 計算測試檔案比例(靜態分析)
4
+ */
5
+ import * as path from 'path';
6
+ /**
7
+ * 測試覆蓋率檢查器
8
+ */
9
+ export class TestCoverageChecker {
10
+ /**
11
+ * 計算測試覆蓋率(測試檔案比例)
12
+ */
13
+ async calculate(files, _projectRoot) {
14
+ // 過濾出源碼檔案和測試檔案
15
+ const sourceFiles = files.filter((file) => this.isSourceFile(file));
16
+ const testFiles = files.filter((file) => this.isTestFile(file));
17
+ if (sourceFiles.length === 0) {
18
+ return 0;
19
+ }
20
+ // 計算測試覆蓋率(測試檔案數 / 源碼檔案數)
21
+ const coverageRatio = testFiles.length / sourceFiles.length;
22
+ // 回傳 0-1 的比例
23
+ return Math.min(coverageRatio, 1);
24
+ }
25
+ /**
26
+ * 判斷是否為源碼檔案
27
+ */
28
+ isSourceFile(file) {
29
+ // TypeScript/JavaScript 檔案
30
+ const ext = path.extname(file);
31
+ if (!['.ts', '.tsx', '.js', '.jsx'].includes(ext)) {
32
+ return false;
33
+ }
34
+ // 排除測試檔案
35
+ if (this.isTestFile(file)) {
36
+ return false;
37
+ }
38
+ // 排除測試目錄
39
+ if (file.includes('/tests/') || file.includes('/__tests__/') || file.includes('/test/')) {
40
+ return false;
41
+ }
42
+ return true;
43
+ }
44
+ /**
45
+ * 判斷是否為測試檔案
46
+ */
47
+ isTestFile(file) {
48
+ const basename = path.basename(file);
49
+ // 常見的測試檔案命名模式
50
+ return (basename.endsWith('.test.ts') ||
51
+ basename.endsWith('.test.tsx') ||
52
+ basename.endsWith('.test.js') ||
53
+ basename.endsWith('.test.jsx') ||
54
+ basename.endsWith('.spec.ts') ||
55
+ basename.endsWith('.spec.tsx') ||
56
+ basename.endsWith('.spec.js') ||
57
+ basename.endsWith('.spec.jsx') ||
58
+ basename.endsWith('.e2e.test.ts') ||
59
+ basename.endsWith('.e2e.test.js'));
60
+ }
61
+ }
62
+ //# sourceMappingURL=test-coverage-checker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-coverage-checker.js","sourceRoot":"","sources":["../../../../src/plugins/typescript/analyzers/test-coverage-checker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B;;GAEG;AACH,MAAM,OAAO,mBAAmB;IAC9B;;OAEG;IACH,KAAK,CAAC,SAAS,CAAC,KAAe,EAAE,YAAoB;QACnD,eAAe;QACf,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;QACpE,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QAEhE,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,2BAA2B;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAClD,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,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxF,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACK,UAAU,CAAC,IAAY;QAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAErC,cAAc;QACd,OAAO,CACL,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;YAC7B,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC;YAC9B,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;YAC7B,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC;YAC9B,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;YAC7B,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC;YAC9B,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;YAC7B,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC;YAC9B,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC;YACjC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,CAClC,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * 型別安全檢查器
3
+ * 檢測 any 型別使用、@ts-ignore、as any、tsconfig strict 模式
4
+ */
5
+ /**
6
+ * 型別安全檢查結果
7
+ */
8
+ export interface TypeSafetyResult {
9
+ readonly anyTypeCount: number;
10
+ readonly tsIgnoreCount: number;
11
+ readonly asAnyCount: number;
12
+ readonly strictModeEnabled: boolean;
13
+ readonly strictNullChecksEnabled: boolean;
14
+ }
15
+ /**
16
+ * 型別安全檢查器
17
+ */
18
+ export declare class TypeSafetyChecker {
19
+ /**
20
+ * 檢查檔案的型別安全問題
21
+ */
22
+ check(files: string[], projectRoot: string): Promise<TypeSafetyResult>;
23
+ /**
24
+ * 檢查 tsconfig.json 的 strict 設定
25
+ */
26
+ private checkTsConfig;
27
+ /**
28
+ * 判斷是否為 TypeScript 檔案
29
+ */
30
+ private isTypeScriptFile;
31
+ }
32
+ //# sourceMappingURL=type-safety-checker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-safety-checker.d.ts","sourceRoot":"","sources":["../../../../src/plugins/typescript/analyzers/type-safety-checker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC,QAAQ,CAAC,uBAAuB,EAAE,OAAO,CAAC;CAC3C;AAED;;GAEG;AACH,qBAAa,iBAAiB;IAC5B;;OAEG;IACG,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAoD5E;;OAEG;YACW,aAAa;IAwB3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAGzB"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * 型別安全檢查器
3
+ * 檢測 any 型別使用、@ts-ignore、as any、tsconfig strict 模式
4
+ */
5
+ import * as fs from 'fs/promises';
6
+ import * as path from 'path';
7
+ /**
8
+ * 型別安全檢查器
9
+ */
10
+ export class TypeSafetyChecker {
11
+ /**
12
+ * 檢查檔案的型別安全問題
13
+ */
14
+ async check(files, projectRoot) {
15
+ let anyTypeCount = 0;
16
+ let tsIgnoreCount = 0;
17
+ let asAnyCount = 0;
18
+ for (const file of files) {
19
+ if (!this.isTypeScriptFile(file)) {
20
+ continue;
21
+ }
22
+ try {
23
+ const content = await fs.readFile(file, 'utf-8');
24
+ // 檢測 any 型別使用(: any)
25
+ const anyMatches = content.match(/:\s*any\b/g);
26
+ if (anyMatches) {
27
+ anyTypeCount += anyMatches.length;
28
+ }
29
+ // 檢測 @ts-ignore
30
+ const tsIgnoreMatches = content.match(/@ts-ignore/g);
31
+ if (tsIgnoreMatches) {
32
+ tsIgnoreCount += tsIgnoreMatches.length;
33
+ }
34
+ // 檢測 as any 和 <any>
35
+ const asAnyMatches = content.match(/as\s+any\b/g);
36
+ if (asAnyMatches) {
37
+ asAnyCount += asAnyMatches.length;
38
+ }
39
+ const castAnyMatches = content.match(/<any>/g);
40
+ if (castAnyMatches) {
41
+ asAnyCount += castAnyMatches.length;
42
+ }
43
+ }
44
+ catch {
45
+ // 忽略無法讀取的檔案
46
+ }
47
+ }
48
+ // 檢查 tsconfig.json
49
+ const tsconfigResult = await this.checkTsConfig(projectRoot);
50
+ return {
51
+ anyTypeCount,
52
+ tsIgnoreCount,
53
+ asAnyCount,
54
+ strictModeEnabled: tsconfigResult.strictModeEnabled,
55
+ strictNullChecksEnabled: tsconfigResult.strictNullChecksEnabled,
56
+ };
57
+ }
58
+ /**
59
+ * 檢查 tsconfig.json 的 strict 設定
60
+ */
61
+ async checkTsConfig(projectRoot) {
62
+ const tsconfigPath = path.join(projectRoot, 'tsconfig.json');
63
+ try {
64
+ const content = await fs.readFile(tsconfigPath, 'utf-8');
65
+ const config = JSON.parse(content);
66
+ const compilerOptions = config.compilerOptions || {};
67
+ return {
68
+ strictModeEnabled: compilerOptions.strict === true,
69
+ strictNullChecksEnabled: compilerOptions.strictNullChecks === true || compilerOptions.strict === true,
70
+ };
71
+ }
72
+ catch {
73
+ return {
74
+ strictModeEnabled: false,
75
+ strictNullChecksEnabled: false,
76
+ };
77
+ }
78
+ }
79
+ /**
80
+ * 判斷是否為 TypeScript 檔案
81
+ */
82
+ isTypeScriptFile(file) {
83
+ return file.endsWith('.ts') || file.endsWith('.tsx');
84
+ }
85
+ }
86
+ //# sourceMappingURL=type-safety-checker.js.map