@xemahq/repo-build-tooling 0.2.2 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xemahq/repo-build-tooling",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "Dev-time build tooling shared by every Xema repository. Ships as plain ESM with zero dependencies so the published artifact is the reviewed source.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Neuralchowder Inc. <developer@xema.dev> (https://xema.dev)",
@@ -17,18 +17,21 @@
17
17
  },
18
18
  "type": "module",
19
19
  "files": [
20
- "README.md"
20
+ "README.md",
21
+ "src"
21
22
  ],
22
23
  "bin": {
23
24
  "xema-scrub-swagger-paths": "src/scrub-swagger-plugin-paths.mjs",
24
- "xema-check-workspace-ranges": "src/check-workspace-range-matches-local.mjs"
25
+ "xema-check-workspace-ranges": "src/check-workspace-range-matches-local.mjs",
26
+ "xema-check-no-vendored-deps": "src/check-no-vendored-deps.mjs"
25
27
  },
26
28
  "exports": {
27
- "./scrub-swagger-plugin-paths": "./src/scrub-swagger-plugin-paths.mjs",
29
+ "./check-no-vendored-deps": "./src/check-no-vendored-deps.mjs",
30
+ "./check-workspace-range-matches-local": "./src/check-workspace-range-matches-local.mjs",
28
31
  "./package.json": "./package.json",
29
- "./check-workspace-range-matches-local": "./src/check-workspace-range-matches-local.mjs"
32
+ "./scrub-swagger-plugin-paths": "./src/scrub-swagger-plugin-paths.mjs"
30
33
  },
31
34
  "scripts": {
32
- "test": "node src/scrub-swagger-plugin-paths.mjs --self-test && node --test src/check-workspace-range-matches-local.test.mjs"
35
+ "test": "node src/scrub-swagger-plugin-paths.mjs --self-test && node --test src/check-workspace-range-matches-local.test.mjs && node --test src/check-no-vendored-deps.test.mjs"
33
36
  }
34
37
  }
