@archwall/core 0.1.0 → 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/dist/index.cjs +53 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +117 -5
- package/dist/index.d.mts +117 -5
- package/dist/index.mjs +53 -8
- package/dist/index.mjs.map +1 -1
- package/dist/internal.cjs +2 -1
- package/dist/internal.d.cts +3 -3
- package/dist/internal.d.mts +3 -3
- package/dist/internal.mjs +2 -2
- package/dist/{prepare-BJHgDEui.mjs → prepare-BjMxyYOm.mjs} +29 -5
- package/dist/prepare-BjMxyYOm.mjs.map +1 -0
- package/dist/{prepare-C1FfL8Qd.cjs → prepare-CEaZxLPI.cjs} +29 -5
- package/dist/prepare-CEaZxLPI.cjs.map +1 -0
- package/dist/{transform-CnUPOO0E.d.mts → transform-CzxyWbUC.d.cts} +139 -14
- package/dist/{transform-CnUPOO0E.d.cts → transform-CzxyWbUC.d.mts} +139 -14
- package/package.json +1 -1
- package/dist/prepare-BJHgDEui.mjs.map +0 -1
- package/dist/prepare-C1FfL8Qd.cjs.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as ProjectGraph, A as primaryEdge, B as EdgeAttributes, C as Violation, D as countBySeverity, E as compareViolations, F as ClassifierContext, G as GraphMutation, H as FIRST_PARTY_KINDS, I as TagPatch, J as MODULE_ID_SCHEMES, K as HostInfo, L as defineClassifier, M as primarySourceLocation, N as renderMessage, O as fingerprintOf, P as Classifier, Q as ModuleNode, R as Capability, S as SeverityCounts, T as ViolationLocation, U as GraphDelivery, V as EdgeKind, X as ModuleIdScheme, Y as ModuleId, Z as ModuleKind, _ as RuleSkippedDetails, a as defineGraphComputation, at as assertIrCompatible, b as FINGERPRINT_SCHEME, ct as isFirstParty, d as ModuleSelection, et as ProjectGraphInit, g as EmptyScopeDetails, h as DiagnosticSeverity, i as GraphComputation, it as WellKnownEdgeKind, j as primaryModule, k as locationsOf, l as GraphView, lt as isThirdParty, m as DiagnosticCode, n as TransformContext, nt as THIRD_PARTY_KINDS, o as EdgeFilter, ot as displayModuleId, p as Diagnostic, q as IR_VERSION, r as defineTransform, rt as WellKnownCapability, st as irMajor, t as GraphTransform, tt as SourceLocation, u as ModuleFilter, ut as parseModuleId, v as UnscannableFilesDetails, w as ViolationInput, x as Severity, y as WellKnownDiagnosticCode, z as Edge } from "./transform-CzxyWbUC.cjs";
|
|
2
2
|
//#region src/analysis/scc.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Strongly connected components over static+reexport edges (a dynamic import is a
|
|
@@ -110,8 +110,26 @@ interface RuleRunInfo {
|
|
|
110
110
|
deprecated?: boolean;
|
|
111
111
|
}
|
|
112
112
|
interface AnalysisResult {
|
|
113
|
-
/**
|
|
113
|
+
/**
|
|
114
|
+
* Findings that COUNT — the ones `failOn` gates and reporters lead with. Deterministically
|
|
115
|
+
* ordered; see `compareViolations`.
|
|
116
|
+
*/
|
|
114
117
|
violations: readonly Violation[];
|
|
118
|
+
/**
|
|
119
|
+
* Findings matched by the baseline and therefore not counted, in the same order.
|
|
120
|
+
*
|
|
121
|
+
* Separate from `violations` rather than a flag on them, because every consumer that exists
|
|
122
|
+
* wants the un-suppressed set by default: a reporter that had to remember to filter would
|
|
123
|
+
* eventually forget, and the failure would be an enforcement tool quietly counting findings
|
|
124
|
+
* the user already accepted.
|
|
125
|
+
*
|
|
126
|
+
* Always present, empty when no baseline is configured — so a reporter written today needs
|
|
127
|
+
* no change when baselines arrive, and `violations.length + suppressed.length` is the total
|
|
128
|
+
* the analysis actually found.
|
|
129
|
+
*
|
|
130
|
+
* @see UserConfig.baseline
|
|
131
|
+
*/
|
|
132
|
+
suppressed: readonly Violation[];
|
|
115
133
|
/** Everything that is not a violation: skipped rules, crashed rules, config problems. */
|
|
116
134
|
diagnostics: readonly Diagnostic[];
|
|
117
135
|
stats: AnalysisStats;
|
|
@@ -205,7 +223,7 @@ interface RuleMeta<Options> {
|
|
|
205
223
|
}
|
|
206
224
|
interface RuleContext<Options> {
|
|
207
225
|
options: Options;
|
|
208
|
-
graph:
|
|
226
|
+
graph: GraphView;
|
|
209
227
|
/**
|
|
210
228
|
* Absolute source root. The base for any path *pattern* a rule matches against, so that
|
|
211
229
|
* rule options read the same way as classifier patterns and `include`/`exclude`.
|
|
@@ -443,6 +461,23 @@ interface FailOnDiagnostics {
|
|
|
443
461
|
invalidConfig?: boolean;
|
|
444
462
|
/** A configured rule is deprecated. Default false. */
|
|
445
463
|
deprecated?: boolean;
|
|
464
|
+
/**
|
|
465
|
+
* In-boundary files the producer could not read, and so never analysed. Default false.
|
|
466
|
+
*
|
|
467
|
+
* Default false only because turning it on would fail CI for every Vue/Svelte/Astro project
|
|
468
|
+
* the moment they upgrade, and a warning they can see beats an error they revert. Turn it on
|
|
469
|
+
* in any repository where "ArchWall looked at all of it" is load-bearing — which, for a tool
|
|
470
|
+
* whose whole failure mode is passing green without looking, is most of them.
|
|
471
|
+
*/
|
|
472
|
+
unscannableFiles?: boolean;
|
|
473
|
+
/**
|
|
474
|
+
* The baseline contains entries this run did not match. Default false.
|
|
475
|
+
*
|
|
476
|
+
* False by default because the common cause is the good one — somebody fixed something — and
|
|
477
|
+
* failing CI for that punishes exactly the behaviour the baseline exists to encourage. Teams
|
|
478
|
+
* that want the file kept honest turn it on and prune as they go.
|
|
479
|
+
*/
|
|
480
|
+
baselineStale?: boolean;
|
|
446
481
|
}
|
|
447
482
|
interface ResolvedFailOnDiagnostics {
|
|
448
483
|
ruleFailed: boolean;
|
|
@@ -452,6 +487,8 @@ interface ResolvedFailOnDiagnostics {
|
|
|
452
487
|
invalidOptions: boolean;
|
|
453
488
|
invalidConfig: boolean;
|
|
454
489
|
deprecated: boolean;
|
|
490
|
+
unscannableFiles: boolean;
|
|
491
|
+
baselineStale: boolean;
|
|
455
492
|
}
|
|
456
493
|
/**
|
|
457
494
|
* Which diagnostic codes each `failOnDiagnostics` switch governs, and whether it is on by
|
|
@@ -494,6 +531,14 @@ declare const DIAGNOSTIC_GATES: {
|
|
|
494
531
|
readonly codes: readonly ["rule-deprecated"];
|
|
495
532
|
readonly default: false;
|
|
496
533
|
};
|
|
534
|
+
readonly unscannableFiles: {
|
|
535
|
+
readonly codes: readonly ["unscannable-files"];
|
|
536
|
+
readonly default: false;
|
|
537
|
+
};
|
|
538
|
+
readonly baselineStale: {
|
|
539
|
+
readonly codes: readonly ["baseline-stale"];
|
|
540
|
+
readonly default: false;
|
|
541
|
+
};
|
|
497
542
|
};
|
|
498
543
|
/**
|
|
499
544
|
* Applies {@link DIAGNOSTIC_GATES}' defaults to whatever the user left unset.
|
|
@@ -587,6 +632,18 @@ interface UserConfig {
|
|
|
587
632
|
* `{ reporter, output }` to send one somewhere other than stdout. Default ["console"].
|
|
588
633
|
*/
|
|
589
634
|
reporters?: ReporterSpec[];
|
|
635
|
+
/**
|
|
636
|
+
* Path to a baseline file of accepted violations, relative to {@link repoRoot}.
|
|
637
|
+
*
|
|
638
|
+
* RESERVED — declared, resolved, and carried on `ResolvedConfig`, but not yet read. See
|
|
639
|
+
* `AnalysisResult.suppressed`.
|
|
640
|
+
*
|
|
641
|
+
* A graph-based linter has no other suppression mechanism available: with no source text
|
|
642
|
+
* there can be no `// archwall-ignore`, so accepting existing findings has to be a file
|
|
643
|
+
* keyed on violation fingerprints. That is what makes ArchWall adoptable on a codebase that
|
|
644
|
+
* did not start with it — the alternative is 400 violations on day one and an uninstall.
|
|
645
|
+
*/
|
|
646
|
+
baseline?: string;
|
|
590
647
|
/** Which VIOLATION severity gates the run. `info` findings never fail it. */
|
|
591
648
|
failOn?: FailOn;
|
|
592
649
|
/** Which DIAGNOSTICS gate the run, regardless of `failOn`. */
|
|
@@ -607,6 +664,8 @@ interface ResolvedRule {
|
|
|
607
664
|
interface ResolvedConfig {
|
|
608
665
|
/** Absolute. Base for reported paths and fingerprints. */
|
|
609
666
|
repoRoot: string;
|
|
667
|
+
/** Absolute path to the baseline file, or null. RESERVED; see {@link UserConfig.baseline}. */
|
|
668
|
+
baseline: string | null;
|
|
610
669
|
/** Absolute, at or below {@link repoRoot}. Base for the boundary and classifiers. */
|
|
611
670
|
sourceRoot: string;
|
|
612
671
|
include: string[];
|
|
@@ -633,12 +692,41 @@ declare function resolveConfig(user: UserConfig, opts?: {
|
|
|
633
692
|
}): ResolvedConfig;
|
|
634
693
|
//#endregion
|
|
635
694
|
//#region src/engine/analyze.d.ts
|
|
695
|
+
/**
|
|
696
|
+
* Per-call knobs, kept OUT of {@link ResolvedConfig}.
|
|
697
|
+
*
|
|
698
|
+
* The distinction is load-bearing: `ResolvedConfig` is the user's declared policy, is
|
|
699
|
+
* serialisable, and is the same for every run. These are properties of one invocation. Folding
|
|
700
|
+
* a cancellation token into the config would make the config unserialisable and would mean two
|
|
701
|
+
* runs of "the same configuration" were not comparable.
|
|
702
|
+
*
|
|
703
|
+
* The parameter exists now, ahead of most of its contents, on purpose: adding a third parameter
|
|
704
|
+
* later is free, but adding it *after* third parties have wrapped `analyze` is not, and every
|
|
705
|
+
* capability that wants a per-call channel (progress, logging, cancellation, incremental reuse)
|
|
706
|
+
* would otherwise arrive as its own breaking change.
|
|
707
|
+
*/
|
|
708
|
+
interface AnalyzeOptions {
|
|
709
|
+
/**
|
|
710
|
+
* Aborts the run between rules. Honoured at rule-dispatch boundaries, not mid-traversal:
|
|
711
|
+
* a rule sees the whole slice it was given or none of it, so a cancelled run never produces
|
|
712
|
+
* the partial findings {@link RuleRun.crashed} exists to discard.
|
|
713
|
+
*/
|
|
714
|
+
signal?: AbortSignal;
|
|
715
|
+
/**
|
|
716
|
+
* RESERVED, and currently ignored. The previous run's result, for incremental reuse.
|
|
717
|
+
*
|
|
718
|
+
* Declared before it is honoured so that the eventual implementation is a behaviour change
|
|
719
|
+
* rather than a signature change. Passing it today is safe and does nothing; do not write
|
|
720
|
+
* code that depends on it having an effect.
|
|
721
|
+
*/
|
|
722
|
+
previous?: AnalysisResult;
|
|
723
|
+
}
|
|
636
724
|
/**
|
|
637
725
|
* The engine: prepare the graph (boundary → transforms → classify), then check it.
|
|
638
726
|
*
|
|
639
727
|
* Pure — no I/O, no reporter calls; reporters are driven by the run edge (integration-kit).
|
|
640
728
|
*/
|
|
641
|
-
declare function analyze(graph: ProjectGraph, config: ResolvedConfig): Promise<AnalysisResult>;
|
|
729
|
+
declare function analyze(graph: ProjectGraph, config: ResolvedConfig, options?: AnalyzeOptions): Promise<AnalysisResult>;
|
|
642
730
|
//#endregion
|
|
643
731
|
//#region src/errors.d.ts
|
|
644
732
|
declare class ArchWallError extends Error {
|
|
@@ -717,5 +805,29 @@ declare function sarifReporter(sink: OutputSink): Reporter;
|
|
|
717
805
|
*/
|
|
718
806
|
declare function dropSelfEdges(): GraphTransform;
|
|
719
807
|
//#endregion
|
|
720
|
-
|
|
808
|
+
//#region src/transforms/drop-type-only-edges.d.ts
|
|
809
|
+
/**
|
|
810
|
+
* Removes edges the host marked `attributes.typeOnly`.
|
|
811
|
+
*
|
|
812
|
+
* This is the *policy* half of type-only support, deliberately separated from the *fact* half.
|
|
813
|
+
* Producers report what the code says; whether an erased import counts as a dependency is a
|
|
814
|
+
* question about the user's architecture, and different answers are legitimately right:
|
|
815
|
+
*
|
|
816
|
+
* - A layering rule usually SHOULD see type-only edges — `domain` importing an
|
|
817
|
+
* `infrastructure` type still couples the two at design time, which is the thing layering
|
|
818
|
+
* exists to prevent.
|
|
819
|
+
* - A cycle rule usually should NOT — a type-only cycle costs nothing at runtime and
|
|
820
|
+
* `no-cycles` flagging one is the most common false positive in this whole category of tool.
|
|
821
|
+
*
|
|
822
|
+
* So it is off by default and opted into per config, rather than being baked into a producer.
|
|
823
|
+
* Before this existed the CLI simply never emitted type-only edges, which made that choice for
|
|
824
|
+
* everyone, made the CLI disagree with every bundler adapter, and left no way to get the
|
|
825
|
+
* edges back.
|
|
826
|
+
*
|
|
827
|
+
* Only meaningful when the host declares `type-only-edges`; against a host that erased type
|
|
828
|
+
* imports before ArchWall saw them, there is nothing here to remove and this is a no-op.
|
|
829
|
+
*/
|
|
830
|
+
declare function dropTypeOnlyEdges(): GraphTransform;
|
|
831
|
+
//#endregion
|
|
832
|
+
export { type AnalysisResult, type AnalysisStats, type AnalyzeOptions, ArchWallError, BUILTIN_REPORTER_NAMES, type BuiltinReporterName, type CallableRule, type Capability, type Classifier, type ClassifierContext, type ConfiguredRule, DIAGNOSTIC_GATES, type Diagnostic, type DiagnosticCode, type DiagnosticSeverity, type Edge, type EdgeAttributes, type EdgeFilter, type EdgeKind, type EmptyScopeDetails, FINGERPRINT_SCHEME, FIRST_PARTY_KINDS, type FailOn, type FailOnDiagnostics, type GraphComputation, type GraphDelivery, type GraphMutation, type GraphTransform, type GraphView, type HostInfo, IR_VERSION, IrVersionMismatchError, MODULE_ID_SCHEMES, type ModuleFilter, type ModuleId, type ModuleIdScheme, type ModuleKind, type ModuleNode, type ModuleSelection, type OutputDestination, type OutputSink, type PathClassifierOptions, type PathPattern, type Preset, type PresetMeta, type PresetSpec, ProjectGraph, type ProjectGraphInit, type Reporter, type ReporterIO, type ReporterOutputSpec, type ReporterSpec, type ResolvedConfig, type ResolvedFailOnDiagnostics, type ResolvedReporters, type ResolvedRule, type Rule, type RuleContext, type RuleDeprecation, type RuleMeta, type RuleOverride, type RuleRunInfo, type RuleScope, type RuleSettings, type RuleSkippedDetails, type RuleSpec, type RuleVisitors, type RunInfo, type Severity, type SeverityCounts, type SourceLocation, type StandardSchemaIssue, type StandardSchemaResult, type StandardSchemaV1, THIRD_PARTY_KINDS, type TagPatch, type TransformContext, type UnscannableFilesDetails, type UserConfig, type Violation, type ViolationInput, type ViolationLocation, type WellKnownCapability, type WellKnownDiagnosticCode, type WellKnownEdgeKind, analyze, assertIrCompatible, compareViolations, configureRule, consoleReporter, countBySeverity, defaultIO, defineClassifier, defineConfig, defineGraphComputation, definePreset, defineReporter, defineRule, defineTransform, displayModuleId, dropSelfEdges, dropTypeOnlyEdges, failingDiagnosticCodes, fingerprintOf, formatViolation, irMajor, isBuiltinReporterName, isFirstParty, isThirdParty, jsonReporter, locationsOf, matchCaptures, matchesPattern, parseModuleId, pathClassifier, primaryEdge, primaryModule, primarySourceLocation, renderMessage, resolveConfig, resolveFailOnDiagnostics, resolveReporters, sarifReporter, stronglyConnectedComponents };
|
|
721
833
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as ProjectGraph, A as primaryEdge, B as EdgeAttributes, C as Violation, D as countBySeverity, E as compareViolations, F as ClassifierContext, G as GraphMutation, H as FIRST_PARTY_KINDS, I as TagPatch, J as MODULE_ID_SCHEMES, K as HostInfo, L as defineClassifier, M as primarySourceLocation, N as renderMessage, O as fingerprintOf, P as Classifier, Q as ModuleNode, R as Capability, S as SeverityCounts, T as ViolationLocation, U as GraphDelivery, V as EdgeKind, X as ModuleIdScheme, Y as ModuleId, Z as ModuleKind, _ as RuleSkippedDetails, a as defineGraphComputation, at as assertIrCompatible, b as FINGERPRINT_SCHEME, ct as isFirstParty, d as ModuleSelection, et as ProjectGraphInit, g as EmptyScopeDetails, h as DiagnosticSeverity, i as GraphComputation, it as WellKnownEdgeKind, j as primaryModule, k as locationsOf, l as GraphView, lt as isThirdParty, m as DiagnosticCode, n as TransformContext, nt as THIRD_PARTY_KINDS, o as EdgeFilter, ot as displayModuleId, p as Diagnostic, q as IR_VERSION, r as defineTransform, rt as WellKnownCapability, st as irMajor, t as GraphTransform, tt as SourceLocation, u as ModuleFilter, ut as parseModuleId, v as UnscannableFilesDetails, w as ViolationInput, x as Severity, y as WellKnownDiagnosticCode, z as Edge } from "./transform-CzxyWbUC.mjs";
|
|
2
2
|
//#region src/analysis/scc.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Strongly connected components over static+reexport edges (a dynamic import is a
|
|
@@ -110,8 +110,26 @@ interface RuleRunInfo {
|
|
|
110
110
|
deprecated?: boolean;
|
|
111
111
|
}
|
|
112
112
|
interface AnalysisResult {
|
|
113
|
-
/**
|
|
113
|
+
/**
|
|
114
|
+
* Findings that COUNT — the ones `failOn` gates and reporters lead with. Deterministically
|
|
115
|
+
* ordered; see `compareViolations`.
|
|
116
|
+
*/
|
|
114
117
|
violations: readonly Violation[];
|
|
118
|
+
/**
|
|
119
|
+
* Findings matched by the baseline and therefore not counted, in the same order.
|
|
120
|
+
*
|
|
121
|
+
* Separate from `violations` rather than a flag on them, because every consumer that exists
|
|
122
|
+
* wants the un-suppressed set by default: a reporter that had to remember to filter would
|
|
123
|
+
* eventually forget, and the failure would be an enforcement tool quietly counting findings
|
|
124
|
+
* the user already accepted.
|
|
125
|
+
*
|
|
126
|
+
* Always present, empty when no baseline is configured — so a reporter written today needs
|
|
127
|
+
* no change when baselines arrive, and `violations.length + suppressed.length` is the total
|
|
128
|
+
* the analysis actually found.
|
|
129
|
+
*
|
|
130
|
+
* @see UserConfig.baseline
|
|
131
|
+
*/
|
|
132
|
+
suppressed: readonly Violation[];
|
|
115
133
|
/** Everything that is not a violation: skipped rules, crashed rules, config problems. */
|
|
116
134
|
diagnostics: readonly Diagnostic[];
|
|
117
135
|
stats: AnalysisStats;
|
|
@@ -205,7 +223,7 @@ interface RuleMeta<Options> {
|
|
|
205
223
|
}
|
|
206
224
|
interface RuleContext<Options> {
|
|
207
225
|
options: Options;
|
|
208
|
-
graph:
|
|
226
|
+
graph: GraphView;
|
|
209
227
|
/**
|
|
210
228
|
* Absolute source root. The base for any path *pattern* a rule matches against, so that
|
|
211
229
|
* rule options read the same way as classifier patterns and `include`/`exclude`.
|
|
@@ -443,6 +461,23 @@ interface FailOnDiagnostics {
|
|
|
443
461
|
invalidConfig?: boolean;
|
|
444
462
|
/** A configured rule is deprecated. Default false. */
|
|
445
463
|
deprecated?: boolean;
|
|
464
|
+
/**
|
|
465
|
+
* In-boundary files the producer could not read, and so never analysed. Default false.
|
|
466
|
+
*
|
|
467
|
+
* Default false only because turning it on would fail CI for every Vue/Svelte/Astro project
|
|
468
|
+
* the moment they upgrade, and a warning they can see beats an error they revert. Turn it on
|
|
469
|
+
* in any repository where "ArchWall looked at all of it" is load-bearing — which, for a tool
|
|
470
|
+
* whose whole failure mode is passing green without looking, is most of them.
|
|
471
|
+
*/
|
|
472
|
+
unscannableFiles?: boolean;
|
|
473
|
+
/**
|
|
474
|
+
* The baseline contains entries this run did not match. Default false.
|
|
475
|
+
*
|
|
476
|
+
* False by default because the common cause is the good one — somebody fixed something — and
|
|
477
|
+
* failing CI for that punishes exactly the behaviour the baseline exists to encourage. Teams
|
|
478
|
+
* that want the file kept honest turn it on and prune as they go.
|
|
479
|
+
*/
|
|
480
|
+
baselineStale?: boolean;
|
|
446
481
|
}
|
|
447
482
|
interface ResolvedFailOnDiagnostics {
|
|
448
483
|
ruleFailed: boolean;
|
|
@@ -452,6 +487,8 @@ interface ResolvedFailOnDiagnostics {
|
|
|
452
487
|
invalidOptions: boolean;
|
|
453
488
|
invalidConfig: boolean;
|
|
454
489
|
deprecated: boolean;
|
|
490
|
+
unscannableFiles: boolean;
|
|
491
|
+
baselineStale: boolean;
|
|
455
492
|
}
|
|
456
493
|
/**
|
|
457
494
|
* Which diagnostic codes each `failOnDiagnostics` switch governs, and whether it is on by
|
|
@@ -494,6 +531,14 @@ declare const DIAGNOSTIC_GATES: {
|
|
|
494
531
|
readonly codes: readonly ["rule-deprecated"];
|
|
495
532
|
readonly default: false;
|
|
496
533
|
};
|
|
534
|
+
readonly unscannableFiles: {
|
|
535
|
+
readonly codes: readonly ["unscannable-files"];
|
|
536
|
+
readonly default: false;
|
|
537
|
+
};
|
|
538
|
+
readonly baselineStale: {
|
|
539
|
+
readonly codes: readonly ["baseline-stale"];
|
|
540
|
+
readonly default: false;
|
|
541
|
+
};
|
|
497
542
|
};
|
|
498
543
|
/**
|
|
499
544
|
* Applies {@link DIAGNOSTIC_GATES}' defaults to whatever the user left unset.
|
|
@@ -587,6 +632,18 @@ interface UserConfig {
|
|
|
587
632
|
* `{ reporter, output }` to send one somewhere other than stdout. Default ["console"].
|
|
588
633
|
*/
|
|
589
634
|
reporters?: ReporterSpec[];
|
|
635
|
+
/**
|
|
636
|
+
* Path to a baseline file of accepted violations, relative to {@link repoRoot}.
|
|
637
|
+
*
|
|
638
|
+
* RESERVED — declared, resolved, and carried on `ResolvedConfig`, but not yet read. See
|
|
639
|
+
* `AnalysisResult.suppressed`.
|
|
640
|
+
*
|
|
641
|
+
* A graph-based linter has no other suppression mechanism available: with no source text
|
|
642
|
+
* there can be no `// archwall-ignore`, so accepting existing findings has to be a file
|
|
643
|
+
* keyed on violation fingerprints. That is what makes ArchWall adoptable on a codebase that
|
|
644
|
+
* did not start with it — the alternative is 400 violations on day one and an uninstall.
|
|
645
|
+
*/
|
|
646
|
+
baseline?: string;
|
|
590
647
|
/** Which VIOLATION severity gates the run. `info` findings never fail it. */
|
|
591
648
|
failOn?: FailOn;
|
|
592
649
|
/** Which DIAGNOSTICS gate the run, regardless of `failOn`. */
|
|
@@ -607,6 +664,8 @@ interface ResolvedRule {
|
|
|
607
664
|
interface ResolvedConfig {
|
|
608
665
|
/** Absolute. Base for reported paths and fingerprints. */
|
|
609
666
|
repoRoot: string;
|
|
667
|
+
/** Absolute path to the baseline file, or null. RESERVED; see {@link UserConfig.baseline}. */
|
|
668
|
+
baseline: string | null;
|
|
610
669
|
/** Absolute, at or below {@link repoRoot}. Base for the boundary and classifiers. */
|
|
611
670
|
sourceRoot: string;
|
|
612
671
|
include: string[];
|
|
@@ -633,12 +692,41 @@ declare function resolveConfig(user: UserConfig, opts?: {
|
|
|
633
692
|
}): ResolvedConfig;
|
|
634
693
|
//#endregion
|
|
635
694
|
//#region src/engine/analyze.d.ts
|
|
695
|
+
/**
|
|
696
|
+
* Per-call knobs, kept OUT of {@link ResolvedConfig}.
|
|
697
|
+
*
|
|
698
|
+
* The distinction is load-bearing: `ResolvedConfig` is the user's declared policy, is
|
|
699
|
+
* serialisable, and is the same for every run. These are properties of one invocation. Folding
|
|
700
|
+
* a cancellation token into the config would make the config unserialisable and would mean two
|
|
701
|
+
* runs of "the same configuration" were not comparable.
|
|
702
|
+
*
|
|
703
|
+
* The parameter exists now, ahead of most of its contents, on purpose: adding a third parameter
|
|
704
|
+
* later is free, but adding it *after* third parties have wrapped `analyze` is not, and every
|
|
705
|
+
* capability that wants a per-call channel (progress, logging, cancellation, incremental reuse)
|
|
706
|
+
* would otherwise arrive as its own breaking change.
|
|
707
|
+
*/
|
|
708
|
+
interface AnalyzeOptions {
|
|
709
|
+
/**
|
|
710
|
+
* Aborts the run between rules. Honoured at rule-dispatch boundaries, not mid-traversal:
|
|
711
|
+
* a rule sees the whole slice it was given or none of it, so a cancelled run never produces
|
|
712
|
+
* the partial findings {@link RuleRun.crashed} exists to discard.
|
|
713
|
+
*/
|
|
714
|
+
signal?: AbortSignal;
|
|
715
|
+
/**
|
|
716
|
+
* RESERVED, and currently ignored. The previous run's result, for incremental reuse.
|
|
717
|
+
*
|
|
718
|
+
* Declared before it is honoured so that the eventual implementation is a behaviour change
|
|
719
|
+
* rather than a signature change. Passing it today is safe and does nothing; do not write
|
|
720
|
+
* code that depends on it having an effect.
|
|
721
|
+
*/
|
|
722
|
+
previous?: AnalysisResult;
|
|
723
|
+
}
|
|
636
724
|
/**
|
|
637
725
|
* The engine: prepare the graph (boundary → transforms → classify), then check it.
|
|
638
726
|
*
|
|
639
727
|
* Pure — no I/O, no reporter calls; reporters are driven by the run edge (integration-kit).
|
|
640
728
|
*/
|
|
641
|
-
declare function analyze(graph: ProjectGraph, config: ResolvedConfig): Promise<AnalysisResult>;
|
|
729
|
+
declare function analyze(graph: ProjectGraph, config: ResolvedConfig, options?: AnalyzeOptions): Promise<AnalysisResult>;
|
|
642
730
|
//#endregion
|
|
643
731
|
//#region src/errors.d.ts
|
|
644
732
|
declare class ArchWallError extends Error {
|
|
@@ -717,5 +805,29 @@ declare function sarifReporter(sink: OutputSink): Reporter;
|
|
|
717
805
|
*/
|
|
718
806
|
declare function dropSelfEdges(): GraphTransform;
|
|
719
807
|
//#endregion
|
|
720
|
-
|
|
808
|
+
//#region src/transforms/drop-type-only-edges.d.ts
|
|
809
|
+
/**
|
|
810
|
+
* Removes edges the host marked `attributes.typeOnly`.
|
|
811
|
+
*
|
|
812
|
+
* This is the *policy* half of type-only support, deliberately separated from the *fact* half.
|
|
813
|
+
* Producers report what the code says; whether an erased import counts as a dependency is a
|
|
814
|
+
* question about the user's architecture, and different answers are legitimately right:
|
|
815
|
+
*
|
|
816
|
+
* - A layering rule usually SHOULD see type-only edges — `domain` importing an
|
|
817
|
+
* `infrastructure` type still couples the two at design time, which is the thing layering
|
|
818
|
+
* exists to prevent.
|
|
819
|
+
* - A cycle rule usually should NOT — a type-only cycle costs nothing at runtime and
|
|
820
|
+
* `no-cycles` flagging one is the most common false positive in this whole category of tool.
|
|
821
|
+
*
|
|
822
|
+
* So it is off by default and opted into per config, rather than being baked into a producer.
|
|
823
|
+
* Before this existed the CLI simply never emitted type-only edges, which made that choice for
|
|
824
|
+
* everyone, made the CLI disagree with every bundler adapter, and left no way to get the
|
|
825
|
+
* edges back.
|
|
826
|
+
*
|
|
827
|
+
* Only meaningful when the host declares `type-only-edges`; against a host that erased type
|
|
828
|
+
* imports before ArchWall saw them, there is nothing here to remove and this is a no-op.
|
|
829
|
+
*/
|
|
830
|
+
declare function dropTypeOnlyEdges(): GraphTransform;
|
|
831
|
+
//#endregion
|
|
832
|
+
export { type AnalysisResult, type AnalysisStats, type AnalyzeOptions, ArchWallError, BUILTIN_REPORTER_NAMES, type BuiltinReporterName, type CallableRule, type Capability, type Classifier, type ClassifierContext, type ConfiguredRule, DIAGNOSTIC_GATES, type Diagnostic, type DiagnosticCode, type DiagnosticSeverity, type Edge, type EdgeAttributes, type EdgeFilter, type EdgeKind, type EmptyScopeDetails, FINGERPRINT_SCHEME, FIRST_PARTY_KINDS, type FailOn, type FailOnDiagnostics, type GraphComputation, type GraphDelivery, type GraphMutation, type GraphTransform, type GraphView, type HostInfo, IR_VERSION, IrVersionMismatchError, MODULE_ID_SCHEMES, type ModuleFilter, type ModuleId, type ModuleIdScheme, type ModuleKind, type ModuleNode, type ModuleSelection, type OutputDestination, type OutputSink, type PathClassifierOptions, type PathPattern, type Preset, type PresetMeta, type PresetSpec, ProjectGraph, type ProjectGraphInit, type Reporter, type ReporterIO, type ReporterOutputSpec, type ReporterSpec, type ResolvedConfig, type ResolvedFailOnDiagnostics, type ResolvedReporters, type ResolvedRule, type Rule, type RuleContext, type RuleDeprecation, type RuleMeta, type RuleOverride, type RuleRunInfo, type RuleScope, type RuleSettings, type RuleSkippedDetails, type RuleSpec, type RuleVisitors, type RunInfo, type Severity, type SeverityCounts, type SourceLocation, type StandardSchemaIssue, type StandardSchemaResult, type StandardSchemaV1, THIRD_PARTY_KINDS, type TagPatch, type TransformContext, type UnscannableFilesDetails, type UserConfig, type Violation, type ViolationInput, type ViolationLocation, type WellKnownCapability, type WellKnownDiagnosticCode, type WellKnownEdgeKind, analyze, assertIrCompatible, compareViolations, configureRule, consoleReporter, countBySeverity, defaultIO, defineClassifier, defineConfig, defineGraphComputation, definePreset, defineReporter, defineRule, defineTransform, displayModuleId, dropSelfEdges, dropTypeOnlyEdges, failingDiagnosticCodes, fingerprintOf, formatViolation, irMajor, isBuiltinReporterName, isFirstParty, isThirdParty, jsonReporter, locationsOf, matchCaptures, matchesPattern, parseModuleId, pathClassifier, primaryEdge, primaryModule, primarySourceLocation, renderMessage, resolveConfig, resolveFailOnDiagnostics, resolveReporters, sarifReporter, stronglyConnectedComponents };
|
|
721
833
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as sourceRelative, _ as isThirdParty, a as filterKey, b as IrVersionMismatchError, d as ProjectGraph, f as THIRD_PARTY_KINDS, g as isFirstParty, h as irMajor, i as GraphQuery, l as IR_VERSION, m as displayModuleId, n as prepareGraph, o as GraphComputationCache, p as assertIrCompatible, s as FIRST_PARTY_KINDS, u as MODULE_ID_SCHEMES, v as parseModuleId, w as toRelative, x as hashParts, y as ArchWallError } from "./prepare-
|
|
1
|
+
import { S as sourceRelative, _ as isThirdParty, a as filterKey, b as IrVersionMismatchError, d as ProjectGraph, f as THIRD_PARTY_KINDS, g as isFirstParty, h as irMajor, i as GraphQuery, l as IR_VERSION, m as displayModuleId, n as prepareGraph, o as GraphComputationCache, p as assertIrCompatible, s as FIRST_PARTY_KINDS, u as MODULE_ID_SCHEMES, v as parseModuleId, w as toRelative, x as hashParts, y as ArchWallError } from "./prepare-BjMxyYOm.mjs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import picomatch from "picomatch";
|
|
4
4
|
//#region src/contracts/analysis.ts
|
|
@@ -326,8 +326,7 @@ function renderMessage(template, data) {
|
|
|
326
326
|
* Fingerprint scheme version. Bump when the algorithm changes so that a stale baseline
|
|
327
327
|
* ERRORS instead of silently mismatching every entry.
|
|
328
328
|
*
|
|
329
|
-
* `aw3` is the first scheme over canonical module ids
|
|
330
|
-
* (docs/adr/0012-canonical-module-identity.md). Before it, a violation about `react` hashed the
|
|
329
|
+
* `aw3` is the first scheme over canonical module ids. Before it, a violation about `react` hashed the
|
|
331
330
|
* host's own id — a resolved `node_modules` path under the CLI, the bare specifier under esbuild
|
|
332
331
|
* — so the same finding fingerprinted differently under two bundlers.
|
|
333
332
|
*/
|
|
@@ -681,6 +680,14 @@ const DIAGNOSTIC_GATES = {
|
|
|
681
680
|
deprecated: {
|
|
682
681
|
codes: ["rule-deprecated"],
|
|
683
682
|
default: false
|
|
683
|
+
},
|
|
684
|
+
unscannableFiles: {
|
|
685
|
+
codes: ["unscannable-files"],
|
|
686
|
+
default: false
|
|
687
|
+
},
|
|
688
|
+
baselineStale: {
|
|
689
|
+
codes: ["baseline-stale"],
|
|
690
|
+
default: false
|
|
684
691
|
}
|
|
685
692
|
};
|
|
686
693
|
const GATE_KEYS = Object.keys(DIAGNOSTIC_GATES);
|
|
@@ -700,7 +707,9 @@ function resolveFailOnDiagnostics(user) {
|
|
|
700
707
|
emptyScope: gate("emptyScope"),
|
|
701
708
|
invalidOptions: gate("invalidOptions"),
|
|
702
709
|
invalidConfig: gate("invalidConfig"),
|
|
703
|
-
deprecated: gate("deprecated")
|
|
710
|
+
deprecated: gate("deprecated"),
|
|
711
|
+
unscannableFiles: gate("unscannableFiles"),
|
|
712
|
+
baselineStale: gate("baselineStale")
|
|
704
713
|
};
|
|
705
714
|
}
|
|
706
715
|
/** The diagnostic codes that should fail a run, given the resolved gates. */
|
|
@@ -904,6 +913,7 @@ function resolveConfig(user, opts) {
|
|
|
904
913
|
const repoRoot = path.resolve(cwd, user.repoRoot ?? ".");
|
|
905
914
|
return {
|
|
906
915
|
repoRoot,
|
|
916
|
+
baseline: user.baseline !== void 0 ? path.resolve(repoRoot, user.baseline) : null,
|
|
907
917
|
sourceRoot: path.resolve(repoRoot, user.sourceRoot ?? "."),
|
|
908
918
|
include: user.include ?? [...DEFAULT_INCLUDE],
|
|
909
919
|
exclude: [...user.excludeDefaults === false ? [] : DEFAULT_EXCLUDE, ...user.exclude ?? []],
|
|
@@ -954,8 +964,9 @@ function defineTransform(transform) {
|
|
|
954
964
|
*
|
|
955
965
|
* Pure — no I/O, no reporter calls; reporters are driven by the run edge (integration-kit).
|
|
956
966
|
*/
|
|
957
|
-
async function analyze(graph, config) {
|
|
967
|
+
async function analyze(graph, config, options = {}) {
|
|
958
968
|
const started = performance.now();
|
|
969
|
+
options.signal?.throwIfAborted();
|
|
959
970
|
assertIrCompatible(graph.irVersion);
|
|
960
971
|
const diagnostics = [...config.diagnostics];
|
|
961
972
|
const effective = new Set(graph.host.capabilities);
|
|
@@ -1124,9 +1135,10 @@ async function analyze(graph, config) {
|
|
|
1124
1135
|
});
|
|
1125
1136
|
}
|
|
1126
1137
|
const active = runs.filter((r) => !r.halted);
|
|
1127
|
-
dispatchVisitors(active, diagnostics, scopeKeyOf);
|
|
1138
|
+
dispatchVisitors(active, diagnostics, scopeKeyOf, options.signal);
|
|
1128
1139
|
for (const run of active) {
|
|
1129
1140
|
if (run.halted || run.resolved.rule.check === void 0) continue;
|
|
1141
|
+
options.signal?.throwIfAborted();
|
|
1130
1142
|
const startedRule = performance.now();
|
|
1131
1143
|
try {
|
|
1132
1144
|
await run.resolved.rule.check(run.ctx);
|
|
@@ -1143,6 +1155,7 @@ async function analyze(graph, config) {
|
|
|
1143
1155
|
diagnostics.push(...auditClassification(classified));
|
|
1144
1156
|
return {
|
|
1145
1157
|
violations: kept.sort(compareViolations),
|
|
1158
|
+
suppressed: [],
|
|
1146
1159
|
diagnostics,
|
|
1147
1160
|
rules: runs.map((r) => r.info),
|
|
1148
1161
|
repoRoot: config.repoRoot,
|
|
@@ -1167,7 +1180,7 @@ async function analyze(graph, config) {
|
|
|
1167
1180
|
* slice, so a rule that throws stops and is marked failed while the other thirty-nine keep
|
|
1168
1181
|
* their results — without paying for exception handling on every edge.
|
|
1169
1182
|
*/
|
|
1170
|
-
function dispatchVisitors(runs, diagnostics, scopeKeyOf) {
|
|
1183
|
+
function dispatchVisitors(runs, diagnostics, scopeKeyOf, signal) {
|
|
1171
1184
|
const edgeBuckets = /* @__PURE__ */ new Map();
|
|
1172
1185
|
const moduleBuckets = /* @__PURE__ */ new Map();
|
|
1173
1186
|
for (const run of runs) {
|
|
@@ -1220,6 +1233,7 @@ function dispatchVisitors(runs, diagnostics, scopeKeyOf) {
|
|
|
1220
1233
|
const items = bucket.slice();
|
|
1221
1234
|
for (const { run, visit } of bucket.members) {
|
|
1222
1235
|
if (run.halted) continue;
|
|
1236
|
+
signal?.throwIfAborted();
|
|
1223
1237
|
const startedRule = performance.now();
|
|
1224
1238
|
try {
|
|
1225
1239
|
for (const item of items) visit(item, run.ctx);
|
|
@@ -1344,6 +1358,37 @@ function dropSelfEdges() {
|
|
|
1344
1358
|
});
|
|
1345
1359
|
}
|
|
1346
1360
|
//#endregion
|
|
1347
|
-
|
|
1361
|
+
//#region src/transforms/drop-type-only-edges.ts
|
|
1362
|
+
/**
|
|
1363
|
+
* Removes edges the host marked `attributes.typeOnly`.
|
|
1364
|
+
*
|
|
1365
|
+
* This is the *policy* half of type-only support, deliberately separated from the *fact* half.
|
|
1366
|
+
* Producers report what the code says; whether an erased import counts as a dependency is a
|
|
1367
|
+
* question about the user's architecture, and different answers are legitimately right:
|
|
1368
|
+
*
|
|
1369
|
+
* - A layering rule usually SHOULD see type-only edges — `domain` importing an
|
|
1370
|
+
* `infrastructure` type still couples the two at design time, which is the thing layering
|
|
1371
|
+
* exists to prevent.
|
|
1372
|
+
* - A cycle rule usually should NOT — a type-only cycle costs nothing at runtime and
|
|
1373
|
+
* `no-cycles` flagging one is the most common false positive in this whole category of tool.
|
|
1374
|
+
*
|
|
1375
|
+
* So it is off by default and opted into per config, rather than being baked into a producer.
|
|
1376
|
+
* Before this existed the CLI simply never emitted type-only edges, which made that choice for
|
|
1377
|
+
* everyone, made the CLI disagree with every bundler adapter, and left no way to get the
|
|
1378
|
+
* edges back.
|
|
1379
|
+
*
|
|
1380
|
+
* Only meaningful when the host declares `type-only-edges`; against a host that erased type
|
|
1381
|
+
* imports before ArchWall saw them, there is nothing here to remove and this is a no-op.
|
|
1382
|
+
*/
|
|
1383
|
+
function dropTypeOnlyEdges() {
|
|
1384
|
+
return defineTransform({
|
|
1385
|
+
name: "drop-type-only-edges",
|
|
1386
|
+
transform(graph) {
|
|
1387
|
+
graph.removeEdges((e) => e.attributes?.typeOnly === true);
|
|
1388
|
+
}
|
|
1389
|
+
});
|
|
1390
|
+
}
|
|
1391
|
+
//#endregion
|
|
1392
|
+
export { ArchWallError, BUILTIN_REPORTER_NAMES, DIAGNOSTIC_GATES, FINGERPRINT_SCHEME, FIRST_PARTY_KINDS, IR_VERSION, IrVersionMismatchError, MODULE_ID_SCHEMES, ProjectGraph, THIRD_PARTY_KINDS, analyze, assertIrCompatible, compareViolations, configureRule, consoleReporter, countBySeverity, defaultIO, defineClassifier, defineConfig, defineGraphComputation, definePreset, defineReporter, defineRule, defineTransform, displayModuleId, dropSelfEdges, dropTypeOnlyEdges, failingDiagnosticCodes, fingerprintOf, formatViolation, irMajor, isBuiltinReporterName, isFirstParty, isThirdParty, jsonReporter, locationsOf, matchCaptures, matchesPattern, parseModuleId, pathClassifier, primaryEdge, primaryModule, primarySourceLocation, renderMessage, resolveConfig, resolveFailOnDiagnostics, resolveReporters, sarifReporter, stronglyConnectedComponents };
|
|
1348
1393
|
|
|
1349
1394
|
//# sourceMappingURL=index.mjs.map
|