From bf48127c1366849b37975f2338a3ad92c6234df2 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Sat, 6 Jun 2026 12:04:18 -0400 Subject: [PATCH] chore(lint): justify intentional no-control-regex (ANSI strip) + ratchet to error (#737) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 5 no-control-regex warnings are all the same intentional ANSI-color-strip pattern /\x1b\[[0-9;]*m/g across 5 test files. The \x1b (ESC) control char is the required leading byte of an ANSI SGR sequence, so matching it is the whole point of stripping color codes from captured CLI/console output. Add an inline eslint-disable-next-line with justification at each site (not a refactor — the control char is essential, not accidental), then flip no-control-regex from warn to error so the debt can't regrow. Refs #736 Co-authored-by: Claude Opus 4.8 --- eslint.config.mjs | 2 +- tests/bug-2957-claude-global-postinstall-message.test.cjs | 1 + tests/bug-3582-codex-skills-materialized.test.cjs | 1 + tests/feat-2795-update-banner.test.cjs | 1 + tests/gsd-statusline.test.cjs | 1 + tests/installer-migration-install-integration.test.cjs | 1 + 6 files changed, 6 insertions(+), 1 deletion(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index f7891018f..17f7c3438 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -222,7 +222,7 @@ export default tseslint.config( // Downgraded from recommended error → warn (pre-existing violations; follow-up to fix) 'no-useless-escape': 'warn', 'no-regex-spaces': 'warn', - 'no-control-regex': 'warn', + 'no-control-regex': 'error', 'no-irregular-whitespace': 'warn', }, }, diff --git a/tests/bug-2957-claude-global-postinstall-message.test.cjs b/tests/bug-2957-claude-global-postinstall-message.test.cjs index 571f20a45..a83758c21 100644 --- a/tests/bug-2957-claude-global-postinstall-message.test.cjs +++ b/tests/bug-2957-claude-global-postinstall-message.test.cjs @@ -39,6 +39,7 @@ function captureFinishInstallOutput(runtime, isGlobal) { console.log = original; } // Strip ANSI color escapes so message-content assertions don't couple to colors. + // eslint-disable-next-line no-control-regex -- \x1b (ESC) is the required leading byte of ANSI SGR color sequences; matching it is the purpose of stripping ANSI codes from captured CLI/console output return lines.join('\n').replace(/\x1B\[[0-9;]*m/g, ''); } diff --git a/tests/bug-3582-codex-skills-materialized.test.cjs b/tests/bug-3582-codex-skills-materialized.test.cjs index ac6ae112d..306e24d7d 100644 --- a/tests/bug-3582-codex-skills-materialized.test.cjs +++ b/tests/bug-3582-codex-skills-materialized.test.cjs @@ -53,6 +53,7 @@ const COMMANDS_DIR = path.join(ROOT, 'commands', 'gsd'); // Strip ANSI color codes so log assertions don't depend on TTY detection. function stripAnsi(s) { + // eslint-disable-next-line no-control-regex -- \x1b (ESC) is the required leading byte of ANSI SGR color sequences; matching it is the purpose of stripping ANSI codes from captured CLI/console output return s.replace(/\x1b\[[0-9;]*m/g, ''); } diff --git a/tests/feat-2795-update-banner.test.cjs b/tests/feat-2795-update-banner.test.cjs index 0189e0e92..b1c49e148 100644 --- a/tests/feat-2795-update-banner.test.cjs +++ b/tests/feat-2795-update-banner.test.cjs @@ -317,6 +317,7 @@ describe('install.js update-banner wiring', () => { // Strip ANSI color escapes before structural assertions — the choice // digits are wrapped in color codes so word-boundary regex against the // raw text would miss them. + // eslint-disable-next-line no-control-regex -- \x1b (ESC) is the required leading byte of ANSI SGR color sequences; matching it is the purpose of stripping ANSI codes from captured CLI/console output const stripped = text.replace(/\x1b\[[0-9;]*m/g, ''); // Prompt must offer at least two choices (default + opt-in). assert.match(stripped, /\b1\b/); diff --git a/tests/gsd-statusline.test.cjs b/tests/gsd-statusline.test.cjs index 4960a6d04..5425bf235 100644 --- a/tests/gsd-statusline.test.cjs +++ b/tests/gsd-statusline.test.cjs @@ -334,6 +334,7 @@ describe('context meter respects CLAUDE_CODE_AUTO_COMPACT_WINDOW (#2219)', () => // Parse normalized used% from the statusline bar output (e.g. "60%") // Strip ANSI escape codes then extract the percentage digit(s) before "%" + // eslint-disable-next-line no-control-regex -- \x1b (ESC) is the required leading byte of ANSI SGR color sequences; matching it is the purpose of stripping ANSI codes from captured CLI/console output const clean = stdout.replace(/\x1b\[[0-9;]*m/g, ''); const match = clean.match(/(\d+)%/); const normalizedUsed = match ? parseInt(match[1], 10) : null; diff --git a/tests/installer-migration-install-integration.test.cjs b/tests/installer-migration-install-integration.test.cjs index 2f4f79dc4..857bc101f 100644 --- a/tests/installer-migration-install-integration.test.cjs +++ b/tests/installer-migration-install-integration.test.cjs @@ -133,6 +133,7 @@ function withSdkDistPresent(fn) { } function stripAnsi(value) { + // eslint-disable-next-line no-control-regex -- \x1b (ESC) is the required leading byte of ANSI SGR color sequences; matching it is the purpose of stripping ANSI codes from captured CLI/console output return value.replace(/\x1b\[[0-9;]*m/g, ''); }