archcheck 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +536 -0
  3. package/dist/archcheck.d.ts +99 -0
  4. package/dist/archcheck.d.ts.map +1 -0
  5. package/dist/archcheck.js +339 -0
  6. package/dist/archcheck.js.map +1 -0
  7. package/dist/baseline/index.d.ts +29 -0
  8. package/dist/baseline/index.d.ts.map +1 -0
  9. package/dist/baseline/index.js +116 -0
  10. package/dist/baseline/index.js.map +1 -0
  11. package/dist/cli/args.d.ts +36 -0
  12. package/dist/cli/args.d.ts.map +1 -0
  13. package/dist/cli/args.js +233 -0
  14. package/dist/cli/args.js.map +1 -0
  15. package/dist/cli/index.d.ts +4 -0
  16. package/dist/cli/index.d.ts.map +1 -0
  17. package/dist/cli/index.js +219 -0
  18. package/dist/cli/index.js.map +1 -0
  19. package/dist/cli/version.d.ts +2 -0
  20. package/dist/cli/version.d.ts.map +1 -0
  21. package/dist/cli/version.js +29 -0
  22. package/dist/cli/version.js.map +1 -0
  23. package/dist/contracts/banned-syntax.d.ts +48 -0
  24. package/dist/contracts/banned-syntax.d.ts.map +1 -0
  25. package/dist/contracts/banned-syntax.js +201 -0
  26. package/dist/contracts/banned-syntax.js.map +1 -0
  27. package/dist/contracts/declared-field.d.ts +39 -0
  28. package/dist/contracts/declared-field.d.ts.map +1 -0
  29. package/dist/contracts/declared-field.js +142 -0
  30. package/dist/contracts/declared-field.js.map +1 -0
  31. package/dist/contracts/encapsulation.d.ts +28 -0
  32. package/dist/contracts/encapsulation.d.ts.map +1 -0
  33. package/dist/contracts/encapsulation.js +130 -0
  34. package/dist/contracts/encapsulation.js.map +1 -0
  35. package/dist/contracts/index.d.ts +10 -0
  36. package/dist/contracts/index.d.ts.map +1 -0
  37. package/dist/contracts/index.js +9 -0
  38. package/dist/contracts/index.js.map +1 -0
  39. package/dist/contracts/judgement.d.ts +21 -0
  40. package/dist/contracts/judgement.d.ts.map +1 -0
  41. package/dist/contracts/judgement.js +109 -0
  42. package/dist/contracts/judgement.js.map +1 -0
  43. package/dist/contracts/layers.d.ts +75 -0
  44. package/dist/contracts/layers.d.ts.map +1 -0
  45. package/dist/contracts/layers.js +244 -0
  46. package/dist/contracts/layers.js.map +1 -0
  47. package/dist/contracts/naming.d.ts +21 -0
  48. package/dist/contracts/naming.d.ts.map +1 -0
  49. package/dist/contracts/naming.js +120 -0
  50. package/dist/contracts/naming.js.map +1 -0
  51. package/dist/contracts/registry.d.ts +23 -0
  52. package/dist/contracts/registry.d.ts.map +1 -0
  53. package/dist/contracts/registry.js +48 -0
  54. package/dist/contracts/registry.js.map +1 -0
  55. package/dist/contracts/required-file.d.ts +29 -0
  56. package/dist/contracts/required-file.d.ts.map +1 -0
  57. package/dist/contracts/required-file.js +131 -0
  58. package/dist/contracts/required-file.js.map +1 -0
  59. package/dist/contracts/types.d.ts +61 -0
  60. package/dist/contracts/types.d.ts.map +1 -0
  61. package/dist/contracts/types.js +2 -0
  62. package/dist/contracts/types.js.map +1 -0
  63. package/dist/coverage/index.d.ts +55 -0
  64. package/dist/coverage/index.d.ts.map +1 -0
  65. package/dist/coverage/index.js +68 -0
  66. package/dist/coverage/index.js.map +1 -0
  67. package/dist/emit/collect.d.ts +20 -0
  68. package/dist/emit/collect.d.ts.map +1 -0
  69. package/dist/emit/collect.js +17 -0
  70. package/dist/emit/collect.js.map +1 -0
  71. package/dist/emit/header.d.ts +21 -0
  72. package/dist/emit/header.d.ts.map +1 -0
  73. package/dist/emit/header.js +20 -0
  74. package/dist/emit/header.js.map +1 -0
  75. package/dist/emit/index.d.ts +57 -0
  76. package/dist/emit/index.d.ts.map +1 -0
  77. package/dist/emit/index.js +128 -0
  78. package/dist/emit/index.js.map +1 -0
  79. package/dist/emit/merge.d.ts +23 -0
  80. package/dist/emit/merge.d.ts.map +1 -0
  81. package/dist/emit/merge.js +71 -0
  82. package/dist/emit/merge.js.map +1 -0
  83. package/dist/emit/write.d.ts +20 -0
  84. package/dist/emit/write.d.ts.map +1 -0
  85. package/dist/emit/write.js +61 -0
  86. package/dist/emit/write.js.map +1 -0
  87. package/dist/exceptions/index.d.ts +46 -0
  88. package/dist/exceptions/index.d.ts.map +1 -0
  89. package/dist/exceptions/index.js +117 -0
  90. package/dist/exceptions/index.js.map +1 -0
  91. package/dist/fs/index.d.ts +12 -0
  92. package/dist/fs/index.d.ts.map +1 -0
  93. package/dist/fs/index.js +78 -0
  94. package/dist/fs/index.js.map +1 -0
  95. package/dist/graph/cache.d.ts +12 -0
  96. package/dist/graph/cache.d.ts.map +1 -0
  97. package/dist/graph/cache.js +76 -0
  98. package/dist/graph/cache.js.map +1 -0
  99. package/dist/graph/edges.d.ts +16 -0
  100. package/dist/graph/edges.d.ts.map +1 -0
  101. package/dist/graph/edges.js +161 -0
  102. package/dist/graph/edges.js.map +1 -0
  103. package/dist/graph/index.d.ts +15 -0
  104. package/dist/graph/index.d.ts.map +1 -0
  105. package/dist/graph/index.js +90 -0
  106. package/dist/graph/index.js.map +1 -0
  107. package/dist/graph/match.d.ts +12 -0
  108. package/dist/graph/match.d.ts.map +1 -0
  109. package/dist/graph/match.js +35 -0
  110. package/dist/graph/match.js.map +1 -0
  111. package/dist/graph/program.d.ts +12 -0
  112. package/dist/graph/program.d.ts.map +1 -0
  113. package/dist/graph/program.js +54 -0
  114. package/dist/graph/program.js.map +1 -0
  115. package/dist/graph/types.d.ts +55 -0
  116. package/dist/graph/types.d.ts.map +1 -0
  117. package/dist/graph/types.js +2 -0
  118. package/dist/graph/types.js.map +1 -0
  119. package/dist/index.d.ts +21 -0
  120. package/dist/index.d.ts.map +1 -0
  121. package/dist/index.js +20 -0
  122. package/dist/index.js.map +1 -0
  123. package/dist/init/index.d.ts +23 -0
  124. package/dist/init/index.d.ts.map +1 -0
  125. package/dist/init/index.js +218 -0
  126. package/dist/init/index.js.map +1 -0
  127. package/dist/normalize/identity.d.ts +4 -0
  128. package/dist/normalize/identity.d.ts.map +1 -0
  129. package/dist/normalize/identity.js +33 -0
  130. package/dist/normalize/identity.js.map +1 -0
  131. package/dist/normalize/index.d.ts +3 -0
  132. package/dist/normalize/index.d.ts.map +1 -0
  133. package/dist/normalize/index.js +3 -0
  134. package/dist/normalize/index.js.map +1 -0
  135. package/dist/normalize/normalize.d.ts +34 -0
  136. package/dist/normalize/normalize.d.ts.map +1 -0
  137. package/dist/normalize/normalize.js +91 -0
  138. package/dist/normalize/normalize.js.map +1 -0
  139. package/dist/probes/graph.d.ts +19 -0
  140. package/dist/probes/graph.d.ts.map +1 -0
  141. package/dist/probes/graph.js +181 -0
  142. package/dist/probes/graph.js.map +1 -0
  143. package/dist/probes/index.d.ts +5 -0
  144. package/dist/probes/index.d.ts.map +1 -0
  145. package/dist/probes/index.js +5 -0
  146. package/dist/probes/index.js.map +1 -0
  147. package/dist/probes/lint.d.ts +17 -0
  148. package/dist/probes/lint.d.ts.map +1 -0
  149. package/dist/probes/lint.js +121 -0
  150. package/dist/probes/lint.js.map +1 -0
  151. package/dist/probes/model/anthropic.d.ts +47 -0
  152. package/dist/probes/model/anthropic.d.ts.map +1 -0
  153. package/dist/probes/model/anthropic.js +100 -0
  154. package/dist/probes/model/anthropic.js.map +1 -0
  155. package/dist/probes/model/budget.d.ts +22 -0
  156. package/dist/probes/model/budget.d.ts.map +1 -0
  157. package/dist/probes/model/budget.js +27 -0
  158. package/dist/probes/model/budget.js.map +1 -0
  159. package/dist/probes/model/cache.d.ts +13 -0
  160. package/dist/probes/model/cache.d.ts.map +1 -0
  161. package/dist/probes/model/cache.js +74 -0
  162. package/dist/probes/model/cache.js.map +1 -0
  163. package/dist/probes/model/index.d.ts +20 -0
  164. package/dist/probes/model/index.d.ts.map +1 -0
  165. package/dist/probes/model/index.js +160 -0
  166. package/dist/probes/model/index.js.map +1 -0
  167. package/dist/probes/model/prompt.d.ts +16 -0
  168. package/dist/probes/model/prompt.d.ts.map +1 -0
  169. package/dist/probes/model/prompt.js +57 -0
  170. package/dist/probes/model/prompt.js.map +1 -0
  171. package/dist/probes/model/provider.d.ts +88 -0
  172. package/dist/probes/model/provider.d.ts.map +1 -0
  173. package/dist/probes/model/provider.js +48 -0
  174. package/dist/probes/model/provider.js.map +1 -0
  175. package/dist/probes/structure.d.ts +3 -0
  176. package/dist/probes/structure.d.ts.map +1 -0
  177. package/dist/probes/structure.js +95 -0
  178. package/dist/probes/structure.js.map +1 -0
  179. package/dist/probes/types.d.ts +46 -0
  180. package/dist/probes/types.d.ts.map +1 -0
  181. package/dist/probes/types.js +15 -0
  182. package/dist/probes/types.js.map +1 -0
  183. package/dist/registry/define.d.ts +40 -0
  184. package/dist/registry/define.d.ts.map +1 -0
  185. package/dist/registry/define.js +4 -0
  186. package/dist/registry/define.js.map +1 -0
  187. package/dist/registry/ids.d.ts +19 -0
  188. package/dist/registry/ids.d.ts.map +1 -0
  189. package/dist/registry/ids.js +86 -0
  190. package/dist/registry/ids.js.map +1 -0
  191. package/dist/registry/index.d.ts +45 -0
  192. package/dist/registry/index.d.ts.map +1 -0
  193. package/dist/registry/index.js +71 -0
  194. package/dist/registry/index.js.map +1 -0
  195. package/dist/registry/load.d.ts +14 -0
  196. package/dist/registry/load.d.ts.map +1 -0
  197. package/dist/registry/load.js +108 -0
  198. package/dist/registry/load.js.map +1 -0
  199. package/dist/registry/validate.d.ts +24 -0
  200. package/dist/registry/validate.d.ts.map +1 -0
  201. package/dist/registry/validate.js +160 -0
  202. package/dist/registry/validate.js.map +1 -0
  203. package/dist/report/index.d.ts +10 -0
  204. package/dist/report/index.d.ts.map +1 -0
  205. package/dist/report/index.js +30 -0
  206. package/dist/report/index.js.map +1 -0
  207. package/dist/report/json.d.ts +20 -0
  208. package/dist/report/json.d.ts.map +1 -0
  209. package/dist/report/json.js +34 -0
  210. package/dist/report/json.js.map +1 -0
  211. package/dist/report/sarif.d.ts +21 -0
  212. package/dist/report/sarif.d.ts.map +1 -0
  213. package/dist/report/sarif.js +138 -0
  214. package/dist/report/sarif.js.map +1 -0
  215. package/dist/report/terminal.d.ts +3 -0
  216. package/dist/report/terminal.d.ts.map +1 -0
  217. package/dist/report/terminal.js +117 -0
  218. package/dist/report/terminal.js.map +1 -0
  219. package/dist/report/types.d.ts +28 -0
  220. package/dist/report/types.d.ts.map +1 -0
  221. package/dist/report/types.js +11 -0
  222. package/dist/report/types.js.map +1 -0
  223. package/dist/report/verdict.d.ts +21 -0
  224. package/dist/report/verdict.d.ts.map +1 -0
  225. package/dist/report/verdict.js +31 -0
  226. package/dist/report/verdict.js.map +1 -0
  227. package/dist/result.d.ts +22 -0
  228. package/dist/result.d.ts.map +1 -0
  229. package/dist/result.js +19 -0
  230. package/dist/result.js.map +1 -0
  231. package/dist/types.d.ts +178 -0
  232. package/dist/types.d.ts.map +1 -0
  233. package/dist/types.js +11 -0
  234. package/dist/types.js.map +1 -0
  235. package/dist/util/compilerApi.d.ts +2 -0
  236. package/dist/util/compilerApi.d.ts.map +1 -0
  237. package/dist/util/compilerApi.js +28 -0
  238. package/dist/util/compilerApi.js.map +1 -0
  239. package/dist/util/glob.d.ts +43 -0
  240. package/dist/util/glob.d.ts.map +1 -0
  241. package/dist/util/glob.js +195 -0
  242. package/dist/util/glob.js.map +1 -0
  243. package/dist/util/paths.d.ts +6 -0
  244. package/dist/util/paths.d.ts.map +1 -0
  245. package/dist/util/paths.js +22 -0
  246. package/dist/util/paths.js.map +1 -0
  247. package/dist/version.d.ts +13 -0
  248. package/dist/version.d.ts.map +1 -0
  249. package/dist/version.js +12 -0
  250. package/dist/version.js.map +1 -0
  251. package/package.json +72 -0
