@nahisaho/musubix-core 1.0.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 (214) hide show
  1. package/bin/musubix.js +18 -0
  2. package/dist/__tests__/index.test.d.ts +2 -0
  3. package/dist/__tests__/index.test.d.ts.map +1 -0
  4. package/dist/__tests__/index.test.js +27 -0
  5. package/dist/__tests__/index.test.js.map +1 -0
  6. package/dist/auth/auth-manager.d.ts +320 -0
  7. package/dist/auth/auth-manager.d.ts.map +1 -0
  8. package/dist/auth/auth-manager.js +580 -0
  9. package/dist/auth/auth-manager.js.map +1 -0
  10. package/dist/cli/base.d.ts +58 -0
  11. package/dist/cli/base.d.ts.map +1 -0
  12. package/dist/cli/base.js +93 -0
  13. package/dist/cli/base.js.map +1 -0
  14. package/dist/cli/commands/help.d.ts +17 -0
  15. package/dist/cli/commands/help.d.ts.map +1 -0
  16. package/dist/cli/commands/help.js +228 -0
  17. package/dist/cli/commands/help.js.map +1 -0
  18. package/dist/cli/commands/index.d.ts +14 -0
  19. package/dist/cli/commands/index.d.ts.map +1 -0
  20. package/dist/cli/commands/index.js +25 -0
  21. package/dist/cli/commands/index.js.map +1 -0
  22. package/dist/cli/commands/init.d.ts +38 -0
  23. package/dist/cli/commands/init.d.ts.map +1 -0
  24. package/dist/cli/commands/init.js +258 -0
  25. package/dist/cli/commands/init.js.map +1 -0
  26. package/dist/cli/index.d.ts +9 -0
  27. package/dist/cli/index.d.ts.map +1 -0
  28. package/dist/cli/index.js +9 -0
  29. package/dist/cli/index.js.map +1 -0
  30. package/dist/codegen/coding-standards.d.ts +250 -0
  31. package/dist/codegen/coding-standards.d.ts.map +1 -0
  32. package/dist/codegen/coding-standards.js +976 -0
  33. package/dist/codegen/coding-standards.js.map +1 -0
  34. package/dist/codegen/coverage-reporter.d.ts +264 -0
  35. package/dist/codegen/coverage-reporter.d.ts.map +1 -0
  36. package/dist/codegen/coverage-reporter.js +697 -0
  37. package/dist/codegen/coverage-reporter.js.map +1 -0
  38. package/dist/codegen/dependency-analyzer.d.ts +271 -0
  39. package/dist/codegen/dependency-analyzer.d.ts.map +1 -0
  40. package/dist/codegen/dependency-analyzer.js +661 -0
  41. package/dist/codegen/dependency-analyzer.js.map +1 -0
  42. package/dist/codegen/generator.d.ts +275 -0
  43. package/dist/codegen/generator.d.ts.map +1 -0
  44. package/dist/codegen/generator.js +781 -0
  45. package/dist/codegen/generator.js.map +1 -0
  46. package/dist/codegen/index.d.ts +18 -0
  47. package/dist/codegen/index.d.ts.map +1 -0
  48. package/dist/codegen/index.js +27 -0
  49. package/dist/codegen/index.js.map +1 -0
  50. package/dist/codegen/integration-test-generator.d.ts +312 -0
  51. package/dist/codegen/integration-test-generator.d.ts.map +1 -0
  52. package/dist/codegen/integration-test-generator.js +765 -0
  53. package/dist/codegen/integration-test-generator.js.map +1 -0
  54. package/dist/codegen/pattern-conformance.d.ts +309 -0
  55. package/dist/codegen/pattern-conformance.d.ts.map +1 -0
  56. package/dist/codegen/pattern-conformance.js +590 -0
  57. package/dist/codegen/pattern-conformance.js.map +1 -0
  58. package/dist/codegen/quality-metrics.d.ts +235 -0
  59. package/dist/codegen/quality-metrics.d.ts.map +1 -0
  60. package/dist/codegen/quality-metrics.js +439 -0
  61. package/dist/codegen/quality-metrics.js.map +1 -0
  62. package/dist/codegen/security-scanner.d.ts +179 -0
  63. package/dist/codegen/security-scanner.d.ts.map +1 -0
  64. package/dist/codegen/security-scanner.js +495 -0
  65. package/dist/codegen/security-scanner.js.map +1 -0
  66. package/dist/codegen/static-analyzer.d.ts +188 -0
  67. package/dist/codegen/static-analyzer.d.ts.map +1 -0
  68. package/dist/codegen/static-analyzer.js +490 -0
  69. package/dist/codegen/static-analyzer.js.map +1 -0
  70. package/dist/codegen/unit-test-generator.d.ts +289 -0
  71. package/dist/codegen/unit-test-generator.d.ts.map +1 -0
  72. package/dist/codegen/unit-test-generator.js +634 -0
  73. package/dist/codegen/unit-test-generator.js.map +1 -0
  74. package/dist/design/adr-generator.d.ts +227 -0
  75. package/dist/design/adr-generator.d.ts.map +1 -0
  76. package/dist/design/adr-generator.js +423 -0
  77. package/dist/design/adr-generator.js.map +1 -0
  78. package/dist/design/c4-generator.d.ts +267 -0
  79. package/dist/design/c4-generator.d.ts.map +1 -0
  80. package/dist/design/c4-generator.js +453 -0
  81. package/dist/design/c4-generator.js.map +1 -0
  82. package/dist/design/framework-optimizer.d.ts +190 -0
  83. package/dist/design/framework-optimizer.d.ts.map +1 -0
  84. package/dist/design/framework-optimizer.js +589 -0
  85. package/dist/design/framework-optimizer.js.map +1 -0
  86. package/dist/design/index.d.ts +12 -0
  87. package/dist/design/index.d.ts.map +1 -0
  88. package/dist/design/index.js +13 -0
  89. package/dist/design/index.js.map +1 -0
  90. package/dist/design/pattern-detector.d.ts +270 -0
  91. package/dist/design/pattern-detector.d.ts.map +1 -0
  92. package/dist/design/pattern-detector.js +621 -0
  93. package/dist/design/pattern-detector.js.map +1 -0
  94. package/dist/design/solid-validator.d.ts +188 -0
  95. package/dist/design/solid-validator.d.ts.map +1 -0
  96. package/dist/design/solid-validator.js +579 -0
  97. package/dist/design/solid-validator.js.map +1 -0
  98. package/dist/error/data-persistence.d.ts +311 -0
  99. package/dist/error/data-persistence.d.ts.map +1 -0
  100. package/dist/error/data-persistence.js +586 -0
  101. package/dist/error/data-persistence.js.map +1 -0
  102. package/dist/error/graceful-degradation.d.ts +309 -0
  103. package/dist/error/graceful-degradation.d.ts.map +1 -0
  104. package/dist/error/graceful-degradation.js +510 -0
  105. package/dist/error/graceful-degradation.js.map +1 -0
  106. package/dist/error/index.d.ts +11 -0
  107. package/dist/error/index.d.ts.map +1 -0
  108. package/dist/error/index.js +19 -0
  109. package/dist/error/index.js.map +1 -0
  110. package/dist/explanation/explanation-generator.d.ts +228 -0
  111. package/dist/explanation/explanation-generator.d.ts.map +1 -0
  112. package/dist/explanation/explanation-generator.js +662 -0
  113. package/dist/explanation/explanation-generator.js.map +1 -0
  114. package/dist/explanation/index.d.ts +11 -0
  115. package/dist/explanation/index.d.ts.map +1 -0
  116. package/dist/explanation/index.js +19 -0
  117. package/dist/explanation/index.js.map +1 -0
  118. package/dist/explanation/reasoning-chain.d.ts +314 -0
  119. package/dist/explanation/reasoning-chain.d.ts.map +1 -0
  120. package/dist/explanation/reasoning-chain.js +414 -0
  121. package/dist/explanation/reasoning-chain.js.map +1 -0
  122. package/dist/explanation/visual-explanation.d.ts +315 -0
  123. package/dist/explanation/visual-explanation.d.ts.map +1 -0
  124. package/dist/explanation/visual-explanation.js +667 -0
  125. package/dist/explanation/visual-explanation.js.map +1 -0
  126. package/dist/index.d.ts +33 -0
  127. package/dist/index.d.ts.map +1 -0
  128. package/dist/index.js +47 -0
  129. package/dist/index.js.map +1 -0
  130. package/dist/requirements/decomposer.d.ts +235 -0
  131. package/dist/requirements/decomposer.d.ts.map +1 -0
  132. package/dist/requirements/decomposer.js +587 -0
  133. package/dist/requirements/decomposer.js.map +1 -0
  134. package/dist/requirements/related-finder.d.ts +261 -0
  135. package/dist/requirements/related-finder.d.ts.map +1 -0
  136. package/dist/requirements/related-finder.js +629 -0
  137. package/dist/requirements/related-finder.js.map +1 -0
  138. package/dist/traceability/impact.d.ts +196 -0
  139. package/dist/traceability/impact.d.ts.map +1 -0
  140. package/dist/traceability/impact.js +438 -0
  141. package/dist/traceability/impact.js.map +1 -0
  142. package/dist/traceability/index.d.ts +9 -0
  143. package/dist/traceability/index.d.ts.map +1 -0
  144. package/dist/traceability/index.js +10 -0
  145. package/dist/traceability/index.js.map +1 -0
  146. package/dist/traceability/manager.d.ts +266 -0
  147. package/dist/traceability/manager.d.ts.map +1 -0
  148. package/dist/traceability/manager.js +412 -0
  149. package/dist/traceability/manager.js.map +1 -0
  150. package/dist/types/common.d.ts +294 -0
  151. package/dist/types/common.d.ts.map +1 -0
  152. package/dist/types/common.js +15 -0
  153. package/dist/types/common.js.map +1 -0
  154. package/dist/types/ears.d.ts +158 -0
  155. package/dist/types/ears.d.ts.map +1 -0
  156. package/dist/types/ears.js +33 -0
  157. package/dist/types/ears.js.map +1 -0
  158. package/dist/types/errors.d.ts +176 -0
  159. package/dist/types/errors.d.ts.map +1 -0
  160. package/dist/types/errors.js +55 -0
  161. package/dist/types/errors.js.map +1 -0
  162. package/dist/types/index.d.ts +10 -0
  163. package/dist/types/index.d.ts.map +1 -0
  164. package/dist/types/index.js +10 -0
  165. package/dist/types/index.js.map +1 -0
  166. package/dist/utils/data-protector.d.ts +122 -0
  167. package/dist/utils/data-protector.d.ts.map +1 -0
  168. package/dist/utils/data-protector.js +275 -0
  169. package/dist/utils/data-protector.js.map +1 -0
  170. package/dist/utils/error-handler.d.ts +101 -0
  171. package/dist/utils/error-handler.d.ts.map +1 -0
  172. package/dist/utils/error-handler.js +324 -0
  173. package/dist/utils/error-handler.js.map +1 -0
  174. package/dist/utils/i18n-manager.d.ts +259 -0
  175. package/dist/utils/i18n-manager.d.ts.map +1 -0
  176. package/dist/utils/i18n-manager.js +554 -0
  177. package/dist/utils/i18n-manager.js.map +1 -0
  178. package/dist/utils/index.d.ts +10 -0
  179. package/dist/utils/index.d.ts.map +1 -0
  180. package/dist/utils/index.js +10 -0
  181. package/dist/utils/index.js.map +1 -0
  182. package/dist/utils/logger.d.ts +120 -0
  183. package/dist/utils/logger.d.ts.map +1 -0
  184. package/dist/utils/logger.js +237 -0
  185. package/dist/utils/logger.js.map +1 -0
  186. package/dist/utils/performance-profiler.d.ts +251 -0
  187. package/dist/utils/performance-profiler.d.ts.map +1 -0
  188. package/dist/utils/performance-profiler.js +458 -0
  189. package/dist/utils/performance-profiler.js.map +1 -0
  190. package/dist/utils/scalability-optimizer.d.ts +294 -0
  191. package/dist/utils/scalability-optimizer.d.ts.map +1 -0
  192. package/dist/utils/scalability-optimizer.js +606 -0
  193. package/dist/utils/scalability-optimizer.js.map +1 -0
  194. package/dist/utils/structured-logger.d.ts +294 -0
  195. package/dist/utils/structured-logger.d.ts.map +1 -0
  196. package/dist/utils/structured-logger.js +630 -0
  197. package/dist/utils/structured-logger.js.map +1 -0
  198. package/dist/utils/version-compatibility.d.ts +217 -0
  199. package/dist/utils/version-compatibility.d.ts.map +1 -0
  200. package/dist/utils/version-compatibility.js +443 -0
  201. package/dist/utils/version-compatibility.js.map +1 -0
  202. package/dist/validators/ears-validator.d.ts +182 -0
  203. package/dist/validators/ears-validator.d.ts.map +1 -0
  204. package/dist/validators/ears-validator.js +357 -0
  205. package/dist/validators/ears-validator.js.map +1 -0
  206. package/dist/validators/index.d.ts +8 -0
  207. package/dist/validators/index.d.ts.map +1 -0
  208. package/dist/validators/index.js +9 -0
  209. package/dist/validators/index.js.map +1 -0
  210. package/dist/version.d.ts +8 -0
  211. package/dist/version.d.ts.map +1 -0
  212. package/dist/version.js +8 -0
  213. package/dist/version.js.map +1 -0
  214. package/package.json +100 -0
