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: '{{! eslint-enable ember/template-no-log }}{{log "x"}}',
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: '{{! template-lint-disable "no-log" }}{{log "x"}}',
+ output: '{{! eslint-disable ember/template-no-log }}{{log "x"}}',
+ errors: [{ messageId: 'convert' }],
+ },
+ {
+ code: '{{! template-lint-disable \'no-log\' }}{{log "x"}}',
+ output: '{{! eslint-disable ember/template-no-log }}{{log "x"}}',
+ errors: [{ messageId: 'convert' }],
+ },
+ {
+ code: '{{! template-lint-disable "no-log" no-debugger }}{{log "x"}}',
+ output:
+ '{{! eslint-disable ember/template-no-log, ember/template-no-debugger }}{{log "x"}}',
+ errors: [{ messageId: 'convert' }],
+ },
+ {
+ code: '{{! template-lint-enable "no-log" }}{{log "x"}}',
+ output: '{{! eslint-enable ember/template-no-log }}{{log "x"}}',
+ 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: '{{! template-lint-disable "no-log\' }}{{log "x"}}',
+ output: '{{! eslint-disable ember/template-"no-log\' }}{{log "x"}}',
+ 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.