From 2f764a11d00a36792488db0ee90be4785fc441b0 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Wed, 18 Mar 2026 18:05:31 -0400 Subject: [PATCH 1/2] Extract rule: template-no-whitespace-within-word --- README.md | 1 + .../template-no-whitespace-within-word.md | 49 ++++++ .../template-no-whitespace-within-word.js | 117 ++++++++++++++ .../template-no-whitespace-within-word.js | 144 ++++++++++++++++++ 4 files changed, 311 insertions(+) create mode 100644 docs/rules/template-no-whitespace-within-word.md create mode 100644 lib/rules/template-no-whitespace-within-word.js create mode 100644 tests/lib/rules/template-no-whitespace-within-word.js diff --git a/README.md b/README.md index 33484c4067..c00551fdda 100644 --- a/README.md +++ b/README.md @@ -197,6 +197,7 @@ rules in templates can be disabled with eslint directives with mustache or html | [template-no-nested-interactive](docs/rules/template-no-nested-interactive.md) | disallow nested interactive elements | | | | | [template-no-nested-landmark](docs/rules/template-no-nested-landmark.md) | disallow nested landmark elements | | | | | [template-no-pointer-down-event-binding](docs/rules/template-no-pointer-down-event-binding.md) | disallow pointer down event bindings | | | | +| [template-no-whitespace-within-word](docs/rules/template-no-whitespace-within-word.md) | disallow excess whitespace within words (e.g. "W e l c o m e") | | | | | [template-require-aria-activedescendant-tabindex](docs/rules/template-require-aria-activedescendant-tabindex.md) | require non-interactive elements with aria-activedescendant to have tabindex | | 🔧 | | | [template-require-iframe-title](docs/rules/template-require-iframe-title.md) | require iframe elements to have a title attribute | | | | | [template-require-input-label](docs/rules/template-require-input-label.md) | require label for form input elements | | | | diff --git a/docs/rules/template-no-whitespace-within-word.md b/docs/rules/template-no-whitespace-within-word.md new file mode 100644 index 0000000000..f75405146e --- /dev/null +++ b/docs/rules/template-no-whitespace-within-word.md @@ -0,0 +1,49 @@ +# ember/template-no-whitespace-within-word + + + +Disallow excess whitespace within words (e.g. "W e l c o m e"). + +## Rule Details + +This rule detects text content where letters are separated by whitespace or whitespace HTML entities, producing a "spaced out" word effect like `W e l c o m e`. This pattern is an accessibility concern because screen readers will read each letter individually instead of reading the word. + +The rule checks `GlimmerTextNode` content (excluding text inside attributes and ``, + ], + invalid: [ + { + code: '', + output: null, + errors: [{ messageId: 'excessWhitespace' }], + }, + { + code: '', + output: null, + errors: [{ messageId: 'excessWhitespace' }], + }, + { + code: '', + output: null, + errors: [{ messageId: 'excessWhitespace' }], + }, + + { + code: '', + output: null, + errors: [{ messageId: 'excessWhitespace' }], + }, + { + code: '', + output: null, + errors: [{ messageId: 'excessWhitespace' }], + }, + { + code: '', + output: null, + errors: [{ messageId: 'excessWhitespace' }], + }, + { + code: '', + output: null, + errors: [{ messageId: 'excessWhitespace' }], + }, + { + code: '', + output: null, + errors: [{ messageId: 'excessWhitespace' }], + }, + { + code: '', + output: null, + errors: [{ messageId: 'excessWhitespace' }], + }, + ], +}); + +const hbsRuleTester = new RuleTester({ + parser: require.resolve('ember-eslint-parser/hbs'), + parserOptions: { + ecmaVersion: 2022, + sourceType: 'module', + }, +}); + +hbsRuleTester.run('template-no-whitespace-within-word', rule, { + valid: [ + 'Welcome', + 'Hey - I like this!', + 'Expected: 5-10 guests', + 'Expected: 5 - 10 guests', + 'It is possible to get some examples of in-word emph a sis past this rule.', + 'However, I do not want a rule that flags annoying false positives for correctly-used single-character words.', + '
Welcome
', + '
We want to ignore values of HTML attributes
', + ``, + ], + invalid: [ + { + code: 'W e l c o m e', + output: null, + errors: [{ message: 'Excess whitespace in layout detected.' }], + }, + { + code: 'W e l c o m e', + output: null, + errors: [{ message: 'Excess whitespace in layout detected.' }], + }, + { + code: 'Wel c o me', + output: null, + errors: [{ message: 'Excess whitespace in layout detected.' }], + }, + { + code: 'Wel c o me', + output: null, + errors: [{ message: 'Excess whitespace in layout detected.' }], + }, + { + code: '
W e l c o m e
', + output: null, + errors: [{ message: 'Excess whitespace in layout detected.' }], + }, + { + code: '
Wel c o me
', + output: null, + errors: [{ message: 'Excess whitespace in layout detected.' }], + }, + { + code: 'A B   C ', + output: null, + errors: [{ message: 'Excess whitespace in layout detected.' }], + }, + ], +}); From ce53f5c7b047d0b1d1b6f34733cbe18a53277be4 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Fri, 20 Mar 2026 20:13:35 -0400 Subject: [PATCH 2/2] Sync with template-lint --- .../template-no-whitespace-within-word.md | 46 +++-- .../template-no-whitespace-within-word.js | 195 +++++++----------- 2 files changed, 102 insertions(+), 139 deletions(-) diff --git a/docs/rules/template-no-whitespace-within-word.md b/docs/rules/template-no-whitespace-within-word.md index f75405146e..1a8e6c0c41 100644 --- a/docs/rules/template-no-whitespace-within-word.md +++ b/docs/rules/template-no-whitespace-within-word.md @@ -2,48 +2,62 @@ -Disallow excess whitespace within words (e.g. "W e l c o m e"). +In practice, the predominant issue raised by inline whitespace styling is that the resultant text "formatting" is entirely visual in nature; the ability to discern the correct manner in which to read the text, and therefore, to correctly comprehend its meaning, is restricted to sighted users. -## Rule Details +Using in-line whitespace word formatting produces results that are explicitly mentioned in [WCAG's list of common sources of web accessibility failures](https://www.w3.org/TR/WCAG20-TECHS/failures.html). Specifically, this common whitespace-within-word-induced web accessibility issue fails to successfully achieve [WCAG Success Criterion 1.3.2: Meaningful Sequence](https://www.w3.org/TR/UNDERSTANDING-WCAG20/content-structure-separation-sequence.html). -This rule detects text content where letters are separated by whitespace or whitespace HTML entities, producing a "spaced out" word effect like `W e l c o m e`. This pattern is an accessibility concern because screen readers will read each letter individually instead of reading the word. - -The rule checks `GlimmerTextNode` content (excluding text inside attributes and ``, - ], - invalid: [ - { - code: '', - output: null, - errors: [{ messageId: 'excessWhitespace' }], - }, - { - code: '', - output: null, - errors: [{ messageId: 'excessWhitespace' }], - }, - { - code: '', - output: null, - errors: [{ messageId: 'excessWhitespace' }], - }, +`, +]; - { - code: '', - output: null, - errors: [{ messageId: 'excessWhitespace' }], - }, - { - code: '', - output: null, - errors: [{ messageId: 'excessWhitespace' }], - }, - { - code: '', - output: null, - errors: [{ messageId: 'excessWhitespace' }], - }, - { - code: '', - output: null, - errors: [{ messageId: 'excessWhitespace' }], - }, - { - code: '', - output: null, - errors: [{ messageId: 'excessWhitespace' }], - }, - { - code: '', - output: null, - errors: [{ messageId: 'excessWhitespace' }], - }, - ], +const invalidHbs = [ + { + code: 'W e l c o m e', + output: null, + errors: [{ message: 'Excess whitespace in layout detected.' }], + }, + { + code: 'W e l c o m e', + output: null, + errors: [{ message: 'Excess whitespace in layout detected.' }], + }, + { + code: 'Wel c o me', + output: null, + errors: [{ message: 'Excess whitespace in layout detected.' }], + }, + { + code: 'Wel c o me', + output: null, + errors: [{ message: 'Excess whitespace in layout detected.' }], + }, + { + code: '
W e l c o m e
', + output: null, + errors: [{ message: 'Excess whitespace in layout detected.' }], + }, + { + code: '
Wel c o me
', + output: null, + errors: [{ message: 'Excess whitespace in layout detected.' }], + }, + { + code: 'A B   C ', + output: null, + errors: [{ message: 'Excess whitespace in layout detected.' }], + }, +]; + +function wrapTemplate(entry) { + if (typeof entry === 'string') { + return ``; + } + + return { + ...entry, + code: ``, + output: entry.output ? `` : entry.output, + }; +} + +const gjsRuleTester = new RuleTester({ + parser: require.resolve('ember-eslint-parser'), + parserOptions: { ecmaVersion: 2022, sourceType: 'module' }, +}); + +gjsRuleTester.run('template-no-whitespace-within-word', rule, { + valid: validHbs.map(wrapTemplate), + invalid: invalidHbs.map(wrapTemplate), }); const hbsRuleTester = new RuleTester({ @@ -89,56 +88,6 @@ const hbsRuleTester = new RuleTester({ }); hbsRuleTester.run('template-no-whitespace-within-word', rule, { - valid: [ - 'Welcome', - 'Hey - I like this!', - 'Expected: 5-10 guests', - 'Expected: 5 - 10 guests', - 'It is possible to get some examples of in-word emph a sis past this rule.', - 'However, I do not want a rule that flags annoying false positives for correctly-used single-character words.', - '
Welcome
', - '
We want to ignore values of HTML attributes
', - ``, - ], - invalid: [ - { - code: 'W e l c o m e', - output: null, - errors: [{ message: 'Excess whitespace in layout detected.' }], - }, - { - code: 'W e l c o m e', - output: null, - errors: [{ message: 'Excess whitespace in layout detected.' }], - }, - { - code: 'Wel c o me', - output: null, - errors: [{ message: 'Excess whitespace in layout detected.' }], - }, - { - code: 'Wel c o me', - output: null, - errors: [{ message: 'Excess whitespace in layout detected.' }], - }, - { - code: '
W e l c o m e
', - output: null, - errors: [{ message: 'Excess whitespace in layout detected.' }], - }, - { - code: '
Wel c o me
', - output: null, - errors: [{ message: 'Excess whitespace in layout detected.' }], - }, - { - code: 'A B   C ', - output: null, - errors: [{ message: 'Excess whitespace in layout detected.' }], - }, - ], + valid: validHbs, + invalid: invalidHbs, });