@girardelli/architect-core 8.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/dist/src/core/analyzer.d.ts +42 -0
  2. package/dist/src/core/analyzer.js +431 -0
  3. package/dist/src/core/analyzer.js.map +1 -0
  4. package/dist/src/core/analyzers/forecast.d.ts +84 -0
  5. package/dist/src/core/analyzers/forecast.js +338 -0
  6. package/dist/src/core/analyzers/forecast.js.map +1 -0
  7. package/dist/src/core/analyzers/index.d.ts +9 -0
  8. package/dist/src/core/analyzers/index.js +7 -0
  9. package/dist/src/core/analyzers/index.js.map +1 -0
  10. package/dist/src/core/analyzers/temporal-scorer.d.ts +71 -0
  11. package/dist/src/core/analyzers/temporal-scorer.js +141 -0
  12. package/dist/src/core/analyzers/temporal-scorer.js.map +1 -0
  13. package/dist/src/core/anti-patterns.d.ts +28 -0
  14. package/dist/src/core/anti-patterns.js +264 -0
  15. package/dist/src/core/anti-patterns.js.map +1 -0
  16. package/dist/src/core/ast/ast-parser.interface.d.ts +20 -0
  17. package/dist/src/core/ast/ast-parser.interface.js +2 -0
  18. package/dist/src/core/ast/ast-parser.interface.js.map +1 -0
  19. package/dist/src/core/ast/path-resolver.d.ts +13 -0
  20. package/dist/src/core/ast/path-resolver.js +54 -0
  21. package/dist/src/core/ast/path-resolver.js.map +1 -0
  22. package/dist/src/core/ast/tree-sitter-parser.d.ts +10 -0
  23. package/dist/src/core/ast/tree-sitter-parser.js +142 -0
  24. package/dist/src/core/ast/tree-sitter-parser.js.map +1 -0
  25. package/dist/src/core/config.d.ts +11 -0
  26. package/dist/src/core/config.js +112 -0
  27. package/dist/src/core/config.js.map +1 -0
  28. package/dist/src/core/diagram.d.ts +9 -0
  29. package/dist/src/core/diagram.js +101 -0
  30. package/dist/src/core/diagram.js.map +1 -0
  31. package/dist/src/core/i18n.d.ts +14 -0
  32. package/dist/src/core/i18n.js +54 -0
  33. package/dist/src/core/i18n.js.map +1 -0
  34. package/dist/src/core/locales/en.d.ts +2 -0
  35. package/dist/src/core/locales/en.js +337 -0
  36. package/dist/src/core/locales/en.js.map +1 -0
  37. package/dist/src/core/locales/pt-BR.d.ts +172 -0
  38. package/dist/src/core/locales/pt-BR.js +337 -0
  39. package/dist/src/core/locales/pt-BR.js.map +1 -0
  40. package/dist/src/core/locales/types.d.ts +86 -0
  41. package/dist/src/core/locales/types.js +2 -0
  42. package/dist/src/core/locales/types.js.map +1 -0
  43. package/dist/src/core/plugin-loader.d.ts +11 -0
  44. package/dist/src/core/plugin-loader.js +67 -0
  45. package/dist/src/core/plugin-loader.js.map +1 -0
  46. package/dist/src/core/project-summarizer.d.ts +16 -0
  47. package/dist/src/core/project-summarizer.js +37 -0
  48. package/dist/src/core/project-summarizer.js.map +1 -0
  49. package/dist/src/core/refactor-engine.d.ts +18 -0
  50. package/dist/src/core/refactor-engine.js +87 -0
  51. package/dist/src/core/refactor-engine.js.map +1 -0
  52. package/dist/src/core/rules/barrel-optimizer.d.ts +13 -0
  53. package/dist/src/core/rules/barrel-optimizer.js +76 -0
  54. package/dist/src/core/rules/barrel-optimizer.js.map +1 -0
  55. package/dist/src/core/rules/dead-code-detector.d.ts +21 -0
  56. package/dist/src/core/rules/dead-code-detector.js +116 -0
  57. package/dist/src/core/rules/dead-code-detector.js.map +1 -0
  58. package/dist/src/core/rules/hub-splitter.d.ts +13 -0
  59. package/dist/src/core/rules/hub-splitter.js +117 -0
  60. package/dist/src/core/rules/hub-splitter.js.map +1 -0
  61. package/dist/src/core/rules/import-organizer.d.ts +13 -0
  62. package/dist/src/core/rules/import-organizer.js +84 -0
  63. package/dist/src/core/rules/import-organizer.js.map +1 -0
  64. package/dist/src/core/rules/module-grouper.d.ts +13 -0
  65. package/dist/src/core/rules/module-grouper.js +116 -0
  66. package/dist/src/core/rules/module-grouper.js.map +1 -0
  67. package/dist/src/core/rules-engine.d.ts +7 -0
  68. package/dist/src/core/rules-engine.js +89 -0
  69. package/dist/src/core/rules-engine.js.map +1 -0
  70. package/dist/src/core/scorer.d.ts +15 -0
  71. package/dist/src/core/scorer.js +165 -0
  72. package/dist/src/core/scorer.js.map +1 -0
  73. package/dist/src/core/summarizer/keyword-extractor.d.ts +6 -0
  74. package/dist/src/core/summarizer/keyword-extractor.js +38 -0
  75. package/dist/src/core/summarizer/keyword-extractor.js.map +1 -0
  76. package/dist/src/core/summarizer/module-inferrer.d.ts +11 -0
  77. package/dist/src/core/summarizer/module-inferrer.js +171 -0
  78. package/dist/src/core/summarizer/module-inferrer.js.map +1 -0
  79. package/dist/src/core/summarizer/package-reader.d.ts +3 -0
  80. package/dist/src/core/summarizer/package-reader.js +33 -0
  81. package/dist/src/core/summarizer/package-reader.js.map +1 -0
  82. package/dist/src/core/summarizer/purpose-inferrer.d.ts +8 -0
  83. package/dist/src/core/summarizer/purpose-inferrer.js +179 -0
  84. package/dist/src/core/summarizer/purpose-inferrer.js.map +1 -0
  85. package/dist/src/core/summarizer/readme-reader.d.ts +3 -0
  86. package/dist/src/core/summarizer/readme-reader.js +24 -0
  87. package/dist/src/core/summarizer/readme-reader.js.map +1 -0
  88. package/dist/src/core/types/architect-rules.d.ts +27 -0
  89. package/dist/src/core/types/architect-rules.js +2 -0
  90. package/dist/src/core/types/architect-rules.js.map +1 -0
  91. package/dist/src/core/types/core.d.ts +87 -0
  92. package/dist/src/core/types/core.js +2 -0
  93. package/dist/src/core/types/core.js.map +1 -0
  94. package/dist/src/core/types/infrastructure.d.ts +38 -0
  95. package/dist/src/core/types/infrastructure.js +2 -0
  96. package/dist/src/core/types/infrastructure.js.map +1 -0
  97. package/dist/src/core/types/plugin.d.ts +12 -0
  98. package/dist/src/core/types/plugin.js +2 -0
  99. package/dist/src/core/types/plugin.js.map +1 -0
  100. package/dist/src/core/types/rules.d.ts +53 -0
  101. package/dist/src/core/types/rules.js +2 -0
  102. package/dist/src/core/types/rules.js.map +1 -0
  103. package/dist/src/core/types/summarizer.d.ts +12 -0
  104. package/dist/src/core/types/summarizer.js +2 -0
  105. package/dist/src/core/types/summarizer.js.map +1 -0
  106. package/dist/src/infrastructure/git-cache.d.ts +6 -0
  107. package/dist/src/infrastructure/git-cache.js +41 -0
  108. package/dist/src/infrastructure/git-cache.js.map +1 -0
  109. package/dist/src/infrastructure/git-history.d.ts +112 -0
  110. package/dist/src/infrastructure/git-history.js +340 -0
  111. package/dist/src/infrastructure/git-history.js.map +1 -0
  112. package/dist/src/infrastructure/logger.d.ts +20 -0
  113. package/dist/src/infrastructure/logger.js +57 -0
  114. package/dist/src/infrastructure/logger.js.map +1 -0
  115. package/dist/src/infrastructure/scanner.d.ts +31 -0
  116. package/dist/src/infrastructure/scanner.js +334 -0
  117. package/dist/src/infrastructure/scanner.js.map +1 -0
  118. package/dist/tests/analyzers-integration.test.d.ts +7 -0
  119. package/dist/tests/analyzers-integration.test.js +140 -0
  120. package/dist/tests/analyzers-integration.test.js.map +1 -0
  121. package/dist/tests/anti-patterns.test.d.ts +1 -0
  122. package/dist/tests/anti-patterns.test.js +81 -0
  123. package/dist/tests/anti-patterns.test.js.map +1 -0
  124. package/dist/tests/ast-parser.test.d.ts +1 -0
  125. package/dist/tests/ast-parser.test.js +94 -0
  126. package/dist/tests/ast-parser.test.js.map +1 -0
  127. package/dist/tests/fixtures/monorepo/packages/app/src/index.d.ts +1 -0
  128. package/dist/tests/fixtures/monorepo/packages/app/src/index.js +9 -0
  129. package/dist/tests/fixtures/monorepo/packages/app/src/index.js.map +1 -0
  130. package/dist/tests/fixtures/monorepo/packages/core/src/index.d.ts +2 -0
  131. package/dist/tests/fixtures/monorepo/packages/core/src/index.js +11 -0
  132. package/dist/tests/fixtures/monorepo/packages/core/src/index.js.map +1 -0
  133. package/dist/tests/forecast.test.d.ts +7 -0
  134. package/dist/tests/forecast.test.js +380 -0
  135. package/dist/tests/forecast.test.js.map +1 -0
  136. package/dist/tests/git-history.test.d.ts +7 -0
  137. package/dist/tests/git-history.test.js +193 -0
  138. package/dist/tests/git-history.test.js.map +1 -0
  139. package/dist/tests/i18n.test.d.ts +1 -0
  140. package/dist/tests/i18n.test.js +39 -0
  141. package/dist/tests/i18n.test.js.map +1 -0
  142. package/dist/tests/monorepo-scan.test.d.ts +11 -0
  143. package/dist/tests/monorepo-scan.test.js +143 -0
  144. package/dist/tests/monorepo-scan.test.js.map +1 -0
  145. package/dist/tests/plugin-loader.test.d.ts +1 -0
  146. package/dist/tests/plugin-loader.test.js +31 -0
  147. package/dist/tests/plugin-loader.test.js.map +1 -0
  148. package/dist/tests/rules-engine.test.d.ts +1 -0
  149. package/dist/tests/rules-engine.test.js +112 -0
  150. package/dist/tests/rules-engine.test.js.map +1 -0
  151. package/dist/tests/scanner.test.d.ts +1 -0
  152. package/dist/tests/scanner.test.js +44 -0
  153. package/dist/tests/scanner.test.js.map +1 -0
  154. package/dist/tests/scorer.test.d.ts +1 -0
  155. package/dist/tests/scorer.test.js +610 -0
  156. package/dist/tests/scorer.test.js.map +1 -0
  157. package/dist/tests/temporal-scorer.test.d.ts +7 -0
  158. package/dist/tests/temporal-scorer.test.js +239 -0
  159. package/dist/tests/temporal-scorer.test.js.map +1 -0
  160. package/package.json +29 -0
  161. package/src/core/analyzer.ts +499 -0
  162. package/src/core/analyzers/forecast.ts +497 -0
  163. package/src/core/analyzers/index.ts +33 -0
  164. package/src/core/analyzers/temporal-scorer.ts +227 -0
  165. package/src/core/anti-patterns.ts +324 -0
  166. package/src/core/ast/ast-parser.interface.ts +21 -0
  167. package/src/core/ast/path-resolver.ts +61 -0
  168. package/src/core/ast/tree-sitter-parser.ts +158 -0
  169. package/src/core/config.ts +125 -0
  170. package/src/core/diagram.ts +129 -0
  171. package/src/core/i18n.ts +64 -0
  172. package/src/core/locales/en.ts +340 -0
  173. package/src/core/locales/pt-BR.ts +341 -0
  174. package/src/core/locales/types.ts +95 -0
  175. package/src/core/plugin-loader.ts +80 -0
  176. package/src/core/project-summarizer.ts +42 -0
  177. package/src/core/refactor-engine.ts +112 -0
  178. package/src/core/rules/barrel-optimizer.ts +99 -0
  179. package/src/core/rules/dead-code-detector.ts +134 -0
  180. package/src/core/rules/hub-splitter.ts +135 -0
  181. package/src/core/rules/import-organizer.ts +100 -0
  182. package/src/core/rules/module-grouper.ts +133 -0
  183. package/src/core/rules-engine.ts +100 -0
  184. package/src/core/scorer.ts +181 -0
  185. package/src/core/summarizer/keyword-extractor.ts +53 -0
  186. package/src/core/summarizer/module-inferrer.ts +194 -0
  187. package/src/core/summarizer/package-reader.ts +34 -0
  188. package/src/core/summarizer/purpose-inferrer.ts +197 -0
  189. package/src/core/summarizer/readme-reader.ts +24 -0
  190. package/src/core/types/architect-rules.ts +29 -0
  191. package/src/core/types/core.ts +94 -0
  192. package/src/core/types/infrastructure.ts +41 -0
  193. package/src/core/types/plugin.ts +19 -0
  194. package/src/core/types/rules.ts +51 -0
  195. package/src/core/types/summarizer.ts +8 -0
  196. package/src/infrastructure/git-cache.ts +52 -0
  197. package/src/infrastructure/git-history.ts +496 -0
  198. package/src/infrastructure/logger.ts +68 -0
  199. package/src/infrastructure/scanner.ts +349 -0
  200. package/tests/analyzers-integration.test.ts +174 -0
  201. package/tests/anti-patterns.test.ts +95 -0
  202. package/tests/ast-parser.test.ts +102 -0
  203. package/tests/fixtures/monorepo/package.json +6 -0
  204. package/tests/fixtures/monorepo/packages/app/package.json +12 -0
  205. package/tests/fixtures/monorepo/packages/app/src/index.ts +6 -0
  206. package/tests/fixtures/monorepo/packages/core/package.json +7 -0
  207. package/tests/fixtures/monorepo/packages/core/src/index.ts +7 -0
  208. package/tests/forecast.test.ts +504 -0
  209. package/tests/git-history.test.ts +254 -0
  210. package/tests/i18n.test.ts +47 -0
  211. package/tests/monorepo-scan.test.ts +170 -0
  212. package/tests/plugin-loader.test.ts +40 -0
  213. package/tests/rules-engine.test.ts +131 -0
  214. package/tests/scanner.test.ts +54 -0
  215. package/tests/scorer.test.ts +675 -0
  216. package/tests/temporal-scorer.test.ts +306 -0
  217. package/tsconfig.json +9 -0
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Tests for GitHistoryAnalyzer
3
+ *
4
+ * Validates git log parsing, file history building, velocity vectors,
5
+ * change coupling detection, and timeline construction.
6
+ */
7
+ export {};
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Tests for GitHistoryAnalyzer
3
+ *
4
+ * Validates git log parsing, file history building, velocity vectors,
5
+ * change coupling detection, and timeline construction.
6
+ */
7
+ import { GitHistoryAnalyzer } from '../src/infrastructure/git-history.js';
8
+ import { execSync } from 'child_process';
9
+ import * as fs from 'fs';
10
+ import * as path from 'path';
11
+ // ═══════════════════════════════════════════════════════════════
12
+ // TEST HELPERS
13
+ // ═══════════════════════════════════════════════════════════════
14
+ const TEST_DIR = path.join('/tmp', 'architect-git-history-test');
15
+ function setupGitRepo() {
16
+ fs.rmSync(TEST_DIR, { recursive: true, force: true });
17
+ fs.mkdirSync(TEST_DIR, { recursive: true });
18
+ execSync('git init', { cwd: TEST_DIR, stdio: 'pipe' });
19
+ execSync('git config user.email "test@test.com"', { cwd: TEST_DIR, stdio: 'pipe' });
20
+ execSync('git config user.name "TestUser"', { cwd: TEST_DIR, stdio: 'pipe' });
21
+ }
22
+ function commitFile(filePath, content, message, author = 'TestUser <test@test.com>') {
23
+ const fullPath = path.join(TEST_DIR, filePath);
24
+ const dir = path.dirname(fullPath);
25
+ fs.mkdirSync(dir, { recursive: true });
26
+ fs.writeFileSync(fullPath, content);
27
+ execSync(`git add "${filePath}"`, { cwd: TEST_DIR, stdio: 'pipe' });
28
+ execSync(`git commit --author="${author}" -m "${message}"`, {
29
+ cwd: TEST_DIR,
30
+ stdio: 'pipe',
31
+ });
32
+ }
33
+ function cleanupRepo() {
34
+ fs.rmSync(TEST_DIR, { recursive: true, force: true });
35
+ }
36
+ // ═══════════════════════════════════════════════════════════════
37
+ // UNIT TESTS — parseLogOutput (via analyze)
38
+ // ═══════════════════════════════════════════════════════════════
39
+ describe('GitHistoryAnalyzer', () => {
40
+ beforeAll(() => {
41
+ setupGitRepo();
42
+ // Create initial files across two modules
43
+ commitFile('src/core.ts', 'export class Core {}', 'initial core', 'Alice <alice@test.com>');
44
+ commitFile('src/utils.ts', 'export function util() {}', 'add utils', 'Alice <alice@test.com>');
45
+ commitFile('lib/helper.ts', 'export function help() {}', 'add helper', 'Bob <bob@test.com>');
46
+ // Add more changes to create churn
47
+ commitFile('src/core.ts', 'export class Core { run() {} }', 'enhance core', 'Bob <bob@test.com>');
48
+ commitFile('src/core.ts', 'export class Core { run() { return 1; } }', 'fix core', 'Alice <alice@test.com>');
49
+ // Concurrent changes for coupling detection
50
+ const coupledContent1 = 'export class Core { run() { return 2; } }';
51
+ const coupledContent2 = 'export function util() { return true; }';
52
+ const p1 = path.join(TEST_DIR, 'src/core.ts');
53
+ const p2 = path.join(TEST_DIR, 'src/utils.ts');
54
+ fs.writeFileSync(p1, coupledContent1);
55
+ fs.writeFileSync(p2, coupledContent2);
56
+ execSync('git add .', { cwd: TEST_DIR, stdio: 'pipe' });
57
+ execSync('git commit --author="Alice <alice@test.com>" -m "coupled change 1"', {
58
+ cwd: TEST_DIR,
59
+ stdio: 'pipe',
60
+ });
61
+ // Another coupled change
62
+ fs.writeFileSync(p1, coupledContent1 + '\n// v2');
63
+ fs.writeFileSync(p2, coupledContent2 + '\n// v2');
64
+ execSync('git add .', { cwd: TEST_DIR, stdio: 'pipe' });
65
+ execSync('git commit --author="Bob <bob@test.com>" -m "coupled change 2"', {
66
+ cwd: TEST_DIR,
67
+ stdio: 'pipe',
68
+ });
69
+ // Third coupled change to meet the default minCochanges=3
70
+ fs.writeFileSync(p1, coupledContent1 + '\n// v3');
71
+ fs.writeFileSync(p2, coupledContent2 + '\n// v3');
72
+ execSync('git add .', { cwd: TEST_DIR, stdio: 'pipe' });
73
+ execSync('git commit --author="Alice <alice@test.com>" -m "coupled change 3"', {
74
+ cwd: TEST_DIR,
75
+ stdio: 'pipe',
76
+ });
77
+ });
78
+ afterAll(() => {
79
+ cleanupRepo();
80
+ });
81
+ describe('analyze()', () => {
82
+ let report;
83
+ beforeAll(async () => {
84
+ const analyzer = new GitHistoryAnalyzer({ periodWeeks: 52 });
85
+ report = await analyzer.analyze(TEST_DIR);
86
+ });
87
+ it('should return correct project path', () => {
88
+ expect(report.projectPath).toBe(TEST_DIR);
89
+ });
90
+ it('should have analyzedAt timestamp', () => {
91
+ expect(report.analyzedAt).toBeDefined();
92
+ expect(new Date(report.analyzedAt).getTime()).not.toBeNaN();
93
+ });
94
+ it('should count total commits', () => {
95
+ expect(report.totalCommits).toBeGreaterThanOrEqual(7);
96
+ });
97
+ it('should count unique authors', () => {
98
+ expect(report.totalAuthors).toBe(2); // Alice + Bob
99
+ });
100
+ it('should detect modules by first directory level', () => {
101
+ const moduleNames = report.modules.map(m => m.modulePath);
102
+ expect(moduleNames).toContain('src');
103
+ expect(moduleNames).toContain('lib');
104
+ });
105
+ it('should build file histories with correct metrics', () => {
106
+ const srcModule = report.modules.find(m => m.modulePath === 'src');
107
+ expect(srcModule).toBeDefined();
108
+ const coreFile = srcModule.files.find(f => f.path === 'src/core.ts');
109
+ expect(coreFile).toBeDefined();
110
+ expect(coreFile.commits).toBeGreaterThanOrEqual(5);
111
+ expect(coreFile.busFactor).toBe(2); // Alice + Bob
112
+ expect(coreFile.totalAdditions).toBeGreaterThan(0);
113
+ });
114
+ it('should calculate churn rate correctly', () => {
115
+ const srcModule = report.modules.find(m => m.modulePath === 'src');
116
+ const coreFile = srcModule.files.find(f => f.path === 'src/core.ts');
117
+ expect(coreFile.churnRate).toBeGreaterThan(0);
118
+ expect(coreFile.churnRate).toBe((coreFile.totalAdditions + coreFile.totalDeletions) / coreFile.commits);
119
+ });
120
+ it('should build weekly timeline', () => {
121
+ expect(report.commitTimeline.length).toBeGreaterThan(0);
122
+ const total = report.commitTimeline.reduce((s, w) => s + w.commits, 0);
123
+ expect(total).toBe(report.totalCommits);
124
+ });
125
+ });
126
+ describe('change coupling', () => {
127
+ it('should detect coupled files', async () => {
128
+ const analyzer = new GitHistoryAnalyzer({ periodWeeks: 52, couplingMinCochanges: 3 });
129
+ const report = await analyzer.analyze(TEST_DIR);
130
+ const coupling = report.changeCouplings.find(c => (c.fileA === 'src/core.ts' && c.fileB === 'src/utils.ts') ||
131
+ (c.fileA === 'src/utils.ts' && c.fileB === 'src/core.ts'));
132
+ expect(coupling).toBeDefined();
133
+ expect(coupling.cochangeCount).toBeGreaterThanOrEqual(3);
134
+ expect(coupling.confidence).toBeGreaterThan(0);
135
+ expect(coupling.confidence).toBeLessThanOrEqual(1);
136
+ });
137
+ });
138
+ describe('velocity vectors', () => {
139
+ it('should calculate velocity for each module', async () => {
140
+ const analyzer = new GitHistoryAnalyzer({ periodWeeks: 52 });
141
+ const report = await analyzer.analyze(TEST_DIR);
142
+ const srcModule = report.modules.find(m => m.modulePath === 'src');
143
+ expect(srcModule).toBeDefined();
144
+ expect(srcModule.velocityVector).toBeDefined();
145
+ expect(srcModule.velocityVector.direction).toMatch(/^(accelerating|stable|decelerating)$/);
146
+ expect(typeof srcModule.velocityVector.commitAcceleration).toBe('number');
147
+ expect(typeof srcModule.velocityVector.churnTrend).toBe('number');
148
+ });
149
+ });
150
+ describe('module aggregation', () => {
151
+ it('should aggregate commits across module files', async () => {
152
+ const analyzer = new GitHistoryAnalyzer({ periodWeeks: 52 });
153
+ const report = await analyzer.analyze(TEST_DIR);
154
+ const srcModule = report.modules.find(m => m.modulePath === 'src');
155
+ expect(srcModule.aggregateCommits).toBe(srcModule.files.reduce((s, f) => s + f.commits, 0));
156
+ });
157
+ it('should calculate bus factor per module', async () => {
158
+ const analyzer = new GitHistoryAnalyzer({ periodWeeks: 52 });
159
+ const report = await analyzer.analyze(TEST_DIR);
160
+ const srcModule = report.modules.find(m => m.modulePath === 'src');
161
+ expect(srcModule.busFactor).toBe(2); // Alice + Bob both committed to src/
162
+ });
163
+ it('should sort modules by aggregate churn descending', async () => {
164
+ const analyzer = new GitHistoryAnalyzer({ periodWeeks: 52 });
165
+ const report = await analyzer.analyze(TEST_DIR);
166
+ for (let i = 1; i < report.modules.length; i++) {
167
+ expect(report.modules[i - 1].aggregateChurn).toBeGreaterThanOrEqual(report.modules[i].aggregateChurn);
168
+ }
169
+ });
170
+ });
171
+ describe('error handling', () => {
172
+ it('should throw for non-git directory', async () => {
173
+ const tmpDir = path.join('/tmp', 'not-a-git-repo');
174
+ fs.mkdirSync(tmpDir, { recursive: true });
175
+ const analyzer = new GitHistoryAnalyzer();
176
+ await expect(analyzer.analyze(tmpDir)).rejects.toThrow('Not a git repository');
177
+ fs.rmSync(tmpDir, { recursive: true, force: true });
178
+ });
179
+ });
180
+ describe('configuration', () => {
181
+ it('should respect custom period weeks', async () => {
182
+ const analyzer = new GitHistoryAnalyzer({ periodWeeks: 1 });
183
+ const report = await analyzer.analyze(TEST_DIR);
184
+ expect(report.periodWeeks).toBe(1);
185
+ });
186
+ it('should respect custom coupling threshold', async () => {
187
+ const analyzer = new GitHistoryAnalyzer({ periodWeeks: 52, couplingMinCochanges: 100 });
188
+ const report = await analyzer.analyze(TEST_DIR);
189
+ expect(report.changeCouplings.length).toBe(0);
190
+ });
191
+ });
192
+ });
193
+ //# sourceMappingURL=git-history.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-history.test.js","sourceRoot":"","sources":["../../tests/git-history.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,39 @@
1
+ import { i18n } from '../src/core/i18n.js';
2
+ describe('I18nEngine', () => {
3
+ beforeEach(() => {
4
+ // Reset to reliable state
5
+ i18n.setLocale('en');
6
+ });
7
+ test('should return english translation by default', () => {
8
+ const text = i18n.t('agents.generatedBy');
9
+ expect(text).toBe('Generated by Architect v8.1');
10
+ });
11
+ test('should change locale to pt-BR', () => {
12
+ i18n.setLocale('pt-BR');
13
+ const text = i18n.t('agents.generatedBy');
14
+ expect(text).toBe('Gerado por Architect v8.1');
15
+ });
16
+ test('should format strings using params', () => {
17
+ const text = i18n.t('agents.backend.title', { lang: 'TYPESCRIPT' });
18
+ expect(text).toBe('🔧 TYPESCRIPT BACKEND DEVELOPER');
19
+ });
20
+ test('should respond with error string for missing keys', () => {
21
+ const text = i18n.t('invalid.key.path');
22
+ expect(text).toBe('[Missing translation: invalid.key.path]');
23
+ });
24
+ test('should fallback to en if present in en but missing in pt-BR', () => {
25
+ // Force a runtime scenario
26
+ const engine = i18n;
27
+ engine.currentLocale = 'pt-BR';
28
+ const dict = engine.getDict();
29
+ // Temporarily delete a key
30
+ const backup = dict.agents.generatedBy;
31
+ delete dict.agents.generatedBy;
32
+ const text = i18n.t('agents.generatedBy');
33
+ // should have fallen back to EN
34
+ expect(text).toBe('Generated by Architect v8.1');
35
+ // Restore
36
+ dict.agents.generatedBy = backup;
37
+ });
38
+ });
39
+ //# sourceMappingURL=i18n.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.test.js","sourceRoot":"","sources":["../../tests/i18n.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAE3C,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,UAAU,CAAC,GAAG,EAAE;QACd,0BAA0B;QAC1B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACxD,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACzC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,sBAAsB,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;QACpE,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC7D,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACvE,2BAA2B;QAC3B,MAAM,MAAM,GAAQ,IAAI,CAAC;QACzB,MAAM,CAAC,aAAa,GAAG,OAAO,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;QAE9B,2BAA2B;QAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QACvC,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QAE/B,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC;QAC1C,gCAAgC;QAChC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QAEjD,UAAU;QACV,IAAI,CAAC,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * E2E Tests — Monorepo Scanning
3
+ *
4
+ * Ensures that the Architect scanner correctly handles monorepo projects
5
+ * with nested node_modules, workspace detection, and framework inference.
6
+ *
7
+ * This test suite was created to prevent regression of the critical bug where
8
+ * node_modules in sub-packages leaked through the glob ignore filter,
9
+ * contaminating all analysis results (29,181 files instead of 245).
10
+ */
11
+ export {};
@@ -0,0 +1,143 @@
1
+ /**
2
+ * E2E Tests — Monorepo Scanning
3
+ *
4
+ * Ensures that the Architect scanner correctly handles monorepo projects
5
+ * with nested node_modules, workspace detection, and framework inference.
6
+ *
7
+ * This test suite was created to prevent regression of the critical bug where
8
+ * node_modules in sub-packages leaked through the glob ignore filter,
9
+ * contaminating all analysis results (29,181 files instead of 245).
10
+ */
11
+ import path from 'path';
12
+ import { ProjectScanner } from '../src/infrastructure/scanner.js';
13
+ import { ArchitectureAnalyzer } from '../src/core/analyzer.js';
14
+ import { AntiPatternDetector } from '../src/core/anti-patterns.js';
15
+ import { ConfigLoader, normalizeIgnorePatterns } from '../src/core/config.js';
16
+ // Use path.resolve for Jest compatibility (import.meta.url not supported by ts-jest)
17
+ const FIXTURE_PATH = path.resolve(process.cwd(), 'packages/architect-core/tests/fixtures/monorepo');
18
+ describe('Monorepo Scanner — node_modules exclusion', () => {
19
+ let config;
20
+ beforeAll(() => {
21
+ config = ConfigLoader.loadConfig(FIXTURE_PATH);
22
+ });
23
+ test('default config uses glob patterns for ignore', () => {
24
+ expect(config.ignore).toBeDefined();
25
+ // Must use glob-style patterns that cover nested directories
26
+ const hasGlobNodeModules = config.ignore.some(p => p.includes('**/node_modules'));
27
+ expect(hasGlobNodeModules).toBe(true);
28
+ });
29
+ test('scans only project source files, not node_modules', () => {
30
+ const scanner = new ProjectScanner(FIXTURE_PATH, config);
31
+ const result = scanner.scan();
32
+ // Only 2 source .ts files exist: core/src/index.ts and app/src/index.ts
33
+ // Plus 3 package.json files (root + core + app)
34
+ const tsFiles = result.totalFiles;
35
+ // node_modules has 4 files (fake-dep/index.js, fake-dep/package.json,
36
+ // another-dep/index.js, root-dep/index.js) — NONE should appear
37
+ expect(tsFiles).toBeLessThanOrEqual(10); // generous upper bound
38
+ expect(tsFiles).toBeGreaterThanOrEqual(2); // at least the 2 .ts files
39
+ // Verify no node_modules paths in the file tree
40
+ const allPaths = getAllFilePaths(result.fileTree);
41
+ const nmPaths = allPaths.filter(p => p.includes('node_modules'));
42
+ expect(nmPaths).toHaveLength(0);
43
+ });
44
+ test('detects workspaces from root package.json', () => {
45
+ const scanner = new ProjectScanner(FIXTURE_PATH, config);
46
+ const result = scanner.scan();
47
+ expect(result.workspaces).toBeDefined();
48
+ expect(result.workspaces.length).toBe(2);
49
+ const names = result.workspaces.map(ws => ws.name);
50
+ expect(names).toContain('@test/core');
51
+ expect(names).toContain('@test/app');
52
+ });
53
+ test('detects Express.js from workspace package.json (not from node_modules)', () => {
54
+ const scanner = new ProjectScanner(FIXTURE_PATH, config);
55
+ const result = scanner.scan();
56
+ expect(result.frameworks).toContain('Express.js');
57
+ });
58
+ test('does NOT detect Vue.js or Mongoose from nested node_modules', () => {
59
+ const scanner = new ProjectScanner(FIXTURE_PATH, config);
60
+ const result = scanner.scan();
61
+ // fake-dep/package.json has vue and mongoose as deps
62
+ // These must NOT appear as project frameworks
63
+ expect(result.frameworks).not.toContain('Vue.js');
64
+ expect(result.frameworks).not.toContain('Mongoose');
65
+ });
66
+ test('does NOT detect Spring Boot or Spring (no Java in project)', () => {
67
+ const scanner = new ProjectScanner(FIXTURE_PATH, config);
68
+ const result = scanner.scan();
69
+ expect(result.frameworks).not.toContain('Spring Boot');
70
+ expect(result.frameworks).not.toContain('Spring');
71
+ });
72
+ test('dependency graph contains no node_modules paths', () => {
73
+ const scanner = new ProjectScanner(FIXTURE_PATH, config);
74
+ const result = scanner.scan();
75
+ const analyzer = new ArchitectureAnalyzer(FIXTURE_PATH);
76
+ const edges = analyzer.analyzeDependencies(result.fileTree);
77
+ for (const edge of edges) {
78
+ expect(edge.from).not.toContain('node_modules');
79
+ expect(edge.to).not.toContain('node_modules');
80
+ }
81
+ });
82
+ test('anti-patterns are only from project files', async () => {
83
+ const scanner = new ProjectScanner(FIXTURE_PATH, config);
84
+ const result = scanner.scan();
85
+ const analyzer = new ArchitectureAnalyzer(FIXTURE_PATH);
86
+ const edges = analyzer.analyzeDependencies(result.fileTree);
87
+ const deps = new Map();
88
+ for (const edge of edges) {
89
+ if (!deps.has(edge.from))
90
+ deps.set(edge.from, new Set());
91
+ deps.get(edge.from).add(edge.to);
92
+ }
93
+ const detector = new AntiPatternDetector(config);
94
+ const patterns = await detector.detect(result.fileTree, deps);
95
+ for (const pattern of patterns) {
96
+ expect(pattern.location).not.toContain('node_modules');
97
+ if (pattern.affectedFiles) {
98
+ for (const file of pattern.affectedFiles) {
99
+ expect(file).not.toContain('node_modules');
100
+ }
101
+ }
102
+ }
103
+ });
104
+ });
105
+ describe('normalizeIgnorePatterns', () => {
106
+ test('converts simple names to glob patterns', () => {
107
+ const result = normalizeIgnorePatterns(['node_modules']);
108
+ expect(result).toContain('**/node_modules/**');
109
+ expect(result).toContain('**/node_modules');
110
+ expect(result).toContain('node_modules/**');
111
+ });
112
+ test('preserves existing glob patterns', () => {
113
+ const result = normalizeIgnorePatterns(['**/dist/**']);
114
+ expect(result).toContain('**/dist/**');
115
+ // Should not double-wrap
116
+ expect(result).not.toContain('**/**/dist/**/**');
117
+ });
118
+ test('handles mixed patterns', () => {
119
+ const result = normalizeIgnorePatterns(['node_modules', '**/custom/**', 'dist']);
120
+ expect(result).toContain('**/node_modules/**');
121
+ expect(result).toContain('**/custom/**');
122
+ expect(result).toContain('**/dist/**');
123
+ });
124
+ test('handles path-like patterns with slashes', () => {
125
+ const result = normalizeIgnorePatterns(['some/specific/path']);
126
+ expect(result).toContain('some/specific/path');
127
+ // Should not expand patterns with slashes
128
+ expect(result).not.toContain('**/some/specific/path/**');
129
+ });
130
+ });
131
+ // Helper
132
+ function getAllFilePaths(node) {
133
+ const paths = [];
134
+ if (node.type === 'file')
135
+ paths.push(node.path);
136
+ if (node.children) {
137
+ for (const child of node.children) {
138
+ paths.push(...getAllFilePaths(child));
139
+ }
140
+ }
141
+ return paths;
142
+ }
143
+ //# sourceMappingURL=monorepo-scan.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"monorepo-scan.test.js","sourceRoot":"","sources":["../../tests/monorepo-scan.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
1
+ import { jest } from '@jest/globals';
2
+ import { PluginLoader } from '../src/core/plugin-loader.js';
3
+ import { logger } from '../src/infrastructure/logger.js';
4
+ describe('PluginLoader', () => {
5
+ const mockConfig = {
6
+ plugins: ['fake-plugin'],
7
+ };
8
+ it('should instantiate empty custom detectors if no plugins config', async () => {
9
+ const loader = new PluginLoader('/fake/path', {});
10
+ await loader.loadPlugins();
11
+ expect(loader.customAntiPatternDetectors.length).toBe(0);
12
+ });
13
+ it('should ignore plugins if empty array provided', async () => {
14
+ const loader = new PluginLoader('/fake/path', { plugins: [] });
15
+ await loader.loadPlugins();
16
+ expect(loader.customAntiPatternDetectors.length).toBe(0);
17
+ });
18
+ // Cannot easily mock native ESM dynamic import() within Jest cleanly without
19
+ // complex module mocks since Jest execution in this repo runs --experimental-vm-modules.
20
+ // We mock a failing dynamic load instead, which should be safely caught.
21
+ it('should gracefully handle missing plugins via dynamic load catch', async () => {
22
+ const loggerSpy = jest.spyOn(logger, 'warn').mockImplementation(() => { });
23
+ const loader = new PluginLoader('/fake/path', mockConfig);
24
+ await loader.loadPlugins();
25
+ // It should log a warning but NOT throw an unhandled promise rejection
26
+ expect(loggerSpy).toHaveBeenCalledWith(expect.stringContaining('[Architect Plugin] Failed to load plugin \'fake-plugin\''));
27
+ expect(loader.customAntiPatternDetectors.length).toBe(0);
28
+ loggerSpy.mockRestore();
29
+ });
30
+ });
31
+ //# sourceMappingURL=plugin-loader.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-loader.test.js","sourceRoot":"","sources":["../../tests/plugin-loader.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D,OAAO,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAEzD,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,MAAM,UAAU,GAAoB;QAClC,OAAO,EAAE,CAAC,aAAa,CAAC;KACzB,CAAC;IAEF,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QAClD,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;QAE3B,MAAM,CAAC,MAAM,CAAC,0BAA0B,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,YAAY,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QAC/D,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;QAE3B,MAAM,CAAC,MAAM,CAAC,0BAA0B,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,8EAA8E;IAC9E,yFAAyF;IACzF,yEAAyE;IACzE,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC1E,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QAE1D,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;QAE3B,uEAAuE;QACvE,MAAM,CAAC,SAAS,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,gBAAgB,CAAC,0DAA0D,CAAC,CAAC,CAAC;QAC5H,MAAM,CAAC,MAAM,CAAC,0BAA0B,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAEzD,SAAS,CAAC,WAAW,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,112 @@
1
+ // @ts-ignore
2
+ import { RulesEngine } from '../src/core/rules-engine.js';
3
+ describe('RulesEngine', () => {
4
+ let engine;
5
+ let mockReport;
6
+ beforeEach(() => {
7
+ engine = new RulesEngine();
8
+ mockReport = {
9
+ timestamp: new Date().toISOString(),
10
+ projectInfo: { path: '.', name: 'Test', frameworks: [], primaryLanguages: ['typescript'], totalFiles: 10, totalLines: 100 },
11
+ score: {
12
+ overall: 85,
13
+ components: [],
14
+ breakdown: { modularity: 80, coupling: 90, cohesion: 85, layering: 85 },
15
+ },
16
+ antiPatterns: [
17
+ { name: 'God Class', severity: 'HIGH', location: 'file1.ts', description: 'x', suggestion: 'y' },
18
+ { name: 'Circular Dependency', severity: 'CRITICAL', location: 'file2.ts', description: 'x', suggestion: 'y' }
19
+ ],
20
+ layers: [],
21
+ dependencyGraph: {
22
+ nodes: ['src/a.ts', 'src/b.ts', 'node_modules/lodash/index.js'],
23
+ edges: [
24
+ { from: 'src/a.ts', to: 'node_modules/lodash/index.js', type: 'import', weight: 1 }
25
+ ]
26
+ },
27
+ suggestions: [],
28
+ diagram: { mermaid: '', type: 'component' }
29
+ };
30
+ });
31
+ describe('Quality Gates', () => {
32
+ it('should fail if overall score is below minimum', () => {
33
+ const rules = {
34
+ version: '1.0',
35
+ quality_gates: { min_overall_score: 90 } // Report has 85
36
+ };
37
+ const result = engine.validate(mockReport, rules);
38
+ expect(result.success).toBe(false);
39
+ expect(result.violations).toHaveLength(1);
40
+ expect(result.violations[0].rule).toBe('quality_gates.min_overall_score');
41
+ expect(result.violations[0].level).toBe('error');
42
+ });
43
+ it('should pass if overall score meets minimum', () => {
44
+ const rules = {
45
+ version: '1.0',
46
+ quality_gates: { min_overall_score: 80 }
47
+ };
48
+ const result = engine.validate(mockReport, rules);
49
+ expect(result.success).toBe(true);
50
+ expect(result.violations).toHaveLength(0);
51
+ });
52
+ it('should fail if critical anti-patterns exceed max', () => {
53
+ const rules = {
54
+ version: '1.0',
55
+ quality_gates: { max_critical_anti_patterns: 0 } // Report has 1
56
+ };
57
+ const result = engine.validate(mockReport, rules);
58
+ expect(result.success).toBe(false);
59
+ expect(result.violations[0].rule).toBe('quality_gates.max_critical_anti_patterns');
60
+ });
61
+ it('should issue warning if high anti-patterns exceed max', () => {
62
+ const rules = {
63
+ version: '1.0',
64
+ quality_gates: { max_high_anti_patterns: 0 } // Report has 1 High, 1 Critical
65
+ };
66
+ const result = engine.validate(mockReport, rules);
67
+ // Warnings do not fail the build
68
+ expect(result.success).toBe(true);
69
+ expect(result.violations).toHaveLength(1);
70
+ expect(result.violations[0].level).toBe('warning');
71
+ expect(result.violations[0].rule).toBe('quality_gates.max_high_anti_patterns');
72
+ });
73
+ });
74
+ describe('Boundaries', () => {
75
+ it('should fail if circular dependencies are found and not allowed', () => {
76
+ const rules = {
77
+ version: '1.0',
78
+ boundaries: { allow_circular_dependencies: false }
79
+ };
80
+ const result = engine.validate(mockReport, rules);
81
+ expect(result.success).toBe(false);
82
+ expect(result.violations[0].rule).toBe('boundaries.allow_circular_dependencies');
83
+ });
84
+ it('should pass if circular dependencies are allowed', () => {
85
+ const rules = {
86
+ version: '1.0',
87
+ boundaries: { allow_circular_dependencies: true }
88
+ };
89
+ const result = engine.validate(mockReport, rules);
90
+ expect(result.success).toBe(true);
91
+ });
92
+ it('should fail if banned imports are used', () => {
93
+ const rules = {
94
+ version: '1.0',
95
+ boundaries: { banned_imports: ['lodash'] }
96
+ };
97
+ const result = engine.validate(mockReport, rules);
98
+ expect(result.success).toBe(false);
99
+ expect(result.violations[0].rule).toBe('boundaries.banned_imports');
100
+ expect(result.violations[0].message).toContain('lodash');
101
+ });
102
+ it('should pass if banned imports are not used', () => {
103
+ const rules = {
104
+ version: '1.0',
105
+ boundaries: { banned_imports: ['underscore'] } // Report uses lodash, not underscore
106
+ };
107
+ const result = engine.validate(mockReport, rules);
108
+ expect(result.success).toBe(true);
109
+ });
110
+ });
111
+ });
112
+ //# sourceMappingURL=rules-engine.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules-engine.test.js","sourceRoot":"","sources":["../../tests/rules-engine.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};