@aoelite/refpact-ts 0.0.0-stage → 0.1.2

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 (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +38 -2
  3. package/dist/baseline.d.ts +26 -0
  4. package/dist/baseline.js +65 -0
  5. package/dist/core/index.d.ts +79 -0
  6. package/dist/core/index.js +90 -0
  7. package/dist/core/model.d.ts +340 -0
  8. package/dist/core/model.js +1 -0
  9. package/dist/core/results.d.ts +237 -0
  10. package/dist/core/results.js +1 -0
  11. package/dist/core/wasm.d.ts +7 -0
  12. package/dist/core/wasm.js +67 -0
  13. package/dist/custom.d.ts +129 -0
  14. package/dist/custom.js +217 -0
  15. package/dist/filters.d.ts +73 -0
  16. package/dist/filters.js +39 -0
  17. package/dist/frontend/checks.d.ts +15 -0
  18. package/dist/frontend/checks.js +12 -0
  19. package/dist/frontend/classic.d.ts +3 -0
  20. package/dist/frontend/classic.js +105 -0
  21. package/dist/frontend/compiler.d.ts +93 -0
  22. package/dist/frontend/compiler.js +116 -0
  23. package/dist/frontend/components.d.ts +29 -0
  24. package/dist/frontend/components.js +111 -0
  25. package/dist/frontend/declarations.d.ts +45 -0
  26. package/dist/frontend/declarations.js +158 -0
  27. package/dist/frontend/dependencies.d.ts +53 -0
  28. package/dist/frontend/dependencies.js +337 -0
  29. package/dist/frontend/imports.d.ts +149 -0
  30. package/dist/frontend/imports.js +765 -0
  31. package/dist/frontend/native.d.ts +3 -0
  32. package/dist/frontend/native.js +165 -0
  33. package/dist/frontend/paths.d.ts +10 -0
  34. package/dist/frontend/paths.js +18 -0
  35. package/dist/frontend/project.d.ts +118 -0
  36. package/dist/frontend/project.js +775 -0
  37. package/dist/group.d.ts +74 -0
  38. package/dist/group.js +106 -0
  39. package/dist/index.d.ts +35 -0
  40. package/dist/index.js +27 -0
  41. package/dist/items.d.ts +133 -0
  42. package/dist/items.js +179 -0
  43. package/dist/layers.d.ts +112 -0
  44. package/dist/layers.js +215 -0
  45. package/dist/onion.d.ts +78 -0
  46. package/dist/onion.js +96 -0
  47. package/dist/patterns.d.ts +14 -0
  48. package/dist/patterns.js +15 -0
  49. package/dist/rules.d.ts +408 -0
  50. package/dist/rules.js +655 -0
  51. package/package.json +52 -4
  52. package/wasm/refpact_core.wasm +0 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AoElite
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,39 @@
1
- # Temporary Holding Version
1
+ # refpact
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Architecture tests for TypeScript 6 and 7: rules about what files may import, checked as
4
+ ordinary tests under Vitest or `node --test`. The compiler of your project resolves each
5
+ import.
6
+
7
+ ```sh
8
+ pnpm add --save-dev @aoelite/refpact-ts
9
+ ```
10
+
11
+ ```ts
12
+ import { test } from "vitest";
13
+ import { anyOf, loadProject, pkg, rule } from "@aoelite/refpact-ts";
14
+
15
+ const app = loadProject("tsconfig.json");
16
+
17
+ test("the user interface does not import the database", () => {
18
+ rule("the user interface does not import the database")
19
+ .files(anyOf("src/ui/**"))
20
+ .mustNotImport(anyOf("src/db/**", pkg("pg")))
21
+ .check(app);
22
+ });
23
+ ```
24
+
25
+ `check` throws an error, and the message of the error is the report:
26
+
27
+ ```text
28
+ rule `the user interface does not import the database` is violated in 1 place(s):
29
+ src/ui/view.ts:3:10: [the user interface does not import the database] src/ui/view.ts uses src/db/client.ts#query (import, written as src/db/index.ts#query)
30
+ ```
31
+
32
+ - [The TypeScript guide](https://github.com/AoElite/RefPact/blob/main/docs/typescript.md):
33
+ how to install the package, every rule, and the limits of the analysis.
34
+ - [All that you can check](https://github.com/AoElite/RefPact#what-you-can-check), also in
35
+ Rust.
36
+
37
+ ## License
38
+
39
+ MIT
@@ -0,0 +1,26 @@
1
+ import type { BaselineEntry, PathFormat, Violation } from "./core/index.ts";
2
+ import type { Failure } from "./rules.ts";
3
+ /**
4
+ * A file of violations that the project accepts for now.
5
+ *
6
+ * A rule uses a baseline only when it is checked with `checkWithBaseline`. Plain `check`
7
+ * never reads one.
8
+ *
9
+ * The file is text, one accepted violation per line, without line numbers of the source.
10
+ * Commit it. To write it, run the tests once with `REFPACT_BASELINE=update`.
11
+ */
12
+ export declare class Baseline {
13
+ /** The absolute path of the file. */
14
+ readonly file: string;
15
+ /** @internal */
16
+ constructor(file: string);
17
+ /** @internal The entries, or the reason why the file cannot be read. A file that is not there is empty. */
18
+ read(): readonly BaselineEntry[] | Failure;
19
+ /** @internal Replaces the entries of one rule with its current violations. */
20
+ write(rule: string, violations: readonly Violation[], format: PathFormat): Failure | undefined;
21
+ }
22
+ /**
23
+ * The baseline in the file at `file`. A relative path is relative to the working directory;
24
+ * in a test, give a path from `import.meta.dirname`.
25
+ */
26
+ export declare function baseline(file: string): Baseline;
@@ -0,0 +1,65 @@
1
+ /** The baseline file. */
2
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { baselineEntries, formatBaseline, parseBaseline } from "./core/index.js";
5
+ /**
6
+ * A file of violations that the project accepts for now.
7
+ *
8
+ * A rule uses a baseline only when it is checked with `checkWithBaseline`. Plain `check`
9
+ * never reads one.
10
+ *
11
+ * The file is text, one accepted violation per line, without line numbers of the source.
12
+ * Commit it. To write it, run the tests once with `REFPACT_BASELINE=update`.
13
+ */
14
+ export class Baseline {
15
+ /** The absolute path of the file. */
16
+ file;
17
+ /** @internal */
18
+ constructor(file) {
19
+ this.file = path.resolve(file);
20
+ }
21
+ /** @internal The entries, or the reason why the file cannot be read. A file that is not there is empty. */
22
+ read() {
23
+ if (!existsSync(this.file)) {
24
+ return [];
25
+ }
26
+ let text;
27
+ try {
28
+ text = readFileSync(this.file, "utf8");
29
+ }
30
+ catch (error) {
31
+ return { type: "baseline", message: `refpact: cannot read ${this.file}: ${error.message}` };
32
+ }
33
+ const parsed = parseBaseline(text);
34
+ if (!parsed.ok) {
35
+ return { type: "baseline", message: `${this.file}:${parsed.line}: this line of the baseline is not valid` };
36
+ }
37
+ return parsed.entries;
38
+ }
39
+ /** @internal Replaces the entries of one rule with its current violations. */
40
+ write(rule, violations, format) {
41
+ const entries = this.read();
42
+ if (!Array.isArray(entries)) {
43
+ return entries;
44
+ }
45
+ const kept = entries.filter((entry) => entry.rule !== rule);
46
+ try {
47
+ mkdirSync(path.dirname(this.file), { recursive: true });
48
+ // Written beside the file and moved, so that a reader never sees half a file.
49
+ const partial = `${this.file}.partial`;
50
+ writeFileSync(partial, formatBaseline([...kept, ...baselineEntries(violations, format)]));
51
+ renameSync(partial, this.file);
52
+ }
53
+ catch (error) {
54
+ return { type: "baseline", message: `refpact: cannot write ${this.file}: ${error.message}` };
55
+ }
56
+ return undefined;
57
+ }
58
+ }
59
+ /**
60
+ * The baseline in the file at `file`. A relative path is relative to the working directory;
61
+ * in a test, give a path from `import.meta.dirname`.
62
+ */
63
+ export function baseline(file) {
64
+ return new Baseline(file);
65
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * The language-neutral core: rules evaluated over facts, reports and baselines.
3
+ *
4
+ * The core is the Rust crate `refpact-core`, run as WebAssembly. This module turns its JSON
5
+ * requests (SPEC section 8) into functions. A fact set crosses into the core once, on its
6
+ * first evaluation, and stays there while the object lives, so each further rule sends only
7
+ * the rule.
8
+ */
9
+ import type { FactSet, Path, RawPattern, Rule, Severity } from "./model.ts";
10
+ import type { Applied, BaselineEntry, BaselineKey, EvaluateResult, ParsedBaseline, PathFormat, RuleError, SelectResult, Violation } from "./results.ts";
11
+ export type * from "./model.ts";
12
+ export type * from "./results.ts";
13
+ /** Evaluates one rule against one fact set (SPEC section 4). */
14
+ export declare function evaluate(rule: Rule, facts: FactSet): EvaluateResult;
15
+ /**
16
+ * Applies the subjects, the filters and the exemptions of a rule with a custom check, and
17
+ * answers what the rule sees (SPEC section 8), so that the caller finds the violations. The
18
+ * check is the constraint of the rule, or the demand of a rule about items.
19
+ */
20
+ export declare function select(rule: Rule, facts: FactSet): SelectResult;
21
+ /** The text form of a diagram: a Mermaid flowchart, or a Graphviz graph in DOT. */
22
+ export type DiagramFormat = "mermaid" | "dot";
23
+ /** The diagram of a rule, or the reasons why the rule cannot be evaluated. */
24
+ export type DiagramResult = {
25
+ /** The rule can be evaluated. */
26
+ readonly ok: true;
27
+ /** The diagram. */
28
+ readonly text: string;
29
+ } | {
30
+ /** The rule cannot be evaluated. */
31
+ readonly ok: false;
32
+ /** The reasons, in the order of the specification. */
33
+ readonly errors: readonly RuleError[];
34
+ };
35
+ /** A layer of a diagram of layers (SPEC 4.17). */
36
+ export interface DiagramLayer {
37
+ /** The name of the layer, which is the label of its node. */
38
+ readonly name: string;
39
+ /** The units of the layer: unit patterns, which match units exactly. */
40
+ readonly units: readonly RawPattern[];
41
+ /** The layers that the layer must not use, by their position in the list of layers. */
42
+ readonly mustNotUse: readonly number[];
43
+ }
44
+ /**
45
+ * The nodes of a diagram: the subjects of the rule when this is `undefined`, the slices of
46
+ * the subjects, or the layers from the top to the bottom.
47
+ */
48
+ export type DiagramNodes = {
49
+ /** The slice patterns, as for `must-be-acyclic` with slices. */
50
+ readonly slices: readonly RawPattern[];
51
+ } | {
52
+ /** The layers, from the top to the bottom. */
53
+ readonly layers: readonly DiagramLayer[];
54
+ } | undefined;
55
+ /**
56
+ * The diagram of what a rule sees (SPEC 4.17): its subjects, the slices or the layers, and the
57
+ * references between them. The constraint of the rule is not evaluated.
58
+ */
59
+ export declare function diagram(rule: Rule, facts: FactSet, nodes: DiagramNodes, format?: DiagramFormat): DiagramResult;
60
+ /** Prints a path as reports print it. */
61
+ export declare function printPath(path: Path, format: PathFormat): string;
62
+ /** One line for one violation: file, line, column, rule name, unit and offending path. */
63
+ export declare function renderViolation(violation: Violation, format: PathFormat): string;
64
+ /** All violations of one rule, one per line, with a heading, and the reason of the rule when it has one. */
65
+ export declare function renderViolations(rule: string, violations: readonly Violation[], format: PathFormat, reason?: string, severity?: Severity): string;
66
+ /** One sentence for one error. */
67
+ export declare function renderError(error: RuleError): string;
68
+ /** All errors of one rule, one per line, with a heading. */
69
+ export declare function renderErrors(rule: string, errors: readonly RuleError[]): string;
70
+ /** The `unit` and `what` of the key of a violation (SPEC 7.1). */
71
+ export declare function baselineKey(violation: Violation, format: PathFormat): BaselineKey;
72
+ /** One entry for each key of the violations, with the number of violations that have it. */
73
+ export declare function baselineEntries(violations: readonly Violation[], format: PathFormat): BaselineEntry[];
74
+ /** Removes the violations of one rule that the baseline accepts (SPEC 7.3). */
75
+ export declare function applyBaseline(rule: string, violations: readonly Violation[], baseline: readonly BaselineEntry[], format: PathFormat): Applied;
76
+ /** Writes the text form of a baseline, sorted, so that a change shows as a small difference. */
77
+ export declare function formatBaseline(entries: readonly BaselineEntry[]): string;
78
+ /** Reads the text form of a baseline (SPEC 7.2). */
79
+ export declare function parseBaseline(text: string): ParsedBaseline;
@@ -0,0 +1,90 @@
1
+ import { call, currentGeneration } from "./wasm.js";
2
+ const loaded = new WeakMap();
3
+ const unload = new FinalizationRegistry(({ handle, generation }) => {
4
+ if (generation === currentGeneration()) {
5
+ call(JSON.stringify({ op: "drop-facts", handle }));
6
+ }
7
+ });
8
+ /** The handle of a fact set in the core, after loading it when it is not loaded. */
9
+ function handleOf(facts) {
10
+ const generation = currentGeneration();
11
+ const known = loaded.get(facts);
12
+ if (known !== undefined && known.generation === generation) {
13
+ return known.handle;
14
+ }
15
+ const { handle } = JSON.parse(call(`{"op":"load-facts","facts":${JSON.stringify(facts)}}`));
16
+ const entry = { handle, generation };
17
+ loaded.set(facts, entry);
18
+ unload.register(facts, entry);
19
+ return handle;
20
+ }
21
+ /** Only the fields of a path format, so that a fact set given as the format does not cross whole. */
22
+ function formatOf(format) {
23
+ return {
24
+ separator: format.separator,
25
+ ...(format.attachedPrefixes !== undefined && { attachedPrefixes: format.attachedPrefixes }),
26
+ ...(format.hiddenPrefixes !== undefined && { hiddenPrefixes: format.hiddenPrefixes }),
27
+ };
28
+ }
29
+ function request(op, body) {
30
+ return JSON.parse(call(JSON.stringify({ op, ...body })));
31
+ }
32
+ /** Evaluates one rule against one fact set (SPEC section 4). */
33
+ export function evaluate(rule, facts) {
34
+ return request("evaluate", { handle: handleOf(facts), rule });
35
+ }
36
+ /**
37
+ * Applies the subjects, the filters and the exemptions of a rule with a custom check, and
38
+ * answers what the rule sees (SPEC section 8), so that the caller finds the violations. The
39
+ * check is the constraint of the rule, or the demand of a rule about items.
40
+ */
41
+ export function select(rule, facts) {
42
+ return request("select", { handle: handleOf(facts), rule });
43
+ }
44
+ /**
45
+ * The diagram of what a rule sees (SPEC 4.17): its subjects, the slices or the layers, and the
46
+ * references between them. The constraint of the rule is not evaluated.
47
+ */
48
+ export function diagram(rule, facts, nodes, format = "mermaid") {
49
+ return request("diagram", { handle: handleOf(facts), rule, ...nodes, format });
50
+ }
51
+ /** Prints a path as reports print it. */
52
+ export function printPath(path, format) {
53
+ return request("print-path", { path, format: formatOf(format) }).text;
54
+ }
55
+ /** One line for one violation: file, line, column, rule name, unit and offending path. */
56
+ export function renderViolation(violation, format) {
57
+ return request("render-violation", { violation, format: formatOf(format) }).text;
58
+ }
59
+ /** All violations of one rule, one per line, with a heading, and the reason of the rule when it has one. */
60
+ export function renderViolations(rule, violations, format, reason, severity = "error") {
61
+ return request("render-violations", { rule, reason, severity, violations, format: formatOf(format) }).text;
62
+ }
63
+ /** One sentence for one error. */
64
+ export function renderError(error) {
65
+ return request("render-error", { error }).text;
66
+ }
67
+ /** All errors of one rule, one per line, with a heading. */
68
+ export function renderErrors(rule, errors) {
69
+ return request("render-errors", { rule, errors }).text;
70
+ }
71
+ /** The `unit` and `what` of the key of a violation (SPEC 7.1). */
72
+ export function baselineKey(violation, format) {
73
+ return request("baseline-key", { violation, format: formatOf(format) });
74
+ }
75
+ /** One entry for each key of the violations, with the number of violations that have it. */
76
+ export function baselineEntries(violations, format) {
77
+ return request("baseline-entries", { violations, format: formatOf(format) }).entries;
78
+ }
79
+ /** Removes the violations of one rule that the baseline accepts (SPEC 7.3). */
80
+ export function applyBaseline(rule, violations, baseline, format) {
81
+ return request("apply-baseline", { rule, violations, entries: baseline, format: formatOf(format) });
82
+ }
83
+ /** Writes the text form of a baseline, sorted, so that a change shows as a small difference. */
84
+ export function formatBaseline(entries) {
85
+ return request("format-baseline", { entries }).text;
86
+ }
87
+ /** Reads the text form of a baseline (SPEC 7.2). */
88
+ export function parseBaseline(text) {
89
+ return request("parse-baseline", { text });
90
+ }
@@ -0,0 +1,340 @@
1
+ /** A path: a non-empty list of non-empty segments (SPEC section 1). */
2
+ export type Path = readonly string[];
3
+ /** A raw pattern: segments that the core validates (SPEC section 2). */
4
+ export type RawPattern = readonly string[];
5
+ /** What a front end found in one project (SPEC section 3). */
6
+ export interface FactSet {
7
+ /** Text that separates segments when a path is printed. */
8
+ readonly separator: string;
9
+ /** Paths of all units. Rust: modules. TypeScript: files. */
10
+ readonly units: readonly Path[];
11
+ /** Paths of all known named things inside units. */
12
+ readonly items: readonly Path[];
13
+ /** The number of lines of each unit, in the order of `units`. Absent or empty for front ends that do not count them. */
14
+ readonly unitLines?: readonly number[];
15
+ /** All reference kinds the front end can produce. */
16
+ readonly kinds: readonly string[];
17
+ /** All markers the front end can produce. */
18
+ readonly markers: readonly string[];
19
+ /** All tags the front end can produce. */
20
+ readonly tags: readonly string[];
21
+ /** The facts, in a stable order. */
22
+ readonly facts: readonly Fact[];
23
+ /** The named items that the units declare, in a stable order. Default: none. */
24
+ readonly declarations?: readonly Declaration[];
25
+ /** All item kinds the front end can produce. Default: none. */
26
+ readonly itemKinds?: readonly string[];
27
+ /** All visibilities the front end can produce. Default: none. */
28
+ readonly visibilities?: readonly string[];
29
+ /** All relations the front end can produce. Default: none. */
30
+ readonly relations?: readonly string[];
31
+ /** All modifiers of declarations the front end can produce. Default: none. */
32
+ readonly modifiers?: readonly string[];
33
+ /** The names of all properties of references the front end can produce. Default: none. */
34
+ readonly properties?: readonly string[];
35
+ /** Segments that reports print without a separator before them, by prefix. Default: none. */
36
+ readonly attachedPrefixes?: readonly string[];
37
+ /** Prefixes that reports leave out of the first segment of a path. Default: none. */
38
+ readonly hiddenPrefixes?: readonly string[];
39
+ }
40
+ /** One observation at one place in the source. */
41
+ export interface Fact {
42
+ /** The unit that contains the fact. */
43
+ readonly unit: Path;
44
+ /** The file, as the front end names it. */
45
+ readonly file: string;
46
+ /** The line in the file. */
47
+ readonly line: number;
48
+ /** The column in the line. */
49
+ readonly column: number;
50
+ /** The tags of the fact. */
51
+ readonly tags: readonly string[];
52
+ /** Text that is copied to the violation. */
53
+ readonly note?: string;
54
+ /**
55
+ * The path of the innermost declaration that contains the fact. Absent outside every
56
+ * declaration, and for front ends that do not record it.
57
+ */
58
+ readonly item?: Path;
59
+ /** What was observed. */
60
+ readonly what: Reference | Marker;
61
+ }
62
+ /** A named item that a unit declares, such as a type or a function (SPEC section 3). */
63
+ export interface Declaration {
64
+ /** The path of the item. */
65
+ readonly path: Path;
66
+ /** The name of the item as the code writes it. */
67
+ readonly name: string;
68
+ /** The unit that declares the item. */
69
+ readonly unit: Path;
70
+ /** The file, as the front end names it. */
71
+ readonly file: string;
72
+ /** The line of the name. */
73
+ readonly line: number;
74
+ /** The column of the name. */
75
+ readonly column: number;
76
+ /** The line on which the item ends. Absent for front ends that do not record it. */
77
+ readonly endLine?: number;
78
+ /** The tags of the declaration. */
79
+ readonly tags: readonly string[];
80
+ /** The kind of item, one of the item kinds of the fact set. */
81
+ readonly kind: string;
82
+ /** The visibility, one of the visibilities of the fact set. */
83
+ readonly visibility: string;
84
+ /** The paths that the item is tied to, such as the classes that it extends. */
85
+ readonly relations: readonly Relation[];
86
+ /**
87
+ * What the declaration says of the item besides its kind and its visibility, such as
88
+ * `async` or `documented`. Each is one of the modifiers of the fact set.
89
+ */
90
+ readonly modifiers: readonly string[];
91
+ }
92
+ /** A tie between a declared item and a path. */
93
+ export interface Relation {
94
+ /** The kind of tie, one of the relations of the fact set. */
95
+ readonly relation: string;
96
+ /** The path. */
97
+ readonly target: Path;
98
+ }
99
+ /** The unit refers to a path. */
100
+ export interface Reference {
101
+ /** Tells a reference from a marker. */
102
+ readonly type: "reference";
103
+ /** The path the code refers to, resolved as far as the front end can. */
104
+ readonly target: Path;
105
+ /** Further paths the same reference denotes, such as the definition behind a re-export. */
106
+ readonly aliases: readonly Path[];
107
+ /** The kind of the reference, one of the kinds of the fact set. */
108
+ readonly kind: string;
109
+ /** Whether the front end proved the path. */
110
+ readonly certainty: Certainty;
111
+ /**
112
+ * What the front end knows of the target besides its path, by name, such as the version
113
+ * of a package. No built-in rule reads them; a check of your own does.
114
+ */
115
+ readonly properties?: Readonly<Record<string, string>>;
116
+ }
117
+ /** The unit contains something that has a name but no path, such as an unsafe block. */
118
+ export interface Marker {
119
+ /** Tells a marker from a reference. */
120
+ readonly type: "marker";
121
+ /** The marker, one of the markers of the fact set. */
122
+ readonly marker: string;
123
+ }
124
+ /** `candidate`: the front end could not prove this path, for example a name behind a glob import. */
125
+ export type Certainty = "exact" | "candidate";
126
+ /** One architecture rule (SPEC section 4). */
127
+ export interface Rule {
128
+ /** The name, printed with every violation. An empty name is an error. */
129
+ readonly name: string;
130
+ /** Why the rule exists, printed with its violations. Default: no reason. */
131
+ readonly reason?: string;
132
+ /**
133
+ * `error`: a violation fails the check. `warning`: a violation is reported, and the check
134
+ * passes. It does not change the evaluation. Default: `error`.
135
+ */
136
+ readonly severity?: Severity;
137
+ /** The units the rule applies to. */
138
+ readonly subjects: Subjects;
139
+ /** What the units must do or must not do. */
140
+ readonly constraint: Constraint;
141
+ /** The reference kinds the rule looks at. Default: all kinds. */
142
+ readonly kinds?: KindFilter;
143
+ /** Facts with one of these tags are not checked. Default: none. */
144
+ readonly ignoreTags?: readonly string[];
145
+ /** Whether candidate references count. Default: `include`. */
146
+ readonly candidates?: Candidates;
147
+ /** References that the rule does not see. Default: none. */
148
+ readonly exemptions?: readonly Exemption[];
149
+ /**
150
+ * The names of the properties of references that the check of the rule reads. One that the
151
+ * front end does not produce is an error. Default: none.
152
+ */
153
+ readonly properties?: readonly string[];
154
+ }
155
+ /**
156
+ * References that a rule does not see (SPEC 4.13): those of the units that a `from` pattern
157
+ * matches exactly, with a path that a `to` pattern matches within.
158
+ */
159
+ export interface Exemption {
160
+ /** The units. An empty list is an error. */
161
+ readonly from: readonly RawPattern[];
162
+ /** The paths. An empty list is an error. */
163
+ readonly to: readonly RawPattern[];
164
+ }
165
+ /** Which units a rule applies to. */
166
+ export interface Subjects {
167
+ /** The units that are selected before the exceptions. */
168
+ readonly include: Include;
169
+ /** Absent: no exceptions. An empty list is an error. */
170
+ readonly except?: readonly RawPattern[];
171
+ }
172
+ /** The units a rule selects before its exceptions: all units, or those that a pattern matches exactly. */
173
+ export type Include = {
174
+ readonly type: "all";
175
+ } | {
176
+ readonly type: "any-of";
177
+ /** The patterns. An empty list is an error. */
178
+ readonly patterns: readonly RawPattern[];
179
+ };
180
+ /**
181
+ * What a rule demands of its subjects (SPEC section 4).
182
+ *
183
+ * - `must-not-use`: no reference may lead to one of the targets.
184
+ * - `must-only-use`: every reference must lead to one of the targets, or stay inside its own unit.
185
+ * - `must-not-contain`: the units must not contain one of the markers.
186
+ * - `must-be-acyclic`: the references between the units, or between the slices, must not form a cycle.
187
+ * - `must-be-independent`: no reference may lead from one slice to another slice.
188
+ * - `must-be-used`: each unit must be referred to from outside itself and the units below it.
189
+ * - `must-not-reach`: no chain of references may lead from the units to one of the targets.
190
+ * - `must-be-reachable-from`: a chain of references must lead from one of the roots to each unit.
191
+ * - `must-be-in`: each unit must be matched exactly by one of the places.
192
+ * - `must-only-be-used-by`: only the users, and the selected units, may refer to the selected units.
193
+ * - `items`: the declarations of the units that the filters select must meet a demand.
194
+ * - `custom`: a check of the binding, which finds the violations itself (SPEC 4.15). Only
195
+ * `select` takes it.
196
+ */
197
+ export type Constraint = {
198
+ readonly type: "must-not-use";
199
+ /** The paths that the units must not refer to. */
200
+ readonly targets: Targets;
201
+ } | {
202
+ readonly type: "must-only-use";
203
+ /** The only paths that the units may refer to outside themselves. */
204
+ readonly targets: Targets;
205
+ } | {
206
+ readonly type: "must-not-contain";
207
+ /** The markers. An empty list is an error. */
208
+ readonly markers: readonly string[];
209
+ } | {
210
+ readonly type: "must-be-acyclic";
211
+ /** Without `slices`, each unit is a node. An empty list is an error. */
212
+ readonly slices?: readonly RawPattern[];
213
+ } | {
214
+ readonly type: "must-be-independent";
215
+ /** The patterns of the slices. An empty list is an error. */
216
+ readonly slices: readonly RawPattern[];
217
+ } | {
218
+ readonly type: "must-be-used";
219
+ } | {
220
+ readonly type: "must-not-reach";
221
+ /** The paths that no chain from the units may end at. */
222
+ readonly targets: Targets;
223
+ } | {
224
+ readonly type: "must-be-reachable-from";
225
+ /** The patterns of the root units. An empty list is an error. */
226
+ readonly roots: readonly RawPattern[];
227
+ } | {
228
+ readonly type: "must-be-in";
229
+ /** The places, which match units exactly. An empty list is an error. */
230
+ readonly places: readonly RawPattern[];
231
+ } | {
232
+ readonly type: "must-only-be-used-by";
233
+ /** The units that may refer to the selected units, which match units exactly. An empty list is an error. */
234
+ readonly users: readonly RawPattern[];
235
+ } | {
236
+ /** Each unit must have at most a number of lines (SPEC 4.16). */
237
+ readonly type: "must-not-exceed-lines";
238
+ /** The number of lines that a unit may have. */
239
+ readonly lines: number;
240
+ } | ({
241
+ readonly type: "items";
242
+ } & Items) | CustomConstraint;
243
+ /**
244
+ * A check of the binding (SPEC 4.15), as a constraint or as the demand of a rule about
245
+ * items. The core applies the rest of the rule, and `select` answers what the rule sees.
246
+ */
247
+ export interface CustomConstraint {
248
+ /** Tells a custom check from the built-in ones. */
249
+ readonly type: "custom";
250
+ /** Lists of paths that the check looks for. For each list, `select` marks the first path of each reference that it matches. */
251
+ readonly targets?: readonly Targets[];
252
+ /** Lists of unit patterns. For each list, `select` answers the units that it matches exactly. */
253
+ readonly units?: readonly (readonly RawPattern[])[];
254
+ }
255
+ /** A rule about declarations (SPEC 4.12): filters, which all must hold, and a demand. */
256
+ export interface Items {
257
+ /** Absent: any name. Otherwise a glob must match the name. An empty list is an error. */
258
+ readonly named?: readonly string[];
259
+ /** Absent: any kind. An empty list is an error. */
260
+ readonly kinds?: readonly string[];
261
+ /** Absent: any visibility. An empty list is an error. */
262
+ readonly visibilities?: readonly string[];
263
+ /** The relations that the item must have, each to one of its paths. Absent or empty: any. */
264
+ readonly related?: readonly Related[];
265
+ /** Absent: any modifiers. Otherwise the item must have one of these. An empty list is an error. */
266
+ readonly modifiers?: readonly string[];
267
+ /** What each selected declaration must meet. */
268
+ readonly must: Demand;
269
+ }
270
+ /** A relation to one of some paths. */
271
+ export interface Related {
272
+ /** The kind of tie, such as `extends`. */
273
+ readonly relation: string;
274
+ /** The paths, which match the target within. An empty list is an error. */
275
+ readonly anyOf: readonly RawPattern[];
276
+ }
277
+ /**
278
+ * What each declaration of a rule about items must meet: not to exist, to reside in one of
279
+ * some units, to have a name that a glob matches, to have a relation or a modifier.
280
+ */
281
+ export type Demand = {
282
+ /** No declaration may be selected. */
283
+ readonly type: "not-exist";
284
+ } | {
285
+ /** The unit of the declaration must be one of the places. */
286
+ readonly type: "reside-in";
287
+ /** The places, which match units exactly. An empty list is an error. */
288
+ readonly places: readonly RawPattern[];
289
+ } | {
290
+ /** A glob must match the name. */
291
+ readonly type: "be-named";
292
+ /** The globs. An empty list is an error. */
293
+ readonly names: readonly string[];
294
+ } | ({
295
+ /** The item must have the relation to one of the paths. */
296
+ readonly type: "have";
297
+ } & Related) | {
298
+ /** The item must have one of the modifiers. */
299
+ readonly type: "have-modifier";
300
+ /** The modifiers. An empty list is an error. */
301
+ readonly modifiers: readonly string[];
302
+ } | {
303
+ /** No reference inside the item may lead to one of the targets (SPEC 4.12). */
304
+ readonly type: "not-use";
305
+ /** The paths that the code of the item must not refer to. */
306
+ readonly targets: Targets;
307
+ } | {
308
+ /** Every reference inside the item must lead to one of the targets, or stay in its unit (SPEC 4.12). */
309
+ readonly type: "only-use";
310
+ /** The only paths that the code of the item may refer to outside its unit. */
311
+ readonly targets: Targets;
312
+ } | {
313
+ /** The item must have at most a number of lines (SPEC 4.16). */
314
+ readonly type: "not-exceed-lines";
315
+ /** The number of lines that an item may have. */
316
+ readonly lines: number;
317
+ } | CustomConstraint;
318
+ /** Targets of a rule about uses: the union of both lists. */
319
+ export interface Targets {
320
+ /** Checked for existence when they are inside the analysed project. */
321
+ readonly anyOf: readonly RawPattern[];
322
+ /** Never checked for existence. */
323
+ readonly unverified: readonly RawPattern[];
324
+ }
325
+ /** How much a violation of a rule weighs (SPEC section 4). */
326
+ export type Severity = "error" | "warning";
327
+ /** Which reference kinds a rule looks at: all kinds, some kinds only, or all kinds except some. */
328
+ export type KindFilter = {
329
+ readonly type: "all";
330
+ } | {
331
+ readonly type: "only";
332
+ /** The kinds the rule looks at. */
333
+ readonly kinds: readonly string[];
334
+ } | {
335
+ readonly type: "except";
336
+ /** The kinds the rule does not look at. */
337
+ readonly kinds: readonly string[];
338
+ };
339
+ /** Whether a rule looks at candidate references. `include`: they count like exact references. */
340
+ export type Candidates = "include" | "ignore";
@@ -0,0 +1 @@
1
+ export {};