@@ -0,0 +1,231 @@
1
+ #!/usr/bin/env node
2
+ // ═══════════════════════════════════════════════════════════════════════════
3
+ // A `workspace:` range for a package this repo does NOT own is a VENDORED
4
+ // UPSTREAM DEP: the name resolves to a local directory instead of the registry
5
+ // version the rest of the fleet installs. Two copies of one class, one of them
6
+ // invisible to every version gate, because a lockfile that never resolved the
7
+ // name has nothing to compare.
8
+ //
9
+ // ── Why this is one shared bin and not four copies ──
10
+ //
11
+ // It was four: xema-kernel-sdk, xema-kernel-contracts, xema-biome-sdk and
12
+ // xema-runtime-core each carried `tooling/boundaries/check-no-vendored-deps.mjs`.
13
+ // All four asserted the IDENTICAL predicate — byte-equivalent modulo quote
14
+ // style — and differed only in how they walked `packages/`. That is not
15
+ // per-repo configuration: all four `pnpm-workspace.yaml` files declare the same
16
+ // two globs, so there was nothing to configure and three of the four traversals
17
+ // were elaborations nobody needed.
18
+ //
19
+ // They had also drifted in a way that MATTERS. xema-kernel-contracts' copy
20
+ // recursed without bound and without stopping at a package leaf, so applied to
21
+ // xema-biome-sdk's tree it ingested two TEST FIXTURES as locally-owned packages
22
+ // — widening the allowed set, latent rather than live only because both
23
+ // fixtures happen to declare registry ranges today. Nothing bound the four
24
+ // copies to each other; `check-carved-lib-parity` covers `lib/` helpers, not
25
+ // gates.
26
+ //
27
+ // ── The vacuous-green hole, fixed here ──
28
+ //
29
+ // All four copies guarded that `packages/` EXISTS and never that any manifest
30
+ // was FOUND. A directory rename below it, or a layout change, and every one of
31
+ // them printed `OK: … (0 local packages scanned)` and exited 0 — green while
32
+ // executing nothing, this fleet's most-repeated defect. The two shallow
33
+ // traversals were precisely the ones a layout change would silently empty.
34
+ // `assertNonEmptyCorpus` below refuses a zero-manifest scan.
35
+ //
36
+ // Usage (from the repository root):
37
+ // xema-check-no-vendored-deps
38
+ // ═══════════════════════════════════════════════════════════════════════════
39
+ import { execFileSync } from 'node:child_process';
40
+ import { existsSync, readFileSync, realpathSync } from 'node:fs';
41
+ import { join, relative } from 'node:path';
42
+ import { pathToFileURL } from 'node:url';
43
+
44
+ const DEP_FIELDS = ['dependencies', 'devDependencies', 'peerDependencies'];
45
+
46
+ /**
47
+ * The DEPTHS at which a workspace manifest may sit, derived from
48
+ * `pnpm-workspace.yaml` rather than assumed.
49
+ *
50
+ * Deriving is what stops the kernel-contracts defect recurring: an unbounded
51
+ * walk ingests a `test/fixtures/**\/package.json` as a locally-owned package,
52
+ * which WIDENS the allowed set — the one direction a gate must never drift in.
53
+ * A glob of `packages/*` admits `packages/<a>/package.json` (2 segments below
54
+ * the root); `packages/*\/*` admits 3.
55
+ *
56
+ * Returns null when the file declares no `packages/`-rooted glob at all, which
57
+ * the caller treats as "this repo is not shaped for this check" rather than as
58
+ * an empty result.
59
+ *
60
+ * The depth is `find`'s, i.e. levels BELOW the `packages` start path, and it
61
+ * equals the glob's segment count: `packages/*` admits `packages/a/package.json`
62
+ * at depth 2, `packages/*\/*` admits `packages/a/b/package.json` at depth 3.
63
+ *
64
+ * Written as `length + 1` first, which passed every repo — because BOTH entries
65
+ * were off by one and the two ranges overlapped on a tree whose packages all
66
+ * sit at one level. The counts matched the four incumbent gates exactly, which
67
+ * is precisely what made it look right. A repo with a manifest directly at
68
+ * `packages/<name>/package.json` would have been silently skipped, and a
69
+ * narrowed scan is the one failure this check exists to prevent.
70
+ */
71
+ export function manifestDepthsFor(workspaceYaml) {
72
+ const depths = new Set();
73
+ for (const line of workspaceYaml.split('\n')) {
74
+ const m = line.match(/^\s*-\s*['"]?(packages\/[^'"#\s]*)['"]?\s*$/);
75
+ if (!m) continue;
76
+ depths.add(m[1].split('/').length);
77
+ }
78
+ return depths.size > 0 ? [...depths].sort((a, b) => a - b) : null;
79
+ }
80
+
81
+ /**
82
+ * Every manifest at exactly the declared depths. `find` rather than a hand
83
+ * walk, for the same reason the sibling check uses it: no dependency, and the
84
+ * depth bounds are expressed once instead of reimplemented per level.
85
+ */
86
+ function listManifests(repoRoot, depths) {
87
+ const out = [];
88
+ for (const depth of depths) {
89
+ let stdout;
90
+ try {
91
+ stdout = execFileSync(
92
+ 'find',
93
+ [
94
+ 'packages',
95
+ '-mindepth', String(depth),
96
+ '-maxdepth', String(depth),
97
+ '-name', 'package.json',
98
+ '-not', '-path', '*/node_modules/*',
99
+ '-not', '-path', '*/dist/*',
100
+ ],
101
+ { cwd: repoRoot, encoding: 'utf8' },
102
+ );
103
+ } catch {
104
+ continue;
105
+ }
106
+ for (const line of stdout.split('\n')) if (line.trim()) out.push(line.trim());
107
+ }
108
+ return [...new Set(out)].sort();
109
+ }
110
+
111
+ /**
112
+ * The finding set. Pure over its inputs so it is testable without a tree.
113
+ *
114
+ * @param {Array<{path:string, manifest:object}>} manifests
115
+ * @returns {Array<{path:string, field:string, depName:string, depRange:string}>}
116
+ */
117
+ export function findVendoredDeps(manifests) {
118
+ const localPackageNames = new Set(
119
+ manifests.map(({ manifest }) => manifest.name).filter(Boolean),
120
+ );
121
+ const offenders = [];
122
+ for (const { path, manifest } of manifests) {
123
+ for (const field of DEP_FIELDS) {
124
+ const deps = manifest[field];
125
+ if (!deps) continue;
126
+ for (const [depName, depRange] of Object.entries(deps)) {
127
+ if (typeof depRange !== 'string') continue;
128
+ if (!depRange.startsWith('workspace:')) continue;
129
+ if (localPackageNames.has(depName)) continue;
130
+ offenders.push({ path, field, depName, depRange });
131
+ }
132
+ }
133
+ }
134
+ return offenders;
135
+ }
136
+
137
+ /**
138
+ * A corpus of zero manifests is a FAILURE, never a pass.
139
+ *
140
+ * This is the assertion all four predecessors lacked. `packages/` existing says
141
+ * nothing about whether anything was read, and a check that reports OK over an
142
+ * empty scan is worse than no check because it reads as protection in review.
143
+ */
144
+ function assertNonEmptyCorpus(count, repoRoot, depths) {
145
+ if (count > 0) return null;
146
+ return (
147
+ `found ZERO package manifests under ${join(repoRoot, 'packages')} at the depth(s) ` +
148
+ `${depths.join(', ')} declared by pnpm-workspace.yaml.\n` +
149
+ 'An empty scan must never read as a passing one. Either the workspace globs and the ' +
150
+ 'tree have diverged, or this check is pointed at the wrong root.'
151
+ );
152
+ }
153
+
154
+ export function main() {
155
+ const repoRoot = process.cwd();
156
+ if (!existsSync(join(repoRoot, 'package.json'))) {
157
+ console.error(
158
+ `::error::${repoRoot} has no package.json — run this from the repository root ` +
159
+ 'so it scans the repository, not whatever directory it was invoked from.',
160
+ );
161
+ return 1;
162
+ }
163
+
164
+ const wsPath = join(repoRoot, 'pnpm-workspace.yaml');
165
+ if (!existsSync(wsPath)) {
166
+ console.error(`::error::no pnpm-workspace.yaml at ${repoRoot}; cannot derive the scan depth.`);
167
+ return 1;
168
+ }
169
+ const depths = manifestDepthsFor(readFileSync(wsPath, 'utf8'));
170
+ if (depths === null) {
171
+ console.error(
172
+ `::error::pnpm-workspace.yaml at ${repoRoot} declares no \`packages/\` glob. ` +
173
+ 'This check asserts a property of that tree; it must not silently pass over its absence.',
174
+ );
175
+ return 1;
176
+ }
177
+
178
+ const manifests = [];
179
+ for (const rel of listManifests(repoRoot, depths)) {
180
+ try {
181
+ manifests.push({ path: rel, manifest: JSON.parse(readFileSync(join(repoRoot, rel), 'utf8')) });
182
+ } catch (error) {
183
+ console.error(`::error::${rel} is not readable JSON: ${error.message}`);
184
+ return 1;
185
+ }
186
+ }
187
+
188
+ const empty = assertNonEmptyCorpus(manifests.length, repoRoot, depths);
189
+ if (empty) {
190
+ console.error(`::error::${empty}`);
191
+ return 1;
192
+ }
193
+
194
+ const offenders = findVendoredDeps(manifests);
195
+ if (offenders.length > 0) {
196
+ console.error('Vendored upstream deps detected (must use the registry version):');
197
+ for (const o of offenders) {
198
+ console.error(` ${o.path} ${o.field}.${o.depName} = ${o.depRange}`);
199
+ }
200
+ console.error(
201
+ '\nA `workspace:` range for a package this repo does not own resolves to a local ' +
202
+ 'directory instead of the registry version the rest of the fleet installs.',
203
+ );
204
+ return 1;
205
+ }
206
+
207
+ console.log(
208
+ `OK: no vendored upstream workspace deps (${manifests.length} local packages scanned ` +
209
+ `at depth ${depths.join(', ')})`,
210
+ );
211
+ return 0;
212
+ }
213
+
214
+ // The sibling `xema-check-workspace-ranges` documents why this guard is written
215
+ // with `realpathSync`: invoked through a pnpm bin shim, `process.argv[1]` is the
216
+ // SYMLINK, so a naive `import.meta.url === pathToFileURL(argv[1]).href` is false
217
+ // and the bin prints nothing and exits 0. That hole shipped, and it was
218
+ // invisible in carved CI — which installs the published tarball, where argv[1]
219
+ // is already a real path. Same shape, same treatment.
220
+ const invokedPath = process.argv[1];
221
+ let invokedRealPath = null;
222
+ if (typeof invokedPath === 'string' && invokedPath.length > 0) {
223
+ try {
224
+ invokedRealPath = realpathSync(invokedPath);
225
+ } catch {
226
+ invokedRealPath = null;
227
+ }
228
+ }
229
+ if (invokedRealPath !== null && import.meta.url === pathToFileURL(invokedRealPath).href) {
230
+ process.exit(main());
231
+ }
@@ -0,0 +1,103 @@
1
+ import { deepStrictEqual, strictEqual } from 'node:assert/strict';
2
+ import { test } from 'node:test';
3
+
4
+ import { findVendoredDeps, manifestDepthsFor } from './check-no-vendored-deps.mjs';
5
+
6
+ // ── manifestDepthsFor ─────────────────────────────────────────────────────
7
+ // The depth is `find`'s: levels BELOW the `packages` start path. It equals the
8
+ // glob's segment count. Both cases below are pinned because the first draft
9
+ // used `length + 1` and PASSED on all four real repositories — the two entries
10
+ // were each off by one and their ranges overlapped on a tree whose packages all
11
+ // sit at one level. Matching counts is exactly what made the bug invisible.
12
+
13
+ test('a one-level glob admits packages/<name>/package.json at depth 2', () => {
14
+ deepStrictEqual(manifestDepthsFor("packages:\n - 'packages/*'\n"), [2]);
15
+ });
16
+
17
+ test('a two-level glob admits packages/<a>/<b>/package.json at depth 3', () => {
18
+ deepStrictEqual(manifestDepthsFor("packages:\n - 'packages/*/*'\n"), [3]);
19
+ });
20
+
21
+ test('both globs together admit both depths, sorted', () => {
22
+ deepStrictEqual(
23
+ manifestDepthsFor("packages:\n - 'packages/*'\n - 'packages/*/*'\n"),
24
+ [2, 3],
25
+ );
26
+ });
27
+
28
+ test('a repo declaring no packages/ glob returns null, never an empty scan', () => {
29
+ // null is "not shaped for this check", which the caller REFUSES. Returning []
30
+ // would let it scan nothing and report OK — the defect this file replaces.
31
+ strictEqual(manifestDepthsFor("packages:\n - 'apps/*'\n"), null);
32
+ });
33
+
34
+ test('unquoted and double-quoted globs parse identically', () => {
35
+ deepStrictEqual(manifestDepthsFor('packages:\n - packages/*\n'), [2]);
36
+ deepStrictEqual(manifestDepthsFor('packages:\n - "packages/*/*"\n'), [3]);
37
+ });
38
+
39
+ // ── findVendoredDeps ──────────────────────────────────────────────────────
40
+
41
+ const local = (name, deps) => ({ path: `packages/${name}/package.json`, manifest: { name, ...deps } });
42
+
43
+ test('a workspace: range for a package this repo OWNS is fine', () => {
44
+ const found = findVendoredDeps([
45
+ local('@x/a', { dependencies: { '@x/b': 'workspace:*' } }),
46
+ local('@x/b', {}),
47
+ ]);
48
+ deepStrictEqual(found, []);
49
+ });
50
+
51
+ test('a workspace: range for a package this repo does NOT own is a finding', () => {
52
+ const found = findVendoredDeps([
53
+ local('@x/a', { dependencies: { '@upstream/c': 'workspace:*' } }),
54
+ ]);
55
+ strictEqual(found.length, 1);
56
+ strictEqual(found[0].depName, '@upstream/c');
57
+ strictEqual(found[0].field, 'dependencies');
58
+ });
59
+
60
+ test('all three dependency fields are examined', () => {
61
+ const found = findVendoredDeps([
62
+ local('@x/a', {
63
+ dependencies: { '@u/one': 'workspace:*' },
64
+ devDependencies: { '@u/two': 'workspace:^1.0.0' },
65
+ peerDependencies: { '@u/three': 'workspace:~2.0.0' },
66
+ }),
67
+ ]);
68
+ deepStrictEqual(found.map((f) => f.field).sort(), [
69
+ 'dependencies', 'devDependencies', 'peerDependencies',
70
+ ]);
71
+ });
72
+
73
+ test('a registry range is never a finding, whatever it names', () => {
74
+ deepStrictEqual(
75
+ findVendoredDeps([local('@x/a', { dependencies: { '@upstream/c': '^1.2.3' } })]),
76
+ [],
77
+ );
78
+ });
79
+
80
+ test('a non-string range is skipped rather than crashing the run', () => {
81
+ deepStrictEqual(
82
+ findVendoredDeps([local('@x/a', { dependencies: { '@u/c': null } })]),
83
+ [],
84
+ );
85
+ });
86
+
87
+ test('a fixture ingested as a local package WIDENS the allowed set', () => {
88
+ // The measured xema-kernel-contracts defect, pinned as behaviour rather than
89
+ // as prose: its unbounded walk ingested two test fixtures under
90
+ // packages/*/*/test/fixtures/, and a fixture whose name matches a declared
91
+ // dependency makes a real finding disappear. The depth bound is what stops
92
+ // it; this asserts the CONSEQUENCE so the bound cannot be relaxed silently.
93
+ const withoutFixture = findVendoredDeps([
94
+ local('@x/a', { dependencies: { '@u/fixture': 'workspace:*' } }),
95
+ ]);
96
+ strictEqual(withoutFixture.length, 1, 'the finding exists when the fixture is out of scope');
97
+
98
+ const withFixture = findVendoredDeps([
99
+ local('@x/a', { dependencies: { '@u/fixture': 'workspace:*' } }),
100
+ { path: 'packages/a/test/fixtures/f/package.json', manifest: { name: '@u/fixture' } },
101
+ ]);
102
+ strictEqual(withFixture.length, 0, 'ingesting the fixture SILENCES it — the widening');
103
+ });
@@ -29,7 +29,7 @@
29
29
  // examined.
