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.
- package/LICENSE +21 -0
- package/README.md +536 -0
- package/dist/archcheck.d.ts +99 -0
- package/dist/archcheck.d.ts.map +1 -0
- package/dist/archcheck.js +339 -0
- package/dist/archcheck.js.map +1 -0
- package/dist/baseline/index.d.ts +29 -0
- package/dist/baseline/index.d.ts.map +1 -0
- package/dist/baseline/index.js +116 -0
- package/dist/baseline/index.js.map +1 -0
- package/dist/cli/args.d.ts +36 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +233 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/index.d.ts +4 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +219 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/version.d.ts +2 -0
- package/dist/cli/version.d.ts.map +1 -0
- package/dist/cli/version.js +29 -0
- package/dist/cli/version.js.map +1 -0
- package/dist/contracts/banned-syntax.d.ts +48 -0
- package/dist/contracts/banned-syntax.d.ts.map +1 -0
- package/dist/contracts/banned-syntax.js +201 -0
- package/dist/contracts/banned-syntax.js.map +1 -0
- package/dist/contracts/declared-field.d.ts +39 -0
- package/dist/contracts/declared-field.d.ts.map +1 -0
- package/dist/contracts/declared-field.js +142 -0
- package/dist/contracts/declared-field.js.map +1 -0
- package/dist/contracts/encapsulation.d.ts +28 -0
- package/dist/contracts/encapsulation.d.ts.map +1 -0
- package/dist/contracts/encapsulation.js +130 -0
- package/dist/contracts/encapsulation.js.map +1 -0
- package/dist/contracts/index.d.ts +10 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +9 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/contracts/judgement.d.ts +21 -0
- package/dist/contracts/judgement.d.ts.map +1 -0
- package/dist/contracts/judgement.js +109 -0
- package/dist/contracts/judgement.js.map +1 -0
- package/dist/contracts/layers.d.ts +75 -0
- package/dist/contracts/layers.d.ts.map +1 -0
- package/dist/contracts/layers.js +244 -0
- package/dist/contracts/layers.js.map +1 -0
- package/dist/contracts/naming.d.ts +21 -0
- package/dist/contracts/naming.d.ts.map +1 -0
- package/dist/contracts/naming.js +120 -0
- package/dist/contracts/naming.js.map +1 -0
- package/dist/contracts/registry.d.ts +23 -0
- package/dist/contracts/registry.d.ts.map +1 -0
- package/dist/contracts/registry.js +48 -0
- package/dist/contracts/registry.js.map +1 -0
- package/dist/contracts/required-file.d.ts +29 -0
- package/dist/contracts/required-file.d.ts.map +1 -0
- package/dist/contracts/required-file.js +131 -0
- package/dist/contracts/required-file.js.map +1 -0
- package/dist/contracts/types.d.ts +61 -0
- package/dist/contracts/types.d.ts.map +1 -0
- package/dist/contracts/types.js +2 -0
- package/dist/contracts/types.js.map +1 -0
- package/dist/coverage/index.d.ts +55 -0
- package/dist/coverage/index.d.ts.map +1 -0
- package/dist/coverage/index.js +68 -0
- package/dist/coverage/index.js.map +1 -0
- package/dist/emit/collect.d.ts +20 -0
- package/dist/emit/collect.d.ts.map +1 -0
- package/dist/emit/collect.js +17 -0
- package/dist/emit/collect.js.map +1 -0
- package/dist/emit/header.d.ts +21 -0
- package/dist/emit/header.d.ts.map +1 -0
- package/dist/emit/header.js +20 -0
- package/dist/emit/header.js.map +1 -0
- package/dist/emit/index.d.ts +57 -0
- package/dist/emit/index.d.ts.map +1 -0
- package/dist/emit/index.js +128 -0
- package/dist/emit/index.js.map +1 -0
- package/dist/emit/merge.d.ts +23 -0
- package/dist/emit/merge.d.ts.map +1 -0
- package/dist/emit/merge.js +71 -0
- package/dist/emit/merge.js.map +1 -0
- package/dist/emit/write.d.ts +20 -0
- package/dist/emit/write.d.ts.map +1 -0
- package/dist/emit/write.js +61 -0
- package/dist/emit/write.js.map +1 -0
- package/dist/exceptions/index.d.ts +46 -0
- package/dist/exceptions/index.d.ts.map +1 -0
- package/dist/exceptions/index.js +117 -0
- package/dist/exceptions/index.js.map +1 -0
- package/dist/fs/index.d.ts +12 -0
- package/dist/fs/index.d.ts.map +1 -0
- package/dist/fs/index.js +78 -0
- package/dist/fs/index.js.map +1 -0
- package/dist/graph/cache.d.ts +12 -0
- package/dist/graph/cache.d.ts.map +1 -0
- package/dist/graph/cache.js +76 -0
- package/dist/graph/cache.js.map +1 -0
- package/dist/graph/edges.d.ts +16 -0
- package/dist/graph/edges.d.ts.map +1 -0
- package/dist/graph/edges.js +161 -0
- package/dist/graph/edges.js.map +1 -0
- package/dist/graph/index.d.ts +15 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +90 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/match.d.ts +12 -0
- package/dist/graph/match.d.ts.map +1 -0
- package/dist/graph/match.js +35 -0
- package/dist/graph/match.js.map +1 -0
- package/dist/graph/program.d.ts +12 -0
- package/dist/graph/program.d.ts.map +1 -0
- package/dist/graph/program.js +54 -0
- package/dist/graph/program.js.map +1 -0
- package/dist/graph/types.d.ts +55 -0
- package/dist/graph/types.d.ts.map +1 -0
- package/dist/graph/types.js +2 -0
- package/dist/graph/types.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/init/index.d.ts +23 -0
- package/dist/init/index.d.ts.map +1 -0
- package/dist/init/index.js +218 -0
- package/dist/init/index.js.map +1 -0
- package/dist/normalize/identity.d.ts +4 -0
- package/dist/normalize/identity.d.ts.map +1 -0
- package/dist/normalize/identity.js +33 -0
- package/dist/normalize/identity.js.map +1 -0
- package/dist/normalize/index.d.ts +3 -0
- package/dist/normalize/index.d.ts.map +1 -0
- package/dist/normalize/index.js +3 -0
- package/dist/normalize/index.js.map +1 -0
- package/dist/normalize/normalize.d.ts +34 -0
- package/dist/normalize/normalize.d.ts.map +1 -0
- package/dist/normalize/normalize.js +91 -0
- package/dist/normalize/normalize.js.map +1 -0
- package/dist/probes/graph.d.ts +19 -0
- package/dist/probes/graph.d.ts.map +1 -0
- package/dist/probes/graph.js +181 -0
- package/dist/probes/graph.js.map +1 -0
- package/dist/probes/index.d.ts +5 -0
- package/dist/probes/index.d.ts.map +1 -0
- package/dist/probes/index.js +5 -0
- package/dist/probes/index.js.map +1 -0
- package/dist/probes/lint.d.ts +17 -0
- package/dist/probes/lint.d.ts.map +1 -0
- package/dist/probes/lint.js +121 -0
- package/dist/probes/lint.js.map +1 -0
- package/dist/probes/model/anthropic.d.ts +47 -0
- package/dist/probes/model/anthropic.d.ts.map +1 -0
- package/dist/probes/model/anthropic.js +100 -0
- package/dist/probes/model/anthropic.js.map +1 -0
- package/dist/probes/model/budget.d.ts +22 -0
- package/dist/probes/model/budget.d.ts.map +1 -0
- package/dist/probes/model/budget.js +27 -0
- package/dist/probes/model/budget.js.map +1 -0
- package/dist/probes/model/cache.d.ts +13 -0
- package/dist/probes/model/cache.d.ts.map +1 -0
- package/dist/probes/model/cache.js +74 -0
- package/dist/probes/model/cache.js.map +1 -0
- package/dist/probes/model/index.d.ts +20 -0
- package/dist/probes/model/index.d.ts.map +1 -0
- package/dist/probes/model/index.js +160 -0
- package/dist/probes/model/index.js.map +1 -0
- package/dist/probes/model/prompt.d.ts +16 -0
- package/dist/probes/model/prompt.d.ts.map +1 -0
- package/dist/probes/model/prompt.js +57 -0
- package/dist/probes/model/prompt.js.map +1 -0
- package/dist/probes/model/provider.d.ts +88 -0
- package/dist/probes/model/provider.d.ts.map +1 -0
- package/dist/probes/model/provider.js +48 -0
- package/dist/probes/model/provider.js.map +1 -0
- package/dist/probes/structure.d.ts +3 -0
- package/dist/probes/structure.d.ts.map +1 -0
- package/dist/probes/structure.js +95 -0
- package/dist/probes/structure.js.map +1 -0
- package/dist/probes/types.d.ts +46 -0
- package/dist/probes/types.d.ts.map +1 -0
- package/dist/probes/types.js +15 -0
- package/dist/probes/types.js.map +1 -0
- package/dist/registry/define.d.ts +40 -0
- package/dist/registry/define.d.ts.map +1 -0
- package/dist/registry/define.js +4 -0
- package/dist/registry/define.js.map +1 -0
- package/dist/registry/ids.d.ts +19 -0
- package/dist/registry/ids.d.ts.map +1 -0
- package/dist/registry/ids.js +86 -0
- package/dist/registry/ids.js.map +1 -0
- package/dist/registry/index.d.ts +45 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +71 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/registry/load.d.ts +14 -0
- package/dist/registry/load.d.ts.map +1 -0
- package/dist/registry/load.js +108 -0
- package/dist/registry/load.js.map +1 -0
- package/dist/registry/validate.d.ts +24 -0
- package/dist/registry/validate.d.ts.map +1 -0
- package/dist/registry/validate.js +160 -0
- package/dist/registry/validate.js.map +1 -0
- package/dist/report/index.d.ts +10 -0
- package/dist/report/index.d.ts.map +1 -0
- package/dist/report/index.js +30 -0
- package/dist/report/index.js.map +1 -0
- package/dist/report/json.d.ts +20 -0
- package/dist/report/json.d.ts.map +1 -0
- package/dist/report/json.js +34 -0
- package/dist/report/json.js.map +1 -0
- package/dist/report/sarif.d.ts +21 -0
- package/dist/report/sarif.d.ts.map +1 -0
- package/dist/report/sarif.js +138 -0
- package/dist/report/sarif.js.map +1 -0
- package/dist/report/terminal.d.ts +3 -0
- package/dist/report/terminal.d.ts.map +1 -0
- package/dist/report/terminal.js +117 -0
- package/dist/report/terminal.js.map +1 -0
- package/dist/report/types.d.ts +28 -0
- package/dist/report/types.d.ts.map +1 -0
- package/dist/report/types.js +11 -0
- package/dist/report/types.js.map +1 -0
- package/dist/report/verdict.d.ts +21 -0
- package/dist/report/verdict.d.ts.map +1 -0
- package/dist/report/verdict.js +31 -0
- package/dist/report/verdict.js.map +1 -0
- package/dist/result.d.ts +22 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +19 -0
- package/dist/result.js.map +1 -0
- package/dist/types.d.ts +178 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/dist/util/compilerApi.d.ts +2 -0
- package/dist/util/compilerApi.d.ts.map +1 -0
- package/dist/util/compilerApi.js +28 -0
- package/dist/util/compilerApi.js.map +1 -0
- package/dist/util/glob.d.ts +43 -0
- package/dist/util/glob.d.ts.map +1 -0
- package/dist/util/glob.js +195 -0
- package/dist/util/glob.js.map +1 -0
- package/dist/util/paths.d.ts +6 -0
- package/dist/util/paths.d.ts.map +1 -0
- package/dist/util/paths.js +22 -0
- package/dist/util/paths.js.map +1 -0
- package/dist/version.d.ts +13 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +12 -0
- package/dist/version.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,48 @@
|
|
|
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 { ok } from '../result.js';
|
|
11
|
+
import { bannedSyntaxContract } from './banned-syntax.js';
|
|
12
|
+
import { declaredFieldContract } from './declared-field.js';
|
|
13
|
+
import { encapsulationContract } from './encapsulation.js';
|
|
14
|
+
import { judgementContract } from './judgement.js';
|
|
15
|
+
import { layersContract } from './layers.js';
|
|
16
|
+
import { namingContract } from './naming.js';
|
|
17
|
+
import { requiredFileContract } from './required-file.js';
|
|
18
|
+
const IMPLEMENTED = [
|
|
19
|
+
layersContract,
|
|
20
|
+
encapsulationContract,
|
|
21
|
+
namingContract,
|
|
22
|
+
bannedSyntaxContract,
|
|
23
|
+
requiredFileContract,
|
|
24
|
+
declaredFieldContract,
|
|
25
|
+
judgementContract,
|
|
26
|
+
];
|
|
27
|
+
const byKind = new Map(IMPLEMENTED.map((c) => [c.kind, c]));
|
|
28
|
+
export function contractFor(kind) {
|
|
29
|
+
return byKind.get(kind);
|
|
30
|
+
}
|
|
31
|
+
export function implementedKinds() {
|
|
32
|
+
return IMPLEMENTED.map((contract) => contract.kind);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The ParamsValidator the registry needs, wired to the kinds. Injected by the facade, which is the
|
|
36
|
+
* only place that knows both halves — the registry knows a rule has a kind, and only a kind knows
|
|
37
|
+
* what its params mean.
|
|
38
|
+
*/
|
|
39
|
+
export function validateParamsByKind(rule, rules) {
|
|
40
|
+
const ctx = { rules };
|
|
41
|
+
return contractFor(rule.kind)?.validate(rule, ctx) ?? ok(undefined);
|
|
42
|
+
}
|
|
43
|
+
/** Things that load fine but somebody should see. Printed by the CLI, never silently dropped. */
|
|
44
|
+
export function warningsFor(rules) {
|
|
45
|
+
const ctx = { rules };
|
|
46
|
+
return rules.flatMap((rule) => contractFor(rule.kind)?.warn?.(rule, ctx) ?? []);
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/contracts/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,EAAE,EAAe,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAG1D,MAAM,WAAW,GAA4B;IAC3C,cAAc;IACd,qBAAqB;IACrB,cAAc;IACd,oBAAoB;IACpB,oBAAoB;IACpB,qBAAqB;IACrB,iBAAiB;CAClB,CAAC;AAEF,MAAM,MAAM,GAAG,IAAI,GAAG,CAA6B,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAExF,MAAM,UAAU,WAAW,CAAC,IAAkB;IAC5C,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACtD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAU,EAAE,KAAsB;IACrE,MAAM,GAAG,GAAgB,EAAE,KAAK,EAAE,CAAC;IACnC,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,CAAC;AACtE,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,WAAW,CAAC,KAAsB;IAChD,MAAM,GAAG,GAAgB,EAAE,KAAK,EAAE,CAAC;IACnC,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;AAClF,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Rule } from '../types.js';
|
|
2
|
+
import type { ContractType } from './types.js';
|
|
3
|
+
export type RequiredFileParams = {
|
|
4
|
+
/** A path glob, or a registry selector like `rule[severity=error]`. */
|
|
5
|
+
forEach: string;
|
|
6
|
+
/**
|
|
7
|
+
* A path template. `{id}` for a rule; for a file, `{dir}`, `{name}`, `{base}`, `{ext}` and
|
|
8
|
+
* `{Base}` — the base with its first letter capitalised, which is what the twin convention
|
|
9
|
+
* `blobStore.ts` → `memoryBlobStore.ts` actually needs.
|
|
10
|
+
*/
|
|
11
|
+
expect: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function asRequiredFileParams(rule: Rule): RequiredFileParams;
|
|
14
|
+
export declare function isRuleSelector(forEach: string): boolean;
|
|
15
|
+
/** One thing that must have a companion file. */
|
|
16
|
+
export type RequiredSubject = {
|
|
17
|
+
/** The file the finding is reported AGAINST — the subject that lacks the companion. */
|
|
18
|
+
subject: string;
|
|
19
|
+
/** What is missing. */
|
|
20
|
+
expected: string;
|
|
21
|
+
/** For evidence and for the message. */
|
|
22
|
+
label: string;
|
|
23
|
+
};
|
|
24
|
+
export declare function subjectsFor(params: RequiredFileParams, ctx: {
|
|
25
|
+
rules: readonly Rule[];
|
|
26
|
+
files: readonly string[];
|
|
27
|
+
}): RequiredSubject[];
|
|
28
|
+
export declare const requiredFileContract: ContractType;
|
|
29
|
+
//# sourceMappingURL=required-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"required-file.d.ts","sourceRoot":"","sources":["../../src/contracts/required-file.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAwB,IAAI,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAgD,MAAM,YAAY,CAAC;AAE7F,MAAM,MAAM,kBAAkB,GAAG;IAC/B,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,GAAG,kBAAkB,CAEnE;AAID,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED,iDAAiD;AACjD,MAAM,MAAM,eAAe,GAAG;IAC5B,uFAAuF;IACvF,OAAO,EAAE,MAAM,CAAC;IAChB,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAiCF,wBAAgB,WAAW,CACzB,MAAM,EAAE,kBAAkB,EAC1B,GAAG,EAAE;IAAE,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACxD,eAAe,EAAE,CAqBnB;AA+DD,eAAO,MAAM,oBAAoB,EAAE,YAMlC,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `required-file` kind — rules about what must EXIST.
|
|
3
|
+
*
|
|
4
|
+
* What this covers that a graph cannot see: every port has a memory twin, every primitive has a
|
|
5
|
+
* story, every error-severity rule has a fixture. Existence is the rule; the content of the
|
|
6
|
+
* required file is deliberately out of scope, because "a file is there" is decidable and "the file
|
|
7
|
+
* is any good" is not.
|
|
8
|
+
*
|
|
9
|
+
* The self-referential case is the important one (plan 16):
|
|
10
|
+
*
|
|
11
|
+
* { forEach: 'rule[severity=error]', expect: 'fixtures/rules/{id}.violation.ts' }
|
|
12
|
+
*
|
|
13
|
+
* A rule that cannot catch a deliberate violation passes every build and looks exactly like
|
|
14
|
+
* compliance. This is the rule that catches that, and it is why "test the checker" stops being
|
|
15
|
+
* discipline and becomes a gate.
|
|
16
|
+
*/
|
|
17
|
+
import { err, ok } from '../result.js';
|
|
18
|
+
export function asRequiredFileParams(rule) {
|
|
19
|
+
return rule.params;
|
|
20
|
+
}
|
|
21
|
+
const RULE_SELECTOR = /^rule\[([a-z]+)=([a-z-]+)\]$/;
|
|
22
|
+
export function isRuleSelector(forEach) {
|
|
23
|
+
return RULE_SELECTOR.test(forEach);
|
|
24
|
+
}
|
|
25
|
+
function expandForFile(template, path) {
|
|
26
|
+
const slash = path.lastIndexOf('/');
|
|
27
|
+
const dir = slash === -1 ? '' : path.slice(0, slash);
|
|
28
|
+
const name = path.slice(slash + 1);
|
|
29
|
+
const dot = name.lastIndexOf('.');
|
|
30
|
+
const base = dot === -1 ? name : name.slice(0, dot);
|
|
31
|
+
const ext = dot === -1 ? '' : name.slice(dot);
|
|
32
|
+
return template
|
|
33
|
+
.replaceAll('{dir}', dir)
|
|
34
|
+
.replaceAll('{name}', name)
|
|
35
|
+
.replaceAll('{Base}', base.charAt(0).toUpperCase() + base.slice(1))
|
|
36
|
+
.replaceAll('{base}', base)
|
|
37
|
+
.replaceAll('{ext}', ext);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A layers rule whose allow-list is `'*'` declares SCOPE rather than constraining anything, so it
|
|
41
|
+
* cannot produce an edge violation and demanding a fixture for it would demand a file that cannot
|
|
42
|
+
* contain one. Derived from the rule's own params, never an exemption list.
|
|
43
|
+
*
|
|
44
|
+
* `catchesUnlayered` is the exception, and it matters: a rule that owns the unlayered-file report
|
|
45
|
+
* CAN fire — on a folder nobody declared — even when its allow-list is `'*'`. Missing that would
|
|
46
|
+
* have quietly excused the one rule in a manifest most worth proving.
|
|
47
|
+
*/
|
|
48
|
+
function canEverFire(rule) {
|
|
49
|
+
if (rule.kind !== 'layers')
|
|
50
|
+
return true;
|
|
51
|
+
const params = rule.params;
|
|
52
|
+
if (params.catchesUnlayered === true)
|
|
53
|
+
return true;
|
|
54
|
+
return params.mayImport !== '*';
|
|
55
|
+
}
|
|
56
|
+
export function subjectsFor(params, ctx) {
|
|
57
|
+
const selector = RULE_SELECTOR.exec(params.forEach);
|
|
58
|
+
if (selector) {
|
|
59
|
+
const [, field, value] = selector;
|
|
60
|
+
return ctx.rules
|
|
61
|
+
.filter((rule) => String(rule[field]) === value)
|
|
62
|
+
.filter(canEverFire)
|
|
63
|
+
.map((rule) => ({
|
|
64
|
+
subject: rule.id,
|
|
65
|
+
expected: params.expect.replaceAll('{id}', rule.id),
|
|
66
|
+
label: `rule '${rule.id}'`,
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
return ctx.files.map((file) => ({
|
|
70
|
+
subject: file,
|
|
71
|
+
expected: expandForFile(params.expect, file),
|
|
72
|
+
label: file,
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
function validateParams(rule, _ctx) {
|
|
76
|
+
const params = rule.params;
|
|
77
|
+
const errors = [];
|
|
78
|
+
if (typeof params.forEach !== 'string' || params.forEach.length === 0) {
|
|
79
|
+
errors.push("params.forEach is required — a path glob, or a selector like 'rule[severity=error]'");
|
|
80
|
+
}
|
|
81
|
+
if (typeof params.expect !== 'string' || params.expect.length === 0) {
|
|
82
|
+
errors.push('params.expect is required — the path template the companion file must be at');
|
|
83
|
+
}
|
|
84
|
+
if (typeof params.forEach === 'string' && typeof params.expect === 'string') {
|
|
85
|
+
if (isRuleSelector(params.forEach) && !params.expect.includes('{id}')) {
|
|
86
|
+
errors.push('params.expect must contain {id} when forEach iterates rules, or every rule expects the same one file');
|
|
87
|
+
}
|
|
88
|
+
if (!isRuleSelector(params.forEach) && !/\{(dir|base|Base|name|ext)\}/.test(params.expect)) {
|
|
89
|
+
errors.push('params.expect must contain {dir}, {base}, {name} or {ext} when forEach iterates files, ' +
|
|
90
|
+
'or every file expects the same one companion');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return errors.length > 0 ? err(errors) : ok(undefined);
|
|
94
|
+
}
|
|
95
|
+
function emitFragments(rule, _ctx) {
|
|
96
|
+
const params = asRequiredFileParams(rule);
|
|
97
|
+
return [
|
|
98
|
+
{
|
|
99
|
+
target: 'test',
|
|
100
|
+
ruleId: rule.id,
|
|
101
|
+
content: {
|
|
102
|
+
forEach: params.forEach,
|
|
103
|
+
expect: params.expect,
|
|
104
|
+
message: `${rule.statement} — ${rule.remedy.summary}`,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
];
|
|
108
|
+
}
|
|
109
|
+
function explainFinding(finding, rule, _ctx) {
|
|
110
|
+
const evidence = finding.evidence;
|
|
111
|
+
return [
|
|
112
|
+
`${String(evidence.label)} has no ${String(evidence.expected)}`,
|
|
113
|
+
` expected at: ${String(evidence.expected)}`,
|
|
114
|
+
` → ${rule.remedy.summary}`,
|
|
115
|
+
].join('\n');
|
|
116
|
+
}
|
|
117
|
+
function refineFinding(finding, rule) {
|
|
118
|
+
const evidence = finding.evidence;
|
|
119
|
+
return {
|
|
120
|
+
statement: `${String(evidence.label)} is missing ${String(evidence.expected)}`,
|
|
121
|
+
remedy: rule.remedy,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
export const requiredFileContract = {
|
|
125
|
+
kind: 'required-file',
|
|
126
|
+
validate: validateParams,
|
|
127
|
+
emit: emitFragments,
|
|
128
|
+
explain: explainFinding,
|
|
129
|
+
refine: refineFinding,
|
|
130
|
+
};
|
|
131
|
+
//# sourceMappingURL=required-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"required-file.js","sourceRoot":"","sources":["../../src/contracts/required-file.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The first seam: a contract kind.
|
|
3
|
+
*
|
|
4
|
+
* What a caller must know: `validate` takes a context the LLD's signature did not, because one
|
|
5
|
+
* question genuinely needs it — "does this layer's mayImport name a layer that exists?" cannot be
|
|
6
|
+
* answered from one rule in isolation, and it is the single most common manifest typo. Everything
|
|
7
|
+
* else about the seam is unchanged.
|
|
8
|
+
*
|
|
9
|
+
* Adding a ninth kind is a design decision, not a task: every kind costs a validator, an emitter,
|
|
10
|
+
* an explainer and a fixture that must fail (LLD §4).
|
|
11
|
+
*/
|
|
12
|
+
import type { Result } from '../result.js';
|
|
13
|
+
import type { ContractKind, Fragment, RawFinding, Remedy, Rule } from '../types.js';
|
|
14
|
+
export type ValidateCtx = {
|
|
15
|
+
/** Every rule in the manifest — a kind whose meaning depends on the set can see the set. */
|
|
16
|
+
rules: readonly Rule[];
|
|
17
|
+
};
|
|
18
|
+
export type EmitCtx = {
|
|
19
|
+
root: string;
|
|
20
|
+
rules: readonly Rule[];
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Explaining needs the rule set for the same reason validating does: a sentence like "domain may
|
|
24
|
+
* import: contracts, rules" is a fact about the manifest, not about the violation. Keeping it out
|
|
25
|
+
* of `evidence` is not cosmetic — evidence feeds the identity hash, so a rule's allow-list growing
|
|
26
|
+
* an unrelated entry would otherwise silently invalidate every baseline entry it touches.
|
|
27
|
+
*/
|
|
28
|
+
export type ExplainCtx = {
|
|
29
|
+
rules: readonly Rule[];
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* A per-finding sharpening of the rule's own words.
|
|
33
|
+
*
|
|
34
|
+
* Why this exists: one rule legitimately covers findings that need different sentences. A `layers`
|
|
35
|
+
* rule states "domain may import only contracts and rules", but an UNLAYERED file broke no
|
|
36
|
+
* allow-list — it matched no layer at all, and telling its author to "invert the call" sends them
|
|
37
|
+
* to the wrong fix. The rule's statement is what the editor squiggle shows (it is per-rule); this
|
|
38
|
+
* is what a diagnostic shows (it is per-finding).
|
|
39
|
+
*/
|
|
40
|
+
export type Refinement = {
|
|
41
|
+
statement?: string;
|
|
42
|
+
remedy?: Remedy;
|
|
43
|
+
};
|
|
44
|
+
export type ContractType = {
|
|
45
|
+
kind: ContractKind;
|
|
46
|
+
/** Params well-formed? Returns every problem, never throws (a bad manifest exits 2). */
|
|
47
|
+
validate(rule: Rule, ctx: ValidateCtx): Result<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Optional: things that load fine but somebody should see. A judgement rule promoted to `error`
|
|
50
|
+
* is legal policy and a visible act — so it warns rather than failing, and warning rather than
|
|
51
|
+
* silence is the whole point.
|
|
52
|
+
*/
|
|
53
|
+
warn?(rule: Rule, ctx: ValidateCtx): string[];
|
|
54
|
+
/** One rule → many sinks. The merger groups fragments by target (LLD §1.2). */
|
|
55
|
+
emit(rule: Rule, ctx: EmitCtx): Fragment[];
|
|
56
|
+
/** Finding → the sentence a person reads. Returns the remedy, not the symptom. */
|
|
57
|
+
explain(finding: RawFinding, rule: Rule, ctx: ExplainCtx): string;
|
|
58
|
+
/** Optional: sharpen the statement or remedy for one finding. See Refinement. */
|
|
59
|
+
refine?(finding: RawFinding, rule: Rule, ctx: ExplainCtx): Refinement | undefined;
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/contracts/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEpF,MAAM,MAAM,WAAW,GAAG;IACxB,4FAA4F;IAC5F,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;CACxB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;CACxB,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,UAAU,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,YAAY,CAAC;IACnB,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IACrD;;;;OAIG;IACH,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,WAAW,GAAG,MAAM,EAAE,CAAC;IAC9C,+EAA+E;IAC/E,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,GAAG,QAAQ,EAAE,CAAC;IAC3C,kFAAkF;IAClF,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,GAAG,MAAM,CAAC;IAClE,iFAAiF;IACjF,MAAM,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC;CACnF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/contracts/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coverage, computed — never claimed.
|
|
3
|
+
*
|
|
4
|
+
* What rule this enforces: the percentage comes from counting the manifest at run time. Add a rule
|
|
5
|
+
* with no real check and the judgement count rises and the percentage falls, in the same commit,
|
|
6
|
+
* with no way to write a nicer number by hand (plan 19). That number is worth watching precisely
|
|
7
|
+
* because nobody can edit it.
|
|
8
|
+
*
|
|
9
|
+
* What a caller must know: `rules.json` is DATA, not HTML. The document reads it. That keeps
|
|
10
|
+
* archcheck independent of anyone's doc format and makes the same data available to a dashboard
|
|
11
|
+
* later without a second emitter.
|
|
12
|
+
*/
|
|
13
|
+
import type { Coverage, Rule } from '../types.js';
|
|
14
|
+
export declare const RULES_JSON = "rules.json";
|
|
15
|
+
/** The mark each tier gets in a document, matching the patterns document's own vocabulary. */
|
|
16
|
+
export declare const MARK: {
|
|
17
|
+
readonly deterministic: "✓";
|
|
18
|
+
readonly proxy: "◑";
|
|
19
|
+
readonly model: "○";
|
|
20
|
+
};
|
|
21
|
+
export type RuleSummary = {
|
|
22
|
+
id: string;
|
|
23
|
+
kind: string;
|
|
24
|
+
statement: string;
|
|
25
|
+
severity: string;
|
|
26
|
+
confidence: string;
|
|
27
|
+
mark: string;
|
|
28
|
+
remedy: string;
|
|
29
|
+
};
|
|
30
|
+
export type RulesDocument = {
|
|
31
|
+
schemaVersion: 1;
|
|
32
|
+
coverage: Coverage & {
|
|
33
|
+
automatable: number;
|
|
34
|
+
};
|
|
35
|
+
rules: RuleSummary[];
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* `deterministic + proxy` over the TOTAL: the share a machine decides without a model.
|
|
39
|
+
*
|
|
40
|
+
* The denominator is every active rule, including the ones nothing checks. Declare a rule of a
|
|
41
|
+
* kind archcheck has not implemented and the percentage falls, which is the whole point of
|
|
42
|
+
* computing this number rather than writing it down.
|
|
43
|
+
*/
|
|
44
|
+
export declare function automatablePercent(coverage: Coverage): number;
|
|
45
|
+
export declare function rulesDocument(rules: readonly Rule[], coverage: Coverage): RulesDocument;
|
|
46
|
+
export declare const FENCE_BEGIN = "<!-- archcheck:begin rules-table -->";
|
|
47
|
+
export declare const FENCE_END = "<!-- archcheck:end rules-table -->";
|
|
48
|
+
/** The generated region: the rule table and the counts. Prose stays hand-written. */
|
|
49
|
+
export declare function renderRulesTable(document: RulesDocument): string;
|
|
50
|
+
/**
|
|
51
|
+
* Replace the fenced region, idempotently. Returns undefined when the document has no fence —
|
|
52
|
+
* a document that never asked for a generated region must not grow one by surprise.
|
|
53
|
+
*/
|
|
54
|
+
export declare function replaceFencedRegion(source: string, replacement: string): string | undefined;
|
|
55
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/coverage/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAElD,eAAO,MAAM,UAAU,eAAe,CAAC;AAEvC,8FAA8F;AAC9F,eAAO,MAAM,IAAI;;;;CAA0D,CAAC;AAE5E,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,aAAa,EAAE,CAAC,CAAC;IACjB,QAAQ,EAAE,QAAQ,GAAG;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAG7D;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,aAAa,CAiBvF;AAED,eAAO,MAAM,WAAW,yCAAyC,CAAC;AAClE,eAAO,MAAM,SAAS,uCAAuC,CAAC;AAM9D,qFAAqF;AACrF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,CAmBhE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK3F"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export const RULES_JSON = 'rules.json';
|
|
2
|
+
/** The mark each tier gets in a document, matching the patterns document's own vocabulary. */
|
|
3
|
+
export const MARK = { deterministic: '✓', proxy: '◑', model: '○' };
|
|
4
|
+
/**
|
|
5
|
+
* `deterministic + proxy` over the TOTAL: the share a machine decides without a model.
|
|
6
|
+
*
|
|
7
|
+
* The denominator is every active rule, including the ones nothing checks. Declare a rule of a
|
|
8
|
+
* kind archcheck has not implemented and the percentage falls, which is the whole point of
|
|
9
|
+
* computing this number rather than writing it down.
|
|
10
|
+
*/
|
|
11
|
+
export function automatablePercent(coverage) {
|
|
12
|
+
if (coverage.total === 0)
|
|
13
|
+
return 0;
|
|
14
|
+
return Math.round(((coverage.deterministic + coverage.proxy) / coverage.total) * 100);
|
|
15
|
+
}
|
|
16
|
+
export function rulesDocument(rules, coverage) {
|
|
17
|
+
return {
|
|
18
|
+
schemaVersion: 1,
|
|
19
|
+
coverage: { ...coverage, automatable: automatablePercent(coverage) },
|
|
20
|
+
rules: rules
|
|
21
|
+
.filter((rule) => rule.severity !== 'off')
|
|
22
|
+
.map((rule) => ({
|
|
23
|
+
id: rule.id,
|
|
24
|
+
kind: rule.kind,
|
|
25
|
+
statement: rule.statement,
|
|
26
|
+
severity: rule.severity,
|
|
27
|
+
confidence: rule.confidence,
|
|
28
|
+
mark: MARK[rule.confidence],
|
|
29
|
+
remedy: rule.remedy.summary,
|
|
30
|
+
}))
|
|
31
|
+
.sort((a, b) => a.id.localeCompare(b.id)),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export const FENCE_BEGIN = '<!-- archcheck:begin rules-table -->';
|
|
35
|
+
export const FENCE_END = '<!-- archcheck:end rules-table -->';
|
|
36
|
+
function escapeCell(text) {
|
|
37
|
+
return text.replaceAll('|', '\\|');
|
|
38
|
+
}
|
|
39
|
+
/** The generated region: the rule table and the counts. Prose stays hand-written. */
|
|
40
|
+
export function renderRulesTable(document) {
|
|
41
|
+
const { coverage } = document;
|
|
42
|
+
const lines = [
|
|
43
|
+
FENCE_BEGIN,
|
|
44
|
+
'',
|
|
45
|
+
`**${coverage.total} rules** · ${MARK.deterministic} ${coverage.deterministic} deterministic · ` +
|
|
46
|
+
`${MARK.proxy} ${coverage.proxy} proxy · ${MARK.model} ${coverage.model} judgement · ` +
|
|
47
|
+
`**${coverage.automatable}% automatable**`,
|
|
48
|
+
'',
|
|
49
|
+
'| | Rule | Statement | Kind | Severity |',
|
|
50
|
+
'|---|---|---|---|---|',
|
|
51
|
+
...document.rules.map((rule) => `| ${rule.mark} | \`${rule.id}\` | ${escapeCell(rule.statement)} | ${rule.kind} | ${rule.severity} |`),
|
|
52
|
+
'',
|
|
53
|
+
FENCE_END,
|
|
54
|
+
];
|
|
55
|
+
return lines.join('\n');
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Replace the fenced region, idempotently. Returns undefined when the document has no fence —
|
|
59
|
+
* a document that never asked for a generated region must not grow one by surprise.
|
|
60
|
+
*/
|
|
61
|
+
export function replaceFencedRegion(source, replacement) {
|
|
62
|
+
const start = source.indexOf(FENCE_BEGIN);
|
|
63
|
+
const end = source.indexOf(FENCE_END);
|
|
64
|
+
if (start === -1 || end === -1 || end < start)
|
|
65
|
+
return undefined;
|
|
66
|
+
return source.slice(0, start) + replacement + source.slice(end + FENCE_END.length);
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/coverage/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fragment collection across every rule.
|
|
3
|
+
*
|
|
4
|
+
* What rule this enforces: one rule may need several configs (LLD §1.2) — `encapsulation` needs a
|
|
5
|
+
* package exports map AND a graph rule, `layers` needs a graph rule AND a lint rule whose message
|
|
6
|
+
* carries the statement. So `emit()` returns an array and the merger groups by sink.
|
|
7
|
+
*
|
|
8
|
+
* What a caller must know: rules are visited in id order. Determinism starts here, not in the
|
|
9
|
+
* writer — a re-emit with an unchanged manifest must be byte-identical or `emit --check` becomes a
|
|
10
|
+
* false-alarm generator and gets switched off.
|
|
11
|
+
*/
|
|
12
|
+
import type { ContractType, EmitCtx } from '../contracts/types.js';
|
|
13
|
+
import type { ContractKind, Fragment, Rule } from '../types.js';
|
|
14
|
+
export type CollectResult = {
|
|
15
|
+
fragments: Fragment[];
|
|
16
|
+
/** Kinds declared in the manifest that no contract type implements yet. */
|
|
17
|
+
unimplemented: ContractKind[];
|
|
18
|
+
};
|
|
19
|
+
export declare function collectFragments(rules: readonly Rule[], contractFor: (kind: ContractKind) => ContractType | undefined, ctx: EmitCtx): CollectResult;
|
|
20
|
+
//# sourceMappingURL=collect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect.d.ts","sourceRoot":"","sources":["../../src/emit/collect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEhE,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,2EAA2E;IAC3E,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B,CAAC;AAEF,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,WAAW,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,YAAY,GAAG,SAAS,EAC7D,GAAG,EAAE,OAAO,GACX,aAAa,CAiBf"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function collectFragments(rules, contractFor, ctx) {
|
|
2
|
+
const sorted = [...rules]
|
|
3
|
+
.filter((rule) => rule.severity !== 'off')
|
|
4
|
+
.sort((a, b) => a.id.localeCompare(b.id));
|
|
5
|
+
const fragments = [];
|
|
6
|
+
const unimplemented = new Set();
|
|
7
|
+
for (const rule of sorted) {
|
|
8
|
+
const contract = contractFor(rule.kind);
|
|
9
|
+
if (!contract) {
|
|
10
|
+
unimplemented.add(rule.kind);
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
fragments.push(...contract.emit(rule, ctx));
|
|
14
|
+
}
|
|
15
|
+
return { fragments, unimplemented: [...unimplemented].sort() };
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=collect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect.js","sourceRoot":"","sources":["../../src/emit/collect.ts"],"names":[],"mappings":"AAoBA,MAAM,UAAU,gBAAgB,CAC9B,KAAsB,EACtB,WAA6D,EAC7D,GAAY;IAEZ,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC;SACtB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,KAAK,CAAC;SACzC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAe,EAAE,CAAC;IACjC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAgB,CAAC;IAE9C,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7B,SAAS;QACX,CAAC;QACD,SAAS,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;AACjE,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The generated header. Every emitted file opens the same way.
|
|
3
|
+
*
|
|
4
|
+
* What rule this enforces: never hand-edit a generated file — edit its source and re-emit. A
|
|
5
|
+
* header is the only warning a reader gets before they start typing, so it names the manifest that
|
|
6
|
+
* produced the file, the rules that contributed to it, and the exact command to regenerate it.
|
|
7
|
+
*
|
|
8
|
+
* What a caller must know: JSON cannot carry a `//` comment, so the same four facts go into a
|
|
9
|
+
* `$generated` key instead. Same information, per-format syntax — not a weaker guarantee.
|
|
10
|
+
*/
|
|
11
|
+
export type GeneratedMeta = {
|
|
12
|
+
by: 'archcheck';
|
|
13
|
+
source: string;
|
|
14
|
+
rules: string[];
|
|
15
|
+
regenerate: string;
|
|
16
|
+
doNotEdit: true;
|
|
17
|
+
};
|
|
18
|
+
export declare const REGENERATE_COMMAND = "npx archcheck emit";
|
|
19
|
+
export declare function generatedMeta(source: string, ruleIds: readonly string[]): GeneratedMeta;
|
|
20
|
+
export declare function commentHeader(source: string, ruleIds: readonly string[]): string;
|
|
21
|
+
//# sourceMappingURL=header.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header.d.ts","sourceRoot":"","sources":["../../src/emit/header.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,WAAW,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,IAAI,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AAEvD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,aAAa,CAQvF;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAQhF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const REGENERATE_COMMAND = 'npx archcheck emit';
|
|
2
|
+
export function generatedMeta(source, ruleIds) {
|
|
3
|
+
return {
|
|
4
|
+
by: 'archcheck',
|
|
5
|
+
source,
|
|
6
|
+
rules: [...ruleIds].sort(),
|
|
7
|
+
regenerate: REGENERATE_COMMAND,
|
|
8
|
+
doNotEdit: true,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function commentHeader(source, ruleIds) {
|
|
12
|
+
const rules = [...ruleIds].sort().join(', ');
|
|
13
|
+
return [
|
|
14
|
+
'// GENERATED BY archcheck — DO NOT EDIT',
|
|
15
|
+
`// source: ${source}`,
|
|
16
|
+
`// rules: ${rules}`,
|
|
17
|
+
`// regenerate: ${REGENERATE_COMMAND}`,
|
|
18
|
+
].join('\n');
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=header.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header.js","sourceRoot":"","sources":["../../src/emit/header.ts"],"names":[],"mappings":"AAkBA,MAAM,CAAC,MAAM,kBAAkB,GAAG,oBAAoB,CAAC;AAEvD,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,OAA0B;IACtE,OAAO;QACL,EAAE,EAAE,WAAW;QACf,MAAM;QACN,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE;QAC1B,UAAU,EAAE,kBAAkB;QAC9B,SAAS,EAAE,IAAI;KAChB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,OAA0B;IACtE,MAAM,KAAK,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7C,OAAO;QACL,yCAAyC;QACzC,cAAc,MAAM,EAAE;QACtB,cAAc,KAAK,EAAE;QACrB,kBAAkB,kBAAkB,EAAE;KACvC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { ContractType } from '../contracts/types.js';
|
|
2
|
+
import { type IdLedger } from '../registry/ids.js';
|
|
3
|
+
import type { ContractKind, Coverage, Rule } from '../types.js';
|
|
4
|
+
import { type SinkFile } from './merge.js';
|
|
5
|
+
import { type EmitTarget, type StaleFile, type WrittenFile } from './write.js';
|
|
6
|
+
export declare const DEFAULT_GENERATED_DIR = "generated";
|
|
7
|
+
export type EmitPlan = {
|
|
8
|
+
files: SinkFile[];
|
|
9
|
+
unimplemented: ContractKind[];
|
|
10
|
+
target: EmitTarget;
|
|
11
|
+
/** Documents whose fenced region this manifest would replace. Paths are repo-relative. */
|
|
12
|
+
docs: {
|
|
13
|
+
path: string;
|
|
14
|
+
content: string;
|
|
15
|
+
}[];
|
|
16
|
+
/**
|
|
17
|
+
* Documents `manifest.docs` names that could not be read. `checkEmit` reports these as
|
|
18
|
+
* `unreadable` rather than dropping them: the operator named the file, so its absence is news,
|
|
19
|
+
* the same way `checkSinks` reports a sink that was never generated. A document that IS there
|
|
20
|
+
* and carries no fence is a different case and is left alone — `src/emit/emit.test.ts` →
|
|
21
|
+
* 'a document the manifest declares' pins both halves.
|
|
22
|
+
*/
|
|
23
|
+
unreadableDocs: string[];
|
|
24
|
+
};
|
|
25
|
+
export type PlanOptions = {
|
|
26
|
+
root: string;
|
|
27
|
+
configPath: string;
|
|
28
|
+
rules: readonly Rule[];
|
|
29
|
+
coverage: Coverage;
|
|
30
|
+
generatedDir?: string;
|
|
31
|
+
/** Repo-relative documents holding an `archcheck:begin rules-table` fence. */
|
|
32
|
+
docs?: readonly string[];
|
|
33
|
+
contractFor(kind: ContractKind): ContractType | undefined;
|
|
34
|
+
};
|
|
35
|
+
export declare function planEmit(options: PlanOptions): EmitPlan;
|
|
36
|
+
/**
|
|
37
|
+
* What `emit` says about a rule kind it generated no configuration for.
|
|
38
|
+
*
|
|
39
|
+
* `emit` is its own command: a CI lane that runs only `archcheck emit` sees neither
|
|
40
|
+
* `RunResult.skipped` nor `Coverage.unchecked`, so without this line a `forbidden` rule emits no
|
|
41
|
+
* fragment, prints nothing, and the editor configs the rule was declared for silently lack it.
|
|
42
|
+
* Same fact `collectFragments` records as `EmitPlan.unimplemented`, read from the rules alone
|
|
43
|
+
* because the CLI holds no plan. `src/emit/emit.test.ts` → 'describeUnimplemented' pins it.
|
|
44
|
+
*/
|
|
45
|
+
export declare function describeUnimplemented(rules: readonly Rule[]): string[];
|
|
46
|
+
export type EmitOutcome = {
|
|
47
|
+
written: WrittenFile[];
|
|
48
|
+
ledgerPath: string;
|
|
49
|
+
};
|
|
50
|
+
/** Writes the sinks, and the id ledger that makes rule ids immutable. */
|
|
51
|
+
export declare function applyEmit(plan: EmitPlan, ledger: IdLedger): EmitOutcome;
|
|
52
|
+
export declare function checkEmit(plan: EmitPlan): StaleFile[];
|
|
53
|
+
export { type CollectResult, collectFragments } from './collect.js';
|
|
54
|
+
export { commentHeader, type GeneratedMeta, generatedMeta, REGENERATE_COMMAND } from './header.js';
|
|
55
|
+
export { mergeBySink, SINK_PATHS, type SinkFile, sortDeep } from './merge.js';
|
|
56
|
+
export { checkSinks, describeStale, type EmitTarget, type StaleFile, type WrittenFile, writeSinks, } from './write.js';
|
|
57
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/emit/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAW,MAAM,uBAAuB,CAAC;AAOnE,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGhE,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,WAAW,EAEjB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,qBAAqB,cAAc,CAAC;AAEjD,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,MAAM,EAAE,UAAU,CAAC;IACnB,0FAA0F;IAC1F,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1C;;;;;;OAMG;IACH,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IACvB,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,YAAY,GAAG,SAAS,CAAC;CAC3D,CAAC;AAEF,wBAAgB,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,QAAQ,CAuCvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,MAAM,EAAE,CActE;AAaD,MAAM,MAAM,WAAW,GAAG;IAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzE,yEAAyE;AACzE,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAG,WAAW,CAkBvE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,EAAE,CAWrD;AAED,OAAO,EAAE,KAAK,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACnG,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,KAAK,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,EACL,UAAU,EACV,aAAa,EACb,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,UAAU,GACX,MAAM,YAAY,CAAC"}
|