@@ -0,0 +1,76 @@
1
+ /**
2
+ * The content-hash cache for extracted file facts.
3
+ *
4
+ * What this honestly buys, stated precisely because the design review caught the overstatement
5
+ * (LLD §1.8): it skips OUR AST walk for a file whose content has not changed. It does not skip
6
+ * TypeScript's own parse — building the Program needs every file — and it does not skip the
7
+ * graph. The walk is the part that scales with rule count, so the saving is real; the claim that
8
+ * a whole file is skipped was not.
9
+ *
10
+ * What a caller must know: a cached edge has no `node`. Its `line`/`col` were precomputed at walk
11
+ * time, so position survives, but anything that needs the AST must check for `node` first.
12
+ */
13
+ import { createHash } from 'node:crypto';
14
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
15
+ import { dirname, join } from 'node:path';
16
+ export const CACHE_DIR = '.archcheck/cache';
17
+ export function hashContent(content) {
18
+ return createHash('sha256').update(content).digest('hex').slice(0, 32);
19
+ }
20
+ function stripNodes(facts) {
21
+ return {
22
+ edges: facts.edges.map(({ node: _node, ...rest }) => rest),
23
+ implementsPorts: facts.implementsPorts,
24
+ exports: facts.exports,
25
+ };
26
+ }
27
+ /** A cache that remembers nothing — the default when a run has nowhere to write. */
28
+ export function createNullCache() {
29
+ return { get: () => undefined, set: () => undefined, flush: () => undefined };
30
+ }
31
+ export function createFactsCache(root, fingerprint) {
32
+ const path = join(root, CACHE_DIR, 'facts.json');
33
+ let loaded = { schemaVersion: 1, fingerprint, files: {} };
34
+ try {
35
+ const parsed = JSON.parse(readFileSync(path, 'utf8'));
36
+ // A compiler-options change invalidates everything: resolution may differ, so every
37
+ // recorded `to` is suspect.
38
+ if (parsed?.schemaVersion === 1 && parsed.fingerprint === fingerprint)
39
+ loaded = parsed;
40
+ }
41
+ catch {
42
+ // No cache yet, or an unreadable one. Either way, start empty rather than fail a run.
43
+ }
44
+ const next = { schemaVersion: 1, fingerprint, files: {} };
45
+ let dirty = false;
46
+ return {
47
+ get(file, contentHash) {
48
+ const entry = loaded.files[`${file}\u0000${contentHash}`];
49
+ if (!entry)
50
+ return undefined;
51
+ next.files[`${file}\u0000${contentHash}`] = entry;
52
+ return {
53
+ file,
54
+ edges: entry.edges.map((edge) => ({ ...edge })),
55
+ implementsPorts: entry.implementsPorts,
56
+ exports: entry.exports,
57
+ };
58
+ },
59
+ set(file, contentHash, facts) {
60
+ next.files[`${file}\u0000${contentHash}`] = stripNodes(facts);
61
+ dirty = true;
62
+ },
63
+ flush() {
64
+ if (!dirty)
65
+ return;
66
+ try {
67
+ mkdirSync(dirname(path), { recursive: true });
68
+ writeFileSync(path, `${JSON.stringify(next)}\n`);
69
+ }
70
+ catch {
71
+ // A cache we cannot write is a slow run, not a failed one.
72
+ }
73
+ },
74
+ };
75
+ }
76
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/graph/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Extracting edges, implemented-port names and exports from one SourceFile.
3
+ *
4
+ * What rule this enforces: the graph must be COMPLETE. Every way one module can reach another is
5
+ * listed here — static import, re-export, `import =`, `require()`, and `import()` in both its
6
+ * literal and its computed form. A form missing from this walk is a layer violation that hides
7
+ * (LLD §1.3), so adding a form to the language means adding it here.
8
+ */
9
+ import ts from 'typescript';
10
+ import type { FileFacts } from './types.js';
11
+ export type ResolveSpecifier = (specifier: string, containingFile: string) => {
12
+ resolved: string | undefined;
13
+ external: boolean;
14
+ };
15
+ export declare function extractFacts(source: ts.SourceFile, checker: ts.TypeChecker, resolve: ResolveSpecifier): FileFacts;
16
+ //# sourceMappingURL=edges.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edges.d.ts","sourceRoot":"","sources":["../../src/graph/edges.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAqB,SAAS,EAAE,MAAM,YAAY,CAAC;AAO/D,MAAM,MAAM,gBAAgB,GAAG,CAC7B,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,KACnB;IAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAiGzD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,EAAE,CAAC,UAAU,EACrB,OAAO,EAAE,EAAE,CAAC,WAAW,EACvB,OAAO,EAAE,gBAAgB,GACxB,SAAS,CA8DX"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Extracting edges, implemented-port names and exports from one SourceFile.
3
+ *
4
+ * What rule this enforces: the graph must be COMPLETE. Every way one module can reach another is
5
+ * listed here — static import, re-export, `import =`, `require()`, and `import()` in both its
6
+ * literal and its computed form. A form missing from this walk is a layer violation that hides
7
+ * (LLD §1.3), so adding a form to the language means adding it here.
8
+ */
9
+ import ts from 'typescript';
10
+ function positionOf(source, node) {
11
+ const { line, character } = source.getLineAndCharacterOfPosition(node.getStart(source));
12
+ return { line: line + 1, col: character + 1 };
13
+ }
14
+ function makeEdge(source, node, specifier, typeOnly, dynamic, resolve) {
15
+ const { resolved, external } = resolve(specifier, source.fileName);
16
+ const { line, col } = positionOf(source, node);
17
+ return {
18
+ from: source.fileName,
19
+ to: resolved ?? specifier,
20
+ specifier,
21
+ external,
22
+ typeOnly,
23
+ dynamic,
24
+ line,
25
+ col,
26
+ node,
27
+ };
28
+ }
29
+ /** `import { type A, type B }` is as type-only as `import type { A, B }`. */
30
+ function isTypeOnlyImport(node) {
31
+ const clause = node.importClause;
32
+ if (!clause)
33
+ return false;
34
+ if (clause.isTypeOnly)
35
+ return true;
36
+ const bindings = clause.namedBindings;
37
+ if (bindings && ts.isNamedImports(bindings) && bindings.elements.length > 0) {
38
+ return bindings.elements.every((element) => element.isTypeOnly);
39
+ }
40
+ return false;
41
+ }
42
+ function literalSpecifier(node) {
43
+ return node !== undefined && ts.isStringLiteralLike(node) ? node.text : undefined;
44
+ }
45
+ function collectImplementedPorts(source, checker) {
46
+ const ports = new Set();
47
+ const recordName = (node) => {
48
+ const symbol = checker.getSymbolAtLocation(node);
49
+ // Resolve through the alias so `import { BlobStore as BS }` still matches `BlobStore`.
50
+ const target = symbol && symbol.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
51
+ if (target)
52
+ ports.add(target.getName());
53
+ else if (ts.isIdentifier(node))
54
+ ports.add(node.text);
55
+ };
56
+ const typeReferenceName = (type) => ts.isTypeReferenceNode(type)
57
+ ? ts.isQualifiedName(type.typeName)
58
+ ? type.typeName.right
59
+ : type.typeName
60
+ : undefined;
61
+ const visit = (node) => {
62
+ if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) {
63
+ for (const clause of node.heritageClauses ?? []) {
64
+ if (clause.token !== ts.SyntaxKind.ImplementsKeyword)
65
+ continue;
66
+ for (const type of clause.types)
67
+ recordName(type.expression);
68
+ }
69
+ }
70
+ // `const store: BlobStore = ...` and `... satisfies BlobStore` — the factory-function style
71
+ // this codebase and its consumers actually use, where there is no class to hang a clause on.
72
+ if (ts.isVariableDeclaration(node) && node.type) {
73
+ const name = typeReferenceName(node.type);
74
+ if (name)
75
+ recordName(name);
76
+ }
77
+ if (ts.isFunctionDeclaration(node) && node.type) {
78
+ const name = typeReferenceName(node.type);
79
+ if (name)
80
+ recordName(name);
81
+ }
82
+ if (ts.isSatisfiesExpression(node)) {
83
+ const name = typeReferenceName(node.type);
84
+ if (name)
85
+ recordName(name);
86
+ }
87
+ ts.forEachChild(node, visit);
88
+ };
89
+ ts.forEachChild(source, visit);
90
+ return [...ports].sort();
91
+ }
92
+ function collectExports(source, checker) {
93
+ const symbol = checker.getSymbolAtLocation(source);
94
+ if (!symbol)
95
+ return [];
96
+ return checker
97
+ .getExportsOfModule(symbol)
98
+ .map((exported) => exported.getName())
99
+ .sort();
100
+ }
101
+ export function extractFacts(source, checker, resolve) {
102
+ const edges = [];
103
+ const visit = (node) => {
104
+ if (ts.isImportDeclaration(node)) {
105
+ const specifier = literalSpecifier(node.moduleSpecifier);
106
+ if (specifier !== undefined) {
107
+ edges.push(makeEdge(source, node, specifier, isTypeOnlyImport(node), 'none', resolve));
108
+ }
109
+ }
110
+ else if (ts.isExportDeclaration(node) && node.moduleSpecifier) {
111
+ const specifier = literalSpecifier(node.moduleSpecifier);
112
+ if (specifier !== undefined) {
113
+ edges.push(makeEdge(source, node, specifier, node.isTypeOnly, 'none', resolve));
114
+ }
115
+ }
116
+ else if (ts.isImportEqualsDeclaration(node) &&
117
+ ts.isExternalModuleReference(node.moduleReference)) {
118
+ const specifier = literalSpecifier(node.moduleReference.expression);
119
+ if (specifier !== undefined) {
120
+ edges.push(makeEdge(source, node, specifier, node.isTypeOnly, 'none', resolve));
121
+ }
122
+ }
123
+ else if (ts.isCallExpression(node)) {
124
+ const isDynamicImport = node.expression.kind === ts.SyntaxKind.ImportKeyword;
125
+ const isRequire = ts.isIdentifier(node.expression) && node.expression.text === 'require';
126
+ if (isDynamicImport || isRequire) {
127
+ const argument = node.arguments[0];
128
+ const specifier = literalSpecifier(argument);
129
+ if (specifier !== undefined) {
130
+ edges.push(makeEdge(source, node, specifier, false, isDynamicImport ? 'literal' : 'none', resolve));
131
+ }
132
+ else if (isDynamicImport) {
133
+ // A computed specifier resolves to nothing. Report it anyway, with the expression text
134
+ // as the specifier, so the ban has something to point at.
135
+ const text = argument ? argument.getText(source) : '';
136
+ const { line, col } = positionOf(source, node);
137
+ edges.push({
138
+ from: source.fileName,
139
+ to: text,
140
+ specifier: text,
141
+ external: false,
142
+ typeOnly: false,
143
+ dynamic: 'computed',
144
+ line,
145
+ col,
146
+ node,
147
+ });
148
+ }
149
+ }
150
+ }
151
+ ts.forEachChild(node, visit);
152
+ };
153
+ ts.forEachChild(source, visit);
154
+ return {
155
+ file: source.fileName,
156
+ edges,
157
+ implementsPorts: collectImplementedPorts(source, checker),
158
+ exports: collectExports(source, checker),
159
+ };
160
+ }
161
+ //# sourceMappingURL=edges.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edges.js","sourceRoot":"","sources":["../../src/graph/edges.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { type Result } from '../result.js';
2
+ import type { ModuleGraph } from './types.js';
3
+ export type ReadOptions = {
4
+ root: string;
5
+ tsconfigPath: string;
6
+ /** Off for tests that must observe every walk. */
7
+ cache?: boolean;
8
+ };
9
+ export declare function readGraph(options: ReadOptions): Result<ModuleGraph>;
10
+ export { CACHE_DIR, createFactsCache, createNullCache, type FactsCache, hashContent, } from './cache.js';
11
+ export { extractFacts, type ResolveSpecifier } from './edges.js';
12
+ export { describeMatch, fileMatches, isImplementsMatch, isValidMatch, type LayerMatch, } from './match.js';
13
+ export { type BuiltProgram, buildProgram } from './program.js';
14
+ export type { DynamicKind, Edge, FileFacts, ModuleGraph } from './types.js';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/graph/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAIpD,OAAO,KAAK,EAAmB,WAAW,EAAE,MAAM,YAAY,CAAC;AAE/D,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAuBF,wBAAgB,SAAS,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC,CAyDnE;AAED,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,KAAK,UAAU,EACf,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EACL,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,YAAY,EACZ,KAAK,UAAU,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,KAAK,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC/D,YAAY,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * The module graph. One parse, shared by every probe.
3
+ *
4
+ * What a caller must know: `read()` builds the whole graph every time — that is honest, and it is
5
+ * unavoidable, because computing "which files depend on the changed ones" needs the whole graph
6
+ * anyway (LLD §1.8). What the cache saves is the per-file walk; what diff scoping saves is rule
7
+ * evaluation and every model call. Those are where the cost actually is.
8
+ */
9
+ import { readFileSync } from 'node:fs';
10
+ import ts from 'typescript';
11
+ import { err, ok } from '../result.js';
12
+ import { createFactsCache, createNullCache, hashContent } from './cache.js';
13
+ import { extractFacts } from './edges.js';
14
+ import { buildProgram } from './program.js';
15
+ function makeResolver(options) {
16
+ const host = ts.createCompilerHost(options, false);
17
+ const moduleCache = ts.createModuleResolutionCache(process.cwd(), (s) => s, options);
18
+ return (specifier, containingFile) => {
19
+ const resolved = ts.resolveModuleName(specifier, containingFile, options, host, moduleCache);
20
+ const module = resolved.resolvedModule;
21
+ if (!module) {
22
+ // Unresolvable. A relative specifier that resolves to nothing is a broken import, which
23
+ // the type checker already reports; a bare one is a package we do not have. Either way it
24
+ // is external as far as the dependency law is concerned.
25
+ return { resolved: undefined, external: !specifier.startsWith('.') };
26
+ }
27
+ return {
28
+ resolved: module.resolvedFileName,
29
+ external: module.isExternalLibraryImport === true ||
30
+ module.resolvedFileName.includes('/node_modules/'),
31
+ };
32
+ };
33
+ }
34
+ export function readGraph(options) {
35
+ const built = buildProgram(options.tsconfigPath);
36
+ if (!built.ok)
37
+ return built;
38
+ const { program, checker, optionsFingerprint } = built.value;
39
+ const cache = options.cache === false
40
+ ? createNullCache()
41
+ : createFactsCache(options.root, optionsFingerprint);
42
+ const resolve = makeResolver(built.value.options);
43
+ const facts = new Map();
44
+ const sources = new Map();
45
+ const edges = [];
46
+ const files = [];
47
+ let walked = 0;
48
+ for (const source of program.getSourceFiles()) {
49
+ if (source.isDeclarationFile)
50
+ continue;
51
+ if (source.fileName.includes('/node_modules/'))
52
+ continue;
53
+ files.push(source.fileName);
54
+ sources.set(source.fileName, source);
55
+ let contentHash;
56
+ try {
57
+ contentHash = hashContent(readFileSync(source.fileName, 'utf8'));
58
+ }
59
+ catch {
60
+ contentHash = hashContent(source.text);
61
+ }
62
+ const cached = cache.get(source.fileName, contentHash);
63
+ if (cached) {
64
+ facts.set(source.fileName, cached);
65
+ edges.push(...cached.edges);
66
+ continue;
67
+ }
68
+ const fresh = extractFacts(source, checker, resolve);
69
+ walked += 1;
70
+ cache.set(source.fileName, contentHash, fresh);
71
+ facts.set(source.fileName, fresh);
72
+ edges.push(...fresh.edges);
73
+ }
74
+ cache.flush();
75
+ if (files.length === 0) {
76
+ return err([`${options.tsconfigPath} yielded no source files to check`]);
77
+ }
78
+ return ok({
79
+ files,
80
+ edges,
81
+ factsFor: (file) => facts.get(file),
82
+ sourceFileFor: (file) => sources.get(file),
83
+ walkedCount: walked,
84
+ });
85
+ }
86
+ export { CACHE_DIR, createFactsCache, createNullCache, hashContent, } from './cache.js';
87
+ export { extractFacts } from './edges.js';
88
+ export { describeMatch, fileMatches, isImplementsMatch, isValidMatch, } from './match.js';
89
+ export { buildProgram } from './program.js';
90
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/graph/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAmB,WAAW,EAAE,MAAM,YAAY,CAAC;AAC7F,OAAO,EAAE,YAAY,EAAyB,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAU5C,SAAS,YAAY,CAAC,OAA2B;IAC/C,MAAM,IAAI,GAAG,EAAE,CAAC,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,EAAE,CAAC,2BAA2B,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACrF,OAAO,CAAC,SAAS,EAAE,cAAc,EAAE,EAAE;QACnC,MAAM,QAAQ,GAAG,EAAE,CAAC,iBAAiB,CAAC,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;QAC7F,MAAM,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC;QACvC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,wFAAwF;YACxF,0FAA0F;YAC1F,yDAAyD;YACzD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACvE,CAAC;QACD,OAAO;YACL,QAAQ,EAAE,MAAM,CAAC,gBAAgB;YACjC,QAAQ,EACN,MAAM,CAAC,uBAAuB,KAAK,IAAI;gBACvC,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC,gBAAgB,CAAC;SACrD,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,OAAoB;IAC5C,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACjD,IAAI,CAAC,KAAK,CAAC,EAAE;QAAE,OAAO,KAAK,CAAC;IAC5B,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC;IAE7D,MAAM,KAAK,GACT,OAAO,CAAC,KAAK,KAAK,KAAK;QACrB,CAAC,CAAC,eAAe,EAAE;QACnB,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;IAEzD,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAClD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAC;IACjD,MAAM,KAAK,GAAW,EAAE,CAAC;IACzB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;QAC9C,IAAI,MAAM,CAAC,iBAAiB;YAAE,SAAS;QACvC,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC;YAAE,SAAS;QACzD,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAErC,IAAI,WAAmB,CAAC;QACxB,IAAI,CAAC;YACH,WAAW,GAAG,WAAW,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;QACnE,CAAC;QAAC,MAAM,CAAC;YACP,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACzC,CAAC;QAED,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QACvD,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACnC,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5B,SAAS;QACX,CAAC;QAED,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACrD,MAAM,IAAI,CAAC,CAAC;QACZ,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;QAC/C,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,KAAK,EAAE,CAAC;IAEd,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,mCAAmC,CAAC,CAAC,CAAC;IAC3E,CAAC;IAED,OAAO,EAAE,CAAC;QACR,KAAK;QACL,KAAK;QACL,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;QACnC,aAAa,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;QAC1C,WAAW,EAAE,MAAM;KACpB,CAAC,CAAC;AACL,CAAC;AAED,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,eAAe,EAEf,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAyB,MAAM,YAAY,CAAC;AACjE,OAAO,EACL,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,YAAY,GAEb,MAAM,YAAY,CAAC;AACpB,OAAO,EAAqB,YAAY,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { FileFacts } from './types.js';
2
+ /** `'src/**'`, a list of those, or a structural match through the type checker. */
3
+ export type LayerMatch = string | string[] | {
4
+ implements: string;
5
+ };
6
+ export declare function isImplementsMatch(match: unknown): match is {
7
+ implements: string;
8
+ };
9
+ export declare function isValidMatch(match: unknown): match is LayerMatch;
10
+ export declare function fileMatches(match: LayerMatch, absoluteFile: string, root: string, facts: FileFacts | undefined): boolean;
11
+ export declare function describeMatch(match: LayerMatch): string;
12
+ //# sourceMappingURL=match.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.d.ts","sourceRoot":"","sources":["../../src/graph/match.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,mFAAmF;AACnF,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAMjF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAIhE;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,UAAU,EACjB,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS,GAAG,SAAS,GAC3B,OAAO,CAMT;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAGvD"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Layer matching: a path glob, or `implements: 'PortName'`.
3
+ *
4
+ * What rule this enforces: the second form is the other reason we own the graph (plan 04). A
5
+ * layer defined as "everything implementing this port" cannot be expressed as a path, and it is
6
+ * the right way to say it — an adapter is an adapter because of what it implements, not because of
7
+ * where someone filed it.
8
+ */
9
+ import { matchesAny } from '../util/glob.js';
10
+ import { repoRelative } from '../util/paths.js';
11
+ export function isImplementsMatch(match) {
12
+ return (typeof match === 'object' &&
13
+ match !== null &&
14
+ typeof match.implements === 'string');
15
+ }
16
+ export function isValidMatch(match) {
17
+ if (typeof match === 'string')
18
+ return match.length > 0;
19
+ if (Array.isArray(match))
20
+ return match.length > 0 && match.every((m) => typeof m === 'string');
21
+ return isImplementsMatch(match);
22
+ }
23
+ export function fileMatches(match, absoluteFile, root, facts) {
24
+ if (isImplementsMatch(match)) {
25
+ return facts?.implementsPorts.includes(match.implements) === true;
26
+ }
27
+ const patterns = typeof match === 'string' ? [match] : match;
28
+ return matchesAny(patterns, repoRelative(root, absoluteFile));
29
+ }
30
+ export function describeMatch(match) {
31
+ if (isImplementsMatch(match))
32
+ return `implements ${match.implements}`;
33
+ return (typeof match === 'string' ? [match] : match).join(', ');
34
+ }
35
+ //# sourceMappingURL=match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.js","sourceRoot":"","sources":["../../src/graph/match.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAMhD,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,OAAQ,KAAkC,CAAC,UAAU,KAAK,QAAQ,CACnE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IACvD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;IAC/F,OAAO,iBAAiB,CAAC,KAAK,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,KAAiB,EACjB,YAAoB,EACpB,IAAY,EACZ,KAA4B;IAE5B,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,KAAK,EAAE,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;IACpE,CAAC;IACD,MAAM,QAAQ,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC7D,OAAO,UAAU,CAAC,QAAQ,EAAE,YAAY,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,IAAI,iBAAiB,CAAC,KAAK,CAAC;QAAE,OAAO,cAAc,KAAK,CAAC,UAAU,EAAE,CAAC;IACtE,OAAO,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAClE,CAAC"}
@@ -0,0 +1,12 @@
1
+ import ts from 'typescript';
2
+ import { type Result } from '../result.js';
3
+ export type BuiltProgram = {
4
+ program: ts.Program;
5
+ checker: ts.TypeChecker;
6
+ options: ts.CompilerOptions;
7
+ tsconfigPath: string;
8
+ /** Hash of the resolved compiler options — half of the cache key. */
9
+ optionsFingerprint: string;
10
+ };
11
+ export declare function buildProgram(tsconfigPath: string): Result<BuiltProgram>;
12
+ //# sourceMappingURL=program.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../../src/graph/program.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAIpD,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC;IACpB,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC;IACxB,OAAO,EAAE,EAAE,CAAC,eAAe,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAUF,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,CAoCvE"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Building the `Program` from the consumer's own tsconfig.
3
+ *
4
+ * Why the compiler API directly rather than a wrapper: it is one peer dependency we already
5
+ * require, there is no second abstraction to learn, and we get the type checker — which is what
6
+ * `match: { implements }` needs and what no graph tool can offer (plan 04).
7
+ *
8
+ * What a caller must know: a tsconfig problem is a CONFIG failure, not a code failure. It comes
9
+ * back as a Result so the CLI can exit 2 rather than 1 and an agent does not go editing source.
10
+ */
11
+ import { dirname } from 'node:path';
12
+ import ts from 'typescript';
13
+ import { err, ok } from '../result.js';
14
+ import { missingCompilerApi } from '../util/compilerApi.js';
15
+ import { toPosix } from '../util/paths.js';
16
+ function fingerprint(options, fileCount) {
17
+ const stable = Object.keys(options)
18
+ .sort()
19
+ .map((key) => `${key}=${String(options[key])}`)
20
+ .join(';');
21
+ return `${stable}|files=${fileCount}`;
22
+ }
23
+ export function buildProgram(tsconfigPath) {
24
+ // Before anything touches `ts.sys`. Without this the failure is
25
+ // "Cannot read properties of undefined (reading 'readFile')", which names nothing.
26
+ const unusable = missingCompilerApi(ts);
27
+ if (unusable)
28
+ return err(unusable);
29
+ const read = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
30
+ if (read.error) {
31
+ return err([
32
+ `${toPosix(tsconfigPath)}: ${ts.flattenDiagnosticMessageText(read.error.messageText, ' ')}`,
33
+ ]);
34
+ }
35
+ const parsed = ts.parseJsonConfigFileContent(read.config, ts.sys, dirname(tsconfigPath));
36
+ if (parsed.errors.length > 0) {
37
+ return err(parsed.errors.map((d) => `${toPosix(tsconfigPath)}: ${ts.flattenDiagnosticMessageText(d.messageText, ' ')}`));
38
+ }
39
+ if (parsed.fileNames.length === 0) {
40
+ return err([
41
+ `${toPosix(tsconfigPath)} matches no files — archcheck has nothing to read`,
42
+ ' → check its include/exclude patterns',
43
+ ]);
44
+ }
45
+ const program = ts.createProgram({ rootNames: parsed.fileNames, options: parsed.options });
46
+ return ok({
47
+ program,
48
+ checker: program.getTypeChecker(),
49
+ options: parsed.options,
50
+ tsconfigPath,
51
+ optionsFingerprint: fingerprint(parsed.options, parsed.fileNames.length),
52
+ });
53
+ }
54
+ //# sourceMappingURL=program.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"program.js","sourceRoot":"","sources":["../../src/graph/program.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAW3C,SAAS,WAAW,CAAC,OAA2B,EAAE,SAAiB;IACjE,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;SAChC,IAAI,EAAE;SACN,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,MAAM,CAAE,OAAmC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;SAC3E,IAAI,CAAC,GAAG,CAAC,CAAC;IACb,OAAO,GAAG,MAAM,UAAU,SAAS,EAAE,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,YAAoB;IAC/C,gEAAgE;IAChE,mFAAmF;IACnF,MAAM,QAAQ,GAAG,kBAAkB,CAAC,EAAE,CAAC,CAAC;IACxC,IAAI,QAAQ;QAAE,OAAO,GAAG,CAAC,QAAQ,CAAC,CAAC;IAEnC,MAAM,IAAI,GAAG,EAAE,CAAC,cAAc,CAAC,YAAY,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC9D,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,GAAG,CAAC;YACT,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,4BAA4B,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC,EAAE;SAC5F,CAAC,CAAC;IACL,CAAC;IAED,MAAM,MAAM,GAAG,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;IACzF,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,GAAG,CACR,MAAM,CAAC,MAAM,CAAC,GAAG,CACf,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,4BAA4B,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,EAAE,CAC1F,CACF,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,OAAO,GAAG,CAAC;YACT,GAAG,OAAO,CAAC,YAAY,CAAC,mDAAmD;YAC3E,wCAAwC;SACzC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3F,OAAO,EAAE,CAAC;QACR,OAAO;QACP,OAAO,EAAE,OAAO,CAAC,cAAc,EAAE;QACjC,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,YAAY;QACZ,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;KACzE,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * The graph vocabulary. The edge is the unit (LLD §4, plan 04).
3
+ *
4
+ * What a caller must know: `from` and `to` are absolute. Everything that reaches a finding, a
5
+ * generated file or an identity hash goes through `repoRelative()` first — an absolute path in
6
+ * evidence makes the hash differ per checkout, which would make the baseline per-machine noise.
7
+ */
8
+ import type ts from 'typescript';
9
+ /**
10
+ * `computed` is the reason we own the graph. A dynamic import with a non-literal specifier
11
+ * resolves to nothing, so it is invisible to a module-graph tool — and it is exactly how a layer
12
+ * violation hides. We report it so `banned-syntax` can forbid it and the graph stays complete.
13
+ */
14
+ export type DynamicKind = 'none' | 'literal' | 'computed';
15
+ export type Edge = {
16
+ /** Absolute path of the importing file. */
17
+ from: string;
18
+ /** Absolute path of the imported file, or the bare specifier when `external`. */
19
+ to: string;
20
+ /** The specifier exactly as written, which is what a remedy has to quote back. */
21
+ specifier: string;
22
+ external: boolean;
23
+ /** `import type` — some rules care, most do not. */
24
+ typeOnly: boolean;
25
+ dynamic: DynamicKind;
26
+ /** 1-based, precomputed so an edge restored from cache keeps its position. */
27
+ line: number;
28
+ col: number;
29
+ /** Absent when this edge came from the cache rather than from a walk. */
30
+ node?: ts.Node;
31
+ };
32
+ export type FileFacts = {
33
+ /** Absolute path. */
34
+ file: string;
35
+ edges: Edge[];
36
+ /** Interface names this file declares an implementation of — for `match: { implements }`. */
37
+ implementsPorts: string[];
38
+ /** Exported symbol names, for the `naming` kind. */
39
+ exports: string[];
40
+ };
41
+ export type ModuleGraph = {
42
+ /** Absolute paths of every file in the program that is not a declaration file. */
43
+ files: readonly string[];
44
+ edges: readonly Edge[];
45
+ factsFor(file: string): FileFacts | undefined;
46
+ /**
47
+ * The SourceFile the reader already parsed. Present when the graph came from a real Program,
48
+ * absent when it was restored from a written report — which is why the lint probe's `run()`
49
+ * needs a program and its `ingest()` does not.
50
+ */
51
+ sourceFileFor(file: string): ts.SourceFile | undefined;
52
+ /** How many files were walked rather than restored from cache — the cache-hit assertion. */
53
+ readonly walkedCount: number;
54
+ };
55
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/graph/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC;AAE1D,MAAM,MAAM,IAAI,GAAG;IACjB,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,EAAE,EAAE,MAAM,CAAC;IACX,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,oDAAoD;IACpD,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,WAAW,CAAC;IACrB,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,yEAAyE;IACzE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,6FAA6F;IAC7F,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,oDAAoD;IACpD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,kFAAkF;IAClF,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;IAC9C;;;;OAIG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,EAAE,CAAC,UAAU,GAAG,SAAS,CAAC;IACvD,4FAA4F;IAC5F,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/graph/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * archcheck's public surface.
3
+ *
4
+ * What a caller must know: this is what `import ... from 'archcheck'` gets. Explicit named exports
5
+ * only — never `export *`, so a dead-code pass can find a symbol nobody consumes. Nothing here has
6
+ * behaviour of its own; it re-exports the facade and the types an agent needs to read a RunResult.
7
+ */
8
+ export { type ArchCheck, type BaselineOutcome, buildInitManifest, type CheckOptions, CONFIG_FILENAME, describeViolations, type EmitResult, EXIT, type ExitCode, exitCodeFor, inferLayers, initSummary, type LoadOptions, load, renderManifest, } from './archcheck.js';
9
+ export { BASELINE_PATH, type Baseline, identitiesOf, readBaseline, } from './baseline/index.js';
10
+ export { type ContractType, type EmitCtx, type ExplainCtx, implementedKinds, type Refinement, type ValidateCtx, } from './contracts/index.js';
11
+ export { automatablePercent, FENCE_BEGIN, FENCE_END, MARK, RULES_JSON, type RuleSummary, type RulesDocument, renderRulesTable, replaceFencedRegion, rulesDocument, } from './coverage/index.js';
12
+ export { type ArchitectureException, applyExceptions, todayIso, validateExceptions, } from './exceptions/index.js';
13
+ export { createMemoryFileSystem, createNodeFileSystem, type FileSystem, } from './fs/index.js';
14
+ export { type Budget, createModelProbe, DEFAULT_BUDGET, DEFAULT_MODEL, type JudgeRequest, type JudgeResponse, type JudgeVerdict, type LlmProvider, } from './probes/model/index.js';
15
+ export { type ArchitectureManifest, defineArchitecture } from './registry/define.js';
16
+ export type { Registry } from './registry/index.js';
17
+ export { type JsonReport, type ReportCtx, type Reporter, type ReporterName, reporterFor, reporterNames, type Verdict, verdictFor, } from './report/index.js';
18
+ export { allOk, err, ok, type Result } from './result.js';
19
+ export { type BaselineEntry, CONTRACT_KINDS, type Confidence, type ContractKind, type Coverage, type Diagnostic, type ExceptionStatus, type Fragment, type FragmentTarget, type RawFinding, type Remedy, type Rule, type RunResult, type Severity, type SkipRecord, } from './types.js';
20
+ export { SCHEMA_VERSION, type SchemaVersion } from './version.js';
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,iBAAiB,EACjB,KAAK,YAAY,EACjB,eAAe,EACf,kBAAkB,EAClB,KAAK,UAAU,EACf,IAAI,EACJ,KAAK,QAAQ,EACb,WAAW,EACX,WAAW,EACX,WAAW,EACX,KAAK,WAAW,EAChB,IAAI,EACJ,cAAc,GACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,aAAa,EACb,KAAK,QAAQ,EACb,YAAY,EACZ,YAAY,GACb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,OAAO,EACZ,KAAK,UAAU,EACf,gBAAgB,EAChB,KAAK,UAAU,EACf,KAAK,WAAW,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,kBAAkB,EAClB,WAAW,EACX,SAAS,EACT,IAAI,EACJ,UAAU,EACV,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,GACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,KAAK,qBAAqB,EAC1B,eAAe,EACf,QAAQ,EACR,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,KAAK,UAAU,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,KAAK,MAAM,EACX,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,WAAW,GACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACrF,YAAY,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EACL,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,WAAW,EACX,aAAa,EACb,KAAK,OAAO,EACZ,UAAU,GACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EACL,KAAK,aAAa,EAClB,cAAc,EACd,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,MAAM,EACX,KAAK,IAAI,EACT,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,UAAU,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC"}