* fix(#4259): fold shell continuations before the T6 docs-parity site scan The scan is $-anchored with [^\n]* on both sides of --grep=, so `git log` and `--grep=` had to share a physical line. A backslash-continued derivation — the natural way to write a git log carrying a long ERE — produced zero hits and T6 passed on it. Both generations of the assertion were defeated. The current anti-revert ban let a wrapped site through outright; at v1.12.0, where T6 instead asserted pattern conformance, a wrapped site was silently exempted from the very checks written to catch the macOS \b-no-op class, so it could have carried exactly the malformed pattern T6 exists to reject. A real candidate implementation for #3926 wrapped its derivation, passed T6, and was caught only by later manual review. Fold the continuations before matching rather than widening the regex: the assertion's message and its PHASE_SCOPE_NUM filter both assume one site is one string, and a [\s\S]*? would run the scan across unrelated statements. Correcting the input repairs everything built on the scan at once. The fold uses [ \t]* after the newline rather than \s* — the shell's own rule, and it cannot swallow a blank line and glue two unrelated statements. The scan is hoisted to findGrepSites so the controls can drive it directly: the continued form is caught, the same-line form still is, a benign --grep stays clean, a wrapped unrelated assignment is not glued, a continuation does not cross a blank line, and the live workflow files still report nothing — so this lands without editing any workflow to appease it. * fix(#4259): honor shell continuation boundaries * test(#4259): use canonical fenced-block scanner * test(#4259): centralize shell continuation scanning --------- Co-authored-by: Tom Boucher <trekkie@nomorestars.com>
37 lines
1.4 KiB
JavaScript
37 lines
1.4 KiB
JavaScript
'use strict';
|
|
|
|
const { scanFencedBlocks } = require('../../gsd-core/bin/lib/markdown-sectionizer.cjs');
|
|
const { splitLines } = require('../../gsd-core/bin/lib/text-lines.cjs');
|
|
|
|
/**
|
|
* Fold unquoted shell backslash-newline continuations into logical lines.
|
|
*
|
|
* A newline is continued only when the immediately preceding backslash run is
|
|
* odd: the final backslash is consumed and every earlier pair stays literal.
|
|
* This deliberately remains a text heuristic, not a shell parser; in
|
|
* particular, a backslash-newline inside single quotes is a known blind spot.
|
|
*/
|
|
function foldShellContinuations(src) {
|
|
return src.replace(
|
|
/(^|[^\\])((?:\\\\)*)\\\n[ \t]*/gm,
|
|
(_match, prefix, literalPairs) => `${prefix}${literalPairs} `,
|
|
);
|
|
}
|
|
|
|
/** Return regex matches from logical lines inside closed bash/sh fences. */
|
|
function findShellFencedMatches(src, pattern) {
|
|
const lines = splitLines(src);
|
|
return scanFencedBlocks(lines).flatMap((block) => {
|
|
if (block.closeLineIdx === -1) return [];
|
|
const language = block.infoString.trim().toLowerCase();
|
|
if (language !== 'bash' && language !== 'sh') return [];
|
|
const body = lines.slice(block.openLineIdx + 1, block.closeLineIdx).join('\n');
|
|
return Array.from(
|
|
foldShellContinuations(body).matchAll(pattern),
|
|
(match) => match[0],
|
|
);
|
|
});
|
|
}
|
|
|
|
module.exports = { foldShellContinuations, findShellFencedMatches };
|