@eddacraft/anvil-core 0.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 (215) hide show
  1. package/LICENSE +14 -0
  2. package/dist/antipattern/index.d.ts +11 -0
  3. package/dist/antipattern/index.d.ts.map +1 -0
  4. package/dist/antipattern/index.js +31 -0
  5. package/dist/antipattern/patterns-css.d.ts +17 -0
  6. package/dist/antipattern/patterns-css.d.ts.map +1 -0
  7. package/dist/antipattern/patterns-css.js +72 -0
  8. package/dist/antipattern/patterns-html.d.ts +21 -0
  9. package/dist/antipattern/patterns-html.d.ts.map +1 -0
  10. package/dist/antipattern/patterns-html.js +139 -0
  11. package/dist/antipattern/patterns.d.ts +72 -0
  12. package/dist/antipattern/patterns.d.ts.map +1 -0
  13. package/dist/antipattern/patterns.js +301 -0
  14. package/dist/antipattern/scanner.d.ts +32 -0
  15. package/dist/antipattern/scanner.d.ts.map +1 -0
  16. package/dist/antipattern/scanner.js +89 -0
  17. package/dist/antipattern/types.d.ts +318 -0
  18. package/dist/antipattern/types.d.ts.map +1 -0
  19. package/dist/antipattern/types.js +278 -0
  20. package/dist/architecture/analyzer.d.ts +123 -0
  21. package/dist/architecture/analyzer.d.ts.map +1 -0
  22. package/dist/architecture/analyzer.js +321 -0
  23. package/dist/architecture/baseline.d.ts +112 -0
  24. package/dist/architecture/baseline.d.ts.map +1 -0
  25. package/dist/architecture/baseline.js +245 -0
  26. package/dist/architecture/compiler.d.ts +24 -0
  27. package/dist/architecture/compiler.d.ts.map +1 -0
  28. package/dist/architecture/compiler.js +57 -0
  29. package/dist/architecture/context.d.ts +129 -0
  30. package/dist/architecture/context.d.ts.map +1 -0
  31. package/dist/architecture/context.js +116 -0
  32. package/dist/architecture/dc-generator.d.ts +9 -0
  33. package/dist/architecture/dc-generator.d.ts.map +1 -0
  34. package/dist/architecture/dc-generator.js +220 -0
  35. package/dist/architecture/definition-schema.d.ts +128 -0
  36. package/dist/architecture/definition-schema.d.ts.map +1 -0
  37. package/dist/architecture/definition-schema.js +94 -0
  38. package/dist/architecture/edge-detector-html.d.ts +6 -0
  39. package/dist/architecture/edge-detector-html.d.ts.map +1 -0
  40. package/dist/architecture/edge-detector-html.js +5 -0
  41. package/dist/architecture/edge-detector-web.d.ts +32 -0
  42. package/dist/architecture/edge-detector-web.d.ts.map +1 -0
  43. package/dist/architecture/edge-detector-web.js +133 -0
  44. package/dist/architecture/edge-detector.d.ts +116 -0
  45. package/dist/architecture/edge-detector.d.ts.map +1 -0
  46. package/dist/architecture/edge-detector.js +229 -0
  47. package/dist/architecture/entry-detector.d.ts +44 -0
  48. package/dist/architecture/entry-detector.d.ts.map +1 -0
  49. package/dist/architecture/entry-detector.js +263 -0
  50. package/dist/architecture/index.d.ts +21 -0
  51. package/dist/architecture/index.d.ts.map +1 -0
  52. package/dist/architecture/index.js +48 -0
  53. package/dist/architecture/layer-detector.d.ts +60 -0
  54. package/dist/architecture/layer-detector.d.ts.map +1 -0
  55. package/dist/architecture/layer-detector.js +331 -0
  56. package/dist/architecture/rego-generator.d.ts +25 -0
  57. package/dist/architecture/rego-generator.d.ts.map +1 -0
  58. package/dist/architecture/rego-generator.js +229 -0
  59. package/dist/architecture/templates/index.d.ts +39 -0
  60. package/dist/architecture/templates/index.d.ts.map +1 -0
  61. package/dist/architecture/templates/index.js +124 -0
  62. package/dist/architecture/types.d.ts +280 -0
  63. package/dist/architecture/types.d.ts.map +1 -0
  64. package/dist/architecture/types.js +269 -0
  65. package/dist/architecture/yaml-parser.d.ts +13 -0
  66. package/dist/architecture/yaml-parser.d.ts.map +1 -0
  67. package/dist/architecture/yaml-parser.js +234 -0
  68. package/dist/config/constants.d.ts +9 -0
  69. package/dist/config/constants.d.ts.map +1 -0
  70. package/dist/config/constants.js +20 -0
  71. package/dist/config/index.d.ts +9 -0
  72. package/dist/config/index.d.ts.map +1 -0
  73. package/dist/config/index.js +8 -0
  74. package/dist/config/loader.d.ts +41 -0
  75. package/dist/config/loader.d.ts.map +1 -0
  76. package/dist/config/loader.js +76 -0
  77. package/dist/config/nudge-config.d.ts +35 -0
  78. package/dist/config/nudge-config.d.ts.map +1 -0
  79. package/dist/config/nudge-config.js +34 -0
  80. package/dist/config/types.d.ts +30 -0
  81. package/dist/config/types.d.ts.map +1 -0
  82. package/dist/config/types.js +4 -0
  83. package/dist/contracts/index.d.ts +14 -0
  84. package/dist/contracts/index.d.ts.map +1 -0
  85. package/dist/contracts/index.js +13 -0
  86. package/dist/contracts/schemas/aps.schema.d.ts +269 -0
  87. package/dist/contracts/schemas/aps.schema.d.ts.map +1 -0
  88. package/dist/contracts/schemas/aps.schema.js +183 -0
  89. package/dist/contracts/schemas/index.d.ts +12 -0
  90. package/dist/contracts/schemas/index.d.ts.map +1 -0
  91. package/dist/contracts/schemas/index.js +14 -0
  92. package/dist/contracts/schemas/json-schema.d.ts +14 -0
  93. package/dist/contracts/schemas/json-schema.d.ts.map +1 -0
  94. package/dist/contracts/schemas/json-schema.js +31 -0
  95. package/dist/contracts/schemas/warning.schema.d.ts +171 -0
  96. package/dist/contracts/schemas/warning.schema.d.ts.map +1 -0
  97. package/dist/contracts/schemas/warning.schema.js +123 -0
  98. package/dist/contracts/types/gate.types.d.ts +194 -0
  99. package/dist/contracts/types/gate.types.d.ts.map +1 -0
  100. package/dist/contracts/types/gate.types.js +19 -0
  101. package/dist/contracts/types/index.d.ts +9 -0
  102. package/dist/contracts/types/index.d.ts.map +1 -0
  103. package/dist/contracts/types/index.js +8 -0
  104. package/dist/crypto/hash.d.ts +47 -0
  105. package/dist/crypto/hash.d.ts.map +1 -0
  106. package/dist/crypto/hash.js +110 -0
  107. package/dist/crypto/index.d.ts +7 -0
  108. package/dist/crypto/index.d.ts.map +1 -0
  109. package/dist/crypto/index.js +6 -0
  110. package/dist/drift/index.d.ts +6 -0
  111. package/dist/drift/index.d.ts.map +1 -0
  112. package/dist/drift/index.js +5 -0
  113. package/dist/drift/report-generator.d.ts +21 -0
  114. package/dist/drift/report-generator.d.ts.map +1 -0
  115. package/dist/drift/report-generator.js +240 -0
  116. package/dist/drift/snapshot-capture.d.ts +26 -0
  117. package/dist/drift/snapshot-capture.d.ts.map +1 -0
  118. package/dist/drift/snapshot-capture.js +195 -0
  119. package/dist/drift/snapshot-compare.d.ts +50 -0
  120. package/dist/drift/snapshot-compare.d.ts.map +1 -0
  121. package/dist/drift/snapshot-compare.js +142 -0
  122. package/dist/drift/snapshot-schema.d.ts +197 -0
  123. package/dist/drift/snapshot-schema.d.ts.map +1 -0
  124. package/dist/drift/snapshot-schema.js +193 -0
  125. package/dist/drift/snapshot-storage.d.ts +25 -0
  126. package/dist/drift/snapshot-storage.d.ts.map +1 -0
  127. package/dist/drift/snapshot-storage.js +179 -0
  128. package/dist/explain/antipattern-explainer.d.ts +4 -0
  129. package/dist/explain/antipattern-explainer.d.ts.map +1 -0
  130. package/dist/explain/antipattern-explainer.js +196 -0
  131. package/dist/explain/boundary-explainer.d.ts +5 -0
  132. package/dist/explain/boundary-explainer.d.ts.map +1 -0
  133. package/dist/explain/boundary-explainer.js +261 -0
  134. package/dist/explain/explain-service.d.ts +19 -0
  135. package/dist/explain/explain-service.d.ts.map +1 -0
  136. package/dist/explain/explain-service.js +106 -0
  137. package/dist/explain/index.d.ts +7 -0
  138. package/dist/explain/index.d.ts.map +1 -0
  139. package/dist/explain/index.js +5 -0
  140. package/dist/explain/template-loader.d.ts +9 -0
  141. package/dist/explain/template-loader.d.ts.map +1 -0
  142. package/dist/explain/template-loader.js +51 -0
  143. package/dist/explain/types.d.ts +46 -0
  144. package/dist/explain/types.d.ts.map +1 -0
  145. package/dist/explain/types.js +31 -0
  146. package/dist/index.d.ts +26 -0
  147. package/dist/index.d.ts.map +1 -0
  148. package/dist/index.js +37 -0
  149. package/dist/provenance/collector.d.ts +86 -0
  150. package/dist/provenance/collector.d.ts.map +1 -0
  151. package/dist/provenance/collector.js +425 -0
  152. package/dist/provenance/git-ai-standard/git-notes.d.ts +85 -0
  153. package/dist/provenance/git-ai-standard/git-notes.d.ts.map +1 -0
  154. package/dist/provenance/git-ai-standard/git-notes.js +292 -0
  155. package/dist/provenance/git-ai-standard/index.d.ts +44 -0
  156. package/dist/provenance/git-ai-standard/index.d.ts.map +1 -0
  157. package/dist/provenance/git-ai-standard/index.js +47 -0
  158. package/dist/provenance/git-ai-standard/serializer.d.ts +54 -0
  159. package/dist/provenance/git-ai-standard/serializer.d.ts.map +1 -0
  160. package/dist/provenance/git-ai-standard/serializer.js +224 -0
  161. package/dist/provenance/git-ai-standard/session.d.ts +51 -0
  162. package/dist/provenance/git-ai-standard/session.d.ts.map +1 -0
  163. package/dist/provenance/git-ai-standard/session.js +118 -0
  164. package/dist/provenance/git-ai-standard/types.d.ts +173 -0
  165. package/dist/provenance/git-ai-standard/types.d.ts.map +1 -0
  166. package/dist/provenance/git-ai-standard/types.js +109 -0
  167. package/dist/provenance/index.d.ts +5 -0
  168. package/dist/provenance/index.d.ts.map +1 -0
  169. package/dist/provenance/index.js +6 -0
  170. package/dist/provenance/store.d.ts +83 -0
  171. package/dist/provenance/store.d.ts.map +1 -0
  172. package/dist/provenance/store.js +248 -0
  173. package/dist/provenance/types.d.ts +160 -0
  174. package/dist/provenance/types.d.ts.map +1 -0
  175. package/dist/provenance/types.js +112 -0
  176. package/dist/suppression/index.d.ts +4 -0
  177. package/dist/suppression/index.d.ts.map +1 -0
  178. package/dist/suppression/index.js +3 -0
  179. package/dist/suppression/parser.d.ts +31 -0
  180. package/dist/suppression/parser.d.ts.map +1 -0
  181. package/dist/suppression/parser.js +219 -0
  182. package/dist/suppression/service.d.ts +29 -0
  183. package/dist/suppression/service.d.ts.map +1 -0
  184. package/dist/suppression/service.js +132 -0
  185. package/dist/suppression/store.d.ts +61 -0
  186. package/dist/suppression/store.d.ts.map +1 -0
  187. package/dist/suppression/store.js +169 -0
  188. package/dist/utils/debug.d.ts +48 -0
  189. package/dist/utils/debug.d.ts.map +1 -0
  190. package/dist/utils/debug.js +100 -0
  191. package/dist/utils/index.d.ts +4 -0
  192. package/dist/utils/index.d.ts.map +1 -0
  193. package/dist/utils/index.js +3 -0
  194. package/dist/utils/path-safety.d.ts +21 -0
  195. package/dist/utils/path-safety.d.ts.map +1 -0
  196. package/dist/utils/path-safety.js +49 -0
  197. package/dist/utils/severity.d.ts +37 -0
  198. package/dist/utils/severity.d.ts.map +1 -0
  199. package/dist/utils/severity.js +22 -0
  200. package/dist/validation/aps-validator.d.ts +66 -0
  201. package/dist/validation/aps-validator.d.ts.map +1 -0
  202. package/dist/validation/aps-validator.js +173 -0
  203. package/dist/validation/errors.d.ts +52 -0
  204. package/dist/validation/errors.d.ts.map +1 -0
  205. package/dist/validation/errors.js +115 -0
  206. package/dist/validation/index.d.ts +8 -0
  207. package/dist/validation/index.d.ts.map +1 -0
  208. package/dist/validation/index.js +13 -0
  209. package/dist/warnings/index.d.ts +2 -0
  210. package/dist/warnings/index.d.ts.map +1 -0
  211. package/dist/warnings/index.js +1 -0
  212. package/dist/warnings/warning-id.d.ts +180 -0
  213. package/dist/warnings/warning-id.d.ts.map +1 -0
  214. package/dist/warnings/warning-id.js +257 -0
  215. package/package.json +79 -0
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Architecture analyzer
3
+ *
4
+ * Main entry point for architecture analysis. Combines layer detection,
5
+ * entry point detection, and dependency analysis.
6
+ */
7
+ import { BaselineManager } from './baseline.js';
8
+ import { type ArchitectureBaseline, type Layers, type EntryPoint, type LayerAssignment, type BoundaryViolation } from './types.js';
9
+ /**
10
+ * Analysis result
11
+ */
12
+ export interface AnalysisResult {
13
+ /** Detected entry points */
14
+ entryPoints: EntryPoint[];
15
+ /** Suggested layer structure */
16
+ layers: Layers;
17
+ /** Layer assignments for all files */
18
+ assignments: LayerAssignment[];
19
+ /** Files with ambiguous layer assignments */
20
+ ambiguous: LayerAssignment[];
21
+ /** Total modules analysed */
22
+ moduleCount: number;
23
+ /** Detected violations */
24
+ violations: BoundaryViolation[];
25
+ /** New violations (not in baseline) */
26
+ newViolations: BoundaryViolation[];
27
+ /** Existing violations (in baseline) */
28
+ existingViolations: BoundaryViolation[];
29
+ }
30
+ /**
31
+ * Analyzer options
32
+ */
33
+ export interface AnalyzerOptions {
34
+ /** Custom layers (overrides detection) */
35
+ layers?: Layers;
36
+ /** Include test files in analysis */
37
+ includeTests?: boolean;
38
+ /** File patterns to include */
39
+ includePatterns?: string[];
40
+ /** File patterns to exclude */
41
+ excludePatterns?: string[];
42
+ }
43
+ /**
44
+ * Architecture analyzer
45
+ */
46
+ export declare class ArchitectureAnalyzer {
47
+ private workspaceRoot;
48
+ private layerDetector;
49
+ private entryPointDetector;
50
+ private baselineManager;
51
+ private options;
52
+ constructor(workspaceRoot: string, options?: AnalyzerOptions);
53
+ /**
54
+ * Analyse the codebase and return results
55
+ */
56
+ analyse(filePaths: string[]): Promise<AnalysisResult>;
57
+ /**
58
+ * Filter files based on include/exclude patterns
59
+ */
60
+ private filterFiles;
61
+ /**
62
+ * Classify violations as new or existing
63
+ */
64
+ private classifyViolations;
65
+ /**
66
+ * Detect boundary violations by extracting imports and checking layer rules.
67
+ *
68
+ * For each import edge that crosses layer boundaries, checks whether the
69
+ * dependency is allowed by the layer's `depends_on` rules. Disallowed
70
+ * cross-layer imports are returned as BoundaryViolations.
71
+ */
72
+ private detectViolations;
73
+ /**
74
+ * Create a baseline from analysis results
75
+ */
76
+ createBaseline(result: AnalysisResult): ArchitectureBaseline;
77
+ /**
78
+ * Update baseline with new analysis
79
+ */
80
+ updateBaseline(result: AnalysisResult): ArchitectureBaseline | null;
81
+ /**
82
+ * Get the baseline manager
83
+ */
84
+ getBaselineManager(): BaselineManager;
85
+ /**
86
+ * Check if baseline exists
87
+ */
88
+ hasBaseline(): boolean;
89
+ /**
90
+ * Load existing baseline
91
+ */
92
+ loadBaseline(): ArchitectureBaseline | null;
93
+ }
94
+ /**
95
+ * Create an architecture analyzer
96
+ */
97
+ export declare function createArchitectureAnalyzer(workspaceRoot: string, options?: AnalyzerOptions): ArchitectureAnalyzer;
98
+ /**
99
+ * Quick analysis helper - analyse and optionally create baseline
100
+ */
101
+ export declare function analyseArchitecture(workspaceRoot: string, filePaths: string[], options?: AnalyzerOptions & {
102
+ createBaseline?: boolean;
103
+ }): Promise<AnalysisResult & {
104
+ baseline?: ArchitectureBaseline;
105
+ }>;
106
+ /**
107
+ * Options for baseline inference
108
+ */
109
+ export interface InferBaselineOptions extends AnalyzerOptions {
110
+ /** Save baseline to .anvil/architecture.json (default: true) */
111
+ save?: boolean;
112
+ }
113
+ /**
114
+ * Infer architecture baseline from codebase
115
+ *
116
+ * Scans the workspace, detects layers and entry points, and creates a baseline.
117
+ * This is the primary entry point for `anvil init` architecture setup.
118
+ */
119
+ export declare function inferBaseline(workspaceRoot: string, options?: InferBaselineOptions): Promise<{
120
+ result: AnalysisResult;
121
+ baseline: ArchitectureBaseline;
122
+ }>;
123
+ //# sourceMappingURL=analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../src/architecture/analyzer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,EAAE,eAAe,EAAyB,MAAM,eAAe,CAAC;AAEvE,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,MAAM,EAEX,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,iBAAiB,EAKvB,MAAM,YAAY,CAAC;AAIpB;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,4BAA4B;IAC5B,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,6CAA6C;IAC7C,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAChC,uCAAuC;IACvC,aAAa,EAAE,iBAAiB,EAAE,CAAC;IACnC,wCAAwC;IACxC,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,+BAA+B;IAC/B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,+BAA+B;IAC/B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AA0BD;;GAEG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,OAAO,CAA4B;gBAE/B,aAAa,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB;IAchE;;OAEG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC;IAwC3D;;OAEG;IACH,OAAO,CAAC,WAAW;IAoBnB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAwC1B;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IA2CxB;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,oBAAoB;IAmB5D;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,oBAAoB,GAAG,IAAI;IAkBnE;;OAEG;IACH,kBAAkB,IAAI,eAAe;IAIrC;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,YAAY,IAAI,oBAAoB,GAAG,IAAI;CAG5C;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,eAAe,GACxB,oBAAoB,CAEtB;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,CAAC,EAAE,eAAe,GAAG;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAE,GACvD,OAAO,CAAC,cAAc,GAAG;IAAE,QAAQ,CAAC,EAAE,oBAAoB,CAAA;CAAE,CAAC,CAU/D;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,eAAe;IAC3D,gEAAgE;IAChE,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,oBAAoB,CAAA;CAAE,CAAC,CAWrE"}
@@ -0,0 +1,321 @@
1
+ /**
2
+ * Architecture analyzer
3
+ *
4
+ * Main entry point for architecture analysis. Combines layer detection,
5
+ * entry point detection, and dependency analysis.
6
+ */
7
+ import { readdirSync, statSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ import { minimatch } from 'minimatch';
10
+ import { createDebugger } from '../utils/debug.js';
11
+ import { createLayerDetector } from './layer-detector.js';
12
+ import { createEntryPointDetector } from './entry-detector.js';
13
+ import { createBaselineManager } from './baseline.js';
14
+ import { extractImportsFromFiles, toDependencyEdge } from './edge-detector.js';
15
+ import { createViolationId, createDefaultLayers, createDefaultBoundaries, } from './types.js';
16
+ const debug = createDebugger('architecture');
17
+ /**
18
+ * Default exclude patterns
19
+ */
20
+ const DEFAULT_EXCLUDE_PATTERNS = [
21
+ '**/node_modules/**',
22
+ '**/.git/**',
23
+ '**/dist/**',
24
+ '**/build/**',
25
+ '**/coverage/**',
26
+ '**/*.d.ts',
27
+ ];
28
+ /**
29
+ * Default include patterns
30
+ */
31
+ const DEFAULT_INCLUDE_PATTERNS = [
32
+ '**/*.ts',
33
+ '**/*.tsx',
34
+ '**/*.js',
35
+ '**/*.jsx',
36
+ '**/*.mjs',
37
+ '**/*.cjs',
38
+ ];
39
+ /**
40
+ * Architecture analyzer
41
+ */
42
+ export class ArchitectureAnalyzer {
43
+ workspaceRoot;
44
+ layerDetector;
45
+ entryPointDetector;
46
+ baselineManager;
47
+ options;
48
+ constructor(workspaceRoot, options = {}) {
49
+ this.workspaceRoot = workspaceRoot;
50
+ this.options = {
51
+ layers: options.layers ?? createDefaultLayers(),
52
+ includeTests: options.includeTests ?? false,
53
+ includePatterns: options.includePatterns ?? DEFAULT_INCLUDE_PATTERNS,
54
+ excludePatterns: options.excludePatterns ?? DEFAULT_EXCLUDE_PATTERNS,
55
+ };
56
+ this.layerDetector = createLayerDetector(this.options.layers);
57
+ this.entryPointDetector = createEntryPointDetector(workspaceRoot);
58
+ this.baselineManager = createBaselineManager(workspaceRoot);
59
+ }
60
+ /**
61
+ * Analyse the codebase and return results
62
+ */
63
+ async analyse(filePaths) {
64
+ // Filter files
65
+ const filteredPaths = this.filterFiles(filePaths);
66
+ // Detect entry points
67
+ let entryPoints = this.entryPointDetector.detectEntryPoints(filteredPaths);
68
+ if (!this.options.includeTests) {
69
+ entryPoints = this.entryPointDetector.filterNonTestEntryPoints(entryPoints);
70
+ }
71
+ // Detect layers
72
+ const assignments = this.layerDetector.detectLayers(filteredPaths);
73
+ const ambiguous = this.layerDetector.findAmbiguousAssignments(filteredPaths);
74
+ // Suggest layers based on detected patterns
75
+ const suggestedLayers = this.layerDetector.suggestLayers(filteredPaths);
76
+ // Use suggested layers if no custom layers provided
77
+ const layers = Object.keys(this.options.layers).length > 0 ? this.options.layers : suggestedLayers;
78
+ // Detect violations by extracting imports and checking against layer boundaries
79
+ const violations = this.detectViolations(filteredPaths, layers);
80
+ // Classify violations as new or existing
81
+ const baseline = this.baselineManager.load();
82
+ const { newViolations, existingViolations } = this.classifyViolations(violations, baseline);
83
+ return {
84
+ entryPoints,
85
+ layers,
86
+ assignments,
87
+ ambiguous,
88
+ moduleCount: filteredPaths.length,
89
+ violations,
90
+ newViolations,
91
+ existingViolations,
92
+ };
93
+ }
94
+ /**
95
+ * Filter files based on include/exclude patterns
96
+ */
97
+ filterFiles(filePaths) {
98
+ return filePaths.filter((path) => {
99
+ // Check excludes
100
+ for (const pattern of this.options.excludePatterns) {
101
+ if (minimatch(path, pattern, { matchBase: true })) {
102
+ return false;
103
+ }
104
+ }
105
+ // Check includes
106
+ for (const pattern of this.options.includePatterns) {
107
+ if (minimatch(path, pattern, { matchBase: true })) {
108
+ return true;
109
+ }
110
+ }
111
+ return false;
112
+ });
113
+ }
114
+ /**
115
+ * Classify violations as new or existing
116
+ */
117
+ classifyViolations(violations, baseline) {
118
+ if (!baseline) {
119
+ // No baseline = all violations are new
120
+ return {
121
+ newViolations: violations.map((v) => ({ ...v, is_new: true })),
122
+ existingViolations: [],
123
+ };
124
+ }
125
+ const baselineIds = new Set(baseline.baseline_snapshot.violations.map((v) => v.id));
126
+ const newViolations = [];
127
+ const existingViolations = [];
128
+ for (const violation of violations) {
129
+ const id = createViolationId(violation.edge.from, violation.edge.to, violation.edge.line);
130
+ if (baselineIds.has(id)) {
131
+ existingViolations.push({
132
+ ...violation,
133
+ is_new: false,
134
+ baseline_id: id,
135
+ });
136
+ }
137
+ else {
138
+ newViolations.push({
139
+ ...violation,
140
+ is_new: true,
141
+ });
142
+ }
143
+ }
144
+ return { newViolations, existingViolations };
145
+ }
146
+ /**
147
+ * Detect boundary violations by extracting imports and checking layer rules.
148
+ *
149
+ * For each import edge that crosses layer boundaries, checks whether the
150
+ * dependency is allowed by the layer's `depends_on` rules. Disallowed
151
+ * cross-layer imports are returned as BoundaryViolations.
152
+ */
153
+ detectViolations(filePaths, layers) {
154
+ const violations = [];
155
+ // Extract all import edges from source files
156
+ const edges = extractImportsFromFiles(filePaths, this.workspaceRoot);
157
+ // Build boundary rules (disallowed layer pairs)
158
+ const boundaries = createDefaultBoundaries(layers);
159
+ const boundaryMap = new Map();
160
+ for (const boundary of boundaries) {
161
+ boundaryMap.set(`${boundary.from}->${boundary.to}`, boundary);
162
+ }
163
+ // Check each edge against layer rules
164
+ for (const edge of edges) {
165
+ const fromAssignment = this.layerDetector.detectLayer(edge.from);
166
+ const toAssignment = this.layerDetector.detectLayer(edge.to);
167
+ const fromLayer = fromAssignment.layer;
168
+ const toLayer = toAssignment.layer;
169
+ // Skip if either file has no layer assignment or they're in the same layer
170
+ if (!fromLayer || !toLayer || fromLayer === toLayer) {
171
+ continue;
172
+ }
173
+ // Check if this cross-layer dependency is allowed
174
+ if (!this.layerDetector.isAllowedDependency(fromLayer, toLayer, layers)) {
175
+ const boundaryKey = `${fromLayer}->${toLayer}`;
176
+ const boundary = boundaryMap.get(boundaryKey);
177
+ violations.push({
178
+ edge: toDependencyEdge(edge, fromLayer, toLayer),
179
+ boundary,
180
+ is_new: true, // Will be reclassified by classifyViolations
181
+ });
182
+ }
183
+ }
184
+ debug(`detected ${violations.length} boundary violations from ${edges.length} edges`);
185
+ return violations;
186
+ }
187
+ /**
188
+ * Create a baseline from analysis results
189
+ */
190
+ createBaseline(result) {
191
+ const violations = result.violations.map((v) => ({
192
+ id: createViolationId(v.edge.from, v.edge.to, v.edge.line),
193
+ from_layer: v.edge.from_layer ?? 'unknown',
194
+ to_layer: v.edge.to_layer ?? 'unknown',
195
+ from_file: v.edge.from,
196
+ to_file: v.edge.to,
197
+ import_line: v.edge.line,
198
+ }));
199
+ return this.baselineManager.create({
200
+ entryPoints: result.entryPoints,
201
+ layers: result.layers,
202
+ boundaries: createDefaultBoundaries(result.layers),
203
+ violations,
204
+ moduleCount: result.moduleCount,
205
+ });
206
+ }
207
+ /**
208
+ * Update baseline with new analysis
209
+ */
210
+ updateBaseline(result) {
211
+ const violations = result.violations.map((v) => ({
212
+ id: createViolationId(v.edge.from, v.edge.to, v.edge.line),
213
+ from_layer: v.edge.from_layer ?? 'unknown',
214
+ to_layer: v.edge.to_layer ?? 'unknown',
215
+ from_file: v.edge.from,
216
+ to_file: v.edge.to,
217
+ import_line: v.edge.line,
218
+ }));
219
+ return this.baselineManager.update({
220
+ entryPoints: result.entryPoints,
221
+ layers: result.layers,
222
+ violations,
223
+ moduleCount: result.moduleCount,
224
+ });
225
+ }
226
+ /**
227
+ * Get the baseline manager
228
+ */
229
+ getBaselineManager() {
230
+ return this.baselineManager;
231
+ }
232
+ /**
233
+ * Check if baseline exists
234
+ */
235
+ hasBaseline() {
236
+ return this.baselineManager.exists();
237
+ }
238
+ /**
239
+ * Load existing baseline
240
+ */
241
+ loadBaseline() {
242
+ return this.baselineManager.load();
243
+ }
244
+ }
245
+ /**
246
+ * Create an architecture analyzer
247
+ */
248
+ export function createArchitectureAnalyzer(workspaceRoot, options) {
249
+ return new ArchitectureAnalyzer(workspaceRoot, options);
250
+ }
251
+ /**
252
+ * Quick analysis helper - analyse and optionally create baseline
253
+ */
254
+ export async function analyseArchitecture(workspaceRoot, filePaths, options) {
255
+ const analyzer = createArchitectureAnalyzer(workspaceRoot, options);
256
+ const result = await analyzer.analyse(filePaths);
257
+ if (options?.createBaseline) {
258
+ const baseline = analyzer.createBaseline(result);
259
+ return { ...result, baseline };
260
+ }
261
+ return result;
262
+ }
263
+ /**
264
+ * Infer architecture baseline from codebase
265
+ *
266
+ * Scans the workspace, detects layers and entry points, and creates a baseline.
267
+ * This is the primary entry point for `anvil init` architecture setup.
268
+ */
269
+ export async function inferBaseline(workspaceRoot, options) {
270
+ const analyzer = createArchitectureAnalyzer(workspaceRoot, options);
271
+ const filePaths = collectSourceFiles(workspaceRoot, options);
272
+ const result = await analyzer.analyse(filePaths);
273
+ const baseline = analyzer.createBaseline(result);
274
+ if (options?.save !== false) {
275
+ analyzer.getBaselineManager().save(baseline);
276
+ }
277
+ return { result, baseline };
278
+ }
279
+ /**
280
+ * Collect source files from workspace
281
+ */
282
+ function collectSourceFiles(workspaceRoot, options) {
283
+ const includePatterns = options?.includePatterns ?? DEFAULT_INCLUDE_PATTERNS;
284
+ const excludePatterns = options?.excludePatterns ?? DEFAULT_EXCLUDE_PATTERNS;
285
+ const files = [];
286
+ function walk(dir, relativePath = '') {
287
+ let entries;
288
+ try {
289
+ entries = readdirSync(dir);
290
+ }
291
+ catch (err) {
292
+ debug('skipping directory (read error):', err);
293
+ return;
294
+ }
295
+ for (const entry of entries) {
296
+ const fullPath = join(dir, entry);
297
+ const relPath = relativePath ? `${relativePath}/${entry}` : entry;
298
+ if (excludePatterns.some((p) => minimatch(relPath, p, { matchBase: true }))) {
299
+ continue;
300
+ }
301
+ let stat;
302
+ try {
303
+ stat = statSync(fullPath);
304
+ }
305
+ catch (err) {
306
+ debug('skipping entry (stat error):', err);
307
+ continue;
308
+ }
309
+ if (stat.isDirectory()) {
310
+ walk(fullPath, relPath);
311
+ }
312
+ else if (stat.isFile()) {
313
+ if (includePatterns.some((p) => minimatch(relPath, p, { matchBase: true }))) {
314
+ files.push(relPath);
315
+ }
316
+ }
317
+ }
318
+ }
319
+ walk(workspaceRoot);
320
+ return files;
321
+ }
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Architecture baseline storage
3
+ *
4
+ * Handles reading/writing .anvil/architecture.json
5
+ */
6
+ import { type ArchitectureBaseline, type Layers, type EntryPoint, type Boundary, type BaselineViolation } from './types.js';
7
+ /**
8
+ * Default baseline file path
9
+ */
10
+ export declare const BASELINE_FILENAME = "architecture.json";
11
+ export declare const ANVIL_DIR = ".anvil";
12
+ /**
13
+ * Get the full path to the baseline file
14
+ */
15
+ export declare function getBaselinePath(workspaceRoot: string): string;
16
+ /**
17
+ * Check if a baseline exists
18
+ */
19
+ export declare function baselineExists(workspaceRoot: string): boolean;
20
+ /**
21
+ * Load the architecture baseline
22
+ */
23
+ export declare function loadBaseline(workspaceRoot: string): ArchitectureBaseline | null;
24
+ /**
25
+ * Save the architecture baseline
26
+ */
27
+ export declare function saveBaseline(workspaceRoot: string, baseline: ArchitectureBaseline): void;
28
+ /**
29
+ * Create a new baseline with defaults
30
+ */
31
+ export declare function createBaseline(options: {
32
+ entryPoints?: EntryPoint[];
33
+ layers?: Layers;
34
+ boundaries?: Boundary[];
35
+ violations?: BaselineViolation[];
36
+ moduleCount?: number;
37
+ }): ArchitectureBaseline;
38
+ /**
39
+ * Update an existing baseline
40
+ */
41
+ export declare function updateBaseline(existing: ArchitectureBaseline, updates: Partial<{
42
+ entryPoints: EntryPoint[];
43
+ layers: Layers;
44
+ boundaries: Boundary[];
45
+ violations: BaselineViolation[];
46
+ moduleCount: number;
47
+ }>): ArchitectureBaseline;
48
+ /**
49
+ * Merge new violations into baseline (for incremental updates)
50
+ */
51
+ export declare function mergeViolations(existing: BaselineViolation[], newViolations: BaselineViolation[]): BaselineViolation[];
52
+ /**
53
+ * Find violations that are NEW (not in baseline)
54
+ */
55
+ export declare function findNewViolations(current: BaselineViolation[], baseline: BaselineViolation[]): BaselineViolation[];
56
+ /**
57
+ * Find violations that were FIXED (in baseline but not current)
58
+ */
59
+ export declare function findFixedViolations(current: BaselineViolation[], baseline: BaselineViolation[]): BaselineViolation[];
60
+ /**
61
+ * Baseline manager for convenient operations
62
+ */
63
+ export declare class BaselineManager {
64
+ private workspaceRoot;
65
+ private baseline;
66
+ constructor(workspaceRoot: string);
67
+ /**
68
+ * Check if baseline exists
69
+ */
70
+ exists(): boolean;
71
+ /**
72
+ * Load baseline (cached)
73
+ */
74
+ load(): ArchitectureBaseline | null;
75
+ /**
76
+ * Force reload baseline
77
+ */
78
+ reload(): ArchitectureBaseline | null;
79
+ /**
80
+ * Save baseline
81
+ */
82
+ save(baseline: ArchitectureBaseline): void;
83
+ /**
84
+ * Create and save a new baseline
85
+ */
86
+ create(options: Parameters<typeof createBaseline>[0]): ArchitectureBaseline;
87
+ /**
88
+ * Update and save existing baseline
89
+ */
90
+ update(updates: Parameters<typeof updateBaseline>[1]): ArchitectureBaseline | null;
91
+ /**
92
+ * Get layers from baseline or defaults
93
+ */
94
+ getLayers(): Layers;
95
+ /**
96
+ * Get boundaries from baseline or defaults
97
+ */
98
+ getBoundaries(): Boundary[];
99
+ /**
100
+ * Check if a violation is new
101
+ */
102
+ isNewViolation(violation: BaselineViolation): boolean;
103
+ /**
104
+ * Get baseline path
105
+ */
106
+ getPath(): string;
107
+ }
108
+ /**
109
+ * Create a baseline manager
110
+ */
111
+ export declare function createBaselineManager(workspaceRoot: string): BaselineManager;
112
+ //# sourceMappingURL=baseline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline.d.ts","sourceRoot":"","sources":["../../src/architecture/baseline.ts"],"names":[],"mappings":"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"}