From 703bf15f9d7ee3fee4861da46b1f5ba03b00287e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20R=C3=B8ed?= Date: Fri, 24 Apr 2026 21:11:24 +0200 Subject: [PATCH 1/3] fix: ignore comment + whitespace nodes in template-no-yield-only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rule flagged yield-only templates by asserting `templateNodes.length === 1 && isYieldOnly(templateNodes[0])`. That works only while the parser strips template comments out of the body, which ember-estree 0.4.2 happened to do. Upstream ember-estree 0.4.3 (#31) began keeping MustacheCommentStatement nodes in the body, so a template like now yields a body of length 2 and silently stops being flagged — which is also why PR #2735 (upgrade to ember-eslint-parser 0.11) fails this rule's CI. Ignoring comment and whitespace-only text nodes before the length check aligns with: - upstream ember-template-lint's `no-yield-only.js` (unchanged there since comments-in-body is the native Glimmer AST shape anyway) - the sibling rule `template-no-bare-yield.js`, which already uses the same `isEmptyNode` filter The fix is a no-op on the currently-pinned ember-eslint-parser@0.10 and fixes the rule under any parser version that preserves comment nodes in the template body. The rule also now correctly catches yield-only templates that contain HTML comments (`{{yield}}`), which it was silently missing before. --- lib/rules/template-no-yield-only.js | 11 ++++++++++- tests/lib/rules/template-no-yield-only.js | 10 ++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/rules/template-no-yield-only.js b/lib/rules/template-no-yield-only.js index 76d859be8d..b4b423b662 100644 --- a/lib/rules/template-no-yield-only.js +++ b/lib/rules/template-no-yield-only.js @@ -1,3 +1,11 @@ +function isEmptyNode(node) { + return ( + node.type === 'GlimmerMustacheCommentStatement' || + node.type === 'GlimmerCommentStatement' || + (node.type === 'GlimmerTextNode' && !node.chars.trim()) + ); +} + function isYieldOnly(node) { return ( node.type === 'GlimmerMustacheStatement' && @@ -44,7 +52,8 @@ module.exports = { ? node.body[0].children : node.body; - if (templateNodes.length === 1 && isYieldOnly(templateNodes[0])) { + const nonEmptyNodes = templateNodes.filter((n) => !isEmptyNode(n)); + if (nonEmptyNodes.length === 1 && isYieldOnly(nonEmptyNodes[0])) { isOnlyYield = true; } }, diff --git a/tests/lib/rules/template-no-yield-only.js b/tests/lib/rules/template-no-yield-only.js index 9129c00828..cfb3fc9797 100644 --- a/tests/lib/rules/template-no-yield-only.js +++ b/tests/lib/rules/template-no-yield-only.js @@ -30,6 +30,16 @@ const invalidHbs = [ output: null, errors: [{ messageId: 'noYieldOnly' }], }, + { + code: '{{!-- long-form comment --}}{{yield}}', + output: null, + errors: [{ messageId: 'noYieldOnly' }], + }, + { + code: '{{yield}}', + output: null, + errors: [{ messageId: 'noYieldOnly' }], + }, ]; function wrapTemplate(entry) { From 19e44c40ec3026d1817e39167b240b537540ad2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20R=C3=B8ed?= Date: Sat, 25 Apr 2026 08:15:28 +0200 Subject: [PATCH 2/3] =?UTF-8?q?BUGFIX:=20template-require-iframe-title=20?= =?UTF-8?q?=E2=80=94=20flag=20invalid=20title=20literals=20+=20add=20allow?= =?UTF-8?q?WhitespaceOnlyTitle=20opt-out?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Treat literal AST values that don't produce a meaningful accessible name as invalid `