arkgate 4.8.24 → 4.8.25
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/CHANGELOG.md +85 -0
- package/README.md +2 -2
- package/bin/ark-check-runtime.mjs +17 -14
- package/bin/ark-layer-match.mjs +115 -13
- package/bin/ark-mcp-runtime.mjs +36 -31
- package/bin/ark-shared.mjs +4 -23
- package/bin/lib/adoption-stance.mjs +2 -2
- package/bin/lib/adr-path.mjs +3 -3
- package/bin/lib/agent-gates.mjs +0 -61
- package/bin/lib/agent-homes.mjs +12 -21
- package/bin/lib/agent-projection-command.mjs +4 -4
- package/bin/lib/ambient-state.mjs +9 -30
- package/bin/lib/analysis-engine.mjs +14 -14
- package/bin/lib/architecture-scan.mjs +11 -9
- package/bin/lib/ark-order-doctor.mjs +3 -28
- package/bin/lib/ark-order-facts.mjs +6 -99
- package/bin/lib/ark-order-types.mjs +1 -2
- package/bin/lib/ark-run-doctor.mjs +3 -28
- package/bin/lib/ark-run-facts.mjs +30 -40
- package/bin/lib/ark-run-sensors.mjs +1 -1
- package/bin/lib/arkrule-file-hints.mjs +2 -47
- package/bin/lib/arkrules-contract.mjs +124 -133
- package/bin/lib/arkrules-sensors.mjs +7 -5
- package/bin/lib/check-args.mjs +63 -1
- package/bin/lib/ci-and-commands.mjs +8 -72
- package/bin/lib/ci-merge-boundary.mjs +1 -1
- package/bin/lib/class-source-scan.mjs +5 -5
- package/bin/lib/clone-detection.mjs +474 -0
- package/bin/lib/codex-home.mjs +1 -1
- package/bin/lib/config-contract-slices.mjs +44 -6
- package/bin/lib/config-contract.mjs +40 -117
- package/bin/lib/config-extras.mjs +16 -22
- package/bin/lib/contract-smells.mjs +33 -15
- package/bin/lib/core-ratchet.mjs +0 -2
- package/bin/lib/dashboard-cli.mjs +2 -2
- package/bin/lib/deep-module-coach.mjs +2 -4
- package/bin/lib/deploy-path.mjs +13 -38
- package/bin/lib/design-smells.mjs +2 -2
- package/bin/lib/diagnostic-catalog.mjs +8 -1
- package/bin/lib/doctor-advisories.mjs +55 -9
- package/bin/lib/doctor-green-cite.mjs +1 -1
- package/bin/lib/doctor-human.mjs +1 -1
- package/bin/lib/doctor-next-actions.mjs +2 -2
- package/bin/lib/doctor-plan.mjs +4 -6
- package/bin/lib/duplication-io.mjs +572 -0
- package/bin/lib/effective-contract-load.mjs +181 -44
- package/bin/lib/entry-points-io.mjs +424 -0
- package/bin/lib/extra-merge-teeth.mjs +36 -0
- package/bin/lib/field-install.mjs +38 -14
- package/bin/lib/first-run-help.mjs +7 -3
- package/bin/lib/flat-parent-importers.mjs +5 -3
- package/bin/lib/gate-files.mjs +30 -89
- package/bin/lib/github-enforcement.mjs +165 -28
- package/bin/lib/golden-pattern.mjs +1 -1
- package/bin/lib/hook-templates.mjs +16 -16
- package/bin/lib/html-report-advisories.mjs +4 -0
- package/bin/lib/html-report-depth.mjs +2 -2
- package/bin/lib/html-report.mjs +2 -2
- package/bin/lib/import-graph-projection.mjs +112 -0
- package/bin/lib/improvement-compass-doctor.mjs +1 -24
- package/bin/lib/invariant-coverage-io.mjs +4 -3
- package/bin/lib/invariant-coverage.mjs +26 -0
- package/bin/lib/invariant-probe-cli.mjs +347 -0
- package/bin/lib/invariant-probe-io.mjs +165 -0
- package/bin/lib/invariant-probe-runner.mjs +268 -0
- package/bin/lib/invariant-probe-sites.mjs +174 -0
- package/bin/lib/invariant-probe-workspace.mjs +183 -0
- package/bin/lib/invariant-probe.mjs +461 -0
- package/bin/lib/invariant-tests-path.mjs +16 -22
- package/bin/lib/literal-path-drift.mjs +4 -2
- package/bin/lib/managed-upgrade.mjs +2 -8
- package/bin/lib/mcp-adoption.mjs +4 -5
- package/bin/lib/mcp-hook-payload.mjs +4 -4
- package/bin/lib/orphan-modules-io.mjs +458 -0
- package/bin/lib/orphan-modules.mjs +251 -0
- package/bin/lib/outside-importers.mjs +197 -0
- package/bin/lib/package-manager.mjs +3 -3
- package/bin/lib/parse-health.mjs +1 -1
- package/bin/lib/persistence-write-hint.mjs +33 -8
- package/bin/lib/pin-dependent-gates.mjs +2 -2
- package/bin/lib/policy-delta-io.mjs +55 -8
- package/bin/lib/post-green-path.mjs +1 -1
- package/bin/lib/prepare-change.mjs +3 -9
- package/bin/lib/prepare-write.mjs +1 -2
- package/bin/lib/presets.mjs +56 -68
- package/bin/lib/product-copy.mjs +1 -6
- package/bin/lib/project-root.mjs +31 -62
- package/bin/lib/resolved-candidate-facts.mjs +90 -62
- package/bin/lib/rules-under-contract.mjs +72 -8
- package/bin/lib/scan-files.mjs +4 -4
- package/bin/lib/schema-validation.mjs +130 -0
- package/bin/lib/sensor-promote-cli.mjs +2 -11
- package/bin/lib/sensor-promote-io.mjs +33 -22
- package/bin/lib/sensor-promotion.mjs +1 -1
- package/bin/lib/skill-catalog-apply.mjs +1 -1
- package/bin/lib/skill-install.mjs +42 -38
- package/bin/lib/snippet-analysis.mjs +1 -1
- package/bin/lib/start-install-recovery.mjs +1 -1
- package/bin/lib/start-preview.mjs +1 -1
- package/bin/lib/states-transitions-presence.mjs +3 -3
- package/bin/lib/status-command.mjs +2 -18
- package/bin/lib/status-manifest.mjs +18 -26
- package/bin/lib/status-transition-catalog.mjs +0 -6
- package/bin/lib/suggestions.mjs +3 -3
- package/bin/lib/team-parliament-io.mjs +3 -17
- package/bin/lib/team-parliament.mjs +15 -9
- package/bin/lib/upgrade-behavior-changes.mjs +2 -2
- package/bin/lib/upgrade-command.mjs +2 -24
- package/bin/lib/upgrade-outcome.mjs +1 -1
- package/bin/lib/upstream-report.mjs +21 -10
- package/bin/lib/violations.mjs +10 -9
- package/bin/lib/weakest-link.mjs +13 -0
- package/bin/lib/write-path-capabilities.mjs +2 -2
- package/dist/chunk-AHACEKSV.js +16 -0
- package/dist/chunk-UN5EH4QV.cjs +16 -0
- package/dist/{configTypes-BJbaeoj4.d.cts → configTypes-GPvvdleM.d.cts} +12 -1
- package/dist/{configTypes-BJbaeoj4.d.ts → configTypes-GPvvdleM.d.ts} +12 -1
- package/dist/eslint/index.cjs +11 -11
- package/dist/eslint/index.d.cts +10 -1
- package/dist/eslint/index.d.ts +10 -1
- package/dist/eslint/index.js +11 -11
- package/dist/index.cjs +34 -34
- package/dist/index.d.cts +587 -515
- package/dist/index.d.ts +587 -515
- package/dist/index.js +34 -34
- package/dist/nestjs/index.cjs +1 -1
- package/dist/nestjs/index.d.cts +1 -1
- package/dist/nestjs/index.d.ts +1 -1
- package/dist/nestjs/index.js +1 -1
- package/dist/order/index.cjs +1 -1
- package/dist/order/index.js +1 -1
- package/dist/runtime/index.cjs +12 -12
- package/dist/runtime/index.d.cts +174 -136
- package/dist/runtime/index.d.ts +174 -136
- package/dist/runtime/index.js +12 -12
- package/dist/{types-DRinG-vT.d.cts → types-CnauMQQL.d.cts} +33 -25
- package/dist/{types-DRinG-vT.d.ts → types-CnauMQQL.d.ts} +33 -25
- package/docs/README.md +2 -1
- package/docs/agent-guide.md +134 -2
- package/docs/ai-gates.md +15 -1
- package/docs/configuration.md +40 -11
- package/docs/diagnostics.md +118 -2
- package/docs/package-surface.md +4 -1
- package/docs/product-voice.md +7 -1
- package/package.json +11 -2
- package/schemas/ark.config.schema.json +31 -3
- package/schemas/ark.invariant-probe.schema.json +368 -0
- package/server.json +2 -2
- package/templates/agent-skills/README.md +1 -1
- package/templates/agent-skills/ark-adopt/SKILL.md +1 -0
- package/templates/agent-skills/ark-contract/SKILL.md +17 -0
- package/templates/agent-skills/ark-coverage/SKILL.md +2 -0
- package/templates/agent-skills/ark-explore/SKILL.md +7 -0
- package/templates/agent-skills/ark-fix/SKILL.md +20 -0
- package/templates/agent-skills/ark-place/SKILL.md +8 -0
- package/templates/skills/ark-adopt.md +1 -0
- package/templates/skills/ark-contract.md +17 -0
- package/templates/skills/ark-coverage.md +2 -0
- package/templates/skills/ark-explore.md +7 -0
- package/templates/skills/ark-fix.md +20 -0
- package/templates/skills/ark-place.md +8 -0
- package/bin/lib/ark-order-error.mjs +0 -18
- package/bin/lib/ark-order-invariants.mjs +0 -388
- package/bin/lib/stable-hash.mjs +0 -90
- package/dist/chunk-MBXCFLO4.js +0 -16
- package/dist/chunk-RNQHRDCQ.cjs +0 -16
|
@@ -11,8 +11,12 @@ import path from 'node:path';
|
|
|
11
11
|
import {
|
|
12
12
|
emptyEffectiveArkRules,
|
|
13
13
|
buildEffectiveArkRules,
|
|
14
|
+
duplicateArkRuleIds,
|
|
14
15
|
loadArkRulesContract,
|
|
16
|
+
sliceScopeEscapes,
|
|
15
17
|
} from './arkrules-contract.mjs';
|
|
18
|
+
import { resolveSliceRulePlan } from '../ark-layer-match.mjs';
|
|
19
|
+
import { collectGovernedFiles } from './scan-files.mjs';
|
|
16
20
|
|
|
17
21
|
export function normalizeProjectRelativePath(value) {
|
|
18
22
|
const normalized = value.replace(/\\/g, '/');
|
|
@@ -33,7 +37,7 @@ export function normalizeProjectRelativePath(value) {
|
|
|
33
37
|
return segments.length > 0 ? segments.join('/') : undefined;
|
|
34
38
|
}
|
|
35
39
|
|
|
36
|
-
|
|
40
|
+
function isWithinRoot(root, candidate) {
|
|
37
41
|
const relative = path.relative(root, candidate);
|
|
38
42
|
return (
|
|
39
43
|
relative === '' ||
|
|
@@ -56,60 +60,124 @@ export function isWithinRoot(root, candidate) {
|
|
|
56
60
|
* from the source counts as an empty layer (a base that predates the file), not an error.
|
|
57
61
|
* @returns {{ arkRules: ReturnType<typeof emptyEffectiveArkRules>, errors: Array<{path:string,message:string}>, referenced: Set<string> }}
|
|
58
62
|
*/
|
|
63
|
+
function declaredLayerNames(config) {
|
|
64
|
+
return new Set(Array.isArray(config?.layers) ? config.layers.map((layer) => layer?.name).filter(Boolean) : []);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function arkRulesRefList(value) {
|
|
68
|
+
if (typeof value === 'string') return value.length > 0 ? [value] : null;
|
|
69
|
+
if (Array.isArray(value) && value.length > 0 && value.every((entry) => typeof entry === 'string' && entry.length > 0)) {
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function pushReadError(errors, pathKey, rel, error) {
|
|
76
|
+
errors.push({
|
|
77
|
+
path: pathKey,
|
|
78
|
+
message:
|
|
79
|
+
error instanceof Error
|
|
80
|
+
? error.message
|
|
81
|
+
: `referenced ArkRules file ${JSON.stringify(rel)} failed to load`,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
59
85
|
export function loadEffectiveArkRules(config, readRelative, opts = {}) {
|
|
60
86
|
const refs = config?.arkRules;
|
|
61
87
|
const referenced = new Set();
|
|
62
|
-
|
|
63
|
-
return { arkRules: emptyEffectiveArkRules(), errors: [], referenced };
|
|
64
|
-
}
|
|
65
|
-
const layerNames = new Set(
|
|
66
|
-
Array.isArray(config.layers) ? config.layers.map((layer) => layer.name) : []
|
|
67
|
-
);
|
|
88
|
+
const layerNames = declaredLayerNames(config);
|
|
68
89
|
const errors = [];
|
|
69
90
|
const parts = [];
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
91
|
+
const hasRefs = Boolean(refs && typeof refs === 'object' && Object.keys(refs).length > 0);
|
|
92
|
+
if (hasRefs) {
|
|
93
|
+
for (const layer of Object.keys(refs).sort()) {
|
|
94
|
+
const raw = refs[layer];
|
|
95
|
+
const paths = arkRulesRefList(raw);
|
|
96
|
+
const pathKey = `$.arkRules[${JSON.stringify(layer)}]`;
|
|
97
|
+
if (!paths) {
|
|
98
|
+
errors.push({ path: pathKey, message: 'must be a non-empty path string or an array of paths' });
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (!layerNames.has(layer)) {
|
|
102
|
+
errors.push({
|
|
103
|
+
path: pathKey,
|
|
104
|
+
message: `layer ${JSON.stringify(layer)} is not declared in layers[]`,
|
|
105
|
+
});
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
paths.forEach((relRaw, index) => {
|
|
109
|
+
const itemKey = paths.length === 1 && typeof raw === 'string' ? pathKey : `${pathKey}[${index}]`;
|
|
110
|
+
const rel = normalizeProjectRelativePath(relRaw);
|
|
111
|
+
if (!rel) {
|
|
112
|
+
errors.push({
|
|
113
|
+
path: itemKey,
|
|
114
|
+
message:
|
|
115
|
+
'must be a project-relative path without absolute roots or parent-directory traversal',
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
referenced.add(rel);
|
|
120
|
+
const read = readRelative(rel);
|
|
121
|
+
if (!read.ok) {
|
|
122
|
+
if (read.missing && opts.missingAsEmpty) return;
|
|
123
|
+
errors.push({ path: itemKey, message: read.message });
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const loaded = loadArkRulesContract(JSON.parse(read.content), rel, layer);
|
|
128
|
+
parts.push({ layer, sourceFile: rel, file: loaded.config });
|
|
129
|
+
} catch (error) {
|
|
130
|
+
pushReadError(errors, itemKey, rel, error);
|
|
131
|
+
}
|
|
90
132
|
});
|
|
91
|
-
continue;
|
|
92
133
|
}
|
|
93
|
-
|
|
94
|
-
|
|
134
|
+
}
|
|
135
|
+
const plan = resolveSliceRulePlan({
|
|
136
|
+
files: Array.isArray(opts.files) ? opts.files : [],
|
|
137
|
+
rules: Array.isArray(config?.rules) ? config.rules : [],
|
|
138
|
+
layers: [...layerNames],
|
|
139
|
+
});
|
|
140
|
+
for (const entry of plan) {
|
|
141
|
+
const read = readRelative(entry.path);
|
|
95
142
|
if (!read.ok) {
|
|
96
|
-
if (read.missing
|
|
97
|
-
errors.push({ path:
|
|
143
|
+
if (read.missing) continue;
|
|
144
|
+
errors.push({ path: entry.path, message: read.message });
|
|
98
145
|
continue;
|
|
99
146
|
}
|
|
147
|
+
referenced.add(entry.path);
|
|
100
148
|
try {
|
|
101
|
-
const loaded = loadArkRulesContract(JSON.parse(read.content),
|
|
102
|
-
|
|
149
|
+
const loaded = loadArkRulesContract(JSON.parse(read.content), entry.path, entry.layer);
|
|
150
|
+
const part = {
|
|
151
|
+
layer: entry.layer,
|
|
152
|
+
sourceFile: entry.path,
|
|
153
|
+
file: loaded.config,
|
|
154
|
+
childId: entry.childId,
|
|
155
|
+
defaultAppliesTo: entry.defaultAppliesTo,
|
|
156
|
+
};
|
|
157
|
+
const escapes = sliceScopeEscapes(part);
|
|
158
|
+
if (escapes.length > 0) {
|
|
159
|
+
errors.push({
|
|
160
|
+
path: entry.path,
|
|
161
|
+
message: `ARKRULE_SCOPE_ESCAPES_SLICE: ${entry.path} appliesTo ${escapes
|
|
162
|
+
.map((row) => row.pattern)
|
|
163
|
+
.join(', ')} escapes ${entry.childId}`,
|
|
164
|
+
});
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
parts.push(part);
|
|
103
168
|
} catch (error) {
|
|
104
|
-
errors.
|
|
105
|
-
path: pathKey,
|
|
106
|
-
message:
|
|
107
|
-
error instanceof Error
|
|
108
|
-
? error.message
|
|
109
|
-
: `referenced ArkRules file ${JSON.stringify(rel)} failed to load`,
|
|
110
|
-
});
|
|
169
|
+
pushReadError(errors, entry.path, entry.path, error);
|
|
111
170
|
}
|
|
112
171
|
}
|
|
172
|
+
for (const dupe of duplicateArkRuleIds(parts)) {
|
|
173
|
+
errors.push({
|
|
174
|
+
path: `$.arkRules[${JSON.stringify(dupe.layer)}]`,
|
|
175
|
+
message: `ARKRULE_DUPLICATE_ID: ${dupe.id} is declared in ${dupe.sourceFiles.join(', ')}`,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
if (!hasRefs && parts.length === 0 && errors.length === 0) {
|
|
179
|
+
return { arkRules: emptyEffectiveArkRules(), errors: [], referenced };
|
|
180
|
+
}
|
|
113
181
|
if (errors.length > 0) return { arkRules: emptyEffectiveArkRules(), errors, referenced };
|
|
114
182
|
return { arkRules: buildEffectiveArkRules(parts), errors: [], referenced };
|
|
115
183
|
}
|
|
@@ -210,7 +278,7 @@ function unreferencedArkRulesWarnings(canonicalRoot, referenced) {
|
|
|
210
278
|
return warnings;
|
|
211
279
|
}
|
|
212
280
|
|
|
213
|
-
|
|
281
|
+
const ARKRULE_FILE_UNREFERENCED = 'ARKRULE_FILE_UNREFERENCED';
|
|
214
282
|
|
|
215
283
|
/**
|
|
216
284
|
* Loader drift warnings as advisory check warnings (never fail --strict-config).
|
|
@@ -233,10 +301,79 @@ export function arkRulesDriftWarnings(warnings) {
|
|
|
233
301
|
* @param {{ observeInput?: (abs: string, kind: string) => void }} [opts]
|
|
234
302
|
* @returns {{ arkRules: ReturnType<typeof emptyEffectiveArkRules>, warnings: Array<{path:string,message:string,severity:string}>, errors: Array<{path:string,message:string}> }}
|
|
235
303
|
*/
|
|
304
|
+
function governedRelativeFiles(canonicalRoot, config) {
|
|
305
|
+
const include = Array.isArray(config?.include) && config.include.length > 0 ? config.include : ['src'];
|
|
306
|
+
return collectGovernedFiles(canonicalRoot, { ...config, include })
|
|
307
|
+
.map((file) => path.relative(canonicalRoot, file).split(path.sep).join('/'))
|
|
308
|
+
.filter((rel) => rel && !rel.startsWith('..'));
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function sliceRuleBasenames(config) {
|
|
312
|
+
return [...declaredLayerNames(config)].map((layer) => `arkrules.${layer}.json`);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/** `arkrules.<Layer>.json` beside a governed file or one of its parents. Not a repo-wide search. */
|
|
316
|
+
function unreferencedSliceRuleWarnings(canonicalRoot, referenced, files, basenames) {
|
|
317
|
+
const wanted = new Set(basenames);
|
|
318
|
+
if (wanted.size === 0) return [];
|
|
319
|
+
const dirs = new Set();
|
|
320
|
+
for (const rel of files) {
|
|
321
|
+
let end = String(rel).lastIndexOf('/');
|
|
322
|
+
while (end > 0) {
|
|
323
|
+
const dir = String(rel).slice(0, end);
|
|
324
|
+
if (dirs.has(dir)) break;
|
|
325
|
+
dirs.add(dir);
|
|
326
|
+
end = dir.lastIndexOf('/');
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
const warnings = [];
|
|
330
|
+
for (const dir of dirs) {
|
|
331
|
+
let names;
|
|
332
|
+
try {
|
|
333
|
+
names = fs.readdirSync(path.join(canonicalRoot, ...dir.split('/')));
|
|
334
|
+
} catch {
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
for (const name of names) {
|
|
338
|
+
if (!wanted.has(name)) continue;
|
|
339
|
+
const candidate = `${dir}/${name}`;
|
|
340
|
+
if (referenced.has(candidate)) continue;
|
|
341
|
+
warnings.push({
|
|
342
|
+
path: candidate,
|
|
343
|
+
message: `ArkRules file ${JSON.stringify(candidate)} is not referenced by arkRules and will not be enforced`,
|
|
344
|
+
severity: 'advisory',
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return warnings;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export function arkRulesLoadFailed(source, errors) {
|
|
352
|
+
const message = (errors ?? []).map((issue) => `- ${issue.path}: ${issue.message}`).join('\n');
|
|
353
|
+
const contractError = (errors ?? []).some(
|
|
354
|
+
(issue) =>
|
|
355
|
+
typeof issue.message === 'string' &&
|
|
356
|
+
(issue.message.includes('ARKRULE_DUPLICATE_ID') || issue.message.includes('ARKRULE_SCOPE_ESCAPES_SLICE'))
|
|
357
|
+
);
|
|
358
|
+
const label = contractError ? 'Invalid ArkGate config' : 'Invalid Effective Contract';
|
|
359
|
+
const error = new Error(`${label} (${source}):\n${message}`);
|
|
360
|
+
error.code = 'ARKRULES_LOAD_FAILED';
|
|
361
|
+
error.issues = errors;
|
|
362
|
+
if (contractError) {
|
|
363
|
+
error.name = 'ArkConfigValidationError';
|
|
364
|
+
error.source = source;
|
|
365
|
+
}
|
|
366
|
+
return error;
|
|
367
|
+
}
|
|
368
|
+
|
|
236
369
|
export function loadEffectiveArkRulesFromDisk(root, config, opts = {}) {
|
|
237
370
|
const canonicalRoot = fs.realpathSync(root);
|
|
238
|
-
const
|
|
371
|
+
const files = Array.isArray(opts.files) ? opts.files : governedRelativeFiles(canonicalRoot, config);
|
|
372
|
+
const loaded = loadEffectiveArkRules(config, directoryArkRulesReader(canonicalRoot, opts), { ...opts, files });
|
|
239
373
|
// Drift runs with or without a map: an arkrules/ directory nobody references is visible.
|
|
240
|
-
const warnings =
|
|
374
|
+
const warnings = [
|
|
375
|
+
...unreferencedArkRulesWarnings(canonicalRoot, loaded.referenced),
|
|
376
|
+
...unreferencedSliceRuleWarnings(canonicalRoot, loaded.referenced, files, sliceRuleBasenames(config)),
|
|
377
|
+
].sort((left, right) => left.path.localeCompare(right.path));
|
|
241
378
|
return { arkRules: loaded.arkRules, warnings, errors: loaded.errors };
|
|
242
379
|
}
|