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 @@
1
+ {"version":3,"file":"judgement.d.ts","sourceRoot":"","sources":["../../src/contracts/judgement.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAwB,IAAI,EAAE,MAAM,aAAa,CAAC;AAE9D,OAAO,KAAK,EAAE,YAAY,EAAoC,MAAM,YAAY,CAAC;AAEjF,MAAM,MAAM,eAAe,GAAG;IAC5B,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC7B,QAAQ,EAAE;QACR,mDAAmD;QACnD,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,+CAA+C;QAC/C,IAAI,EAAE,MAAM,EAAE,CAAC;KAChB,CAAC;IACF,2FAA2F;IAC3F,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,eAAe,CAE7D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAGvF;AAED,kEAAkE;AAClE,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AA+FD,eAAO,MAAM,iBAAiB,EAAE,YAM/B,CAAC"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * The `judgement` kind — rules in plain English, with enough structure to be checkable.
3
+ *
4
+ * What rule this enforces, and why each field is REQUIRED rather than optional:
5
+ *
6
+ * - `examples` are the quality lever. A rule with a sentence and no examples flags everything,
7
+ * people stop reading the advisory stream, and the whole tier dies. The validator refuses to
8
+ * load one, which is the only moment anybody is willing to write examples.
9
+ * - `cite` forces falsifiability. The model must return the span it judged, and a verdict with no
10
+ * citation is discarded by the probe. That removes most confident-sounding noise for free.
11
+ *
12
+ * Severity is POLICED, not forced. Setting a judgement rule to `error` is allowed — it is policy,
13
+ * not a type constraint — but it emits a warning naming the rule, so promoting one is a visible
14
+ * act rather than a quiet default. `confidence` is forced to `model` regardless of what the
15
+ * manifest says, because a judgement rule is not deterministic however it is labelled.
16
+ */
17
+ import { err, ok } from '../result.js';
18
+ import { matchesAny } from '../util/glob.js';
19
+ export function asJudgementParams(rule) {
20
+ return rule.params;
21
+ }
22
+ export function judgementApplies(params, relativePath) {
23
+ const globs = typeof params.appliesTo === 'string' ? [params.appliesTo] : params.appliesTo;
24
+ return matchesAny(globs, relativePath);
25
+ }
26
+ /** `confidence` is not the manifest's to decide for this kind. */
27
+ export function effectiveConfidence() {
28
+ return 'model';
29
+ }
30
+ function validateParams(rule, _ctx) {
31
+ const params = rule.params;
32
+ const errors = [];
33
+ if (typeof params.statement !== 'string' || params.statement.trim().length === 0) {
34
+ errors.push('params.statement is required — the rule in one plain-English sentence');
35
+ }
36
+ const appliesTo = params.appliesTo;
37
+ const globs = typeof appliesTo === 'string' ? [appliesTo] : appliesTo;
38
+ if (!Array.isArray(globs) || globs.length === 0 || !globs.every((g) => typeof g === 'string')) {
39
+ errors.push('params.appliesTo is required — a path glob, or a list of them');
40
+ }
41
+ const examples = params.examples;
42
+ const isNonEmptyStrings = (value) => Array.isArray(value) &&
43
+ value.length > 0 &&
44
+ value.every((v) => typeof v === 'string' && v.trim().length > 0);
45
+ if (!isNonEmptyStrings(examples?.pass)) {
46
+ errors.push('params.examples.pass is required — at least one example that must NOT be flagged. ' +
47
+ 'A judgement rule with no examples flags everything, and the advisory stream dies');
48
+ }
49
+ if (!isNonEmptyStrings(examples?.fail)) {
50
+ errors.push('params.examples.fail is required — at least one example that MUST be flagged. ' +
51
+ 'Without it nothing proves the rule can fire');
52
+ }
53
+ if (typeof params.cite !== 'string' || params.cite.trim().length === 0) {
54
+ errors.push('params.cite is required — what the model must quote to justify a verdict. ' +
55
+ 'A verdict with no citation is discarded, which is what keeps this tier honest');
56
+ }
57
+ return errors.length > 0 ? err(errors) : ok(undefined);
58
+ }
59
+ /** Policed at load: allowed, but never quiet. */
60
+ function warnAboutRule(rule) {
61
+ const warnings = [];
62
+ if (rule.severity === 'error' || rule.severity === 'warn') {
63
+ warnings.push(`${rule.id}: a judgement rule at severity '${rule.severity}' can block a build on a ` +
64
+ 'non-deterministic verdict. That is allowed — it is policy — but it is the fastest way ' +
65
+ "for a check suite to lose trust. The default is 'advisory'.");
66
+ }
67
+ if (rule.confidence !== 'model') {
68
+ warnings.push(`${rule.id}: confidence '${rule.confidence}' is ignored for a judgement rule — it is always 'model'.`);
69
+ }
70
+ return warnings;
71
+ }
72
+ function emitFragments(rule, _ctx) {
73
+ const params = asJudgementParams(rule);
74
+ return [
75
+ {
76
+ // The model sink: what the judge reads. Emitted so the prompt is reviewable as a committed
77
+ // artefact rather than assembled invisibly at run time.
78
+ target: 'test',
79
+ ruleId: rule.id,
80
+ content: {
81
+ judge: true,
82
+ statement: params.statement,
83
+ files: typeof params.appliesTo === 'string' ? [params.appliesTo] : params.appliesTo,
84
+ examples: params.examples,
85
+ cite: params.cite,
86
+ message: `${rule.statement} — ${rule.remedy.summary}`,
87
+ },
88
+ },
89
+ ];
90
+ }
91
+ function explainFinding(finding, rule, _ctx) {
92
+ const evidence = finding.evidence;
93
+ return [
94
+ rule.statement,
95
+ ` ${finding.file}${finding.line === undefined ? '' : `:${finding.line}`}`,
96
+ ` cited: ${String(evidence.cited ?? '')}`,
97
+ ` the judge said: ${String(evidence.reason ?? '')}`,
98
+ ` → ${rule.remedy.summary}`,
99
+ ' (advisory: a model decided this, so treat it as a prompt to look, not a verdict)',
100
+ ].join('\n');
101
+ }
102
+ export const judgementContract = {
103
+ kind: 'judgement',
104
+ validate: validateParams,
105
+ warn: warnAboutRule,
106
+ emit: emitFragments,
107
+ explain: explainFinding,
108
+ };
109
+ //# sourceMappingURL=judgement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"judgement.js","sourceRoot":"","sources":["../../src/contracts/judgement.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * The `layers` kind — the dependency law.
3
+ *
4
+ * What rule this enforces: no module imports a module it is not declared to reach. Stated that
5
+ * precisely on purpose: "dependency direction is one-way" is the intent, and this is the part a
6
+ * machine can decide.
7
+ *
8
+ * DEFAULT DENY is a property of this kind, not a setting. Resolution order for an edge A → B:
9
+ *
10
+ * 1. A and B in the same layer → allowed
11
+ * 2. B is external → allowed (a separate rule governs dependencies)
12
+ * 3. B's layer ∈ A's layer.mayImport → allowed
13
+ * 4. anything else → VIOLATION
14
+ * 5. A matches no layer → VIOLATION: unlayered, a different message
15
+ *
16
+ * Case 5 matters more than it looks. A new folder nobody declared fails on its first commit
17
+ * rather than being silently legal, and that is the property that makes a rule set complete
18
+ * rather than merely non-empty.
19
+ *
20
+ * What a caller must know: one rule declares ONE layer, and the layer table is the set of all
21
+ * `layers` rules. A violation is attributed to the SOURCE layer's rule, because the source is
22
+ * what has to change.
23
+ */
24
+ import { describeMatch, type LayerMatch } from '../graph/match.js';
25
+ import type { Rule } from '../types.js';
26
+ import type { ContractType } from './types.js';
27
+ export type LayersParams = {
28
+ name: string;
29
+ match: LayerMatch;
30
+ /** Layer names this layer may import, or `'*'` for the composition root. */
31
+ mayImport: string[] | '*';
32
+ /**
33
+ * Exactly one `layers` rule owns the unlayered-file report. It needs an owner because a file
34
+ * that matches nothing has, by definition, no layer rule of its own to be attributed to — and
35
+ * a finding with no rule id has no statement, no remedy and no baseline entry.
36
+ */
37
+ catchesUnlayered?: boolean;
38
+ /** Exempt `import type` edges. Off by default: a type-only edge is still a dependency. */
39
+ ignoreTypeOnly?: boolean;
40
+ };
41
+ export type Layer = {
42
+ ruleId: string;
43
+ name: string;
44
+ match: LayerMatch;
45
+ mayImport: string[] | '*';
46
+ ignoreTypeOnly: boolean;
47
+ };
48
+ export type LayerTable = {
49
+ layers: readonly Layer[];
50
+ /** The rule id that owns the unlayered report, or undefined when no layers rule is active. */
51
+ unlayeredOwner: string | undefined;
52
+ };
53
+ export declare function asLayersParams(rule: Rule): LayersParams;
54
+ /** The layer table is the SET of layers rules — default deny cannot be decided from one. */
55
+ export declare function buildLayerTable(rules: readonly Rule[]): LayerTable;
56
+ export type EdgeVerdict = {
57
+ allowed: true;
58
+ } | {
59
+ allowed: false;
60
+ ruleId: string;
61
+ fromLayer: string;
62
+ toLayer: string;
63
+ mayImport: readonly string[];
64
+ };
65
+ /**
66
+ * The whole decision, as a pure function of layer names. No paths, no AST, no I/O — so the
67
+ * resolution order above is testable line by line without a fixture repo.
68
+ */
69
+ export declare function resolveEdge(table: LayerTable, fromLayer: Layer | undefined, toLayerName: string | undefined, edge: {
70
+ external: boolean;
71
+ typeOnly: boolean;
72
+ }): EdgeVerdict;
73
+ export declare const layersContract: ContractType;
74
+ export { describeMatch };
75
+ //# sourceMappingURL=layers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layers.d.ts","sourceRoot":"","sources":["../../src/contracts/layers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,aAAa,EAAmC,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpG,OAAO,KAAK,EAAwB,IAAI,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAgD,MAAM,YAAY,CAAC;AAE7F,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,UAAU,CAAC;IAClB,4EAA4E;IAC5E,SAAS,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IAC1B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,0FAA0F;IAC1F,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IAC1B,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IACzB,8FAA8F;IAC9F,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC,CAAC;AAEF,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,CAEvD;AAED,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,UAAU,CAgBlE;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GACjB;IACE,OAAO,EAAE,KAAK,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B,CAAC;AAEN;;;GAGG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,UAAU,EACjB,SAAS,EAAE,KAAK,GAAG,SAAS,EAC5B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,IAAI,EAAE;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GAC7C,WAAW,CAqBb;AA0LD,eAAO,MAAM,cAAc,EAAE,YAM5B,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,244 @@
1
+ /**
2
+ * The `layers` kind — the dependency law.
3
+ *
4
+ * What rule this enforces: no module imports a module it is not declared to reach. Stated that
5
+ * precisely on purpose: "dependency direction is one-way" is the intent, and this is the part a
6
+ * machine can decide.
7
+ *
8
+ * DEFAULT DENY is a property of this kind, not a setting. Resolution order for an edge A → B:
9
+ *
10
+ * 1. A and B in the same layer → allowed
11
+ * 2. B is external → allowed (a separate rule governs dependencies)
12
+ * 3. B's layer ∈ A's layer.mayImport → allowed
13
+ * 4. anything else → VIOLATION
14
+ * 5. A matches no layer → VIOLATION: unlayered, a different message
15
+ *
16
+ * Case 5 matters more than it looks. A new folder nobody declared fails on its first commit
17
+ * rather than being silently legal, and that is the property that makes a rule set complete
18
+ * rather than merely non-empty.
19
+ *
20
+ * What a caller must know: one rule declares ONE layer, and the layer table is the set of all
21
+ * `layers` rules. A violation is attributed to the SOURCE layer's rule, because the source is
22
+ * what has to change.
23
+ */
24
+ import { describeMatch, isImplementsMatch, isValidMatch } from '../graph/match.js';
25
+ import { err, ok } from '../result.js';
26
+ export function asLayersParams(rule) {
27
+ return rule.params;
28
+ }
29
+ /** The layer table is the SET of layers rules — default deny cannot be decided from one. */
30
+ export function buildLayerTable(rules) {
31
+ const active = rules.filter((rule) => rule.kind === 'layers' && rule.severity !== 'off');
32
+ const layers = active.map((rule) => {
33
+ const params = asLayersParams(rule);
34
+ return {
35
+ ruleId: rule.id,
36
+ name: params.name,
37
+ match: params.match,
38
+ mayImport: params.mayImport,
39
+ ignoreTypeOnly: params.ignoreTypeOnly === true,
40
+ };
41
+ });
42
+ const owner = active.find((rule) => asLayersParams(rule).catchesUnlayered === true)?.id ??
43
+ (active.length === 1 ? active[0]?.id : undefined);
44
+ return { layers, unlayeredOwner: owner };
45
+ }
46
+ /**
47
+ * The whole decision, as a pure function of layer names. No paths, no AST, no I/O — so the
48
+ * resolution order above is testable line by line without a fixture repo.
49
+ */
50
+ export function resolveEdge(table, fromLayer, toLayerName, edge) {
51
+ if (edge.external)
52
+ return { allowed: true };
53
+ if (fromLayer === undefined)
54
+ return { allowed: true };
55
+ if (fromLayer.ignoreTypeOnly && edge.typeOnly)
56
+ return { allowed: true };
57
+ if (toLayerName === undefined) {
58
+ // The target is internal but declared by nobody. Its own `unlayered` finding is the report:
59
+ // declaring the missing layer is the fix, and blaming the importer would send a reader to the
60
+ // wrong file.
61
+ return { allowed: true };
62
+ }
63
+ if (toLayerName === fromLayer.name)
64
+ return { allowed: true };
65
+ if (fromLayer.mayImport === '*')
66
+ return { allowed: true };
67
+ if (fromLayer.mayImport.includes(toLayerName))
68
+ return { allowed: true };
69
+ void table;
70
+ return {
71
+ allowed: false,
72
+ ruleId: fromLayer.ruleId,
73
+ fromLayer: fromLayer.name,
74
+ toLayer: toLayerName,
75
+ mayImport: fromLayer.mayImport,
76
+ };
77
+ }
78
+ /**
79
+ * Derive import-path patterns for a layer, for the lint sink. A layer matched by `implements`
80
+ * has no path form, so it contributes nothing here and the graph sink carries it alone — stated
81
+ * rather than silently dropped.
82
+ */
83
+ function pathPatternsFor(layer) {
84
+ if (isImplementsMatch(layer.match))
85
+ return [];
86
+ const globs = typeof layer.match === 'string' ? [layer.match] : layer.match;
87
+ return globs.filter((glob) => !glob.startsWith('!'));
88
+ }
89
+ function validateParams(rule, ctx) {
90
+ const params = rule.params;
91
+ const errors = [];
92
+ if (typeof params.name !== 'string' || params.name.length === 0) {
93
+ errors.push('params.name is required — a layer needs a name to be referred to');
94
+ }
95
+ if (!isValidMatch(params.match)) {
96
+ errors.push("params.match must be a glob, a list of globs, or { implements: 'PortName' } " +
97
+ `(got ${JSON.stringify(params.match)})`);
98
+ }
99
+ const mayImport = params.mayImport;
100
+ if (mayImport !== '*' && !Array.isArray(mayImport)) {
101
+ errors.push("params.mayImport must be a list of layer names, or '*' for the composition root");
102
+ }
103
+ else if (Array.isArray(mayImport)) {
104
+ const known = new Set(ctx.rules
105
+ .filter((other) => other.kind === 'layers')
106
+ .map((other) => other.params.name)
107
+ .filter((name) => typeof name === 'string'));
108
+ for (const name of mayImport) {
109
+ if (typeof name !== 'string') {
110
+ errors.push(`params.mayImport contains ${JSON.stringify(name)}, which is not a layer name`);
111
+ }
112
+ else if (!known.has(name)) {
113
+ errors.push(`params.mayImport names an unknown layer '${name}' — known layers are ${[...known].sort().join(', ')}`);
114
+ }
115
+ else if (name === params.name) {
116
+ errors.push(`params.mayImport lists its own layer '${name}' — a layer always reaches itself`);
117
+ }
118
+ }
119
+ }
120
+ const owners = ctx.rules.filter((other) => other.kind === 'layers' &&
121
+ other.severity !== 'off' &&
122
+ other.params.catchesUnlayered === true);
123
+ const activeLayers = ctx.rules.filter((other) => other.kind === 'layers' && other.severity !== 'off');
124
+ if (owners.length > 1) {
125
+ errors.push(`params.catchesUnlayered is set on ${owners.length} rules (${owners.map((o) => o.id).join(', ')}) — ` +
126
+ 'exactly one layers rule owns the unlayered-file report');
127
+ }
128
+ else if (owners.length === 0 && activeLayers.length > 1) {
129
+ errors.push('no layers rule sets params.catchesUnlayered — one must, or a folder nobody declared is ' +
130
+ 'silently legal, which is the failure default-deny exists to prevent');
131
+ }
132
+ return errors.length > 0 ? err(errors) : ok(undefined);
133
+ }
134
+ function emitFragments(rule, ctx) {
135
+ const table = buildLayerTable(ctx.rules);
136
+ const self = table.layers.find((layer) => layer.ruleId === rule.id);
137
+ if (!self)
138
+ return [];
139
+ const fragments = [
140
+ {
141
+ target: 'graph',
142
+ ruleId: rule.id,
143
+ content: {
144
+ layer: self.name,
145
+ match: self.match,
146
+ mayImport: self.mayImport,
147
+ ignoreTypeOnly: self.ignoreTypeOnly,
148
+ catchesUnlayered: table.unlayeredOwner === rule.id,
149
+ statement: rule.statement,
150
+ },
151
+ },
152
+ ];
153
+ const selfPatterns = pathPatternsFor(self);
154
+ if (selfPatterns.length === 0 || self.mayImport === '*')
155
+ return fragments;
156
+ const forbidden = table.layers
157
+ .filter((other) => other.name !== self.name && !self.mayImport.includes(other.name))
158
+ .flatMap((other) => pathPatternsFor(other).map((glob) => ({ layer: other.name, glob })));
159
+ if (forbidden.length === 0)
160
+ return fragments;
161
+ // The statement goes INTO the message. This is the fix for the biggest problem the review
162
+ // found: the editor squiggle shows the architecture's own sentence, not a rule name.
163
+ fragments.push({
164
+ target: 'lint',
165
+ ruleId: rule.id,
166
+ content: {
167
+ files: selfPatterns,
168
+ forbid: 'import-path-matching',
169
+ patterns: forbidden.map((entry) => entry.glob).sort(),
170
+ forbiddenLayers: [...new Set(forbidden.map((entry) => entry.layer))].sort(),
171
+ message: `${rule.statement} — ${rule.remedy.summary}`,
172
+ },
173
+ });
174
+ return fragments;
175
+ }
176
+ function explainFinding(finding, rule, ctx) {
177
+ const evidence = finding.evidence;
178
+ const fromLayer = String(evidence.fromLayer ?? '?');
179
+ const toLayer = evidence.toLayer === undefined ? undefined : String(evidence.toLayer);
180
+ // From the manifest, never from evidence — see ExplainCtx.
181
+ const params = asLayersParams(rule);
182
+ const allowed = params.mayImport === '*' ? ['anything'] : (params.mayImport ?? []);
183
+ if (evidence.unlayered === true) {
184
+ const declared = buildLayerTable(ctx.rules)
185
+ .layers.map((layer) => layer.name)
186
+ .sort()
187
+ .join(', ');
188
+ return [
189
+ `${finding.file} belongs to no declared layer`,
190
+ ` declared layers: ${declared}`,
191
+ ` → ${rule.remedy.summary}`,
192
+ ].join('\n');
193
+ }
194
+ return [
195
+ `${fromLayer} may not import ${toLayer ?? 'that'}`,
196
+ ` ${finding.file} → ${String(evidence.to ?? '')}`,
197
+ ` ${fromLayer} may import: ${allowed.length > 0 ? allowed.join(', ') : 'nothing'}`,
198
+ ` → ${rule.remedy.summary}`,
199
+ ].join('\n');
200
+ }
201
+ /**
202
+ * Case 5 of the resolution order needs its own words. "domain may import only contracts and rules"
203
+ * is true but irrelevant to a file that matched no layer, and "invert the call" is the wrong fix.
204
+ */
205
+ function refineFinding(finding, rule, ctx) {
206
+ const evidence = finding.evidence;
207
+ if (evidence.unlayered === true) {
208
+ const declared = buildLayerTable(ctx.rules)
209
+ .layers.map((layer) => layer.name)
210
+ .sort()
211
+ .join(', ');
212
+ return {
213
+ statement: `${finding.file} belongs to no declared layer`,
214
+ remedy: {
215
+ // Deliberately no `allowed` list here. The declared layers go in the sentence instead:
216
+ // labelling them "allowed" would say this file may import them, which is not the problem.
217
+ summary: `declare the layer this path belongs to in architecture.config.ts (declared so far: ` +
218
+ `${declared}), or move the file into one of them`,
219
+ },
220
+ };
221
+ }
222
+ const fromLayer = evidence.fromLayer;
223
+ const toLayer = evidence.toLayer;
224
+ if (typeof fromLayer === 'string' && typeof toLayer === 'string') {
225
+ const params = asLayersParams(rule);
226
+ return {
227
+ statement: `${fromLayer} may not import ${toLayer}`,
228
+ remedy: {
229
+ ...rule.remedy,
230
+ allowed: params.mayImport === '*' ? ['anything'] : (params.mayImport ?? []),
231
+ },
232
+ };
233
+ }
234
+ return undefined;
235
+ }
236
+ export const layersContract = {
237
+ kind: 'layers',
238
+ validate: validateParams,
239
+ emit: emitFragments,
240
+ explain: explainFinding,
241
+ refine: refineFinding,
242
+ };
243
+ export { describeMatch };
244
+ //# sourceMappingURL=layers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layers.js","sourceRoot":"","sources":["../../src/contracts/layers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,YAAY,EAAmB,MAAM,mBAAmB,CAAC;AACpG,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,cAAc,CAAC;AAiCpD,MAAM,UAAU,cAAc,CAAC,IAAU;IACvC,OAAO,IAAI,CAAC,MAAiC,CAAC;AAChD,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,eAAe,CAAC,KAAsB;IACpD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC;IACzF,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACjC,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACpC,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,cAAc,EAAE,MAAM,CAAC,cAAc,KAAK,IAAI;SAC/C,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,MAAM,KAAK,GACT,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,gBAAgB,KAAK,IAAI,CAAC,EAAE,EAAE;QACzE,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACpD,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC;AAC3C,CAAC;AAYD;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,KAAiB,EACjB,SAA4B,EAC5B,WAA+B,EAC/B,IAA8C;IAE9C,IAAI,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC5C,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACtD,IAAI,SAAS,CAAC,cAAc,IAAI,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACxE,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,4FAA4F;QAC5F,8FAA8F;QAC9F,cAAc;QACd,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IACD,IAAI,WAAW,KAAK,SAAS,CAAC,IAAI;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC7D,IAAI,SAAS,CAAC,SAAS,KAAK,GAAG;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC1D,IAAI,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACxE,KAAK,KAAK,CAAC;IACX,OAAO;QACL,OAAO,EAAE,KAAK;QACd,MAAM,EAAE,SAAS,CAAC,MAAM;QACxB,SAAS,EAAE,SAAS,CAAC,IAAI;QACzB,OAAO,EAAE,WAAW;QACpB,SAAS,EAAE,SAAS,CAAC,SAAS;KAC/B,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,KAAY;IACnC,IAAI,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC9C,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;IAC5E,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,cAAc,CAAC,IAAU,EAAE,GAAgB;IAClD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAiC,CAAC;IACtD,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChE,MAAM,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;IAClF,CAAC;IACD,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,MAAM,CAAC,IAAI,CACT,8EAA8E;YAC5E,QAAQ,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAC1C,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IACnC,IAAI,SAAS,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACnD,MAAM,CAAC,IAAI,CAAC,iFAAiF,CAAC,CAAC;IACjG,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,IAAI,GAAG,CACnB,GAAG,CAAC,KAAK;aACN,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC;aAC1C,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAE,KAAK,CAAC,MAAkC,CAAC,IAAI,CAAC;aAC9D,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAC9D,CAAC;QACF,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC7B,MAAM,CAAC,IAAI,CAAC,6BAA6B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;YAC9F,CAAC;iBAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,MAAM,CAAC,IAAI,CACT,4CAA4C,IAAI,wBAAwB,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACvG,CAAC;YACJ,CAAC;iBAAM,IAAI,IAAI,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC;gBAChC,MAAM,CAAC,IAAI,CACT,yCAAyC,IAAI,mCAAmC,CACjF,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAC7B,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,IAAI,KAAK,QAAQ;QACvB,KAAK,CAAC,QAAQ,KAAK,KAAK;QACvB,KAAK,CAAC,MAAkC,CAAC,gBAAgB,KAAK,IAAI,CACtE,CAAC;IACF,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CACnC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,QAAQ,KAAK,KAAK,CAC/D,CAAC;IACF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,IAAI,CACT,qCAAqC,MAAM,CAAC,MAAM,WAAW,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;YACnG,wDAAwD,CAC3D,CAAC;IACJ,CAAC;SAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1D,MAAM,CAAC,IAAI,CACT,yFAAyF;YACvF,qEAAqE,CACxE,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,aAAa,CAAC,IAAU,EAAE,GAAY;IAC7C,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC;IACpE,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IAErB,MAAM,SAAS,GAAe;QAC5B;YACE,MAAM,EAAE,OAAO;YACf,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,OAAO,EAAE;gBACP,KAAK,EAAE,IAAI,CAAC,IAAI;gBAChB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,cAAc,EAAE,IAAI,CAAC,cAAc;gBACnC,gBAAgB,EAAE,KAAK,CAAC,cAAc,KAAK,IAAI,CAAC,EAAE;gBAClD,SAAS,EAAE,IAAI,CAAC,SAAS;aAC1B;SACF;KACF,CAAC;IAEF,MAAM,YAAY,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,KAAK,GAAG;QAAE,OAAO,SAAS,CAAC;IAE1E,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM;SAC3B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;SACnF,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3F,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAE7C,0FAA0F;IAC1F,qFAAqF;IACrF,SAAS,CAAC,IAAI,CAAC;QACb,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,OAAO,EAAE;YACP,KAAK,EAAE,YAAY;YACnB,MAAM,EAAE,sBAAsB;YAC9B,QAAQ,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE;YACrD,eAAe,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;YAC3E,OAAO,EAAE,GAAG,IAAI,CAAC,SAAS,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;SACtD;KACF,CAAC,CAAC;IAEH,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,cAAc,CAAC,OAAmB,EAAE,IAAU,EAAE,GAAe;IACtE,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAmC,CAAC;IAC7D,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,IAAI,GAAG,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACtF,2DAA2D;IAC3D,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IAEnF,IAAI,QAAQ,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC;aACxC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;aACjC,IAAI,EAAE;aACN,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,OAAO;YACL,GAAG,OAAO,CAAC,IAAI,+BAA+B;YAC9C,sBAAsB,QAAQ,EAAE;YAChC,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;SAC7B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;IAED,OAAO;QACL,GAAG,SAAS,mBAAmB,OAAO,IAAI,MAAM,EAAE;QAClD,KAAK,OAAO,CAAC,IAAI,MAAM,MAAM,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE;QAClD,KAAK,SAAS,gBAAgB,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE;QACnF,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;KAC7B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,SAAS,aAAa,CAAC,OAAmB,EAAE,IAAU,EAAE,GAAe;IACrE,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAmC,CAAC;IAC7D,IAAI,QAAQ,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC;aACxC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;aACjC,IAAI,EAAE;aACN,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,OAAO;YACL,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,+BAA+B;YACzD,MAAM,EAAE;gBACN,uFAAuF;gBACvF,0FAA0F;gBAC1F,OAAO,EACL,qFAAqF;oBACrF,GAAG,QAAQ,sCAAsC;aACpD;SACF,CAAC;IACJ,CAAC;IACD,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAC;IACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;IACjC,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QACjE,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACpC,OAAO;YACL,SAAS,EAAE,GAAG,SAAS,mBAAmB,OAAO,EAAE;YACnD,MAAM,EAAE;gBACN,GAAG,IAAI,CAAC,MAAM;gBACd,OAAO,EAAE,MAAM,CAAC,SAAS,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;aAC5E;SACF,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAiB;IAC1C,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,cAAc;IACxB,IAAI,EAAE,aAAa;IACnB,OAAO,EAAE,cAAc;IACvB,MAAM,EAAE,aAAa;CACtB,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { Rule } from '../types.js';
2
+ import type { ContractType } from './types.js';
3
+ /** What is being named. */
4
+ export type NamingTarget = 'files' | 'exports' | 'both';
5
+ export type NamingParams = {
6
+ /** Path globs. A leading `!` excludes, so entry points can be carved out. */
7
+ appliesTo: string | string[];
8
+ target?: NamingTarget;
9
+ /** A regular expression the name must match. */
10
+ pattern?: string;
11
+ /** Sugar for the commonest case: the name must start with one of these. */
12
+ prefixes?: string[];
13
+ };
14
+ export declare function asNamingParams(rule: Rule): NamingParams;
15
+ export declare function appliesToGlobs(appliesTo: string | string[]): string[];
16
+ export declare function namingApplies(params: NamingParams, relativePath: string): boolean;
17
+ /** True when the name is acceptable. */
18
+ export declare function nameIsWellFormed(params: NamingParams, name: string): boolean;
19
+ export declare function describeExpectation(params: NamingParams): string;
20
+ export declare const namingContract: ContractType;
21
+ //# sourceMappingURL=naming.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"naming.d.ts","sourceRoot":"","sources":["../../src/contracts/naming.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAwB,IAAI,EAAE,MAAM,aAAa,CAAC;AAE9D,OAAO,KAAK,EAAE,YAAY,EAAgD,MAAM,YAAY,CAAC;AAE7F,2BAA2B;AAC3B,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAExD,MAAM,MAAM,YAAY,GAAG;IACzB,6EAA6E;IAC7E,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC;AAEF,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,CAEvD;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,CAErE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAEjF;AAED,wCAAwC;AACxC,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAO5E;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAOhE;AAgFD,eAAO,MAAM,cAAc,EAAE,YAM5B,CAAC"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * The `naming` kind. Thirty-one of the ninety-one rules land in this kind and the next, which makes
3
+ * these two the highest coverage per unit of work in the whole plan set (plan 12).
4
+ *
5
+ * What rule this enforces: hook `use` prefix, twin factories (`createMemory*`), selectors
6
+ * (`select*`), boolean prefixes, filenames, test-id casing. All of them are "this name must look
7
+ * like this", so all of them are one kind.
8
+ *
9
+ * What a caller must know: `appliesTo` is a path GLOB (which files this rule looks at) and
10
+ * `pattern` is a REGULAR EXPRESSION (what the name must look like). Two different jobs, so two
11
+ * different languages — a glob cannot say "camelCase", and a regex over paths reads badly.
12
+ * `remedy.autofix` stays false: renaming an export is a change to every caller.
13
+ */
14
+ import { err, ok } from '../result.js';
15
+ import { matchesAny } from '../util/glob.js';
16
+ export function asNamingParams(rule) {
17
+ return rule.params;
18
+ }
19
+ export function appliesToGlobs(appliesTo) {
20
+ return typeof appliesTo === 'string' ? [appliesTo] : appliesTo;
21
+ }
22
+ export function namingApplies(params, relativePath) {
23
+ return matchesAny(appliesToGlobs(params.appliesTo), relativePath);
24
+ }
25
+ /** True when the name is acceptable. */
26
+ export function nameIsWellFormed(params, name) {
27
+ if (params.prefixes && params.prefixes.length > 0) {
28
+ if (params.prefixes.some((prefix) => name.startsWith(prefix)))
29
+ return true;
30
+ if (params.pattern === undefined)
31
+ return false;
32
+ }
33
+ if (params.pattern === undefined)
34
+ return true;
35
+ return new RegExp(params.pattern).test(name);
36
+ }
37
+ export function describeExpectation(params) {
38
+ const parts = [];
39
+ if (params.prefixes && params.prefixes.length > 0) {
40
+ parts.push(`start with ${params.prefixes.map((p) => `'${p}'`).join(' or ')}`);
41
+ }
42
+ if (params.pattern !== undefined)
43
+ parts.push(`match /${params.pattern}/`);
44
+ return parts.join(', or ');
45
+ }
46
+ function validateParams(rule, _ctx) {
47
+ const params = rule.params;
48
+ const errors = [];
49
+ const appliesTo = params.appliesTo;
50
+ const globs = typeof appliesTo === 'string' ? [appliesTo] : appliesTo;
51
+ if (!Array.isArray(globs) || globs.length === 0 || !globs.every((g) => typeof g === 'string')) {
52
+ errors.push('params.appliesTo is required — a path glob, or a list of them');
53
+ }
54
+ if (params.target !== undefined &&
55
+ !['files', 'exports', 'both'].includes(String(params.target))) {
56
+ errors.push(`params.target must be files | exports | both (got ${JSON.stringify(params.target)})`);
57
+ }
58
+ const hasPattern = typeof params.pattern === 'string' && params.pattern.length > 0;
59
+ const hasPrefixes = Array.isArray(params.prefixes) && params.prefixes.length > 0;
60
+ if (!hasPattern && !hasPrefixes) {
61
+ errors.push('params needs a pattern or prefixes — a naming rule with neither matches nothing');
62
+ }
63
+ if (hasPattern) {
64
+ try {
65
+ new RegExp(params.pattern);
66
+ }
67
+ catch (error) {
68
+ errors.push(`params.pattern is not a valid regular expression: ${error.message}`);
69
+ }
70
+ }
71
+ if (params.prefixes !== undefined && !Array.isArray(params.prefixes)) {
72
+ errors.push('params.prefixes must be a list of strings');
73
+ }
74
+ return errors.length > 0 ? err(errors) : ok(undefined);
75
+ }
76
+ function emitFragments(rule, _ctx) {
77
+ const params = asNamingParams(rule);
78
+ return [
79
+ {
80
+ target: 'lint',
81
+ ruleId: rule.id,
82
+ content: {
83
+ files: appliesToGlobs(params.appliesTo),
84
+ forbid: 'name-not-matching',
85
+ target: params.target ?? 'exports',
86
+ ...(params.pattern === undefined ? {} : { pattern: params.pattern }),
87
+ ...(params.prefixes === undefined ? {} : { prefixes: params.prefixes }),
88
+ // The statement goes into the message, so the editor shows the rule's own sentence.
89
+ message: `${rule.statement} — ${rule.remedy.summary}`,
90
+ autofix: false,
91
+ },
92
+ },
93
+ ];
94
+ }
95
+ function explainFinding(finding, rule, _ctx) {
96
+ const evidence = finding.evidence;
97
+ const what = evidence.namedThing === 'file' ? 'file' : 'export';
98
+ return [
99
+ `${what} '${String(evidence.name)}' does not follow the naming rule`,
100
+ ` ${finding.file}`,
101
+ ` expected: ${describeExpectation(asNamingParams(rule))}`,
102
+ ` → ${rule.remedy.summary}`,
103
+ ].join('\n');
104
+ }
105
+ function refineFinding(finding, rule) {
106
+ const evidence = finding.evidence;
107
+ const what = evidence.namedThing === 'file' ? 'file' : 'export';
108
+ return {
109
+ statement: `${what} '${String(evidence.name)}' must ${describeExpectation(asNamingParams(rule))}`,
110
+ remedy: { ...rule.remedy, autofix: false },
111
+ };
112
+ }
113
+ export const namingContract = {
114
+ kind: 'naming',
115
+ validate: validateParams,
116
+ emit: emitFragments,
117
+ explain: explainFinding,
118
+ refine: refineFinding,
119
+ };
120
+ //# sourceMappingURL=naming.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"naming.js","sourceRoot":"","sources":["../../src/contracts/naming.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * kind → ContractType.
3
+ *
4
+ * What a caller must know: a kind in the closed set of eight that has no entry here is not a
5
+ * config error. It validates, it counts toward coverage, and the run records a skip saying no
6
+ * probe handles it. That is deliberate: rejecting a `judgement` rule on a version that has not
7
+ * shipped the model probe would force a consumer to delete rules in order to upgrade, and the
8
+ * honest report is "declared, not checked yet" — which is exactly what `skipped` is for.
9
+ */
10
+ import { type Result } from '../result.js';
11
+ import type { ContractKind, Rule } from '../types.js';
12
+ import type { ContractType } from './types.js';
13
+ export declare function contractFor(kind: ContractKind): ContractType | undefined;
14
+ export declare function implementedKinds(): readonly ContractKind[];
15
+ /**
16
+ * The ParamsValidator the registry needs, wired to the kinds. Injected by the facade, which is the
17
+ * only place that knows both halves — the registry knows a rule has a kind, and only a kind knows
18
+ * what its params mean.
19
+ */
20
+ export declare function validateParamsByKind(rule: Rule, rules: readonly Rule[]): Result<void>;
21
+ /** Things that load fine but somebody should see. Printed by the CLI, never silently dropped. */
22
+ export declare function warningsFor(rules: readonly Rule[]): string[];
23
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/contracts/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAM,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAQtD,OAAO,KAAK,EAAE,YAAY,EAAe,MAAM,YAAY,CAAC;AAc5D,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,YAAY,GAAG,SAAS,CAExE;AAED,wBAAgB,gBAAgB,IAAI,SAAS,YAAY,EAAE,CAE1D;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAGrF;AAED,iGAAiG;AACjG,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,MAAM,EAAE,CAG5D"}