@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.
- package/LICENSE +14 -0
- package/dist/antipattern/index.d.ts +11 -0
- package/dist/antipattern/index.d.ts.map +1 -0
- package/dist/antipattern/index.js +31 -0
- package/dist/antipattern/patterns-css.d.ts +17 -0
- package/dist/antipattern/patterns-css.d.ts.map +1 -0
- package/dist/antipattern/patterns-css.js +72 -0
- package/dist/antipattern/patterns-html.d.ts +21 -0
- package/dist/antipattern/patterns-html.d.ts.map +1 -0
- package/dist/antipattern/patterns-html.js +139 -0
- package/dist/antipattern/patterns.d.ts +72 -0
- package/dist/antipattern/patterns.d.ts.map +1 -0
- package/dist/antipattern/patterns.js +301 -0
- package/dist/antipattern/scanner.d.ts +32 -0
- package/dist/antipattern/scanner.d.ts.map +1 -0
- package/dist/antipattern/scanner.js +89 -0
- package/dist/antipattern/types.d.ts +318 -0
- package/dist/antipattern/types.d.ts.map +1 -0
- package/dist/antipattern/types.js +278 -0
- package/dist/architecture/analyzer.d.ts +123 -0
- package/dist/architecture/analyzer.d.ts.map +1 -0
- package/dist/architecture/analyzer.js +321 -0
- package/dist/architecture/baseline.d.ts +112 -0
- package/dist/architecture/baseline.d.ts.map +1 -0
- package/dist/architecture/baseline.js +245 -0
- package/dist/architecture/compiler.d.ts +24 -0
- package/dist/architecture/compiler.d.ts.map +1 -0
- package/dist/architecture/compiler.js +57 -0
- package/dist/architecture/context.d.ts +129 -0
- package/dist/architecture/context.d.ts.map +1 -0
- package/dist/architecture/context.js +116 -0
- package/dist/architecture/dc-generator.d.ts +9 -0
- package/dist/architecture/dc-generator.d.ts.map +1 -0
- package/dist/architecture/dc-generator.js +220 -0
- package/dist/architecture/definition-schema.d.ts +128 -0
- package/dist/architecture/definition-schema.d.ts.map +1 -0
- package/dist/architecture/definition-schema.js +94 -0
- package/dist/architecture/edge-detector-html.d.ts +6 -0
- package/dist/architecture/edge-detector-html.d.ts.map +1 -0
- package/dist/architecture/edge-detector-html.js +5 -0
- package/dist/architecture/edge-detector-web.d.ts +32 -0
- package/dist/architecture/edge-detector-web.d.ts.map +1 -0
- package/dist/architecture/edge-detector-web.js +133 -0
- package/dist/architecture/edge-detector.d.ts +116 -0
- package/dist/architecture/edge-detector.d.ts.map +1 -0
- package/dist/architecture/edge-detector.js +229 -0
- package/dist/architecture/entry-detector.d.ts +44 -0
- package/dist/architecture/entry-detector.d.ts.map +1 -0
- package/dist/architecture/entry-detector.js +263 -0
- package/dist/architecture/index.d.ts +21 -0
- package/dist/architecture/index.d.ts.map +1 -0
- package/dist/architecture/index.js +48 -0
- package/dist/architecture/layer-detector.d.ts +60 -0
- package/dist/architecture/layer-detector.d.ts.map +1 -0
- package/dist/architecture/layer-detector.js +331 -0
- package/dist/architecture/rego-generator.d.ts +25 -0
- package/dist/architecture/rego-generator.d.ts.map +1 -0
- package/dist/architecture/rego-generator.js +229 -0
- package/dist/architecture/templates/index.d.ts +39 -0
- package/dist/architecture/templates/index.d.ts.map +1 -0
- package/dist/architecture/templates/index.js +124 -0
- package/dist/architecture/types.d.ts +280 -0
- package/dist/architecture/types.d.ts.map +1 -0
- package/dist/architecture/types.js +269 -0
- package/dist/architecture/yaml-parser.d.ts +13 -0
- package/dist/architecture/yaml-parser.d.ts.map +1 -0
- package/dist/architecture/yaml-parser.js +234 -0
- package/dist/config/constants.d.ts +9 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +20 -0
- package/dist/config/index.d.ts +9 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +8 -0
- package/dist/config/loader.d.ts +41 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +76 -0
- package/dist/config/nudge-config.d.ts +35 -0
- package/dist/config/nudge-config.d.ts.map +1 -0
- package/dist/config/nudge-config.js +34 -0
- package/dist/config/types.d.ts +30 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +4 -0
- package/dist/contracts/index.d.ts +14 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +13 -0
- package/dist/contracts/schemas/aps.schema.d.ts +269 -0
- package/dist/contracts/schemas/aps.schema.d.ts.map +1 -0
- package/dist/contracts/schemas/aps.schema.js +183 -0
- package/dist/contracts/schemas/index.d.ts +12 -0
- package/dist/contracts/schemas/index.d.ts.map +1 -0
- package/dist/contracts/schemas/index.js +14 -0
- package/dist/contracts/schemas/json-schema.d.ts +14 -0
- package/dist/contracts/schemas/json-schema.d.ts.map +1 -0
- package/dist/contracts/schemas/json-schema.js +31 -0
- package/dist/contracts/schemas/warning.schema.d.ts +171 -0
- package/dist/contracts/schemas/warning.schema.d.ts.map +1 -0
- package/dist/contracts/schemas/warning.schema.js +123 -0
- package/dist/contracts/types/gate.types.d.ts +194 -0
- package/dist/contracts/types/gate.types.d.ts.map +1 -0
- package/dist/contracts/types/gate.types.js +19 -0
- package/dist/contracts/types/index.d.ts +9 -0
- package/dist/contracts/types/index.d.ts.map +1 -0
- package/dist/contracts/types/index.js +8 -0
- package/dist/crypto/hash.d.ts +47 -0
- package/dist/crypto/hash.d.ts.map +1 -0
- package/dist/crypto/hash.js +110 -0
- package/dist/crypto/index.d.ts +7 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +6 -0
- package/dist/drift/index.d.ts +6 -0
- package/dist/drift/index.d.ts.map +1 -0
- package/dist/drift/index.js +5 -0
- package/dist/drift/report-generator.d.ts +21 -0
- package/dist/drift/report-generator.d.ts.map +1 -0
- package/dist/drift/report-generator.js +240 -0
- package/dist/drift/snapshot-capture.d.ts +26 -0
- package/dist/drift/snapshot-capture.d.ts.map +1 -0
- package/dist/drift/snapshot-capture.js +195 -0
- package/dist/drift/snapshot-compare.d.ts +50 -0
- package/dist/drift/snapshot-compare.d.ts.map +1 -0
- package/dist/drift/snapshot-compare.js +142 -0
- package/dist/drift/snapshot-schema.d.ts +197 -0
- package/dist/drift/snapshot-schema.d.ts.map +1 -0
- package/dist/drift/snapshot-schema.js +193 -0
- package/dist/drift/snapshot-storage.d.ts +25 -0
- package/dist/drift/snapshot-storage.d.ts.map +1 -0
- package/dist/drift/snapshot-storage.js +179 -0
- package/dist/explain/antipattern-explainer.d.ts +4 -0
- package/dist/explain/antipattern-explainer.d.ts.map +1 -0
- package/dist/explain/antipattern-explainer.js +196 -0
- package/dist/explain/boundary-explainer.d.ts +5 -0
- package/dist/explain/boundary-explainer.d.ts.map +1 -0
- package/dist/explain/boundary-explainer.js +261 -0
- package/dist/explain/explain-service.d.ts +19 -0
- package/dist/explain/explain-service.d.ts.map +1 -0
- package/dist/explain/explain-service.js +106 -0
- package/dist/explain/index.d.ts +7 -0
- package/dist/explain/index.d.ts.map +1 -0
- package/dist/explain/index.js +5 -0
- package/dist/explain/template-loader.d.ts +9 -0
- package/dist/explain/template-loader.d.ts.map +1 -0
- package/dist/explain/template-loader.js +51 -0
- package/dist/explain/types.d.ts +46 -0
- package/dist/explain/types.d.ts.map +1 -0
- package/dist/explain/types.js +31 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/provenance/collector.d.ts +86 -0
- package/dist/provenance/collector.d.ts.map +1 -0
- package/dist/provenance/collector.js +425 -0
- package/dist/provenance/git-ai-standard/git-notes.d.ts +85 -0
- package/dist/provenance/git-ai-standard/git-notes.d.ts.map +1 -0
- package/dist/provenance/git-ai-standard/git-notes.js +292 -0
- package/dist/provenance/git-ai-standard/index.d.ts +44 -0
- package/dist/provenance/git-ai-standard/index.d.ts.map +1 -0
- package/dist/provenance/git-ai-standard/index.js +47 -0
- package/dist/provenance/git-ai-standard/serializer.d.ts +54 -0
- package/dist/provenance/git-ai-standard/serializer.d.ts.map +1 -0
- package/dist/provenance/git-ai-standard/serializer.js +224 -0
- package/dist/provenance/git-ai-standard/session.d.ts +51 -0
- package/dist/provenance/git-ai-standard/session.d.ts.map +1 -0
- package/dist/provenance/git-ai-standard/session.js +118 -0
- package/dist/provenance/git-ai-standard/types.d.ts +173 -0
- package/dist/provenance/git-ai-standard/types.d.ts.map +1 -0
- package/dist/provenance/git-ai-standard/types.js +109 -0
- package/dist/provenance/index.d.ts +5 -0
- package/dist/provenance/index.d.ts.map +1 -0
- package/dist/provenance/index.js +6 -0
- package/dist/provenance/store.d.ts +83 -0
- package/dist/provenance/store.d.ts.map +1 -0
- package/dist/provenance/store.js +248 -0
- package/dist/provenance/types.d.ts +160 -0
- package/dist/provenance/types.d.ts.map +1 -0
- package/dist/provenance/types.js +112 -0
- package/dist/suppression/index.d.ts +4 -0
- package/dist/suppression/index.d.ts.map +1 -0
- package/dist/suppression/index.js +3 -0
- package/dist/suppression/parser.d.ts +31 -0
- package/dist/suppression/parser.d.ts.map +1 -0
- package/dist/suppression/parser.js +219 -0
- package/dist/suppression/service.d.ts +29 -0
- package/dist/suppression/service.d.ts.map +1 -0
- package/dist/suppression/service.js +132 -0
- package/dist/suppression/store.d.ts +61 -0
- package/dist/suppression/store.d.ts.map +1 -0
- package/dist/suppression/store.js +169 -0
- package/dist/utils/debug.d.ts +48 -0
- package/dist/utils/debug.d.ts.map +1 -0
- package/dist/utils/debug.js +100 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/path-safety.d.ts +21 -0
- package/dist/utils/path-safety.d.ts.map +1 -0
- package/dist/utils/path-safety.js +49 -0
- package/dist/utils/severity.d.ts +37 -0
- package/dist/utils/severity.d.ts.map +1 -0
- package/dist/utils/severity.js +22 -0
- package/dist/validation/aps-validator.d.ts +66 -0
- package/dist/validation/aps-validator.d.ts.map +1 -0
- package/dist/validation/aps-validator.js +173 -0
- package/dist/validation/errors.d.ts +52 -0
- package/dist/validation/errors.d.ts.map +1 -0
- package/dist/validation/errors.js +115 -0
- package/dist/validation/index.d.ts +8 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +13 -0
- package/dist/warnings/index.d.ts +2 -0
- package/dist/warnings/index.d.ts.map +1 -0
- package/dist/warnings/index.js +1 -0
- package/dist/warnings/warning-id.d.ts +180 -0
- package/dist/warnings/warning-id.d.ts.map +1 -0
- package/dist/warnings/warning-id.js +257 -0
- package/package.json +79 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Edge detector for architecture boundary analysis
|
|
3
|
+
*
|
|
4
|
+
* Extracts import edges from source files and compares them against
|
|
5
|
+
* the baseline to identify NEW vs existing violations.
|
|
6
|
+
*
|
|
7
|
+
* **Limitations**:
|
|
8
|
+
* - Import extraction is line-based regex. Multi-line imports split across
|
|
9
|
+
* lines (e.g., imports with many named exports) may not be detected.
|
|
10
|
+
* - For accurate detection, use TypeScript compiler API in production.
|
|
11
|
+
*/
|
|
12
|
+
import type { DependencyEdge, BaselineViolation } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Import edge extracted from source code
|
|
15
|
+
*/
|
|
16
|
+
export interface ImportEdge {
|
|
17
|
+
/** Source file path (relative to workspace) */
|
|
18
|
+
from: string;
|
|
19
|
+
/** Target file path (resolved, relative to workspace) - used for baseline comparison */
|
|
20
|
+
to: string;
|
|
21
|
+
/** Line number of import statement (1-based) */
|
|
22
|
+
line: number;
|
|
23
|
+
/** Type of import */
|
|
24
|
+
type: 'import' | 'require' | 'dynamic';
|
|
25
|
+
/** Raw import specifier as written in code */
|
|
26
|
+
specifier: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Result of baseline comparison
|
|
30
|
+
*/
|
|
31
|
+
export interface BaselineComparison {
|
|
32
|
+
/** Edges that exist in baseline (existing violations) */
|
|
33
|
+
existing: ImportEdge[];
|
|
34
|
+
/** Edges NOT in baseline (new violations) */
|
|
35
|
+
new: ImportEdge[];
|
|
36
|
+
/** Edges in baseline but not in current (fixed violations) */
|
|
37
|
+
fixed: BaselineViolation[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Options for import extraction
|
|
41
|
+
*/
|
|
42
|
+
export interface ExtractOptions {
|
|
43
|
+
/** Include dynamic imports (default: true) */
|
|
44
|
+
includeDynamic?: boolean;
|
|
45
|
+
/** Include require() calls (default: true) */
|
|
46
|
+
includeRequire?: boolean;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Resolve an import specifier to a workspace-relative path
|
|
50
|
+
*
|
|
51
|
+
* Relative imports (./foo, ../bar) are resolved against the importing file.
|
|
52
|
+
* Absolute/package imports are returned as-is (external dependencies).
|
|
53
|
+
*/
|
|
54
|
+
export declare function resolveImportPath(specifier: string, fromFile: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* Create a stable fingerprint for an edge
|
|
57
|
+
*
|
|
58
|
+
* Used for deduplication and baseline comparison.
|
|
59
|
+
* Format: SHA-256 hash of "from:to:line"
|
|
60
|
+
*/
|
|
61
|
+
export declare function createEdgeFingerprint(from: string, to: string, line: number): string;
|
|
62
|
+
/**
|
|
63
|
+
* Create a fingerprint for an ImportEdge
|
|
64
|
+
*/
|
|
65
|
+
export declare function fingerprintEdge(edge: ImportEdge): string;
|
|
66
|
+
/**
|
|
67
|
+
* Extract all import edges from a source file
|
|
68
|
+
*
|
|
69
|
+
* @param filePath - Path to source file (relative to workspace)
|
|
70
|
+
* @param workspaceRoot - Workspace root directory
|
|
71
|
+
* @param options - Extraction options
|
|
72
|
+
* @returns Array of import edges found in the file
|
|
73
|
+
*/
|
|
74
|
+
export declare function extractImports(filePath: string, workspaceRoot: string, options?: ExtractOptions): ImportEdge[];
|
|
75
|
+
/**
|
|
76
|
+
* Extract imports from multiple files
|
|
77
|
+
*
|
|
78
|
+
* @param filePaths - Array of file paths (relative to workspace)
|
|
79
|
+
* @param workspaceRoot - Workspace root directory
|
|
80
|
+
* @param options - Extraction options
|
|
81
|
+
* @returns Array of all import edges
|
|
82
|
+
*/
|
|
83
|
+
export declare function extractImportsFromFiles(filePaths: string[], workspaceRoot: string, options?: ExtractOptions): ImportEdge[];
|
|
84
|
+
/**
|
|
85
|
+
* Compare current edges against baseline violations
|
|
86
|
+
*
|
|
87
|
+
* @param currentEdges - Edges extracted from current code
|
|
88
|
+
* @param baselineViolations - Violations recorded in baseline
|
|
89
|
+
* @returns Comparison result with new, existing, and fixed violations
|
|
90
|
+
*/
|
|
91
|
+
export declare function compareToBaseline(currentEdges: ImportEdge[], baselineViolations: BaselineViolation[]): BaselineComparison;
|
|
92
|
+
/**
|
|
93
|
+
* Convert ImportEdge to DependencyEdge
|
|
94
|
+
*
|
|
95
|
+
* @param edge - Import edge to convert
|
|
96
|
+
* @param fromLayer - Source layer (null if unknown)
|
|
97
|
+
* @param toLayer - Target layer (null if unknown)
|
|
98
|
+
* @returns DependencyEdge for use in violation tracking
|
|
99
|
+
*/
|
|
100
|
+
export declare function toDependencyEdge(edge: ImportEdge, fromLayer?: string | null, toLayer?: string | null): DependencyEdge;
|
|
101
|
+
/**
|
|
102
|
+
* Deduplicate edges by fingerprint
|
|
103
|
+
*
|
|
104
|
+
* @param edges - Array of edges (may contain duplicates)
|
|
105
|
+
* @returns Deduplicated array
|
|
106
|
+
*/
|
|
107
|
+
export declare function deduplicateEdges(edges: ImportEdge[]): ImportEdge[];
|
|
108
|
+
/**
|
|
109
|
+
* Filter edges to only include those crossing layer boundaries
|
|
110
|
+
*
|
|
111
|
+
* @param edges - All import edges
|
|
112
|
+
* @param getLayer - Function to determine layer for a file path
|
|
113
|
+
* @returns Edges that cross layer boundaries
|
|
114
|
+
*/
|
|
115
|
+
export declare function filterCrossLayerEdges(edges: ImportEdge[], getLayer: (filePath: string) => string | null): ImportEdge[];
|
|
116
|
+
//# sourceMappingURL=edge-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edge-detector.d.ts","sourceRoot":"","sources":["../../src/architecture/edge-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAOpE;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,wFAAwF;IACxF,EAAE,EAAE,MAAM,CAAC;IACX,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;IACvC,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,yDAAyD;IACzD,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,6CAA6C;IAC7C,GAAG,EAAE,UAAU,EAAE,CAAC;IAClB,8DAA8D;IAC9D,KAAK,EAAE,iBAAiB,EAAE,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,8CAA8C;IAC9C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8CAA8C;IAC9C,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAOD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO7E;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGpF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAExD;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,cAAmB,GAC3B,UAAU,EAAE,CA8Ed;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EAAE,EACnB,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,cAAmB,GAC3B,UAAU,EAAE,CASd;AAMD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,UAAU,EAAE,EAC1B,kBAAkB,EAAE,iBAAiB,EAAE,GACtC,kBAAkB,CAuBpB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,UAAU,EAChB,SAAS,GAAE,MAAM,GAAG,IAAW,EAC/B,OAAO,GAAE,MAAM,GAAG,IAAW,GAC5B,cAAc,CAShB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CAalE;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,UAAU,EAAE,EACnB,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAC5C,UAAU,EAAE,CAQd"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Edge detector for architecture boundary analysis
|
|
3
|
+
*
|
|
4
|
+
* Extracts import edges from source files and compares them against
|
|
5
|
+
* the baseline to identify NEW vs existing violations.
|
|
6
|
+
*
|
|
7
|
+
* **Limitations**:
|
|
8
|
+
* - Import extraction is line-based regex. Multi-line imports split across
|
|
9
|
+
* lines (e.g., imports with many named exports) may not be detected.
|
|
10
|
+
* - For accurate detection, use TypeScript compiler API in production.
|
|
11
|
+
*/
|
|
12
|
+
import { readFileSync } from 'node:fs';
|
|
13
|
+
import { join, dirname, normalize, extname } from 'node:path';
|
|
14
|
+
import { createHash } from 'node:crypto';
|
|
15
|
+
import { createViolationId } from './types.js';
|
|
16
|
+
import { extractHtmlEdges, extractCssEdges } from './edge-detector-web.js';
|
|
17
|
+
import { createDebugger } from '../utils/debug.js';
|
|
18
|
+
const debug = createDebugger('edge-detector');
|
|
19
|
+
const IMPORT_FROM_REGEX = /import\s+(?:[\w\s{},*]+\s+from\s+)?['"]([^'"]+)['"]/g;
|
|
20
|
+
const DYNAMIC_IMPORT_REGEX = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
21
|
+
const REQUIRE_REGEX = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
22
|
+
const EXPORT_FROM_REGEX = /export\s+(?:[\w\s{},*]+\s+from\s+)['"]([^'"]+)['"]/g;
|
|
23
|
+
/**
|
|
24
|
+
* Resolve an import specifier to a workspace-relative path
|
|
25
|
+
*
|
|
26
|
+
* Relative imports (./foo, ../bar) are resolved against the importing file.
|
|
27
|
+
* Absolute/package imports are returned as-is (external dependencies).
|
|
28
|
+
*/
|
|
29
|
+
export function resolveImportPath(specifier, fromFile) {
|
|
30
|
+
if (specifier.startsWith('.')) {
|
|
31
|
+
const fromDir = dirname(fromFile);
|
|
32
|
+
const resolved = normalize(join(fromDir, specifier));
|
|
33
|
+
return resolved.replace(/\\/g, '/');
|
|
34
|
+
}
|
|
35
|
+
return specifier;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create a stable fingerprint for an edge
|
|
39
|
+
*
|
|
40
|
+
* Used for deduplication and baseline comparison.
|
|
41
|
+
* Format: SHA-256 hash of "from:to:line"
|
|
42
|
+
*/
|
|
43
|
+
export function createEdgeFingerprint(from, to, line) {
|
|
44
|
+
const input = `${from}:${to}:${line}`;
|
|
45
|
+
return createHash('sha256').update(input).digest('hex').slice(0, 16);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Create a fingerprint for an ImportEdge
|
|
49
|
+
*/
|
|
50
|
+
export function fingerprintEdge(edge) {
|
|
51
|
+
return createEdgeFingerprint(edge.from, edge.to, edge.line);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Extract all import edges from a source file
|
|
55
|
+
*
|
|
56
|
+
* @param filePath - Path to source file (relative to workspace)
|
|
57
|
+
* @param workspaceRoot - Workspace root directory
|
|
58
|
+
* @param options - Extraction options
|
|
59
|
+
* @returns Array of import edges found in the file
|
|
60
|
+
*/
|
|
61
|
+
export function extractImports(filePath, workspaceRoot, options = {}) {
|
|
62
|
+
const { includeDynamic = true, includeRequire = true } = options;
|
|
63
|
+
const edges = [];
|
|
64
|
+
let content;
|
|
65
|
+
try {
|
|
66
|
+
const fullPath = workspaceRoot ? join(workspaceRoot, filePath) : filePath;
|
|
67
|
+
content = readFileSync(fullPath, 'utf-8');
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
debug('failed to read file for import extraction:', err);
|
|
71
|
+
return edges;
|
|
72
|
+
}
|
|
73
|
+
// Delegate to HTML/CSS extractors based on file extension
|
|
74
|
+
const ext = extname(filePath).toLowerCase();
|
|
75
|
+
if (ext === '.html' || ext === '.htm') {
|
|
76
|
+
return extractHtmlEdges(filePath, content);
|
|
77
|
+
}
|
|
78
|
+
if (ext === '.css' || ext === '.scss' || ext === '.less') {
|
|
79
|
+
return extractCssEdges(filePath, content);
|
|
80
|
+
}
|
|
81
|
+
const lines = content.split('\n');
|
|
82
|
+
for (let i = 0; i < lines.length; i++) {
|
|
83
|
+
const line = lines[i];
|
|
84
|
+
const lineNumber = i + 1;
|
|
85
|
+
for (const match of line.matchAll(IMPORT_FROM_REGEX)) {
|
|
86
|
+
const specifier = match[1];
|
|
87
|
+
edges.push({
|
|
88
|
+
from: filePath,
|
|
89
|
+
to: resolveImportPath(specifier, filePath),
|
|
90
|
+
line: lineNumber,
|
|
91
|
+
type: 'import',
|
|
92
|
+
specifier,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
for (const match of line.matchAll(EXPORT_FROM_REGEX)) {
|
|
96
|
+
const specifier = match[1];
|
|
97
|
+
edges.push({
|
|
98
|
+
from: filePath,
|
|
99
|
+
to: resolveImportPath(specifier, filePath),
|
|
100
|
+
line: lineNumber,
|
|
101
|
+
type: 'import',
|
|
102
|
+
specifier,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (includeDynamic) {
|
|
106
|
+
for (const match of line.matchAll(DYNAMIC_IMPORT_REGEX)) {
|
|
107
|
+
const specifier = match[1];
|
|
108
|
+
edges.push({
|
|
109
|
+
from: filePath,
|
|
110
|
+
to: resolveImportPath(specifier, filePath),
|
|
111
|
+
line: lineNumber,
|
|
112
|
+
type: 'dynamic',
|
|
113
|
+
specifier,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (includeRequire) {
|
|
118
|
+
for (const match of line.matchAll(REQUIRE_REGEX)) {
|
|
119
|
+
const specifier = match[1];
|
|
120
|
+
edges.push({
|
|
121
|
+
from: filePath,
|
|
122
|
+
to: resolveImportPath(specifier, filePath),
|
|
123
|
+
line: lineNumber,
|
|
124
|
+
type: 'require',
|
|
125
|
+
specifier,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return edges;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Extract imports from multiple files
|
|
134
|
+
*
|
|
135
|
+
* @param filePaths - Array of file paths (relative to workspace)
|
|
136
|
+
* @param workspaceRoot - Workspace root directory
|
|
137
|
+
* @param options - Extraction options
|
|
138
|
+
* @returns Array of all import edges
|
|
139
|
+
*/
|
|
140
|
+
export function extractImportsFromFiles(filePaths, workspaceRoot, options = {}) {
|
|
141
|
+
const allEdges = [];
|
|
142
|
+
for (const filePath of filePaths) {
|
|
143
|
+
const edges = extractImports(filePath, workspaceRoot, options);
|
|
144
|
+
allEdges.push(...edges);
|
|
145
|
+
}
|
|
146
|
+
return allEdges;
|
|
147
|
+
}
|
|
148
|
+
function edgeToViolationId(edge) {
|
|
149
|
+
return createViolationId(edge.from, edge.to, edge.line);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Compare current edges against baseline violations
|
|
153
|
+
*
|
|
154
|
+
* @param currentEdges - Edges extracted from current code
|
|
155
|
+
* @param baselineViolations - Violations recorded in baseline
|
|
156
|
+
* @returns Comparison result with new, existing, and fixed violations
|
|
157
|
+
*/
|
|
158
|
+
export function compareToBaseline(currentEdges, baselineViolations) {
|
|
159
|
+
const baselineIds = new Set(baselineViolations.map((v) => v.id));
|
|
160
|
+
const currentIds = new Set(currentEdges.map((e) => edgeToViolationId(e)));
|
|
161
|
+
const existingEdges = [];
|
|
162
|
+
const newEdges = [];
|
|
163
|
+
for (const edge of currentEdges) {
|
|
164
|
+
const violationId = edgeToViolationId(edge);
|
|
165
|
+
if (baselineIds.has(violationId)) {
|
|
166
|
+
existingEdges.push(edge);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
newEdges.push(edge);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const fixedViolations = baselineViolations.filter((v) => !currentIds.has(v.id));
|
|
173
|
+
return {
|
|
174
|
+
existing: existingEdges,
|
|
175
|
+
new: newEdges,
|
|
176
|
+
fixed: fixedViolations,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Convert ImportEdge to DependencyEdge
|
|
181
|
+
*
|
|
182
|
+
* @param edge - Import edge to convert
|
|
183
|
+
* @param fromLayer - Source layer (null if unknown)
|
|
184
|
+
* @param toLayer - Target layer (null if unknown)
|
|
185
|
+
* @returns DependencyEdge for use in violation tracking
|
|
186
|
+
*/
|
|
187
|
+
export function toDependencyEdge(edge, fromLayer = null, toLayer = null) {
|
|
188
|
+
return {
|
|
189
|
+
from: edge.from,
|
|
190
|
+
to: edge.to,
|
|
191
|
+
from_layer: fromLayer,
|
|
192
|
+
to_layer: toLayer,
|
|
193
|
+
line: edge.line,
|
|
194
|
+
type: edge.type,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Deduplicate edges by fingerprint
|
|
199
|
+
*
|
|
200
|
+
* @param edges - Array of edges (may contain duplicates)
|
|
201
|
+
* @returns Deduplicated array
|
|
202
|
+
*/
|
|
203
|
+
export function deduplicateEdges(edges) {
|
|
204
|
+
const seen = new Set();
|
|
205
|
+
const unique = [];
|
|
206
|
+
for (const edge of edges) {
|
|
207
|
+
const fingerprint = fingerprintEdge(edge);
|
|
208
|
+
if (!seen.has(fingerprint)) {
|
|
209
|
+
seen.add(fingerprint);
|
|
210
|
+
unique.push(edge);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return unique;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Filter edges to only include those crossing layer boundaries
|
|
217
|
+
*
|
|
218
|
+
* @param edges - All import edges
|
|
219
|
+
* @param getLayer - Function to determine layer for a file path
|
|
220
|
+
* @returns Edges that cross layer boundaries
|
|
221
|
+
*/
|
|
222
|
+
export function filterCrossLayerEdges(edges, getLayer) {
|
|
223
|
+
return edges.filter((edge) => {
|
|
224
|
+
const fromLayer = getLayer(edge.from);
|
|
225
|
+
const toLayer = getLayer(edge.to);
|
|
226
|
+
// Only include if both have layers and they're different
|
|
227
|
+
return fromLayer !== null && toLayer !== null && fromLayer !== toLayer;
|
|
228
|
+
});
|
|
229
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entry point detection heuristics
|
|
3
|
+
*
|
|
4
|
+
* Detects application entry points from file patterns and exports.
|
|
5
|
+
*/
|
|
6
|
+
import type { EntryPoint } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Entry point detector
|
|
9
|
+
*/
|
|
10
|
+
export declare class EntryPointDetector {
|
|
11
|
+
private workspaceRoot;
|
|
12
|
+
constructor(workspaceRoot: string);
|
|
13
|
+
/**
|
|
14
|
+
* Detect entry point type for a file
|
|
15
|
+
*
|
|
16
|
+
* Detection priority:
|
|
17
|
+
* 1. package.json bin entries (highest - explicit CLI declaration)
|
|
18
|
+
* 2. File name matches (specific file names like main.ts, cli.ts)
|
|
19
|
+
* 3. Directory matches (files in specific directories like routes/, workers/)
|
|
20
|
+
* 4. package.json main/exports (fallback for package entries)
|
|
21
|
+
*/
|
|
22
|
+
detectEntryPoint(filePath: string): EntryPoint | null;
|
|
23
|
+
/**
|
|
24
|
+
* Check if file is a bin entry in package.json
|
|
25
|
+
*/
|
|
26
|
+
private checkPackageJsonBin;
|
|
27
|
+
/**
|
|
28
|
+
* Check if file is referenced in package.json main or exports
|
|
29
|
+
*/
|
|
30
|
+
private checkPackageJsonMainExports;
|
|
31
|
+
/**
|
|
32
|
+
* Detect all entry points from a list of files
|
|
33
|
+
*/
|
|
34
|
+
detectEntryPoints(filePaths: string[]): EntryPoint[];
|
|
35
|
+
/**
|
|
36
|
+
* Filter to only non-test entry points
|
|
37
|
+
*/
|
|
38
|
+
filterNonTestEntryPoints(entryPoints: EntryPoint[]): EntryPoint[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Create an entry point detector
|
|
42
|
+
*/
|
|
43
|
+
export declare function createEntryPointDetector(workspaceRoot: string): EntryPointDetector;
|
|
44
|
+
//# sourceMappingURL=entry-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry-detector.d.ts","sourceRoot":"","sources":["../../src/architecture/entry-detector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAuC,MAAM,YAAY,CAAC;AA8ElF;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,aAAa,CAAS;gBAElB,aAAa,EAAE,MAAM;IAIjC;;;;;;;;OAQG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAuDrD;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAgC3B;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAiEnC;;OAEG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE;IAgCpD;;OAEG;IACH,wBAAwB,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE;CAGlE;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,aAAa,EAAE,MAAM,GAAG,kBAAkB,CAElF"}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entry point detection heuristics
|
|
3
|
+
*
|
|
4
|
+
* Detects application entry points from file patterns and exports.
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
7
|
+
import { join, basename, dirname } from 'node:path';
|
|
8
|
+
import { createDebugger } from '../utils/debug.js';
|
|
9
|
+
const debug = createDebugger('entry-detector');
|
|
10
|
+
/**
|
|
11
|
+
* Default entry point patterns
|
|
12
|
+
*
|
|
13
|
+
* Order matters: more specific patterns (application, cli, worker) come before
|
|
14
|
+
* generic ones (package). File name matches take priority over directory matches.
|
|
15
|
+
*/
|
|
16
|
+
const ENTRY_POINT_PATTERNS = [
|
|
17
|
+
// Tests (check first - test files should always be identified as tests)
|
|
18
|
+
{
|
|
19
|
+
type: 'test',
|
|
20
|
+
filePatterns: [/\.(test|spec)\.(ts|js)$/, /^test\.(ts|js)$/],
|
|
21
|
+
directoryPatterns: [/^__tests__$/, /^tests?$/, /^spec$/],
|
|
22
|
+
confidence: 'high',
|
|
23
|
+
},
|
|
24
|
+
// Application entries (specific file names)
|
|
25
|
+
{
|
|
26
|
+
type: 'application',
|
|
27
|
+
filePatterns: [
|
|
28
|
+
/^main\.(ts|js|mjs|cjs)$/,
|
|
29
|
+
/^app\.(ts|js|mjs|cjs)$/,
|
|
30
|
+
/^server\.(ts|js|mjs|cjs)$/,
|
|
31
|
+
/^start\.(ts|js|mjs|cjs)$/,
|
|
32
|
+
],
|
|
33
|
+
directoryPatterns: [/^app$/, /^server$/], // Removed /^src$/ - too generic
|
|
34
|
+
confidence: 'high',
|
|
35
|
+
},
|
|
36
|
+
// CLI commands (specific file names and directories)
|
|
37
|
+
{
|
|
38
|
+
type: 'cli',
|
|
39
|
+
filePatterns: [/^cli\.(ts|js)$/, /^bin\.(ts|js)$/, /^command\.(ts|js)$/],
|
|
40
|
+
directoryPatterns: [/^cli$/, /^bin$/, /^commands$/],
|
|
41
|
+
confidence: 'high',
|
|
42
|
+
},
|
|
43
|
+
// Workers (specific file names and directories)
|
|
44
|
+
{
|
|
45
|
+
type: 'worker',
|
|
46
|
+
filePatterns: [/^worker\.(ts|js)$/, /^job\.(ts|js)$/, /^consumer\.(ts|js)$/],
|
|
47
|
+
directoryPatterns: [/^workers$/, /^jobs$/, /^consumers$/, /^queues$/],
|
|
48
|
+
confidence: 'high',
|
|
49
|
+
},
|
|
50
|
+
// HTTP handlers (specific directories)
|
|
51
|
+
{
|
|
52
|
+
type: 'http',
|
|
53
|
+
filePatterns: [/^routes\.(ts|js)$/, /^router\.(ts|js)$/],
|
|
54
|
+
directoryPatterns: [/^routes$/, /^controllers$/, /^handlers$/],
|
|
55
|
+
confidence: 'high',
|
|
56
|
+
},
|
|
57
|
+
// API handlers (specific directories)
|
|
58
|
+
{
|
|
59
|
+
type: 'api',
|
|
60
|
+
filePatterns: [/^api\.(ts|js)$/, /^handler\.(ts|js)$/],
|
|
61
|
+
directoryPatterns: [/^api$/, /^endpoints$/],
|
|
62
|
+
confidence: 'medium',
|
|
63
|
+
},
|
|
64
|
+
// Package entries (generic - check last)
|
|
65
|
+
{
|
|
66
|
+
type: 'package',
|
|
67
|
+
filePatterns: [/^index\.(ts|js|mjs|cjs)$/],
|
|
68
|
+
directoryPatterns: [], // Removed /^src$/ - too generic, causes false positives
|
|
69
|
+
confidence: 'high',
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
/**
|
|
73
|
+
* Entry point detector
|
|
74
|
+
*/
|
|
75
|
+
export class EntryPointDetector {
|
|
76
|
+
workspaceRoot;
|
|
77
|
+
constructor(workspaceRoot) {
|
|
78
|
+
this.workspaceRoot = workspaceRoot;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Detect entry point type for a file
|
|
82
|
+
*
|
|
83
|
+
* Detection priority:
|
|
84
|
+
* 1. package.json bin entries (highest - explicit CLI declaration)
|
|
85
|
+
* 2. File name matches (specific file names like main.ts, cli.ts)
|
|
86
|
+
* 3. Directory matches (files in specific directories like routes/, workers/)
|
|
87
|
+
* 4. package.json main/exports (fallback for package entries)
|
|
88
|
+
*/
|
|
89
|
+
detectEntryPoint(filePath) {
|
|
90
|
+
const fileName = basename(filePath);
|
|
91
|
+
const relativePath = filePath.startsWith(this.workspaceRoot)
|
|
92
|
+
? filePath.slice(this.workspaceRoot.length + 1)
|
|
93
|
+
: filePath;
|
|
94
|
+
// Get all directory segments for matching (e.g., src/api/v1 -> ['src', 'api', 'v1'])
|
|
95
|
+
const pathSegments = dirname(relativePath).split(/[/\\]/).filter(Boolean);
|
|
96
|
+
// First: check package.json bin entries (explicit CLI declaration takes priority)
|
|
97
|
+
const binEntry = this.checkPackageJsonBin(relativePath);
|
|
98
|
+
if (binEntry) {
|
|
99
|
+
return binEntry;
|
|
100
|
+
}
|
|
101
|
+
// Second: check file name patterns (highest priority for pattern matching)
|
|
102
|
+
for (const pattern of ENTRY_POINT_PATTERNS) {
|
|
103
|
+
const fileMatch = pattern.filePatterns.some((p) => p.test(fileName));
|
|
104
|
+
if (fileMatch) {
|
|
105
|
+
const dirMatch = pathSegments.some((segment) => pattern.directoryPatterns.some((p) => p.test(segment)));
|
|
106
|
+
return {
|
|
107
|
+
path: relativePath,
|
|
108
|
+
type: pattern.type,
|
|
109
|
+
confidence: fileMatch && dirMatch ? 'high' : pattern.confidence,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Third: check directory patterns (any segment in path)
|
|
114
|
+
for (const pattern of ENTRY_POINT_PATTERNS) {
|
|
115
|
+
const dirMatch = pathSegments.some((segment) => pattern.directoryPatterns.some((p) => p.test(segment)));
|
|
116
|
+
if (dirMatch) {
|
|
117
|
+
return {
|
|
118
|
+
path: relativePath,
|
|
119
|
+
type: pattern.type,
|
|
120
|
+
confidence: pattern.confidence,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Fourth: check package.json main/exports (fallback)
|
|
125
|
+
const pkgEntry = this.checkPackageJsonMainExports(relativePath);
|
|
126
|
+
if (pkgEntry) {
|
|
127
|
+
return pkgEntry;
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Check if file is a bin entry in package.json
|
|
133
|
+
*/
|
|
134
|
+
checkPackageJsonBin(filePath) {
|
|
135
|
+
const pkgPath = join(this.workspaceRoot, 'package.json');
|
|
136
|
+
if (!existsSync(pkgPath)) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
141
|
+
const normalisedPath = filePath.replace(/\\/g, '/');
|
|
142
|
+
if (pkg.bin) {
|
|
143
|
+
const binEntries = typeof pkg.bin === 'string' ? { [pkg.name]: pkg.bin } : pkg.bin;
|
|
144
|
+
for (const binPath of Object.values(binEntries)) {
|
|
145
|
+
const normalisedBin = binPath.replace(/^\.\//, '');
|
|
146
|
+
if (normalisedPath === normalisedBin || normalisedPath.endsWith(normalisedBin)) {
|
|
147
|
+
return {
|
|
148
|
+
path: filePath,
|
|
149
|
+
type: 'cli',
|
|
150
|
+
confidence: 'high',
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
debug('failed to parse package.json bin entries', err);
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Check if file is referenced in package.json main or exports
|
|
163
|
+
*/
|
|
164
|
+
checkPackageJsonMainExports(filePath) {
|
|
165
|
+
const pkgPath = join(this.workspaceRoot, 'package.json');
|
|
166
|
+
if (!existsSync(pkgPath)) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
171
|
+
const normalisedPath = filePath.replace(/\\/g, '/');
|
|
172
|
+
// Check main entry
|
|
173
|
+
if (pkg.main) {
|
|
174
|
+
const mainPath = pkg.main.replace(/^\.\//, '');
|
|
175
|
+
if (normalisedPath === mainPath || normalisedPath.endsWith(mainPath)) {
|
|
176
|
+
return {
|
|
177
|
+
path: filePath,
|
|
178
|
+
type: 'package',
|
|
179
|
+
confidence: 'high',
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Check exports (depth-limited to prevent abuse via deeply nested exports)
|
|
184
|
+
if (pkg.exports) {
|
|
185
|
+
const MAX_EXPORTS_DEPTH = 10;
|
|
186
|
+
const checkExports = (exports, prefix = '', depth = 0) => {
|
|
187
|
+
if (depth >= MAX_EXPORTS_DEPTH)
|
|
188
|
+
return null;
|
|
189
|
+
for (const [key, value] of Object.entries(exports)) {
|
|
190
|
+
if (typeof value === 'string') {
|
|
191
|
+
const exportPath = value.replace(/^\.\//, '');
|
|
192
|
+
if (normalisedPath === exportPath || normalisedPath.endsWith(exportPath)) {
|
|
193
|
+
return {
|
|
194
|
+
path: filePath,
|
|
195
|
+
type: 'package',
|
|
196
|
+
confidence: 'high',
|
|
197
|
+
exports: [prefix + key],
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else if (typeof value === 'object' && value !== null) {
|
|
202
|
+
const result = checkExports(value, prefix + key + '/', depth + 1);
|
|
203
|
+
if (result)
|
|
204
|
+
return result;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return null;
|
|
208
|
+
};
|
|
209
|
+
const exportEntry = checkExports(pkg.exports);
|
|
210
|
+
if (exportEntry)
|
|
211
|
+
return exportEntry;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
catch (err) {
|
|
215
|
+
debug('failed to parse package.json main/exports', err);
|
|
216
|
+
}
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Detect all entry points from a list of files
|
|
221
|
+
*/
|
|
222
|
+
detectEntryPoints(filePaths) {
|
|
223
|
+
const entryPoints = [];
|
|
224
|
+
const seen = new Set();
|
|
225
|
+
for (const filePath of filePaths) {
|
|
226
|
+
const entry = this.detectEntryPoint(filePath);
|
|
227
|
+
if (entry && !seen.has(entry.path)) {
|
|
228
|
+
seen.add(entry.path);
|
|
229
|
+
entryPoints.push(entry);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// Sort by confidence and type
|
|
233
|
+
return entryPoints.sort((a, b) => {
|
|
234
|
+
const confOrder = { high: 0, medium: 1, low: 2 };
|
|
235
|
+
const confDiff = confOrder[a.confidence] - confOrder[b.confidence];
|
|
236
|
+
if (confDiff !== 0)
|
|
237
|
+
return confDiff;
|
|
238
|
+
const typeOrder = {
|
|
239
|
+
package: 0,
|
|
240
|
+
application: 1,
|
|
241
|
+
http: 2,
|
|
242
|
+
api: 3,
|
|
243
|
+
cli: 4,
|
|
244
|
+
worker: 5,
|
|
245
|
+
test: 6,
|
|
246
|
+
unknown: 7,
|
|
247
|
+
};
|
|
248
|
+
return typeOrder[a.type] - typeOrder[b.type];
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Filter to only non-test entry points
|
|
253
|
+
*/
|
|
254
|
+
filterNonTestEntryPoints(entryPoints) {
|
|
255
|
+
return entryPoints.filter((e) => e.type !== 'test');
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Create an entry point detector
|
|
260
|
+
*/
|
|
261
|
+
export function createEntryPointDetector(workspaceRoot) {
|
|
262
|
+
return new EntryPointDetector(workspaceRoot);
|
|
263
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Architecture analysis module
|
|
3
|
+
*
|
|
4
|
+
* Provides architecture baseline management, layer detection,
|
|
5
|
+
* entry point detection, and boundary violation analysis.
|
|
6
|
+
*/
|
|
7
|
+
export { EntryPointTypeSchema, type EntryPointType, DetectionConfidenceSchema, type DetectionConfidence, EntryPointSchema, type EntryPoint, StandardLayerSchema, type StandardLayer, LayerSchema, type Layer, LayersSchema, type Layers, BoundarySchema, type Boundary, BaselineViolationSchema, type BaselineViolation, BaselineSnapshotSchema, type BaselineSnapshot, ArchitectureBaselineSchema, type ArchitectureBaseline, LayerAssignmentSchema, type LayerAssignment, DependencyEdgeSchema, type DependencyEdge, BoundaryViolationSchema, type BoundaryViolation, createViolationId, isExistingViolation, createDefaultLayers, createDefaultBoundaries, } from './types.js';
|
|
8
|
+
export { LayerDetector, createLayerDetector } from './layer-detector.js';
|
|
9
|
+
export { EntryPointDetector, createEntryPointDetector } from './entry-detector.js';
|
|
10
|
+
export { BASELINE_FILENAME, ANVIL_DIR, getBaselinePath, baselineExists, loadBaseline, saveBaseline, createBaseline, updateBaseline, mergeViolations, findNewViolations, findFixedViolations, BaselineManager, createBaselineManager, } from './baseline.js';
|
|
11
|
+
export { type AnalysisResult, type AnalyzerOptions, type InferBaselineOptions, ArchitectureAnalyzer, createArchitectureAnalyzer, analyseArchitecture, inferBaseline, } from './analyzer.js';
|
|
12
|
+
export { extractHtmlEdges, extractCssEdges } from './edge-detector-web.js';
|
|
13
|
+
export { type ImportEdge, type BaselineComparison, type ExtractOptions, createEdgeFingerprint, fingerprintEdge, resolveImportPath, extractImports, extractImportsFromFiles, compareToBaseline, toDependencyEdge, deduplicateEdges, filterCrossLayerEdges, } from './edge-detector.js';
|
|
14
|
+
export { ArchitectureTemplateSchema, type ArchitectureTemplate, LayerDefinitionSchema, type LayerDefinition, BoundedContextSchema, type BoundedContext, RuleSeveritySchema, type RuleSeverity, ArchitectureRuleSchema, type ArchitectureRule, ArchitectureOptionsSchema, type ArchitectureOptions, ArchitectureDefinitionSchema, type ArchitectureDefinition, AVAILABLE_TEMPLATES, getAvailableTemplates, isValidTemplate, ARCHITECTURE_DEFINITION_VERSION, validateArchitectureDefinition, getDefaultOptions, } from './definition-schema.js';
|
|
15
|
+
export { ARCHITECTURE_YAML_FILENAME, getArchitectureYamlPath, architectureYamlExists, parseArchitectureDefinition, writeArchitectureYaml, getTemplateDefaults, mergeWithTemplate, createDefinitionFromTemplate, } from './yaml-parser.js';
|
|
16
|
+
export { DC_CONFIG_FILENAME, getDCConfigPath, dcConfigExists, needsRegeneration, writeDCConfig, generateDCConfig, } from './dc-generator.js';
|
|
17
|
+
export { GENERATED_POLICIES_DIR, REGO_FILENAME, REGO_PACKAGE, getRegoPath, regoExists, needsRegoRegeneration, writeRegoPolicy, generateRegoPolicy, } from './rego-generator.js';
|
|
18
|
+
export { type CompileResult, type CompileOptions, compileArchitecture, needsCompilation, } from './compiler.js';
|
|
19
|
+
export { type TemplateFile, type LoadedTemplate, TemplateLoader, getTemplateLoader, listTemplates, getTemplate as getArchitectureTemplate, validateTemplate, } from './templates/index.js';
|
|
20
|
+
export { ArchViolationSeveritySchema, type ArchViolationSeverity, ArchViolationSchema, type ArchViolation, ModuleInfoSchema, type ModuleInfo, LayerStatsSchema, type LayerStats, ArchitectureContextSchema, type ArchitectureContext, createEmptyContext, ArchitectureContextBuilder, createContextBuilder, } from './context.js';
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|