@@ -97,11 +97,80 @@ import { readFileSync, existsSync } from 'node:fs';
9797import { fileURLToPath } from 'node:url' ;
9898import { dirname , join , resolve } from 'node:path' ;
9999import { isEntrypoint } from './invoked-as.mjs' ;
100- import { blank , scanSource } from './js-comment-mask.mjs' ;
100+ import { maskCommentsAndLiterals } from './js-comment-mask.mjs' ;
101101
102102const here = dirname ( fileURLToPath ( import . meta. url ) ) ;
103103const 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, '..');
124193export 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 */
214216export 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. */
257259export 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 */
289291export function tupleFirstItems ( body ) {
290- const mask = maskLiterals ( body ) ;
292+ const mask = maskCommentsAndLiterals ( body ) ;
291293 const out = [ ] ;
292294 let depth = 0 ;
293295 let taken = false ;
0 commit comments