Skip to content

Commit 6c546ab

Browse files
claude[bot]claude
andauthored
refactor(devx): the eight remaining comment-mask callers take the projection from js-comment-mask (#16300)
`js-comment-mask.mjs` publishes `maskCommentsAndLiterals` (#15594, PR #15774), which converted the two callers that ruling named. Eight more spelled the same `comment | literal` -> `blank` composition under eight more names, each composing the shared scanner and carrying no scanning logic of its own, none with a shared pin. All eight now read the module's export. Three return a PAIR of projections and keep their return shape as a wrapper over the exports rather than a straight substitution: `maskedProjections` (`check-test-source-alias`), `projections` (`check-error-status-conformance`) and `project` (`check-docs-section-name`, which still reads `scanSource` for the raw `comment`/`literal` flags one of its rules indexes directly). Two keep their own name for the projection through an import alias, because the file's self-test row labels and its prose read that name: `codeOnly` in `check-parse-guard` and in `docs-audit/affected-docs`. `measure-self-test-floor.mjs` carried a local copy under the SHARED NAME -- a local definition, not a completed conversion -- so the import replaces it and the same name is re-exported. Each deleted docblock's gate-specific facts move with the conversion rather than becoming a stale assertion about a function that is gone. Behaviour byte-identical, proven per gate by diffing plain and `--self-test` output before and after: 16 runs, 16 empty diffs, exit 0 on every side. Part of #15776 Claude-Session: https://claude.ai/code/session_01Vbw3RPgdtqesx4azk9SbW8 Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 8cf806f commit 6c546ab

8 files changed

Lines changed: 136 additions & 155 deletions

scripts/check-console-intercept-disarm.mjs

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -89,26 +89,19 @@ import { existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync,
8989
import { dirname, join, resolve } from 'node:path';
9090
import { tmpdir } from 'node:os';
9191
import { fileURLToPath } from 'node:url';
92-
import { blank, scanSource } from './js-comment-mask.mjs';
92+
import { maskCommentsAndLiterals } from './js-comment-mask.mjs';
9393
import { isEntrypoint } from './invoked-as.mjs';
9494

95-
/**
96-
* Comments AND string/template/regex content blanked, offsets kept. This gate
97-
* looks for a bare code-position `disableConsoleIntercept: true`, so unlike
98-
* the gates whose signal IS a string literal, a quoted spelling here is never
99-
* the real setting — it is prose (an error message, a doc snippet) and
100-
* blanking it keeps prose from satisfying the check. The boundary this
101-
* accepts: a config spelling the KEY as a quoted property
102-
* (`'disableConsoleIntercept': true`) reds the gate even though vitest would
103-
* honour it — the failure is loud, names the file, and the remedy is the
104-
* unquoted spelling every other config uses.
105-
*/
106-
function maskProse(source) {
107-
const { comment, literal } = scanSource(source);
108-
const flags = new Uint8Array(comment.length);
109-
for (let i = 0; i < flags.length; i++) flags[i] = comment[i] | literal[i];
110-
return blank(source, flags);
111-
}
95+
// Why this gate reads `maskCommentsAndLiterals` — the tree's one
96+
// comments+literals projection, imported rather than re-derived here (#15776).
97+
// This gate looks for a bare code-position `disableConsoleIntercept: true`, so
98+
// unlike the gates whose signal IS a string literal, a quoted spelling here is
99+
// never the real setting — it is prose (an error message, a doc snippet) and
100+
// blanking it keeps prose from satisfying the check. The boundary this accepts:
101+
// a config spelling the KEY as a quoted property
102+
// (`'disableConsoleIntercept': true`) reds the gate even though vitest would
103+
// honour it — the failure is loud, names the file, and the remedy is the
104+
// unquoted spelling every other config uses.
112105

113106
const HERE = dirname(fileURLToPath(import.meta.url));
114107
const REPO_ROOT = resolve(HERE, '..');
@@ -261,7 +254,7 @@ export function scan(root) {
261254
);
262255
continue;
263256
}
264-
const masked = maskProse(readFileSync(join(dir, configName), 'utf8'));
257+
const masked = maskCommentsAndLiterals(readFileSync(join(dir, configName), 'utf8'));
265258
if (REARM_RE.test(masked)) {
266259
findings.push(
267260
`${rel(root, dir)}/${configName}: sets disableConsoleIntercept: FALSE — this ` +

scripts/check-docs-section-name.mjs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ import YAML from 'yaml';
215215

216216
import { fencedBlocks } from './check-react-page-adapter-contract.mjs';
217217
import { isEntrypoint } from './invoked-as.mjs';
218-
import { blank, scanSource } from './js-comment-mask.mjs';
218+
import { maskCommentsAndLiterals, scanSource } from './js-comment-mask.mjs';
219219

220220
// ── The self-test's own battery roster and floor (#13489) ──────────────────
221221
//
@@ -444,14 +444,17 @@ export function docsFiles(root) {
444444
/**
445445
* The two projections of one scan. Both share byte offsets with `body`.
446446
*
447+
* `codeOnly` is `js-comment-mask.mjs`'s own `maskCommentsAndLiterals` (#15776),
448+
* not a composition re-derived here; the raw `comment`/`literal` flags are what
449+
* this gate still needs `scanSource` for (a rule below reads `literal[i] === 0`
450+
* directly), and they address `body` at the same offsets the mask does.
451+
*
447452
* @param {string} body
448453
* @returns {{ codeOnly: string, comment: Uint8Array, literal: Uint8Array }}
449454
*/
450455
export function project(body) {
451456
const { comment, literal } = scanSource(body);
452-
const both = new Uint8Array(body.length);
453-
for (let i = 0; i < body.length; i++) both[i] = comment[i] || literal[i] ? 1 : 0;
454-
return { codeOnly: blank(body, both), comment, literal };
457+
return { codeOnly: maskCommentsAndLiterals(body), comment, literal };
455458
}
456459

457460
/**

scripts/check-error-status-conformance.mjs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@
154154
// `scripts/error-status-unpinned-baseline.json`; a NEW one fails the gate, and a
155155
// row that becomes pinned fails it too (ratchet down with `--update`).
156156
import { readdirSync, readFileSync, writeFileSync, statSync, existsSync } from 'node:fs';
157-
import { maskComments, scanSource, blank } from './js-comment-mask.mjs';
157+
import { maskComments, maskCommentsAndLiterals } from './js-comment-mask.mjs';
158158
import { join, relative } from 'node:path';
159159
import { isEntrypoint } from './invoked-as.mjs';
160160

@@ -401,7 +401,8 @@ function classBodies(src) {
401401
const lineOf = (src, idx) => src.slice(0, idx).split('\n').length;
402402

403403
/**
404-
* The two projections a rule may read, from ONE scan of the source.
404+
* The two projections a rule may read, both `js-comment-mask.mjs`'s own exports
405+
* (#15776) rather than a composition re-derived here.
405406
*
406407
* `src` comments blanked, string/template/regex CONTENT intact — what
407408
* every rule matches on, because a gate's signal (`code:
@@ -414,10 +415,7 @@ const lineOf = (src, idx) => src.slice(0, idx).split('\n').length;
414415
* mask, so a line number read off either is true of the original.
415416
*/
416417
function projections(raw) {
417-
const { comment, literal } = scanSource(raw);
418-
const both = new Uint8Array(raw.length);
419-
for (let k = 0; k < both.length; k++) both[k] = comment[k] || literal[k];
420-
return { src: blank(raw, comment), structural: blank(raw, both) };
418+
return { src: maskComments(raw), structural: maskCommentsAndLiterals(raw) };
421419
}
422420

423421
/**

scripts/check-parse-guard.mjs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,12 @@ import { join, relative, resolve } from 'node:path';
122122
import { fileURLToPath } from 'node:url';
123123

124124
import { isEntrypoint } from './invoked-as.mjs';
125-
import { blank, scanSource } from './js-comment-mask.mjs';
125+
// This gate's `codeOnly` IS the tree's one comments+literals projection, not a
126+
// local re-derivation of it (#15776): `js-comment-mask.mjs` owns the projections
127+
// and its `--self-test` pins this one. The name stays because this gate's prose,
128+
// its self-test rows and its findings all read `codeOnly`.
129+
import { maskCommentsAndLiterals as codeOnly } from './js-comment-mask.mjs';
130+
export { codeOnly };
126131

127132
// ── The self-test's own battery roster and floor (#13489) ──────────────────
128133
//
@@ -382,14 +387,6 @@ function walkOutside(dir, out = []) {
382387
return out;
383388
}
384389

385-
/** Code only: comments, strings, templates and regex literals all blanked. */
386-
export function codeOnly(source) {
387-
const { comment, literal } = scanSource(source);
388-
const both = new Uint8Array(comment.length);
389-
for (let i = 0; i < both.length; i++) both[i] = comment[i] || literal[i];
390-
return blank(source, both);
391-
}
392-
393390
function lineOf(source, index) {
394391
return source.slice(0, index).split('\n').length;
395392
}

scripts/check-stack-collection-maps.mjs

Lines changed: 74 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,80 @@ import { readFileSync, existsSync } from 'node:fs';
9797
import { fileURLToPath } from 'node:url';
9898
import { dirname, join, resolve } from 'node:path';
9999
import { isEntrypoint } from './invoked-as.mjs';
100-
import { blank, scanSource } from './js-comment-mask.mjs';
100+
import { maskCommentsAndLiterals } from './js-comment-mask.mjs';
101101

102102
const here = dirname(fileURLToPath(import.meta.url));
103103
const repoRoot = resolve(here, '..');
104104

105+
// ───────────────────────────────────────────────────────────────────────────
106+
// The mask every scan below reads -- IMPORTED, not re-derived (#15776)
107+
// ───────────────────────────────────────────────────────────────────────────
108+
//
109+
// `maskCommentsAndLiterals` is the tree's one comments+literals projection and
110+
// `js-comment-mask.mjs` owns it; this gate used to spell a private `maskLiterals`
111+
// that composed the same shared scanner by hand. What follows is the fact that
112+
// belongs to THIS gate -- why a bracket counter here may read nothing else, and
113+
// what the conversion onto the shared scanner measured when it happened.
114+
//
115+
// Blank out everything a bracket counter must not read: comment bodies, string
116+
// and template contents, and regex literals. Returns a string of the SAME LENGTH
117+
// as the input, so every index still addresses the original source — callers
118+
// count structure on the mask and slice text from the original.
119+
//
120+
// Length-preserving masking rather than a `strip`: the first draft of this gate
121+
// stripped comments and counted brackets over the rest, and one unbalanced paren
122+
// inside PROSE — `.describe('Screen Flows (ADR-0019)')` — closed the
123+
// `ObjectStackDefinitionSchema` literal 14 collections early. The gate then
124+
// reconciled all seven sites against a truncated source of truth and reported
125+
// 114 deviations, every one of them its own. A parser that fails toward "less
126+
// schema" makes every consumer look wrong, which is the loudest possible way to
127+
// be useless.
128+
//
129+
// String DELIMITERS survive (their contents do not), so a quoted object key and
130+
// an array of string literals are both still locatable by index.
131+
//
132+
// ## CONVERTED onto the shared scanner (#13143)
133+
//
134+
// This body used to be a private left-to-right scanner written out here, and it
135+
// was the one piece of comment-scanning code in this directory that no gate
136+
// could see. `check-comment-mask-adoption.mjs` watches for exactly this shape
137+
// and walks `packages` + `examples` only; `check-parse-guard.mjs` walks this
138+
// directory for a different subject (the three TypeScript parser entry points).
139+
// A private stripper here sits inside one gate's population and outside its
140+
// subject, and inside the other's subject and outside its population, so
141+
// nothing reds. Routing through the shared module is the half of that gap a
142+
// caller can close on its own.
143+
//
144+
// A conversion is a MEASUREMENT rather than a mechanical edit, so here is the
145+
// reading. The private scanner against `scanSource()`'s `comment | literal`
146+
// projection, over THE POPULATION THIS GATE ACTUALLY READS (the seven SITE
147+
// files plus `stack.zod.ts`, 1,028,984 chars): 3 of the 8 files disagree, 49
148+
// spans, 247 characters. Two classes, and only one of them is a defect.
149+
//
150+
// - 18 spans are a PROJECTION difference and nothing else: the private copy
151+
// blanked a regex literal's slash delimiters, the shared scanner keeps them
152+
// as code. No bracket is a slash, so no caller here could ever see it.
153+
// - 31 spans are the private scanner mis-reading a NESTED TEMPLATE. It closed
154+
// an outer template at the first backtick inside a `${...}`, which flipped
155+
// the parity of every backtick after it and handed the bracket counter 20
156+
// bracket characters out of the interiors of string and template literals.
157+
// Both files it happens in are live SITE files: `packages/objectql/src/
158+
// engine.ts` and `packages/metadata/src/plugin.ts`. That is the same family
159+
// as the `(ADR-0019)` incident above, arriving through a different door.
160+
//
161+
// Both directions of that defect are pinned in `--self-test` on synthetic
162+
// bodies, because today's tree happens to punish neither: a nested template
163+
// holding a `]` makes `stringArrayItems` DROP a real key, and one holding a
164+
// quote makes it FABRICATE `${v}` as an enumerated key. The gate's verdict does
165+
// NOT move on this tree -- `--list` is byte for byte identical before and after
166+
// -- which is a fact about where this tree's nested templates sit, not a reason
167+
// the private copy was safe.
168+
//
169+
// The instrument was shown able to fail before its empty results were read as
170+
// agreement: the naive two-regex pair diffed against the shared scanner over
171+
// the same eight files disagrees on 8 of 8, and the shared scanner diffed
172+
// against itself returns nothing.
173+
105174
// ───────────────────────────────────────────────────────────────────────────
106175
// Extraction -- pure, over source text
107176
// ───────────────────────────────────────────────────────────────────────────
@@ -124,7 +193,7 @@ const repoRoot = resolve(here, '..');
124193
export function sliceBody(source, anchor, from = 0) {
125194
const at = source.indexOf(anchor, from);
126195
if (at === -1) return null;
127-
const mask = maskLiterals(source);
196+
const mask = maskCommentsAndLiterals(source);
128197
const openAt = at + anchor.length - 1;
129198
const open = source[openAt];
130199
const close = open === '{' ? '}' : ']';
@@ -140,79 +209,12 @@ export function sliceBody(source, anchor, from = 0) {
140209
return null;
141210
}
142211

143-
/**
144-
* Blank out everything a bracket counter must not read: comment bodies, string
145-
* and template contents, and regex literals. Returns a string of the SAME LENGTH
146-
* as the input, so every index still addresses the original source — callers
147-
* count structure on the mask and slice text from the original.
148-
*
149-
* Length-preserving masking rather than a `strip`: the first draft of this gate
150-
* stripped comments and counted brackets over the rest, and one unbalanced paren
151-
* inside PROSE — `.describe('Screen Flows (ADR-0019)')` — closed the
152-
* `ObjectStackDefinitionSchema` literal 14 collections early. The gate then
153-
* reconciled all seven sites against a truncated source of truth and reported
154-
* 114 deviations, every one of them its own. A parser that fails toward "less
155-
* schema" makes every consumer look wrong, which is the loudest possible way to
156-
* be useless.
157-
*
158-
* String DELIMITERS survive (their contents do not), so a quoted object key and
159-
* an array of string literals are both still locatable by index.
160-
*
161-
* ## CONVERTED onto the shared scanner (#13143)
162-
*
163-
* This body used to be a private left-to-right scanner written out here, and it
164-
* was the one piece of comment-scanning code in this directory that no gate
165-
* could see. `check-comment-mask-adoption.mjs` watches for exactly this shape
166-
* and walks `packages` + `examples` only; `check-parse-guard.mjs` walks this
167-
* directory for a different subject (the three TypeScript parser entry points).
168-
* A private stripper here sits inside one gate's population and outside its
169-
* subject, and inside the other's subject and outside its population, so
170-
* nothing reds. Routing through the shared module is the half of that gap a
171-
* caller can close on its own.
172-
*
173-
* A conversion is a MEASUREMENT rather than a mechanical edit, so here is the
174-
* reading. The private scanner against `scanSource()`'s `comment | literal`
175-
* projection, over THE POPULATION THIS GATE ACTUALLY READS (the seven SITE
176-
* files plus `stack.zod.ts`, 1,028,984 chars): 3 of the 8 files disagree, 49
177-
* spans, 247 characters. Two classes, and only one of them is a defect.
178-
*
179-
* - 18 spans are a PROJECTION difference and nothing else: the private copy
180-
* blanked a regex literal's slash delimiters, the shared scanner keeps them
181-
* as code. No bracket is a slash, so no caller here could ever see it.
182-
* - 31 spans are the private scanner mis-reading a NESTED TEMPLATE. It closed
183-
* an outer template at the first backtick inside a `${...}`, which flipped
184-
* the parity of every backtick after it and handed the bracket counter 20
185-
* bracket characters out of the interiors of string and template literals.
186-
* Both files it happens in are live SITE files: `packages/objectql/src/
187-
* engine.ts` and `packages/metadata/src/plugin.ts`. That is the same family
188-
* as the `(ADR-0019)` incident above, arriving through a different door.
189-
*
190-
* Both directions of that defect are pinned in `--self-test` on synthetic
191-
* bodies, because today's tree happens to punish neither: a nested template
192-
* holding a `]` makes `stringArrayItems` DROP a real key, and one holding a
193-
* quote makes it FABRICATE `${v}` as an enumerated key. The gate's verdict does
194-
* NOT move on this tree -- `--list` is byte for byte identical before and after
195-
* -- which is a fact about where this tree's nested templates sit, not a reason
196-
* the private copy was safe.
197-
*
198-
* The instrument was shown able to fail before its empty results were read as
199-
* agreement: the naive two-regex pair diffed against the shared scanner over
200-
* the same eight files disagrees on 8 of 8, and the shared scanner diffed
201-
* against itself returns nothing.
202-
*/
203-
export function maskLiterals(source) {
204-
const { comment, literal } = scanSource(source);
205-
const both = new Uint8Array(source.length);
206-
for (let i = 0; i < source.length; i++) both[i] = comment[i] | literal[i];
207-
return blank(source, both);
208-
}
209-
210212
/**
211213
* Top-level keys of an object-literal body, each with its value's source text.
212214
* Depth-aware: a nested literal never contributes its own keys.
213215
*/
214216
export function objectEntries(body) {
215-
const mask = maskLiterals(body);
217+
const mask = maskCommentsAndLiterals(body);
216218
const out = [];
217219
let depth = 0;
218220
let i = 0;
@@ -255,7 +257,7 @@ export function objectEntries(body) {
255257

256258
/** String literals at depth 0 of an array-literal body. */
257259
export function stringArrayItems(body) {
258-
const mask = maskLiterals(body);
260+
const mask = maskCommentsAndLiterals(body);
259261
const out = [];
260262
let depth = 0;
261263
for (let i = 0; i < body.length; i++) {
@@ -287,7 +289,7 @@ export function stringArrayItems(body) {
287289
* answer at all, not to rescue the gate from a silent pass it never had.
288290
*/
289291
export function tupleFirstItems(body) {
290-
const mask = maskLiterals(body);
292+
const mask = maskCommentsAndLiterals(body);
291293
const out = [];
292294
let depth = 0;
293295
let taken = false;

scripts/check-test-source-alias.mjs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@
311311
// node scripts/check-test-source-alias.mjs --self-test
312312

313313
import { readFileSync, readdirSync, statSync, existsSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
314-
import { stripComments, scanSource, blank } from './js-comment-mask.mjs';
314+
import { stripComments, maskComments, maskCommentsAndLiterals } from './js-comment-mask.mjs';
315315
import { join, resolve, relative, dirname } from 'node:path';
316316
import { fileURLToPath } from 'node:url';
317317
import {
@@ -809,12 +809,13 @@ const TYPE_QUERY_BEFORE = /\btypeof\s*$/;
809809
* thing in both: `commentsOnly` keeps every string intact (the import regex has
810810
* to read the specifier), `codeOnly` masks literal CONTENT as well (the brace
811811
* scanner must not count a `{` inside a string or a template).
812+
*
813+
* Both are `js-comment-mask.mjs`'s own exports (#15776) rather than a projection
814+
* re-derived here. They agree offset-for-offset because BOTH blank in place --
815+
* that is the module's contract, not a property of deriving them from one scan.
812816
*/
813817
function maskedProjections(source) {
814-
const { comment, literal } = scanSource(source);
815-
const both = new Uint8Array(source.length);
816-
for (let i = 0; i < source.length; i++) both[i] = comment[i] || literal[i] ? 1 : 0;
817-
return { commentsOnly: blank(source, comment), codeOnly: blank(source, both) };
818+
return { commentsOnly: maskComments(source), codeOnly: maskCommentsAndLiterals(source) };
818819
}
819820

820821
/**

0 commit comments

Comments
 (0)