From f01e795b81c8fab7faa2840d4ff108d8a1ebc478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20R=C3=B8ed?= Date: Fri, 31 Jul 2026 14:28:41 +0200 Subject: [PATCH] fix(template-no-template-lint-directives): unquote rule names when converting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ember-template-lint accepts quoted rule names in its directives — it maps `unquote` over every name in a `template-lint-disable` / `-enable` list — so `{{! template-lint-disable "no-log" }}` is a live directive, not a typo. The conversion fixer pasted the name through verbatim and emitted `ember/template-"no-log"`, a rule name that matches nothing. Running `--fix` over a codebase that used quoted names therefore silently dropped those suppressions. Mirror upstream's `unquote`: strip only when the first and last character are the same quote character, so a mismatched quote is still passed through unchanged. --- .../template-no-template-lint-directives.js | 17 +++++++++- .../template-no-template-lint-directives.js | 31 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/lib/rules/template-no-template-lint-directives.js b/lib/rules/template-no-template-lint-directives.js index 168efc52b9..041e6d9cea 100644 --- a/lib/rules/template-no-template-lint-directives.js +++ b/lib/rules/template-no-template-lint-directives.js @@ -69,6 +69,21 @@ module.exports = { }, }; +// ember-template-lint accepts quoted rule names in its directives and strips +// the quotes before matching, so `{{! template-lint-disable "no-log" }}` is a +// live directive. Mirror its `unquote` exactly: strip only when the first and +// last character are the same quote character. +function unquote(name) { + if (name.length < 3) { + return name; + } + const first = name[0]; + if (first === name.at(-1) && (first === '"' || first === "'")) { + return name.slice(1, -1); + } + return name; +} + function convertComment(rawComment) { const match = rawComment.match(DIRECTIVE_COMMENT); if (!match) { @@ -82,7 +97,7 @@ function convertComment(rawComment) { .trim() .split(/\s+/) .filter(Boolean) - .map((r) => `ember/template-${r}`) + .map((r) => `ember/template-${unquote(r)}`) .join(', '); const body = rules ? `eslint-${action} ${rules}` : `eslint-${action}`; // Emit symmetric markers regardless of what the source did. diff --git a/tests/lib/rules/template-no-template-lint-directives.js b/tests/lib/rules/template-no-template-lint-directives.js index 163902d6d9..51b3626beb 100644 --- a/tests/lib/rules/template-no-template-lint-directives.js +++ b/tests/lib/rules/template-no-template-lint-directives.js @@ -44,6 +44,37 @@ ruleTester.run('template-no-template-lint-directives', rule, { output: '', errors: [{ messageId: 'convert' }], }, + // ember-template-lint unquotes each rule name (single or double quotes), + // so quoted names are live directives in migrating codebases and must + // convert to bare eslint rule names. + { + code: '', + output: '', + errors: [{ messageId: 'convert' }], + }, + { + code: '', + output: '', + errors: [{ messageId: 'convert' }], + }, + { + code: '', + output: + '', + errors: [{ messageId: 'convert' }], + }, + { + code: '', + output: '', + errors: [{ messageId: 'convert' }], + }, + // Mismatched or lone quotes are not a quoted name — upstream's unquote + // only strips when the first and last character are the same quote. + { + code: '', + output: '', + errors: [{ messageId: 'convert' }], + }, // Directive inside an element's opening tag is lifted to before the // element so the eslint-disable scope covers the line where the // violation is reported.