@@ -0,0 +1,661 @@
1
+ /**
2
+ * Dependency Analyzer
3
+ *
4
+ * Analyzes code dependencies and generates dependency graphs
5
+ *
6
+ * @packageDocumentation
7
+ * @module codegen/dependency-analyzer
8
+ *
9
+ * @see REQ-COD-004 - Dependency Analysis
10
+ * @see Article VI - Implementation Standards
11
+ */
12
+ /**
13
+ * Default configuration
14
+ */
15
+ export const DEFAULT_ANALYZER_CONFIG = {
16
+ includeDevDependencies: false,
17
+ includeTypeOnly: true,
18
+ maxDependenciesPerModule: 20,
19
+ maxCouplingFactor: 0.5,
20
+ detectCycles: true,
21
+ detectUnused: true,
22
+ };
23
+ /**
24
+ * Built-in Node.js modules
25
+ */
26
+ const BUILTIN_MODULES = new Set([
27
+ 'assert', 'buffer', 'child_process', 'cluster', 'console', 'constants',
28
+ 'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'https',
29
+ 'module', 'net', 'os', 'path', 'perf_hooks', 'process', 'punycode',
30
+ 'querystring', 'readline', 'repl', 'stream', 'string_decoder', 'sys',
31
+ 'timers', 'tls', 'tty', 'url', 'util', 'v8', 'vm', 'wasi', 'worker_threads', 'zlib',
32
+ 'node:assert', 'node:buffer', 'node:child_process', 'node:cluster',
33
+ 'node:console', 'node:constants', 'node:crypto', 'node:dgram', 'node:dns',
34
+ 'node:domain', 'node:events', 'node:fs', 'node:http', 'node:https',
35
+ 'node:module', 'node:net', 'node:os', 'node:path', 'node:perf_hooks',
36
+ 'node:process', 'node:punycode', 'node:querystring', 'node:readline',
37
+ 'node:repl', 'node:stream', 'node:string_decoder', 'node:sys',
38
+ 'node:timers', 'node:tls', 'node:tty', 'node:url', 'node:util', 'node:v8',
39
+ 'node:vm', 'node:wasi', 'node:worker_threads', 'node:zlib',
40
+ ]);
41
+ /**
42
+ * Dependency Analyzer
43
+ */
44
+ export class DependencyAnalyzer {
45
+ config;
46
+ constructor(config) {
47
+ this.config = { ...DEFAULT_ANALYZER_CONFIG, ...config };
48
+ }
49
+ /**
50
+ * Analyze dependencies in code
51
+ */
52
+ analyze(code, filePath) {
53
+ const dependencies = [];
54
+ // Parse import statements
55
+ dependencies.push(...this.parseImports(code, filePath));
56
+ // Parse require statements
57
+ dependencies.push(...this.parseRequires(code, filePath));
58
+ // Parse class relationships
59
+ dependencies.push(...this.parseClassRelationships(code, filePath));
60
+ // Parse type references
61
+ if (this.config.includeTypeOnly) {
62
+ dependencies.push(...this.parseTypeReferences(code, filePath));
63
+ }
64
+ return dependencies;
65
+ }
66
+ /**
67
+ * Analyze multiple files and build graph
68
+ */
69
+ analyzeProject(files) {
70
+ const graph = this.buildGraph(files);
71
+ const metrics = this.calculateMetrics(graph);
72
+ const issues = this.detectIssues(graph, metrics);
73
+ const recommendations = this.generateRecommendations(graph, metrics, issues);
74
+ return {
75
+ graph,
76
+ metrics,
77
+ issues,
78
+ recommendations,
79
+ };
80
+ }
81
+ /**
82
+ * Parse ES6 import statements
83
+ */
84
+ parseImports(code, source) {
85
+ const dependencies = [];
86
+ // Standard imports: import { x } from 'module'
87
+ const importRegex = /import\s+(?:(type)\s+)?(?:(\*\s+as\s+\w+)|(\w+)(?:\s*,\s*\{([^}]*)\})?|\{([^}]*)\})\s+from\s+['"]([^'"]+)['"]/g;
88
+ let match;
89
+ while ((match = importRegex.exec(code)) !== null) {
90
+ const isTypeOnly = match[1] === 'type';
91
+ const isNamespace = !!match[2];
92
+ const defaultImport = match[3];
93
+ const namedWithDefault = match[4];
94
+ const namedImports = match[5];
95
+ const target = match[6];
96
+ const line = code.substring(0, match.index).split('\n').length;
97
+ const specifiers = [];
98
+ if (defaultImport)
99
+ specifiers.push(defaultImport);
100
+ if (namedWithDefault) {
101
+ specifiers.push(...namedWithDefault.split(',').map((s) => s.trim()));
102
+ }
103
+ if (namedImports) {
104
+ specifiers.push(...namedImports.split(',').map((s) => s.trim().split(' as ')[0]));
105
+ }
106
+ dependencies.push({
107
+ source,
108
+ target,
109
+ type: 'import',
110
+ strength: this.calculateStrength(target),
111
+ moduleType: this.getModuleType(target),
112
+ specifiers: specifiers.length > 0 ? specifiers : undefined,
113
+ isDefault: !!defaultImport,
114
+ isNamespace,
115
+ isTypeOnly,
116
+ location: { line, column: 0 },
117
+ });
118
+ }
119
+ // Side-effect imports: import 'module'
120
+ const sideEffectRegex = /import\s+['"]([^'"]+)['"]/g;
121
+ while ((match = sideEffectRegex.exec(code)) !== null) {
122
+ const target = match[1];
123
+ const line = code.substring(0, match.index).split('\n').length;
124
+ // Skip if already captured
125
+ if (dependencies.some((d) => d.target === target))
126
+ continue;
127
+ dependencies.push({
128
+ source,
129
+ target,
130
+ type: 'import',
131
+ strength: 'weak',
132
+ moduleType: this.getModuleType(target),
133
+ location: { line, column: 0 },
134
+ });
135
+ }
136
+ return dependencies;
137
+ }
138
+ /**
139
+ * Parse CommonJS require statements
140
+ */
141
+ parseRequires(code, source) {
142
+ const dependencies = [];
143
+ const requireRegex = /(?:const|let|var)\s+(?:(\w+)|{([^}]+)})\s*=\s*require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
144
+ let match;
145
+ while ((match = requireRegex.exec(code)) !== null) {
146
+ const defaultRequire = match[1];
147
+ const destructured = match[2];
148
+ const target = match[3];
149
+ const line = code.substring(0, match.index).split('\n').length;
150
+ const specifiers = [];
151
+ if (defaultRequire)
152
+ specifiers.push(defaultRequire);
153
+ if (destructured) {
154
+ specifiers.push(...destructured.split(',').map((s) => s.trim().split(':')[0]));
155
+ }
156
+ dependencies.push({
157
+ source,
158
+ target,
159
+ type: 'require',
160
+ strength: this.calculateStrength(target),
161
+ moduleType: this.getModuleType(target),
162
+ specifiers: specifiers.length > 0 ? specifiers : undefined,
163
+ isDefault: !!defaultRequire,
164
+ location: { line, column: 0 },
165
+ });
166
+ }
167
+ // Dynamic require
168
+ const dynamicRegex = /require\s*\(\s*(['"`])([^'"]+)\1\s*\)/g;
169
+ while ((match = dynamicRegex.exec(code)) !== null) {
170
+ const target = match[2];
171
+ if (dependencies.some((d) => d.target === target))
172
+ continue;
173
+ const line = code.substring(0, match.index).split('\n').length;
174
+ dependencies.push({
175
+ source,
176
+ target,
177
+ type: 'dynamic',
178
+ strength: 'weak',
179
+ moduleType: this.getModuleType(target),
180
+ location: { line, column: 0 },
181
+ });
182
+ }
183
+ return dependencies;
184
+ }
185
+ /**
186
+ * Parse class relationships (extends, implements)
187
+ */
188
+ parseClassRelationships(code, source) {
189
+ const dependencies = [];
190
+ const classRegex = /class\s+\w+(?:\s+extends\s+(\w+))?(?:\s+implements\s+([^{]+))?\s*\{/g;
191
+ let match;
192
+ while ((match = classRegex.exec(code)) !== null) {
193
+ const extendsClass = match[1];
194
+ const implementsList = match[2];
195
+ const line = code.substring(0, match.index).split('\n').length;
196
+ if (extendsClass) {
197
+ dependencies.push({
198
+ source,
199
+ target: extendsClass,
200
+ type: 'extends',
201
+ strength: 'strong',
202
+ moduleType: 'internal',
203
+ location: { line, column: 0 },
204
+ });
205
+ }
206
+ if (implementsList) {
207
+ for (const impl of implementsList.split(',')) {
208
+ dependencies.push({
209
+ source,
210
+ target: impl.trim(),
211
+ type: 'implements',
212
+ strength: 'strong',
213
+ moduleType: 'internal',
214
+ location: { line, column: 0 },
215
+ });
216
+ }
217
+ }
218
+ }
219
+ return dependencies;
220
+ }
221
+ /**
222
+ * Parse type references
223
+ */
224
+ parseTypeReferences(code, source) {
225
+ const dependencies = [];
226
+ // Type annotations: : TypeName
227
+ const typeRegex = /:\s*(\w+)(?:<[^>]+>)?(?:\[\])?/g;
228
+ let match;
229
+ const foundTypes = new Set();
230
+ while ((match = typeRegex.exec(code)) !== null) {
231
+ const typeName = match[1];
232
+ // Skip primitives and common types
233
+ if (this.isPrimitive(typeName))
234
+ continue;
235
+ if (foundTypes.has(typeName))
236
+ continue;
237
+ foundTypes.add(typeName);
238
+ const line = code.substring(0, match.index).split('\n').length;
239
+ dependencies.push({
240
+ source,
241
+ target: typeName,
242
+ type: 'type-reference',
243
+ strength: 'weak',
244
+ moduleType: 'internal',
245
+ isTypeOnly: true,
246
+ location: { line, column: 0 },
247
+ });
248
+ }
249
+ return dependencies;
250
+ }
251
+ /**
252
+ * Build dependency graph
253
+ */
254
+ buildGraph(files) {
255
+ const modules = new Map();
256
+ const allDependencies = [];
257
+ // First pass: analyze all files
258
+ for (const file of files) {
259
+ const deps = this.analyze(file.content, file.path);
260
+ const exports = this.parseExports(file.content);
261
+ modules.set(file.path, {
262
+ path: file.path,
263
+ name: this.getModuleName(file.path),
264
+ type: 'internal',
265
+ exports,
266
+ dependencies: deps,
267
+ dependents: [],
268
+ });
269
+ allDependencies.push(...deps);
270
+ }
271
+ // Second pass: build dependents
272
+ for (const [path, module] of modules) {
273
+ for (const dep of module.dependencies) {
274
+ const resolvedTarget = this.resolveModule(dep.target, path);
275
+ const targetModule = modules.get(resolvedTarget);
276
+ if (targetModule) {
277
+ targetModule.dependents.push(path);
278
+ }
279
+ }
280
+ }
281
+ // Find roots and leaves
282
+ const roots = [...modules.entries()]
283
+ .filter(([_, m]) => m.dependents.length === 0)
284
+ .map(([p]) => p);
285
+ const leaves = [...modules.entries()]
286
+ .filter(([_, m]) => m.dependencies.filter((d) => d.moduleType === 'internal').length === 0)
287
+ .map(([p]) => p);
288
+ // Detect cycles
289
+ const cycles = this.config.detectCycles ? this.detectCycles(modules) : [];
290
+ return {
291
+ modules,
292
+ dependencies: allDependencies,
293
+ roots,
294
+ leaves,
295
+ cycles,
296
+ };
297
+ }
298
+ /**
299
+ * Parse exports
300
+ */
301
+ parseExports(code) {
302
+ const exports = [];
303
+ // Named exports
304
+ const namedExportRegex = /export\s+(?:(async\s+)?function|class|const|let|var|interface|type|enum)\s+(\w+)/g;
305
+ let match;
306
+ while ((match = namedExportRegex.exec(code)) !== null) {
307
+ const name = match[2];
308
+ const line = code.substring(0, match.index).split('\n').length;
309
+ const isFunction = match[0].includes('function');
310
+ const isClass = match[0].includes('class');
311
+ const isInterface = match[0].includes('interface');
312
+ const isType = match[0].includes('type');
313
+ const isEnum = match[0].includes('enum');
314
+ exports.push({
315
+ name,
316
+ isDefault: false,
317
+ type: isFunction ? 'function' :
318
+ isClass ? 'class' :
319
+ isInterface ? 'interface' :
320
+ isType ? 'type' :
321
+ isEnum ? 'enum' : 'variable',
322
+ line,
323
+ });
324
+ }
325
+ // Default export
326
+ const defaultExportRegex = /export\s+default\s+(?:(async\s+)?function|class)?\s*(\w+)?/g;
327
+ while ((match = defaultExportRegex.exec(code)) !== null) {
328
+ const name = match[2] || 'default';
329
+ const line = code.substring(0, match.index).split('\n').length;
330
+ exports.push({
331
+ name,
332
+ isDefault: true,
333
+ type: match[0].includes('class') ? 'class' :
334
+ match[0].includes('function') ? 'function' : 'variable',
335
+ line,
336
+ });
337
+ }
338
+ return exports;
339
+ }
340
+ /**
341
+ * Calculate metrics
342
+ */
343
+ calculateMetrics(graph) {
344
+ const totalModules = graph.modules.size;
345
+ const internalDeps = graph.dependencies.filter((d) => d.moduleType === 'internal');
346
+ const externalDeps = graph.dependencies.filter((d) => d.moduleType === 'external');
347
+ let maxDeps = 0;
348
+ let maxDepsModule;
349
+ for (const [path, module] of graph.modules) {
350
+ const depCount = module.dependencies.length;
351
+ if (depCount > maxDeps) {
352
+ maxDeps = depCount;
353
+ maxDepsModule = path;
354
+ }
355
+ }
356
+ const avgDeps = totalModules > 0
357
+ ? graph.dependencies.length / totalModules
358
+ : 0;
359
+ // Coupling factor: actual dependencies / maximum possible dependencies
360
+ const maxPossibleDeps = totalModules * (totalModules - 1);
361
+ const couplingFactor = maxPossibleDeps > 0
362
+ ? internalDeps.length / maxPossibleDeps
363
+ : 0;
364
+ // Graph complexity: edges - nodes + 2 * connected components
365
+ const edges = internalDeps.length;
366
+ const nodes = totalModules;
367
+ const connectedComponents = this.countConnectedComponents(graph);
368
+ const graphComplexity = Math.max(0, edges - nodes + 2 * connectedComponents);
369
+ return {
370
+ totalModules,
371
+ totalDependencies: graph.dependencies.length,
372
+ internalDependencies: internalDeps.length,
373
+ externalDependencies: externalDeps.length,
374
+ avgDependenciesPerModule: Math.round(avgDeps * 100) / 100,
375
+ maxDependencies: maxDeps,
376
+ maxDependenciesModule: maxDepsModule,
377
+ couplingFactor: Math.round(couplingFactor * 1000) / 1000,
378
+ graphComplexity,
379
+ cycleCount: graph.cycles.length,
380
+ };
381
+ }
382
+ /**
383
+ * Count connected components
384
+ */
385
+ countConnectedComponents(graph) {
386
+ const visited = new Set();
387
+ let components = 0;
388
+ for (const path of graph.modules.keys()) {
389
+ if (!visited.has(path)) {
390
+ this.dfs(path, graph, visited);
391
+ components++;
392
+ }
393
+ }
394
+ return components;
395
+ }
396
+ /**
397
+ * DFS for connected components
398
+ */
399
+ dfs(start, graph, visited) {
400
+ const stack = [start];
401
+ while (stack.length > 0) {
402
+ const current = stack.pop();
403
+ if (visited.has(current))
404
+ continue;
405
+ visited.add(current);
406
+ const module = graph.modules.get(current);
407
+ if (module) {
408
+ for (const dep of module.dependencies) {
409
+ const resolved = this.resolveModule(dep.target, current);
410
+ if (graph.modules.has(resolved) && !visited.has(resolved)) {
411
+ stack.push(resolved);
412
+ }
413
+ }
414
+ for (const dependent of module.dependents) {
415
+ if (!visited.has(dependent)) {
416
+ stack.push(dependent);
417
+ }
418
+ }
419
+ }
420
+ }
421
+ }
422
+ /**
423
+ * Detect cycles using DFS
424
+ */
425
+ detectCycles(modules) {
426
+ const cycles = [];
427
+ const visited = new Set();
428
+ const recursionStack = new Set();
429
+ const path = [];
430
+ const dfs = (node) => {
431
+ if (recursionStack.has(node)) {
432
+ // Found cycle
433
+ const cycleStart = path.indexOf(node);
434
+ const cycle = path.slice(cycleStart);
435
+ cycle.push(node);
436
+ cycles.push(cycle);
437
+ return;
438
+ }
439
+ if (visited.has(node))
440
+ return;
441
+ visited.add(node);
442
+ recursionStack.add(node);
443
+ path.push(node);
444
+ const module = modules.get(node);
445
+ if (module) {
446
+ for (const dep of module.dependencies) {
447
+ if (dep.moduleType === 'internal') {
448
+ const resolved = this.resolveModule(dep.target, node);
449
+ if (modules.has(resolved)) {
450
+ dfs(resolved);
451
+ }
452
+ }
453
+ }
454
+ }
455
+ path.pop();
456
+ recursionStack.delete(node);
457
+ };
458
+ for (const path of modules.keys()) {
459
+ visited.clear();
460
+ recursionStack.clear();
461
+ dfs(path);
462
+ }
463
+ return cycles;
464
+ }
465
+ /**
466
+ * Detect issues
467
+ */
468
+ detectIssues(graph, metrics) {
469
+ const issues = [];
470
+ // Circular dependencies
471
+ for (const cycle of graph.cycles) {
472
+ issues.push({
473
+ id: `cycle-${cycle.join('-')}`,
474
+ severity: 'error',
475
+ type: 'cycle',
476
+ message: `Circular dependency detected: ${cycle.join(' → ')}`,
477
+ modules: cycle,
478
+ suggestion: 'Consider extracting shared code into a separate module',
479
+ });
480
+ }
481
+ // High coupling modules
482
+ for (const [path, module] of graph.modules) {
483
+ if (module.dependencies.length > this.config.maxDependenciesPerModule) {
484
+ issues.push({
485
+ id: `high-coupling-${path}`,
486
+ severity: 'warning',
487
+ type: 'coupling',
488
+ message: `Module ${path} has too many dependencies (${module.dependencies.length} > ${this.config.maxDependenciesPerModule})`,
489
+ modules: [path],
490
+ suggestion: 'Consider splitting this module or using dependency injection',
491
+ });
492
+ }
493
+ }
494
+ // High overall coupling
495
+ if (metrics.couplingFactor > this.config.maxCouplingFactor) {
496
+ issues.push({
497
+ id: 'high-overall-coupling',
498
+ severity: 'warning',
499
+ type: 'coupling',
500
+ message: `Overall coupling factor is too high (${metrics.couplingFactor} > ${this.config.maxCouplingFactor})`,
501
+ modules: [],
502
+ suggestion: 'Consider refactoring to reduce inter-module dependencies',
503
+ });
504
+ }
505
+ // Unused exports (if detectUnused is enabled)
506
+ if (this.config.detectUnused) {
507
+ for (const [path, module] of graph.modules) {
508
+ for (const exp of module.exports) {
509
+ const isUsed = [...graph.modules.values()].some((m) => m.dependencies.some((d) => d.specifiers?.includes(exp.name)));
510
+ if (!isUsed && !exp.isDefault && module.dependents.length === 0) {
511
+ issues.push({
512
+ id: `unused-export-${path}-${exp.name}`,
513
+ severity: 'info',
514
+ type: 'unused',
515
+ message: `Export '${exp.name}' in ${path} appears to be unused`,
516
+ modules: [path],
517
+ });
518
+ }
519
+ }
520
+ }
521
+ }
522
+ return issues;
523
+ }
524
+ /**
525
+ * Generate recommendations
526
+ */
527
+ generateRecommendations(graph, metrics, issues) {
528
+ const recommendations = [];
529
+ // Based on issues
530
+ if (issues.some((i) => i.type === 'cycle')) {
531
+ recommendations.push('Break circular dependencies by extracting shared interfaces');
532
+ }
533
+ if (issues.some((i) => i.type === 'coupling')) {
534
+ recommendations.push('Use dependency injection to reduce coupling');
535
+ recommendations.push('Consider applying the SOLID principles');
536
+ }
537
+ // Based on metrics
538
+ if (metrics.avgDependenciesPerModule > 10) {
539
+ recommendations.push('Average dependencies per module is high - consider splitting modules');
540
+ }
541
+ if (graph.roots.length === 0 && graph.modules.size > 0) {
542
+ recommendations.push('No root modules found - all modules have dependents');
543
+ }
544
+ if (metrics.graphComplexity > metrics.totalModules) {
545
+ recommendations.push('Graph complexity is high - simplify module relationships');
546
+ }
547
+ return recommendations;
548
+ }
549
+ /**
550
+ * Get module type
551
+ */
552
+ getModuleType(target) {
553
+ if (BUILTIN_MODULES.has(target))
554
+ return 'builtin';
555
+ if (target.startsWith('.') || target.startsWith('/'))
556
+ return 'relative';
557
+ if (target.startsWith('@') || /^[a-z]/i.test(target))
558
+ return 'external';
559
+ return 'internal';
560
+ }
561
+ /**
562
+ * Calculate dependency strength
563
+ */
564
+ calculateStrength(target) {
565
+ const type = this.getModuleType(target);
566
+ if (type === 'external')
567
+ return 'strong';
568
+ if (type === 'relative')
569
+ return 'medium';
570
+ return 'weak';
571
+ }
572
+ /**
573
+ * Check if type is primitive
574
+ */
575
+ isPrimitive(type) {
576
+ return ['string', 'number', 'boolean', 'void', 'null', 'undefined',
577
+ 'any', 'unknown', 'never', 'object', 'symbol', 'bigint',
578
+ 'Array', 'Object', 'Function', 'Promise', 'Map', 'Set',
579
+ 'Record', 'Partial', 'Required', 'Readonly', 'Pick', 'Omit'].includes(type);
580
+ }
581
+ /**
582
+ * Get module name from path
583
+ */
584
+ getModuleName(path) {
585
+ const parts = path.split('/');
586
+ const filename = parts[parts.length - 1];
587
+ return filename.replace(/\.(ts|js|tsx|jsx)$/, '');
588
+ }
589
+ /**
590
+ * Resolve module path
591
+ */
592
+ resolveModule(target, source) {
593
+ // Handle aliases
594
+ if (this.config.aliases) {
595
+ for (const [alias, path] of Object.entries(this.config.aliases)) {
596
+ if (target.startsWith(alias)) {
597
+ return target.replace(alias, path);
598
+ }
599
+ }
600
+ }
601
+ // Handle relative paths
602
+ if (target.startsWith('.')) {
603
+ const sourceParts = source.split('/');
604
+ sourceParts.pop();
605
+ const targetParts = target.split('/');
606
+ for (const part of targetParts) {
607
+ if (part === '..') {
608
+ sourceParts.pop();
609
+ }
610
+ else if (part !== '.') {
611
+ sourceParts.push(part);
612
+ }
613
+ }
614
+ return sourceParts.join('/');
615
+ }
616
+ return target;
617
+ }
618
+ /**
619
+ * Generate dependency report
620
+ */
621
+ generateReport(result) {
622
+ const lines = [];
623
+ lines.push('# Dependency Analysis Report');
624
+ lines.push('');
625
+ lines.push('## Metrics');
626
+ lines.push(`- Total Modules: ${result.metrics.totalModules}`);
627
+ lines.push(`- Total Dependencies: ${result.metrics.totalDependencies}`);
628
+ lines.push(`- Internal Dependencies: ${result.metrics.internalDependencies}`);
629
+ lines.push(`- External Dependencies: ${result.metrics.externalDependencies}`);
630
+ lines.push(`- Avg Dependencies/Module: ${result.metrics.avgDependenciesPerModule}`);
631
+ lines.push(`- Coupling Factor: ${result.metrics.couplingFactor}`);
632
+ lines.push(`- Cycles: ${result.metrics.cycleCount}`);
633
+ lines.push('');
634
+ if (result.issues.length > 0) {
635
+ lines.push('## Issues');
636
+ for (const issue of result.issues) {
637
+ const icon = issue.severity === 'error' ? '❌' :
638
+ issue.severity === 'warning' ? '⚠️' : 'ℹ️';
639
+ lines.push(`${icon} [${issue.type}] ${issue.message}`);
640
+ if (issue.suggestion) {
641
+ lines.push(` → ${issue.suggestion}`);
642
+ }
643
+ }
644
+ lines.push('');
645
+ }
646
+ if (result.recommendations.length > 0) {
647
+ lines.push('## Recommendations');
648
+ for (const rec of result.recommendations) {
649
+ lines.push(`- ${rec}`);
650
+ }
651
+ }
652
+ return lines.join('\n');
653
+ }
654
+ }
655
+ /**
656
+ * Create dependency analyzer instance
657
+ */
658
+ export function createDependencyAnalyzer(config) {
659
+ return new DependencyAnalyzer(config);
660
+ }
661
+ //# sourceMappingURL=dependency-analyzer.js.map