BUGFIX: template-require-iframe-title — flag title={{null|undefined|number}}#57
BUGFIX: template-require-iframe-title — flag title={{null|undefined|number}}#57
Conversation
🏎️ Benchmark Comparison
Full mitata output |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Updates ember/template-require-iframe-title to more accurately reject non-string “title” literals (null/undefined/boolean/number) and introduces an option to allow whitespace-only static titles while keeping the default behavior strict.
Changes:
- Reject additional Glimmer literal AST node types for
title={{...}}andtitle="{{...}}". - Add
allowWhitespaceOnlyTitlerule option to permit whitespace-only static titles. - Extend documentation and tests, plus add a non-CI “peer parity” audit fixture.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| tests/lib/rules/template-require-iframe-title.js | Adds test coverage for new invalid literals and the whitespace-only option behavior. |
| tests/audit/iframe-title/peer-parity.js | Adds an offline audit fixture encoding current behavior vs peer plugins. |
| lib/rules/template-require-iframe-title.js | Implements isInvalidTitleLiteral() and the allowWhitespaceOnlyTitle option + updated checks. |
| docs/rules/template-require-iframe-title.md | Documents new option and clarifies rule rationale and references. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
06219b7 to
1fd8b3b
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@copilot can you check all references to wcag and w3 to check if the actual spec says what the inline reference / paragraph says? bonus points for adding precise link to the section in the spec |
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 <template>{{! some comment }}{{yield}}</template> now yields a body of length 2 and silently stops being flagged — which is also why PR ember-cli#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 [email protected] 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 (`<!-- x -->{{yield}}`), which it was silently missing before.
…only-filter-comments fix: ignore comment + whitespace nodes in template-no-yield-only
… add allowWhitespaceOnlyTitle opt-out
Treat literal AST values that don't produce a meaningful accessible name
as invalid `<iframe title>` values:
- `GlimmerBooleanLiteral` / `GlimmerNullLiteral` / `GlimmerUndefinedLiteral` /
`GlimmerNumberLiteral` → flagged with a new `invalidTitleLiteral` messageId.
Coerce-to-string runtime values like "true" / "null" / "42" don't
describe the frame contents, regardless of framework behavior.
- `GlimmerStringLiteral` resolving to empty / whitespace → flagged as
`emptyTitle` (resolution shared with the text-node case via a
`processStaticTitle` helper). Closes a bypass that jsx-a11y already
catches via `getLiteralPropValue`.
Both literal classes apply to the bare-mustache `title={{x}}` form AND
the single-part concat `title="{{x}}"` form.
Whitespace-only static title (`title=" "`) is now opt-out via a new
`allowWhitespaceOnlyTitle: true` schema option. ACCNAME 1.2 §4.3.2 step
2I (Tooltip) does not whitespace-trim — so a 3-space accessible name is
spec-assigned. The check stays on by default as authoring hygiene; teams
that want strict spec parity can opt out. Empty-string `title=""` and
the non-string-literal cases above are not affected by this option —
they are always flagged as correctness.
Refs:
- WCAG SC 4.1.2: https://www.w3.org/TR/UNDERSTANDING-WCAG20/ensure-compat-rsv.html
- ACCNAME 1.2 §4.3.2: https://www.w3.org/TR/accname-1.2/#computation-steps
5dd3c75 to
19e44c4
Compare
…tle option Whitespace-only titles are never intentional and the option added API surface with no real-world use case. Always flag empty/whitespace title values as errors.
[Mirror of ember-cli#2731 for Copilot review]
Note
This is part of a series where Claude has audited
eslint-plugin-emberagainst jsx-a11y, vuejs-accessibility, angular-eslint, lit-a11y and html-validate,ember-template-lint, and the HTML and WCAG specs.Summary
Premise 1:
<iframe>elements require an accessible name so assistive tech can convey their content. The normative source is WCAG SC 4.1.2 Name, Role, Value; Technique H64 is a sufficient technique citingtitleas one way to provide it.Premise 2: Mustache literal title values don't supply an author-intended name. At runtime Ember either drops the attribute when the bound value is nullish (no accessible name) or stringifies the literal to
"null"/"undefined"/"42"(a coerced placeholder). Empty string literals like{{""}}resolve to""— same effect astitle="".Premise 3: Today our rule only rejects
title={{false}}.title={{null}},title={{undefined}},title={{42}},title={{""}}, and theirtitle="{{x}}"concat equivalents silently pass.Conclusion: Treat
GlimmerBooleanLiteral,GlimmerNullLiteral,GlimmerUndefinedLiteral,GlimmerNumberLiteral, and empty/whitespaceGlimmerStringLiteralas invalid title values in both thetitle={{x}}andtitle="{{x}}"positions.Fix: extract
isInvalidTitleLiteralPath()for the four non-string literal types and a sharedprocessStaticTitle()helper that handles text-node, mustache-string-literal, and concat-string-literal forms uniformly. Empty / whitespace string literals follow the same emptiness path as text-nodetitle="".Tests cover each literal type × each syntax form (bare-mustache and concat).
Whitespace-only title — now opt-out via schema option
The rule previously flagged
title=" "(whitespace-only static) as a hard error. This is stricter than ACCNAME — ACCNAME 1.2 §4.3.2 step 2I (Tooltip) just says "return its value" with no trim (unlike step D AriaLabel, which has an explicitnor, when trimmed of whitespace, is not the empty stringcheck), so a 3-space accessible name is technically assigned. The check remains on by default as an authoring-hygiene guard (useless in practice), but teams that want spec-aligned behavior can opt out via the newallowWhitespaceOnlyTitle: trueoption. Empty-stringtitle="", the non-string literal cases above, and empty-string-literal mustaches are not affected by this option — they are always flagged as correctness.Prior art
Peers diverge materially on empty/non-string title handling. Don't assume parity:
iframe-has-titleif (title && typeof title === 'string')→ bail. Flagstitle=""(falsy), flagstitle={42}(not a string), flagstitle={null}(falsy). Does NOT flagtitle=" "(truthy string).iframe-has-titletitle === null || !["string","object"].includes(typeof title)→ flag. Does NOT flagtitle=""(typeof "string"). Flags:title='2'(number not a string).iframe-title!element.attribs.title || element.attribs.title === undefined. Flagstitle=""(falsy), does NOT flag non-string values (parse5 yields strings only).iframe-titleequivalent in the rules directory.