30
30
  // ═══════════════════════════════════════════════════════════════════════════
31
31
  import { execFileSync } from 'node:child_process';
32
- import { existsSync, readFileSync, writeFileSync } from 'node:fs';
32
+ import { existsSync, readFileSync, realpathSync, writeFileSync } from 'node:fs';
33
33
  import { join, relative } from 'node:path';
34
34
  import { pathToFileURL } from 'node:url';
35
35
 
@@ -173,6 +173,42 @@ function main() {
173
173
 
174
174
  // Importing this module must not run the scan — the test suite imports it for
175
175
  // `satisfies` alone.
176
- if (import.meta.url === pathToFileURL(process.argv[1] ?? '.').href) {
176
+ //
177
+ // COMPARE REALPATHS. `import.meta.url` is the RESOLVED path of this file;
178
+ // `process.argv[1]` is the path the shell was handed. Inside the xema-monorepo
179
+ // aggregator those are different strings for the same file, because
180
+ // `node_modules/@xemahq/repo-build-tooling` is a symlink into the workspace and
181
+ // pnpm's bin shim execs THROUGH it:
182
+ //
183
+ // argv[1] …/node_modules/@xemahq/repo-build-tooling/src/check-…mjs
184
+ // resolved …/repos/xema-runtime-core/packages/sdks/repo-build-tooling/src/check-…mjs
185
+ //
186
+ // So the guard was false, `main()` never ran, and the bin printed NOTHING and
187
+ // exited 0 — the check reporting green while executing nothing, which is this
188
+ // fleet's most-repeated defect and the one it has the most machinery against.
189
+ //
190
+ // Measured 2026-08-21: `repos/xema-biome-sdk` carried two `workspace:^6.1.0`
191
+ // declarations against a local `@xemahq/biome-sdk@7.0.0` — the exact dropped
192
+ // build edge this file exists to catch, and a range pnpm refuses outright with
193
+ // ERR_PNPM_NO_MATCHING_VERSION_INSIDE_WORKSPACE. `xema-check-workspace-ranges`
194
+ // exited 0 in silence; the same file run by its real path exited 1 and named
195
+ // both. Every carved repo's `pnpm check` and every pre-push hook in this
196
+ // checkout invoked it the silent way.
197
+ //
198
+ // A carved repo's own CI installs the PUBLISHED tarball, so there argv[1] is
199
+ // already a real path and the guard held. That is why the hole survived: it is
200
+ // invisible in exactly the lane people point at as proof.
201
+ const invokedPath = process.argv[1];
202
+ let invokedRealPath = null;
203
+ if (typeof invokedPath === 'string' && invokedPath.length > 0) {
204
+ try {
205
+ invokedRealPath = realpathSync(invokedPath);
206
+ } catch {
207
+ // Not a path on disk (a `node -e` entry, say). Nothing was invoked, so
208
+ // nothing should run — fall through as a plain import.
209
+ invokedRealPath = null;
210
+ }
211
+ }
212
+ if (invokedRealPath !== null && import.meta.url === pathToFileURL(invokedRealPath).href) {
177
213
  process.exit(main());
178
214
  }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The whole check rests on ONE predicate — `satisfies` — so that is what these
3
+ * tests attack.
4
+ *
5
+ * The failure this guard exists to prevent is subtle in exactly one place: npm's
6
+ * `^0.y.z` rule pins the MINOR, not the major. A `satisfies` that treats `^` as
7
+ * "same major" uniformly would call `0.3.0` a match for `^0.2.0` and report a
8
+ * clean scan over all 58 real violations — a check that reports green while
9
+ * examining everything and concluding nothing. Every 0.x case below is aimed at
10
+ * that specific wrong implementation.
11
+ */
12
+ import assert from 'node:assert/strict';
13
+ import test from 'node:test';
14
+
15
+ import { satisfies } from './check-workspace-range-matches-local.mjs';
16
+
17
+ test('^0.y.z pins the MINOR — the rule the whole check turns on', () => {
18
+ // The real defect: a client moved 0.2.0 -> 0.3.0 and fell out of every
19
+ // consumer's range, silently dropping the build edge.
20
+ assert.equal(satisfies('0.3.0', '^0.2.0'), false);
21
+ assert.equal(satisfies('0.2.9', '^0.2.0'), true);
22
+ assert.equal(satisfies('0.2.0', '^0.2.1'), false); // below the floor
23
+ assert.equal(satisfies('1.0.0', '^0.2.0'), false);
24
+ });
25
+
26
+ test('^x.y.z (x > 0) pins the MAJOR', () => {
27
+ assert.equal(satisfies('1.9.3', '^1.2.0'), true);
28
+ assert.equal(satisfies('2.0.0', '^1.2.0'), false);
29
+ assert.equal(satisfies('1.1.0', '^1.2.0'), false); // below the floor
30
+ });
31
+
32
+ test('~ pins the minor at every major', () => {
33
+ assert.equal(satisfies('1.2.9', '~1.2.0'), true);
34
+ assert.equal(satisfies('1.3.0', '~1.2.0'), false);
35
+ assert.equal(satisfies('0.2.9', '~0.2.0'), true);
36
+ assert.equal(satisfies('0.3.0', '~0.2.0'), false);
37
+ });
38
+
39
+ test('>= is a floor with no ceiling', () => {
40
+ assert.equal(satisfies('7.5.0', '>=0.14.0'), true);
41
+ assert.equal(satisfies('0.13.0', '>=0.14.0'), false);
42
+ });
43
+
44
+ test('an exact range means exactly that version', () => {
45
+ assert.equal(satisfies('1.2.3', '1.2.3'), true);
46
+ assert.equal(satisfies('1.2.4', '1.2.3'), false);
47
+ });
48
+
49
+ test('a prerelease is compared on its release part, never string-wise', () => {
50
+ // `0.3.0-rc.1` must not read as "less than 0.3.0 therefore outside ^0.2.0
51
+ // is fine" — the range check has to reach the same verdict as `0.3.0`.
52
+ assert.equal(satisfies('0.3.0-rc.1', '^0.2.0'), false);
53
+ assert.equal(satisfies('0.2.5-rc.1', '^0.2.0'), true);
54
+ });
@@ -303,7 +303,6 @@ function reExportsReach(entry, target, depth = 6, seen = new Set()) {
303
303
  } catch {
304
304
  return false;
305
305
  }
306
- const dir = dirname(entry);
307
306
  for (const m of src.matchAll(/require\("(\.[^"]*)"\)/g)) {
308
307
  let next;
309
308
  try {
@@ -499,7 +498,7 @@ async function assertScannable(dir) {
499
498
  }
500
499
  if (!s.isDirectory()) throw new ScrubFailure(`not a directory: ${dir}`);
501
500
 
502
- for await (const _file of walk(dir)) return; // eslint-disable-line no-unused-vars
501
+ for await (const _file of walk(dir)) return;
503
502
  throw new ScrubFailure(
504
503
  `output directory holds no compiled .js: ${dir}\n` +
505
504
  ` Same failure as a missing directory: nothing was scrubbed and nothing was verified.`,