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
package/dist/cli/args.js
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Argument parsing, and nothing else.
|
|
3
|
+
*
|
|
4
|
+
* What a caller must know: this returns a Result too. An unknown flag is a CONFIG-class mistake —
|
|
5
|
+
* exit 2, not 1 — because an agent that typed the wrong flag must not read "no violations" as
|
|
6
|
+
* success.
|
|
7
|
+
*/
|
|
8
|
+
import { execFileSync } from 'node:child_process';
|
|
9
|
+
import { err, ok } from '../result.js';
|
|
10
|
+
const FORMATS = {
|
|
11
|
+
terminal: 'terminal',
|
|
12
|
+
json: 'json',
|
|
13
|
+
'json-pretty': 'json-pretty',
|
|
14
|
+
sarif: 'sarif',
|
|
15
|
+
verdict: 'verdict',
|
|
16
|
+
};
|
|
17
|
+
const TIERS = {
|
|
18
|
+
deterministic: 'deterministic',
|
|
19
|
+
proxy: 'proxy',
|
|
20
|
+
model: 'model',
|
|
21
|
+
};
|
|
22
|
+
export const HELP = `archcheck — architecture conformance, declared once and checked everywhere
|
|
23
|
+
|
|
24
|
+
archcheck run every rule, terminal output
|
|
25
|
+
archcheck --changed diff-scoped · the pre-commit path
|
|
26
|
+
archcheck --format json the agent format
|
|
27
|
+
archcheck --format sarif SARIF 2.1.0, for CI code scanning and editors
|
|
28
|
+
archcheck --format verdict one blocking answer, for a hook
|
|
29
|
+
archcheck --only deterministic skip the proxy and model tiers
|
|
30
|
+
archcheck --show-baselined include findings the baseline records
|
|
31
|
+
archcheck --write-graph write .archcheck/graph.json for later gates to ingest
|
|
32
|
+
archcheck --ingest-graph read .archcheck/graph.json instead of re-reading the graph
|
|
33
|
+
|
|
34
|
+
archcheck emit regenerate the emitted configs
|
|
35
|
+
archcheck emit --check fail if the committed output is stale
|
|
36
|
+
archcheck explain <ruleId> statement, remedy and current violations
|
|
37
|
+
archcheck coverage the three counts, computed from the manifest
|
|
38
|
+
archcheck baseline --write record today's violations as pre-existing debt
|
|
39
|
+
archcheck baseline --prune drop entries that no longer reproduce
|
|
40
|
+
archcheck init write a starting architecture.config.ts from the folders
|
|
41
|
+
archcheck --version
|
|
42
|
+
|
|
43
|
+
exit codes
|
|
44
|
+
0 clean, or only baselined and advisory findings
|
|
45
|
+
1 new violations of error-severity rules → fix the code
|
|
46
|
+
2 configuration invalid → fix the manifest, not the code
|
|
47
|
+
3 emitted output is stale → run archcheck emit
|
|
48
|
+
4 a baselined finding no longer reproduces → run archcheck baseline --prune
|
|
49
|
+
`;
|
|
50
|
+
/**
|
|
51
|
+
* Ask git for the changed set. Local only — archcheck makes no network call it was not told to.
|
|
52
|
+
*
|
|
53
|
+
* A git that cannot answer is a CONFIG failure (exit 2), never an empty changed set. git missing
|
|
54
|
+
* from PATH, an unborn or detached HEAD, or a directory outside any work tree used to be swallowed
|
|
55
|
+
* by a bare catch returning `[]`: every probe then filtered to nothing and the run reported clean,
|
|
56
|
+
* so a pre-commit hook passed every commit forever. Exit 2 because the manifest and the code are
|
|
57
|
+
* both fine — the environment is not, which is the same call `init` makes when it cannot read the
|
|
58
|
+
* module graph. `tests/cli.test.ts` → '--changed > git failing is a config error (2)' pins it.
|
|
59
|
+
*/
|
|
60
|
+
export function gitChangedFiles(cwd) {
|
|
61
|
+
const files = new Set();
|
|
62
|
+
for (const args of [
|
|
63
|
+
['diff', '--name-only', '--diff-filter=ACMR', 'HEAD'],
|
|
64
|
+
['diff', '--name-only', '--diff-filter=ACMR', '--cached'],
|
|
65
|
+
['ls-files', '--others', '--exclude-standard'],
|
|
66
|
+
]) {
|
|
67
|
+
let output;
|
|
68
|
+
try {
|
|
69
|
+
output = execFileSync('git', args, {
|
|
70
|
+
cwd,
|
|
71
|
+
encoding: 'utf8',
|
|
72
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
const said = error.stderr;
|
|
77
|
+
const detail = said === undefined || said.trim() === '' ? describeError(error) : said.trim();
|
|
78
|
+
return err([
|
|
79
|
+
`--changed asked git for the changed set, and \`git ${args.join(' ')}\` failed:`,
|
|
80
|
+
// git answers a misuse with its whole usage screen. The first two lines carry the reason;
|
|
81
|
+
// the rest would bury the two suggestions below.
|
|
82
|
+
...detail
|
|
83
|
+
.split('\n')
|
|
84
|
+
.filter((line) => line.trim() !== '')
|
|
85
|
+
.slice(0, 2)
|
|
86
|
+
.map((line) => ` ${line.trim()}`),
|
|
87
|
+
' → the environment is wrong, not the code: an empty changed set would check nothing',
|
|
88
|
+
' → name the files yourself (--changed a.ts,b.ts), or drop --changed to check everything',
|
|
89
|
+
]);
|
|
90
|
+
}
|
|
91
|
+
for (const line of output.split('\n')) {
|
|
92
|
+
const file = line.trim();
|
|
93
|
+
if (file.length > 0)
|
|
94
|
+
files.add(file);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return ok([...files].sort());
|
|
98
|
+
}
|
|
99
|
+
function describeError(error) {
|
|
100
|
+
return error instanceof Error ? error.message : String(error);
|
|
101
|
+
}
|
|
102
|
+
export function parseArgs(argv) {
|
|
103
|
+
const parsed = {
|
|
104
|
+
command: 'check',
|
|
105
|
+
format: 'terminal',
|
|
106
|
+
emitCheck: false,
|
|
107
|
+
force: false,
|
|
108
|
+
showBaselined: false,
|
|
109
|
+
ingestGraph: false,
|
|
110
|
+
writeGraph: false,
|
|
111
|
+
noColor: false,
|
|
112
|
+
};
|
|
113
|
+
const errors = [];
|
|
114
|
+
const rest = [...argv];
|
|
115
|
+
let sawCommand = false;
|
|
116
|
+
// The subcommand is recognised WHEREVER it appears, not only at argv[0]. `--cwd x baseline
|
|
117
|
+
// --write` is a perfectly natural thing to type, and a parser that silently rejected it read
|
|
118
|
+
// as "unexpected argument 'baseline'" — which names the wrong thing.
|
|
119
|
+
const COMMANDS = new Set(['check', 'emit', 'explain', 'coverage', 'baseline', 'init']);
|
|
120
|
+
while (rest.length > 0) {
|
|
121
|
+
const arg = rest.shift();
|
|
122
|
+
const [flag, inlineValue] = arg.startsWith('--') && arg.includes('=')
|
|
123
|
+
? [arg.slice(0, arg.indexOf('=')), arg.slice(arg.indexOf('=') + 1)]
|
|
124
|
+
: [arg, undefined];
|
|
125
|
+
const takeValue = () => inlineValue ?? (rest[0]?.startsWith('-') === false ? rest.shift() : undefined);
|
|
126
|
+
switch (flag) {
|
|
127
|
+
case '--version':
|
|
128
|
+
case '-v':
|
|
129
|
+
parsed.command = 'version';
|
|
130
|
+
break;
|
|
131
|
+
case '--help':
|
|
132
|
+
case '-h':
|
|
133
|
+
parsed.command = 'help';
|
|
134
|
+
break;
|
|
135
|
+
case '--format': {
|
|
136
|
+
const value = takeValue();
|
|
137
|
+
const format = value === undefined ? undefined : FORMATS[value];
|
|
138
|
+
if (format === undefined) {
|
|
139
|
+
errors.push(`--format expects one of ${Object.keys(FORMATS).join(', ')} (got ${String(value)})`);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
parsed.format = format;
|
|
143
|
+
}
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
case '--only': {
|
|
147
|
+
const value = takeValue();
|
|
148
|
+
const tier = value === undefined ? undefined : TIERS[value];
|
|
149
|
+
if (tier === undefined) {
|
|
150
|
+
errors.push(`--only expects one of ${Object.keys(TIERS).join(', ')} (got ${String(value)})`);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
parsed.only = tier;
|
|
154
|
+
}
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
case '--changed': {
|
|
158
|
+
const value = takeValue();
|
|
159
|
+
parsed.changed =
|
|
160
|
+
value === undefined
|
|
161
|
+
? []
|
|
162
|
+
: value
|
|
163
|
+
.split(',')
|
|
164
|
+
.map((f) => f.trim())
|
|
165
|
+
.filter(Boolean);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case '--check':
|
|
169
|
+
parsed.emitCheck = true;
|
|
170
|
+
break;
|
|
171
|
+
case '--write':
|
|
172
|
+
parsed.baselineMode = 'write';
|
|
173
|
+
break;
|
|
174
|
+
case '--prune':
|
|
175
|
+
parsed.baselineMode = 'prune';
|
|
176
|
+
break;
|
|
177
|
+
case '--force':
|
|
178
|
+
parsed.force = true;
|
|
179
|
+
break;
|
|
180
|
+
case '--show-baselined':
|
|
181
|
+
parsed.showBaselined = true;
|
|
182
|
+
break;
|
|
183
|
+
case '--ingest-graph':
|
|
184
|
+
parsed.ingestGraph = true;
|
|
185
|
+
break;
|
|
186
|
+
case '--write-graph':
|
|
187
|
+
parsed.writeGraph = true;
|
|
188
|
+
break;
|
|
189
|
+
case '--no-color':
|
|
190
|
+
parsed.noColor = true;
|
|
191
|
+
break;
|
|
192
|
+
case '--cwd': {
|
|
193
|
+
const value = takeValue();
|
|
194
|
+
if (value === undefined)
|
|
195
|
+
errors.push('--cwd expects a directory');
|
|
196
|
+
else
|
|
197
|
+
parsed.cwd = value;
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
default:
|
|
201
|
+
if (flag.startsWith('-'))
|
|
202
|
+
errors.push(`unknown flag '${flag}' — see archcheck --help`);
|
|
203
|
+
else if (COMMANDS.has(flag) && !sawCommand) {
|
|
204
|
+
parsed.command = flag;
|
|
205
|
+
sawCommand = true;
|
|
206
|
+
}
|
|
207
|
+
else if (parsed.command === 'explain' && parsed.ruleId === undefined)
|
|
208
|
+
parsed.ruleId = flag;
|
|
209
|
+
else
|
|
210
|
+
errors.push(`unexpected argument '${flag}'`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (parsed.command === 'explain' && parsed.ruleId === undefined) {
|
|
214
|
+
errors.push('explain needs a rule id: archcheck explain <ruleId>');
|
|
215
|
+
}
|
|
216
|
+
if (parsed.emitCheck && parsed.command !== 'emit') {
|
|
217
|
+
errors.push('--check applies to `archcheck emit` only');
|
|
218
|
+
}
|
|
219
|
+
if (parsed.baselineMode !== undefined && parsed.command !== 'baseline') {
|
|
220
|
+
errors.push('--write and --prune apply to `archcheck baseline` only');
|
|
221
|
+
}
|
|
222
|
+
if (parsed.force && parsed.command !== 'init') {
|
|
223
|
+
errors.push('--force applies to `archcheck init` only');
|
|
224
|
+
}
|
|
225
|
+
if (parsed.command === 'baseline' && parsed.baselineMode === undefined) {
|
|
226
|
+
errors.push("baseline needs a mode: --write to record today's violations, --prune to drop what no longer reproduces");
|
|
227
|
+
}
|
|
228
|
+
if (parsed.writeGraph && parsed.ingestGraph) {
|
|
229
|
+
errors.push('--write-graph and --ingest-graph are mutually exclusive: one produces the report the other consumes');
|
|
230
|
+
}
|
|
231
|
+
return errors.length > 0 ? err(errors) : ok(parsed);
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=args.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAYA,OAAO,EAIL,KAAK,QAAQ,EAId,MAAM,iBAAiB,CAAC;AAgLzB,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CA0BrE"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* The command surface. Thin by construction: parse args → one ArchCheck method → a reporter.
|
|
4
|
+
*
|
|
5
|
+
* What rule this enforces: this file owns NO behaviour. Every capability is reachable through
|
|
6
|
+
* `ArchCheck`, because the agent hook does not shell out (plan 10). A feature that only works from
|
|
7
|
+
* here would be a feature an agent cannot use.
|
|
8
|
+
*
|
|
9
|
+
* This is an app entry point — the one place allowed to write to the console (PROD-1).
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, writeFileSync } from 'node:fs';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
import { buildInitManifest, CONFIG_FILENAME, EXIT, exitCodeFor, initSummary, load, } from '../archcheck.js';
|
|
14
|
+
import { automatablePercent, MARK } from '../coverage/index.js';
|
|
15
|
+
import { describeUnimplemented } from '../emit/index.js';
|
|
16
|
+
import { describeStale } from '../emit/write.js';
|
|
17
|
+
import { reporterFor } from '../report/index.js';
|
|
18
|
+
import { gitChangedFiles, HELP, parseArgs } from './args.js';
|
|
19
|
+
import { packageVersion } from './version.js';
|
|
20
|
+
function fail(lines, code) {
|
|
21
|
+
for (const line of lines)
|
|
22
|
+
console.error(line);
|
|
23
|
+
return code;
|
|
24
|
+
}
|
|
25
|
+
async function runCheck(args, cwd) {
|
|
26
|
+
const loaded = load({ cwd });
|
|
27
|
+
if (!loaded.ok)
|
|
28
|
+
return fail(loaded.error, EXIT.config);
|
|
29
|
+
// Load-time warnings first: a judgement rule promoted to `error` is legal, and it must not be
|
|
30
|
+
// possible to promote one quietly.
|
|
31
|
+
for (const warning of loaded.value.registry.warnings())
|
|
32
|
+
console.error(`warning: ${warning}`);
|
|
33
|
+
// `--changed` with no value means "ask git". A git that cannot answer is a failure, never an
|
|
34
|
+
// empty changed set: every probe would filter to nothing and the run would read as clean
|
|
35
|
+
// (gitChangedFiles, src/cli/args.ts).
|
|
36
|
+
let changed = args.changed;
|
|
37
|
+
if (args.changed?.length === 0) {
|
|
38
|
+
const asked = gitChangedFiles(cwd);
|
|
39
|
+
if (!asked.ok)
|
|
40
|
+
return fail(asked.error, EXIT.config);
|
|
41
|
+
changed = asked.value;
|
|
42
|
+
}
|
|
43
|
+
const result = await loaded.value.check({
|
|
44
|
+
...(changed === undefined ? {} : { changed }),
|
|
45
|
+
...(args.only === undefined ? {} : { only: args.only }),
|
|
46
|
+
ingestGraph: args.ingestGraph,
|
|
47
|
+
writeGraph: args.writeGraph,
|
|
48
|
+
});
|
|
49
|
+
if (!result.ok)
|
|
50
|
+
return fail(result.error, EXIT.config);
|
|
51
|
+
const text = await reporterFor(args.format).report(result.value, {
|
|
52
|
+
showBaselined: args.showBaselined,
|
|
53
|
+
noColor: args.noColor || process.env.NO_COLOR !== undefined || !process.stdout.isTTY,
|
|
54
|
+
root: cwd,
|
|
55
|
+
});
|
|
56
|
+
if (typeof text === 'string')
|
|
57
|
+
process.stdout.write(text);
|
|
58
|
+
return exitCodeFor(result.value);
|
|
59
|
+
}
|
|
60
|
+
async function runEmit(args, cwd) {
|
|
61
|
+
// `emit` is the command that WRITES the id ledger, so it must be able to run while the ledger
|
|
62
|
+
// and the manifest disagree — otherwise recording a new id would require the record to exist.
|
|
63
|
+
const loaded = load({ cwd, skipIdCheck: args.emitCheck === false });
|
|
64
|
+
if (!loaded.ok)
|
|
65
|
+
return fail(loaded.error, EXIT.config);
|
|
66
|
+
// Skipping the immutability check is not the same as accepting a ledger nobody could read:
|
|
67
|
+
// `emit` WRITES the ledger, so it would replace it with one rebuilt from today's manifest and
|
|
68
|
+
// every retired id would vanish. `readIdLedger` (src/registry/ids.ts) marks it.
|
|
69
|
+
const ledger = loaded.value.registry.ledger();
|
|
70
|
+
if (ledger.unreadable !== undefined)
|
|
71
|
+
return fail([ledger.unreadable], EXIT.config);
|
|
72
|
+
// A kind no contract type implements generates nothing. `emit` has no `skipped` channel, so
|
|
73
|
+
// this is the one place it is said — on both the write and the --check path.
|
|
74
|
+
for (const line of describeUnimplemented(loaded.value.registry.all()))
|
|
75
|
+
console.error(line);
|
|
76
|
+
if (args.emitCheck) {
|
|
77
|
+
const stale = loaded.value.emitCheck();
|
|
78
|
+
if (!stale.ok)
|
|
79
|
+
return fail(stale.error, EXIT.config);
|
|
80
|
+
if (stale.value.length === 0) {
|
|
81
|
+
console.log('emitted output is up to date');
|
|
82
|
+
return EXIT.clean;
|
|
83
|
+
}
|
|
84
|
+
return fail([
|
|
85
|
+
'emitted output is stale:',
|
|
86
|
+
...describeStale(stale.value).map((line) => ` ${line}`),
|
|
87
|
+
// `unreadable` is the one reason re-emitting cannot fix — the document `docs` names is not
|
|
88
|
+
// there — so an agent is not sent round a loop that changes nothing.
|
|
89
|
+
...(stale.value.some((file) => file.reason !== 'unreadable')
|
|
90
|
+
? [' → run: npx archcheck emit']
|
|
91
|
+
: []),
|
|
92
|
+
], EXIT.stale);
|
|
93
|
+
}
|
|
94
|
+
const emitted = loaded.value.emit();
|
|
95
|
+
if (!emitted.ok)
|
|
96
|
+
return fail(emitted.error, EXIT.config);
|
|
97
|
+
const changed = emitted.value.written.filter((file) => file.changed);
|
|
98
|
+
if (changed.length === 0)
|
|
99
|
+
console.log('emitted output already matched the manifest');
|
|
100
|
+
for (const file of changed)
|
|
101
|
+
console.log(`wrote ${file.path}`);
|
|
102
|
+
console.log(`wrote ${emitted.value.ledgerPath}`);
|
|
103
|
+
return EXIT.clean;
|
|
104
|
+
}
|
|
105
|
+
function runInit(args, cwd) {
|
|
106
|
+
const configPath = join(cwd, CONFIG_FILENAME);
|
|
107
|
+
if (existsSync(configPath) && !args.force) {
|
|
108
|
+
return fail([
|
|
109
|
+
`${CONFIG_FILENAME} already exists — archcheck init will not overwrite your manifest`,
|
|
110
|
+
' → pass --force if you really mean to replace it',
|
|
111
|
+
], EXIT.config);
|
|
112
|
+
}
|
|
113
|
+
const built = buildInitManifest(cwd, join(cwd, 'tsconfig.json'));
|
|
114
|
+
if (!built.ok)
|
|
115
|
+
return fail(built.error, EXIT.config);
|
|
116
|
+
writeFileSync(configPath, built.value.manifest);
|
|
117
|
+
for (const line of initSummary(cwd, built.value.layers))
|
|
118
|
+
console.log(line);
|
|
119
|
+
console.log('');
|
|
120
|
+
if (!built.value.observed) {
|
|
121
|
+
// Never silent. Without the graph every allow-list is empty, so the manifest names the layers
|
|
122
|
+
// and describes nothing about how they depend on each other.
|
|
123
|
+
for (const line of built.value.notObservedBecause ?? [])
|
|
124
|
+
console.error(`warning: ${line}`);
|
|
125
|
+
console.error('');
|
|
126
|
+
console.error(`wrote ${CONFIG_FILENAME}, but archcheck could not read your module graph, so every ` +
|
|
127
|
+
'mayImport list is EMPTY.');
|
|
128
|
+
console.error(' → fix the problem above, delete the file, and run `archcheck init --force`');
|
|
129
|
+
return EXIT.config;
|
|
130
|
+
}
|
|
131
|
+
console.log(`wrote ${CONFIG_FILENAME} — every rule is 'warn', so the first run is green`);
|
|
132
|
+
console.log(' next: npx archcheck see what it observes');
|
|
133
|
+
console.log(' npx archcheck emit write the generated configs');
|
|
134
|
+
return EXIT.clean;
|
|
135
|
+
}
|
|
136
|
+
async function runBaseline(args, cwd) {
|
|
137
|
+
const loaded = load({ cwd });
|
|
138
|
+
if (!loaded.ok)
|
|
139
|
+
return fail(loaded.error, EXIT.config);
|
|
140
|
+
const outcome = await loaded.value.baseline(args.baselineMode ?? 'write');
|
|
141
|
+
if (!outcome.ok)
|
|
142
|
+
return fail(outcome.error, EXIT.config);
|
|
143
|
+
const { path, entries, removed, reduced } = outcome.value;
|
|
144
|
+
// Both halves of the ratchet, on one line: a prune that drops nothing and only lowers a recorded
|
|
145
|
+
// count has still tightened it, and `removed` alone reported that as having done nothing
|
|
146
|
+
// (`BaselineOutcome.reduced`, src/archcheck.ts).
|
|
147
|
+
console.log(args.baselineMode === 'prune'
|
|
148
|
+
? `pruned ${removed} entr${removed === 1 ? 'y' : 'ies'}, reduced ${reduced} ` +
|
|
149
|
+
`count${reduced === 1 ? '' : 's'} — ${entries} remaining in ${path}`
|
|
150
|
+
: `recorded ${entries} entr${entries === 1 ? 'y' : 'ies'} in ${path}`);
|
|
151
|
+
if (args.baselineMode === 'write' && entries > 0) {
|
|
152
|
+
console.log(' these are debt, not policy: no owner and no expiry, so they stay visible');
|
|
153
|
+
}
|
|
154
|
+
return EXIT.clean;
|
|
155
|
+
}
|
|
156
|
+
async function runExplain(args, cwd) {
|
|
157
|
+
const loaded = load({ cwd });
|
|
158
|
+
if (!loaded.ok)
|
|
159
|
+
return fail(loaded.error, EXIT.config);
|
|
160
|
+
const explained = await loaded.value.explain(args.ruleId ?? '');
|
|
161
|
+
if (!explained.ok)
|
|
162
|
+
return fail(explained.error, EXIT.config);
|
|
163
|
+
console.log(explained.value);
|
|
164
|
+
return EXIT.clean;
|
|
165
|
+
}
|
|
166
|
+
function runCoverage(cwd) {
|
|
167
|
+
const loaded = load({ cwd });
|
|
168
|
+
if (!loaded.ok)
|
|
169
|
+
return fail(loaded.error, EXIT.config);
|
|
170
|
+
const coverage = loaded.value.coverage();
|
|
171
|
+
const { total, deterministic, proxy, model, unchecked } = coverage;
|
|
172
|
+
console.log(`${MARK.deterministic} ${deterministic} deterministic`);
|
|
173
|
+
console.log(`${MARK.proxy} ${proxy} proxy`);
|
|
174
|
+
console.log(`${MARK.model} ${model} judgement`);
|
|
175
|
+
if (unchecked > 0) {
|
|
176
|
+
console.log(` ${unchecked} declared, but no version of archcheck checks their kind yet`);
|
|
177
|
+
}
|
|
178
|
+
console.log(` ${total} rules total · ${automatablePercent(coverage)}% automatable`);
|
|
179
|
+
return EXIT.clean;
|
|
180
|
+
}
|
|
181
|
+
export async function main(argv) {
|
|
182
|
+
const parsed = parseArgs(argv);
|
|
183
|
+
if (!parsed.ok)
|
|
184
|
+
return fail([...parsed.error, '', 'see archcheck --help'], EXIT.config);
|
|
185
|
+
const args = parsed.value;
|
|
186
|
+
const cwd = args.cwd ?? process.cwd();
|
|
187
|
+
switch (args.command) {
|
|
188
|
+
case 'version':
|
|
189
|
+
console.log(packageVersion());
|
|
190
|
+
return EXIT.clean;
|
|
191
|
+
case 'help':
|
|
192
|
+
console.log(HELP);
|
|
193
|
+
return EXIT.clean;
|
|
194
|
+
case 'emit':
|
|
195
|
+
return runEmit(args, cwd);
|
|
196
|
+
case 'explain':
|
|
197
|
+
return runExplain(args, cwd);
|
|
198
|
+
case 'coverage':
|
|
199
|
+
return runCoverage(cwd);
|
|
200
|
+
case 'baseline':
|
|
201
|
+
return runBaseline(args, cwd);
|
|
202
|
+
case 'init':
|
|
203
|
+
return runInit(args, cwd);
|
|
204
|
+
case 'check':
|
|
205
|
+
return runCheck(args, cwd);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// This module IS the bin, and nothing imports it, so it runs unconditionally. It previously
|
|
209
|
+
// guarded on `process.argv[1]` ending in `cli/index.js` — which is false when npm installs the
|
|
210
|
+
// package, because argv[1] is then the `node_modules/.bin/archcheck` symlink. The CLI silently
|
|
211
|
+
// did nothing and exited 0, so a consumer read "clean" from a check that never ran. A guard that
|
|
212
|
+
// can be wrong about whether to run at all has no place in an entry point.
|
|
213
|
+
main(process.argv.slice(2))
|
|
214
|
+
.then((code) => process.exit(code))
|
|
215
|
+
.catch((error) => {
|
|
216
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
217
|
+
process.exit(EXIT.config);
|
|
218
|
+
});
|
|
219
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/cli/version.ts"],"names":[],"mappings":"AAWA,wBAAgB,cAAc,IAAI,MAAM,CAkBvC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The package version, read from package.json at run time.
|
|
3
|
+
*
|
|
4
|
+
* Why read rather than inline: an inlined version drifts from the manifest the first time
|
|
5
|
+
* someone bumps one and not the other, and `archcheck --version` is the field a bug report
|
|
6
|
+
* quotes. `node:` builtins only — src/ stays Node-compatible.
|
|
7
|
+
*/
|
|
8
|
+
import { readFileSync } from 'node:fs';
|
|
9
|
+
import { dirname, join } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
export function packageVersion() {
|
|
12
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
// src/cli/ in development, dist/cli/ once built — package.json is two levels up from both.
|
|
14
|
+
for (const candidate of [
|
|
15
|
+
join(here, '..', '..', 'package.json'),
|
|
16
|
+
join(here, '..', 'package.json'),
|
|
17
|
+
]) {
|
|
18
|
+
try {
|
|
19
|
+
const raw = JSON.parse(readFileSync(candidate, 'utf8'));
|
|
20
|
+
if (raw.name === 'archcheck' && typeof raw.version === 'string')
|
|
21
|
+
return raw.version;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// try the next candidate — a missing package.json here is not an error yet
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return '0.0.0-unknown';
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/cli/version.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,cAAc;IAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,2FAA2F;IAC3F,KAAK,MAAM,SAAS,IAAI;QACtB,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC;QACtC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC;KACjC,EAAE,CAAC;QACF,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAGrD,CAAC;YACF,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ;gBAAE,OAAO,GAAG,CAAC,OAAO,CAAC;QACtF,CAAC;QAAC,MAAM,CAAC;YACP,2EAA2E;QAC7E,CAAC;IACH,CAAC;IACD,OAAO,eAAe,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `banned-syntax` kind. Constructs that are wrong wherever they appear in a given scope.
|
|
3
|
+
*
|
|
4
|
+
* What rule this enforces, and why the selector is a CLOSED SET rather than a selector language:
|
|
5
|
+
* the six rule families this kind exists for are
|
|
6
|
+
* no clock in a pure rule, no computed dynamic import, no console outside an entry point,
|
|
7
|
+
* no inline suppression comment, no branching on a literal name, no empty catch.
|
|
8
|
+
* Each is one named construct. A CSS-ish selector string would have to be parsed, would be
|
|
9
|
+
* half-implemented for years, and would let a manifest declare a selector that silently matches
|
|
10
|
+
* nothing — which looks exactly like compliance. A closed enum cannot do that: an unknown
|
|
11
|
+
* construct fails validation and exits 2.
|
|
12
|
+
*
|
|
13
|
+
* The inline-suppression ban is self-referential and deliberate. Exceptions live in the manifest
|
|
14
|
+
* with an owner and an expiry (plan 15); making the inline escape hatch itself a violation is what
|
|
15
|
+
* stops the manifest being bypassed.
|
|
16
|
+
*
|
|
17
|
+
* What a caller must know: these are evaluated over OUR OWN AST. We already hold the program from
|
|
18
|
+
* the graph reader, so a second parse would be waste. `remedy.autofix` stays false.
|
|
19
|
+
*/
|
|
20
|
+
import ts from 'typescript';
|
|
21
|
+
import type { Edge } from '../graph/types.js';
|
|
22
|
+
import type { Rule } from '../types.js';
|
|
23
|
+
import type { ContractType } from './types.js';
|
|
24
|
+
/** The closed set. Adding one is a deliberate change with a fixture, not a config value. */
|
|
25
|
+
export declare const BANNED_CONSTRUCTS: readonly ["member-access", "new-expression", "computed-dynamic-import", "suppression-comment", "string-literal-comparison", "empty-catch"];
|
|
26
|
+
export type BannedConstruct = (typeof BANNED_CONSTRUCTS)[number];
|
|
27
|
+
export type BannedSyntaxParams = {
|
|
28
|
+
appliesTo: string | string[];
|
|
29
|
+
selector: BannedConstruct;
|
|
30
|
+
/** The dotted name to ban, e.g. `Date.now` or `console`. Required by some constructs. */
|
|
31
|
+
target?: string;
|
|
32
|
+
};
|
|
33
|
+
export declare function asBannedSyntaxParams(rule: Rule): BannedSyntaxParams;
|
|
34
|
+
export declare function bannedSyntaxApplies(params: BannedSyntaxParams, relativePath: string): boolean;
|
|
35
|
+
export type BannedOccurrence = {
|
|
36
|
+
line: number;
|
|
37
|
+
col: number;
|
|
38
|
+
snippet: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Occurrences of the banned construct in one file.
|
|
42
|
+
*
|
|
43
|
+
* `computedImports` comes from the graph reader, which already detects a computed dynamic import —
|
|
44
|
+
* re-detecting it here would be a second implementation of the one thing that is hard to get right.
|
|
45
|
+
*/
|
|
46
|
+
export declare function findBannedOccurrences(params: BannedSyntaxParams, source: ts.SourceFile | undefined, computedImports: readonly Edge[]): BannedOccurrence[];
|
|
47
|
+
export declare const bannedSyntaxContract: ContractType;
|
|
48
|
+
//# sourceMappingURL=banned-syntax.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"banned-syntax.d.ts","sourceRoot":"","sources":["../../src/contracts/banned-syntax.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,KAAK,EAAwB,IAAI,EAAE,MAAM,aAAa,CAAC;AAE9D,OAAO,KAAK,EAAE,YAAY,EAAgD,MAAM,YAAY,CAAC;AAE7F,4FAA4F;AAC5F,eAAO,MAAM,iBAAiB,4IAOpB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAKjE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC7B,QAAQ,EAAE,eAAe,CAAC;IAC1B,yFAAyF;IACzF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,GAAG,kBAAkB,CAEnE;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAG7F;AAED,MAAM,MAAM,gBAAgB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AA0G9E;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,EAAE,CAAC,UAAU,GAAG,SAAS,EACjC,eAAe,EAAE,SAAS,IAAI,EAAE,GAC/B,gBAAgB,EAAE,CAepB;AA6DD,eAAO,MAAM,oBAAoB,EAAE,YAMlC,CAAC"}
|