@archwall/core 0.1.0 → 0.2.1
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 +82 -0
- 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 +10 -4
- package/dist/prepare-BJHgDEui.mjs.map +0 -1
- package/dist/prepare-C1FfL8Qd.cjs.map +0 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# @archwall/core
|
|
2
|
+
|
|
3
|
+
## 0.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- c512a8a: Fix unusable published packages. `0.1.0` and `0.2.0` should not be installed.
|
|
8
|
+
|
|
9
|
+
Both earlier releases went to npm with manifests that were never rewritten for publishing:
|
|
10
|
+
|
|
11
|
+
- `exports` still pointed at `./src/*.ts`, which no tarball contains — `files` is `["dist"]`. Any
|
|
12
|
+
import of any package threw `ERR_MODULE_NOT_FOUND`.
|
|
13
|
+
- Internal dependencies were published as `"@archwall/core": "workspace:^"`, so installing anything
|
|
14
|
+
with an internal dependency failed with `EUNSUPPORTEDPROTOCOL`.
|
|
15
|
+
|
|
16
|
+
Both fields come from Yarn features — `publishConfig.exports` and the `workspace:` protocol — that
|
|
17
|
+
Yarn substitutes when it packs. Releases ran through `changeset publish`, which shells out to
|
|
18
|
+
`npm publish`; npm treats `publishConfig` as npm config, warns `Unknown publishConfig config
|
|
19
|
+
"exports"`, and drops it. The pack smoke test never caught it because it packs with Yarn, so it was
|
|
20
|
+
checking a tarball no release ever uploaded.
|
|
21
|
+
|
|
22
|
+
Releases now pack with Yarn and upload the finished tarball with `npm publish`, which keeps the
|
|
23
|
+
correct manifest and keeps OIDC trusted publishing (Yarn's own publisher has no token exchange).
|
|
24
|
+
`verify:pack` gained two guards: no `workspace:` range in a publishable manifest, and every
|
|
25
|
+
advertised entrypoint must exist in the tarball — including for ESM-only packages, which the CJS
|
|
26
|
+
load check skips.
|
|
27
|
+
|
|
28
|
+
`@archwall/test-utils` is published for the first time in this release.
|
|
29
|
+
|
|
30
|
+
## 0.2.0
|
|
31
|
+
|
|
32
|
+
### Minor Changes
|
|
33
|
+
|
|
34
|
+
- 1321ebb: Contract corrections. These are the changes that are cheap now and a
|
|
35
|
+
major version later, so they are made together while the packages are still 0.x.
|
|
36
|
+
|
|
37
|
+
**Type-only edges are a fact, not a producer's private decision.** `Edge` gains an open
|
|
38
|
+
`attributes` bag, with `typeOnly` as its first well-known member and a `type-only-edges`
|
|
39
|
+
capability gating it. The CLI previously _deleted_ type-only edges during its scan, which made
|
|
40
|
+
it silently disagree with every bundler adapter about what the graph contained, with no way for
|
|
41
|
+
a user to get them back. It now labels them, and whether an erased import counts as a dependency
|
|
42
|
+
is answered by configuration — a new `dropTypeOnlyEdges()` transform — rather than by whichever
|
|
43
|
+
producer happened to build the graph. `kind` keeps answering exactly one question, so a
|
|
44
|
+
re-export that is also type-only is finally expressible.
|
|
45
|
+
|
|
46
|
+
Edges that dedupe onto one another now _merge_ their attributes by intersection rather than
|
|
47
|
+
first-wins. `import type { A } from "./x"` beside `import { b } from "./x"` is one dependency
|
|
48
|
+
and it is not type-only; union semantics there would let a "type-only may cross this boundary"
|
|
49
|
+
rule wave through a real violation.
|
|
50
|
+
|
|
51
|
+
**The CLI no longer passes green over files it never read.** It lexes JavaScript and TypeScript
|
|
52
|
+
only, so `.vue`, `.svelte`, and `.astro` files inside the project boundary produced no module, no
|
|
53
|
+
edge, and no warning — a green CI run over a codebase half of which was invisible. A new
|
|
54
|
+
`unscannable-files` diagnostic names the count, the extensions, and a sample of paths, gated by
|
|
55
|
+
`failOnDiagnostics.unscannableFiles` (default off, so nobody's CI breaks on upgrade).
|
|
56
|
+
**Breaking:** `buildGraphFromFilesystem` now returns `{ graph, diagnostics }` rather than a
|
|
57
|
+
`ProjectGraph`.
|
|
58
|
+
|
|
59
|
+
**Rules receive a `GraphView`, not a `GraphQuery`.** The read surface a rule may rely on is now
|
|
60
|
+
an interface; `GraphQuery` is its sole implementation and has moved to `@archwall/core/internal`.
|
|
61
|
+
Naming the class froze the implementation into the public contract, made test doubles impossible,
|
|
62
|
+
and would have turned any future interned or columnar store into a breaking change.
|
|
63
|
+
**Breaking:** import `GraphQuery` from `@archwall/core/internal` if you were constructing one —
|
|
64
|
+
or, if you were doing so to test a rule, use `@archwall/test-utils` instead.
|
|
65
|
+
|
|
66
|
+
**`@archwall/test-utils` is now published.** There is no rule ecosystem without a supported way
|
|
67
|
+
to test a rule, and `ProjectGraph` is opaque by design, so building a fixture graph by hand is
|
|
68
|
+
not something a third party could otherwise do. `runRule` drives the real engine, so scoping,
|
|
69
|
+
option validation, and message rendering behave in a test exactly as they do in a build.
|
|
70
|
+
|
|
71
|
+
**Reserved seams, declared before they are honoured.** `analyze()` takes an optional third
|
|
72
|
+
parameter (`signal` is honoured between rules; `previous` is accepted and ignored, reserving the
|
|
73
|
+
name for incremental reuse). `ProjectGraph` carries a `revision`. `AnalysisResult` always carries
|
|
74
|
+
a `suppressed` list, `UserConfig` accepts `baseline`, and a `baseline-stale` diagnostic gate
|
|
75
|
+
exists — all inert for now. Each of these lives on a type that is about to be frozen, and adding
|
|
76
|
+
them after the freeze would cost a major apiece.
|
|
77
|
+
|
|
78
|
+
## 0.1.0
|
|
79
|
+
|
|
80
|
+
### Minor Changes
|
|
81
|
+
|
|
82
|
+
- 4415522: Initial release.
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_prepare = require("./prepare-
|
|
2
|
+
const require_prepare = require("./prepare-CEaZxLPI.cjs");
|
|
3
3
|
let node_path = require("node:path");
|
|
4
4
|
node_path = require_prepare.__toESM(node_path, 1);
|
|
5
5
|
let picomatch = require("picomatch");
|
|
@@ -329,8 +329,7 @@ function renderMessage(template, data) {
|
|
|
329
329
|
* Fingerprint scheme version. Bump when the algorithm changes so that a stale baseline
|
|
330
330
|
* ERRORS instead of silently mismatching every entry.
|
|
331
331
|
*
|
|
332
|
-
* `aw3` is the first scheme over canonical module ids
|
|
333
|
-
* (docs/adr/0012-canonical-module-identity.md). Before it, a violation about `react` hashed the
|
|
332
|
+
* `aw3` is the first scheme over canonical module ids. Before it, a violation about `react` hashed the
|
|
334
333
|
* host's own id — a resolved `node_modules` path under the CLI, the bare specifier under esbuild
|
|
335
334
|
* — so the same finding fingerprinted differently under two bundlers.
|
|
336
335
|
*/
|
|
@@ -684,6 +683,14 @@ const DIAGNOSTIC_GATES = {
|
|
|
684
683
|
deprecated: {
|
|
685
684
|
codes: ["rule-deprecated"],
|
|
686
685
|
default: false
|
|
686
|
+
},
|
|
687
|
+
unscannableFiles: {
|
|
688
|
+
codes: ["unscannable-files"],
|
|
689
|
+
default: false
|
|
690
|
+
},
|
|
691
|
+
baselineStale: {
|
|
692
|
+
codes: ["baseline-stale"],
|
|
693
|
+
default: false
|
|
687
694
|
}
|
|
688
695
|
};
|
|
689
696
|
const GATE_KEYS = Object.keys(DIAGNOSTIC_GATES);
|
|
@@ -703,7 +710,9 @@ function resolveFailOnDiagnostics(user) {
|
|
|
703
710
|
emptyScope: gate("emptyScope"),
|
|
704
711
|
invalidOptions: gate("invalidOptions"),
|
|
705
712
|
invalidConfig: gate("invalidConfig"),
|
|
706
|
-
deprecated: gate("deprecated")
|
|
713
|
+
deprecated: gate("deprecated"),
|
|
714
|
+
unscannableFiles: gate("unscannableFiles"),
|
|
715
|
+
baselineStale: gate("baselineStale")
|
|
707
716
|
};
|
|
708
717
|
}
|
|
709
718
|
/** The diagnostic codes that should fail a run, given the resolved gates. */
|
|
@@ -907,6 +916,7 @@ function resolveConfig(user, opts) {
|
|
|
907
916
|
const repoRoot = node_path.resolve(cwd, user.repoRoot ?? ".");
|
|
908
917
|
return {
|
|
909
918
|
repoRoot,
|
|
919
|
+
baseline: user.baseline !== void 0 ? node_path.resolve(repoRoot, user.baseline) : null,
|
|
910
920
|
sourceRoot: node_path.resolve(repoRoot, user.sourceRoot ?? "."),
|
|
911
921
|
include: user.include ?? [...DEFAULT_INCLUDE],
|
|
912
922
|
exclude: [...user.excludeDefaults === false ? [] : DEFAULT_EXCLUDE, ...user.exclude ?? []],
|
|
@@ -957,8 +967,9 @@ function defineTransform(transform) {
|
|
|
957
967
|
*
|
|
958
968
|
* Pure — no I/O, no reporter calls; reporters are driven by the run edge (integration-kit).
|
|
959
969
|
*/
|
|
960
|
-
async function analyze(graph, config) {
|
|
970
|
+
async function analyze(graph, config, options = {}) {
|
|
961
971
|
const started = performance.now();
|
|
972
|
+
options.signal?.throwIfAborted();
|
|
962
973
|
require_prepare.assertIrCompatible(graph.irVersion);
|
|
963
974
|
const diagnostics = [...config.diagnostics];
|
|
964
975
|
const effective = new Set(graph.host.capabilities);
|
|
@@ -1127,9 +1138,10 @@ async function analyze(graph, config) {
|
|
|
1127
1138
|
});
|
|
1128
1139
|
}
|
|
1129
1140
|
const active = runs.filter((r) => !r.halted);
|
|
1130
|
-
dispatchVisitors(active, diagnostics, scopeKeyOf);
|
|
1141
|
+
dispatchVisitors(active, diagnostics, scopeKeyOf, options.signal);
|
|
1131
1142
|
for (const run of active) {
|
|
1132
1143
|
if (run.halted || run.resolved.rule.check === void 0) continue;
|
|
1144
|
+
options.signal?.throwIfAborted();
|
|
1133
1145
|
const startedRule = performance.now();
|
|
1134
1146
|
try {
|
|
1135
1147
|
await run.resolved.rule.check(run.ctx);
|
|
@@ -1146,6 +1158,7 @@ async function analyze(graph, config) {
|
|
|
1146
1158
|
diagnostics.push(...auditClassification(classified));
|
|
1147
1159
|
return {
|
|
1148
1160
|
violations: kept.sort(compareViolations),
|
|
1161
|
+
suppressed: [],
|
|
1149
1162
|
diagnostics,
|
|
1150
1163
|
rules: runs.map((r) => r.info),
|
|
1151
1164
|
repoRoot: config.repoRoot,
|
|
@@ -1170,7 +1183,7 @@ async function analyze(graph, config) {
|
|
|
1170
1183
|
* slice, so a rule that throws stops and is marked failed while the other thirty-nine keep
|
|
1171
1184
|
* their results — without paying for exception handling on every edge.
|
|
1172
1185
|
*/
|
|
1173
|
-
function dispatchVisitors(runs, diagnostics, scopeKeyOf) {
|
|
1186
|
+
function dispatchVisitors(runs, diagnostics, scopeKeyOf, signal) {
|
|
1174
1187
|
const edgeBuckets = /* @__PURE__ */ new Map();
|
|
1175
1188
|
const moduleBuckets = /* @__PURE__ */ new Map();
|
|
1176
1189
|
for (const run of runs) {
|
|
@@ -1223,6 +1236,7 @@ function dispatchVisitors(runs, diagnostics, scopeKeyOf) {
|
|
|
1223
1236
|
const items = bucket.slice();
|
|
1224
1237
|
for (const { run, visit } of bucket.members) {
|
|
1225
1238
|
if (run.halted) continue;
|
|
1239
|
+
signal?.throwIfAborted();
|
|
1226
1240
|
const startedRule = performance.now();
|
|
1227
1241
|
try {
|
|
1228
1242
|
for (const item of items) visit(item, run.ctx);
|
|
@@ -1347,12 +1361,42 @@ function dropSelfEdges() {
|
|
|
1347
1361
|
});
|
|
1348
1362
|
}
|
|
1349
1363
|
//#endregion
|
|
1364
|
+
//#region src/transforms/drop-type-only-edges.ts
|
|
1365
|
+
/**
|
|
1366
|
+
* Removes edges the host marked `attributes.typeOnly`.
|
|
1367
|
+
*
|
|
1368
|
+
* This is the *policy* half of type-only support, deliberately separated from the *fact* half.
|
|
1369
|
+
* Producers report what the code says; whether an erased import counts as a dependency is a
|
|
1370
|
+
* question about the user's architecture, and different answers are legitimately right:
|
|
1371
|
+
*
|
|
1372
|
+
* - A layering rule usually SHOULD see type-only edges — `domain` importing an
|
|
1373
|
+
* `infrastructure` type still couples the two at design time, which is the thing layering
|
|
1374
|
+
* exists to prevent.
|
|
1375
|
+
* - A cycle rule usually should NOT — a type-only cycle costs nothing at runtime and
|
|
1376
|
+
* `no-cycles` flagging one is the most common false positive in this whole category of tool.
|
|
1377
|
+
*
|
|
1378
|
+
* So it is off by default and opted into per config, rather than being baked into a producer.
|
|
1379
|
+
* Before this existed the CLI simply never emitted type-only edges, which made that choice for
|
|
1380
|
+
* everyone, made the CLI disagree with every bundler adapter, and left no way to get the
|
|
1381
|
+
* edges back.
|
|
1382
|
+
*
|
|
1383
|
+
* Only meaningful when the host declares `type-only-edges`; against a host that erased type
|
|
1384
|
+
* imports before ArchWall saw them, there is nothing here to remove and this is a no-op.
|
|
1385
|
+
*/
|
|
1386
|
+
function dropTypeOnlyEdges() {
|
|
1387
|
+
return defineTransform({
|
|
1388
|
+
name: "drop-type-only-edges",
|
|
1389
|
+
transform(graph) {
|
|
1390
|
+
graph.removeEdges((e) => e.attributes?.typeOnly === true);
|
|
1391
|
+
}
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
//#endregion
|
|
1350
1395
|
exports.ArchWallError = require_prepare.ArchWallError;
|
|
1351
1396
|
exports.BUILTIN_REPORTER_NAMES = BUILTIN_REPORTER_NAMES;
|
|
1352
1397
|
exports.DIAGNOSTIC_GATES = DIAGNOSTIC_GATES;
|
|
1353
1398
|
exports.FINGERPRINT_SCHEME = FINGERPRINT_SCHEME;
|
|
1354
1399
|
exports.FIRST_PARTY_KINDS = require_prepare.FIRST_PARTY_KINDS;
|
|
1355
|
-
exports.GraphQuery = require_prepare.GraphQuery;
|
|
1356
1400
|
exports.IR_VERSION = require_prepare.IR_VERSION;
|
|
1357
1401
|
exports.IrVersionMismatchError = require_prepare.IrVersionMismatchError;
|
|
1358
1402
|
exports.MODULE_ID_SCHEMES = require_prepare.MODULE_ID_SCHEMES;
|
|
@@ -1374,6 +1418,7 @@ exports.defineRule = defineRule;
|
|
|
1374
1418
|
exports.defineTransform = defineTransform;
|
|
1375
1419
|
exports.displayModuleId = require_prepare.displayModuleId;
|
|
1376
1420
|
exports.dropSelfEdges = dropSelfEdges;
|
|
1421
|
+
exports.dropTypeOnlyEdges = dropTypeOnlyEdges;
|
|
1377
1422
|
exports.failingDiagnosticCodes = failingDiagnosticCodes;
|
|
1378
1423
|
exports.fingerprintOf = fingerprintOf;
|
|
1379
1424
|
exports.formatViolation = formatViolation;
|