Skip to content

fix(template-no-yield-only): filter comments/whitespace before length check - #4

Open
NullVoxPopuli-ai-agent wants to merge 1 commit into
nvp/update-parserfrom
fix/yield-only-comment-filter
Open

fix(template-no-yield-only): filter comments/whitespace before length check#4
NullVoxPopuli-ai-agent wants to merge 1 commit into
nvp/update-parserfrom
fix/yield-only-comment-filter

Conversation

@NullVoxPopuli-ai-agent

Copy link
Copy Markdown
Owner

Fix proposed for ember-cli#2735, which is currently failing on build (ubuntu, 24.x) with two template-no-yield-only invalid-case failures (the ones containing {{! some comment }}).

Why it's failing

ember-eslint-parser@0.11 (via ember-estree@0.6.x) intentionally keeps GlimmerMustacheCommentStatement and GlimmerCommentStatement nodes in their parent's body/children. Whitespace-only GlimmerTextNodes still get stripped, but comments don't — because:

  • template-no-html-comments flags HTML comments via sourceCode.getAllComments(), which is populated by an AST-traversal-based collector in ember-eslint-parser. If comments were stripped from body upstream in ember-estree, the collector would never see them → ast.comments empties → that rule silently stops working, and {{! eslint-disable }} / <!-- eslint-disable --> inline directives in templates also stop working. Verified by patching removeFromParent(comments) in ember-estree/src/transforms.js — 6 other tests then break.
  • template-block-indentation, template-table-groups, template-no-bare-yield already handle in-body comment nodes explicitly.

So the parser contract is: comments live in body AND in ast.comments (template-lint tradition, not ESLint-strict). Rules counting structural children must filter.

template-no-bare-yield already does — it has a local isEmptyNode(node) helper. template-no-yield-only didn't.

What this PR does

  1. Extract isEmptyNode to lib/utils/glimmer-ast.js — whitespace-only GlimmerTextNode + both comment node types, with a docstring pinning down the parser contract so future rule authors know.
  2. Fix template-no-yield-only — filter ignorable nodes before the length === 1 gate. The four existing invalid cases (including the two {{! ... }} ones) all pass in both gjs and hbs modes.
  3. DRY template-no-bare-yield — drop its inline copy of the helper, import from the shared util.
  4. Unit-test the util — six cases covering both comment types, whitespace-only text, text with visible content, and two non-comment node types.

Verification

  • npx vitest run9107 / 9107 pass (was 9099 / 9101 on nvp/update-parser tip).
  • pnpm lint:prettier clean; no lint errors on the changed files.

How to pull into ember-cli#2735

git fetch https://github.com/NullVoxPopuli-ai-agent/eslint-plugin-ember.git fix/yield-only-comment-filter
git cherry-pick FETCH_HEAD

Latent issue (out of scope, separate fix)

template-no-only-default-slot.js:34 does parent.children.length === 1 and would also silently miss detection when an adjacent {{! comment }} is present. No test covers that case today. Worth a follow-up.

🤖 Generated with Claude Code

… check

ember-eslint-parser 0.11 keeps `{{! ... }}` and `<!-- ... -->` nodes in the
template body so that `template-no-html-comments` and `{{! eslint-disable }}`
inline-config scanning continue to work. Rules that count "meaningful"
children must now filter them explicitly, as `template-no-bare-yield`
already does.

- Extract `isEmptyNode` (whitespace-only GlimmerTextNode + both comment
  node types) to a new `lib/utils/glimmer-ast.js`, with a docstring
  documenting the parser contract.
- Apply it in `template-no-yield-only` before the `length === 1` check.
  Fixes the two `{{! ... }}` invalid-case regressions.
- Replace the inline copy of the same helper in `template-no-bare-yield`
  with the shared util.
- Unit-test the util.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🏎️ Benchmark Comparison

Benchmark Control (p50) Experiment (p50) Δ
🟢 js small 14.38 ms 13.22 ms -8.1%
🟢 js medium 6.67 ms 6.52 ms -2.3%
js large 2.65 ms 2.60 ms -1.7%
gjs small 1.11 ms 1.10 ms -0.9%
gjs medium 552.70 µs 552.36 µs -0.1%
gjs large 219.87 µs 219.62 µs -0.1%
gts small 1.10 ms 1.10 ms -0.4%
gts medium 554.23 µs 553.70 µs -0.1%
gts large 220.04 µs 219.95 µs -0.0%

🟢 faster · 🔴 slower · 🟠 slightly slower · ⚪ within 2%

Full mitata output
clk: ~2.74 GHz
cpu: AMD EPYC 9V74 80-Core Processor
runtime: node 24.14.1 (x64-linux)

benchmark                   avg (min … max) p75 / p99    (min … top 1%)
------------------------------------------- -------------------------------
js small (control)            16.44 ms/iter  17.53 ms █                    
                      (11.45 ms … 31.51 ms)  28.89 ms █ ▆                  
                    (  5.76 mb …  10.65 mb)   7.29 mb ████▆█▄█▄▁▁▁▄▄▄▁▁▄▄▄▄

js small (experiment)         14.01 ms/iter  14.46 ms ▄   █                
                      (11.93 ms … 19.16 ms)  18.56 ms █████ ▅▅▅    ▅       
                    (  6.26 mb …   8.35 mb)   6.83 mb █████▅███▁█▁▅█▁█▁▁▅▁▅

                             ┌                                            ┐
                             ╷  ┌─────────┬──┐                            ╷
          js small (control) ├──┤         │  ├────────────────────────────┤
                             ╵  └─────────┴──┘                            ╵
                              ╷ ┌───┬┐         ╷
       js small (experiment)  ├─┤   │├─────────┤
                              ╵ └───┴┘         ╵
                             └                                            ┘
                             11.45 ms           20.17 ms           28.89 ms

summary
  js small (experiment)
   1.17x faster than js small (control)

------------------------------------------- -------------------------------
js medium (control)            7.41 ms/iter   7.72 ms  █                   
                       (6.18 ms … 17.07 ms)  14.44 ms ██▃                  
                    (  2.31 mb …   5.42 mb)   3.55 mb ███▂█▄▃▂▃▂▁▂▁▂▁▁▂▁▁▂▂

js medium (experiment)         7.26 ms/iter   7.58 ms ▂█                   
                       (6.11 ms … 15.15 ms)  14.13 ms ██                   
                    (  3.05 mb …   3.97 mb)   3.54 mb ███▃▆▂▆▂▃▃▁▁▂▁▁▂▂▁▁▁▂

                             ┌                                            ┐
                             ╷ ┌────┬─┐                                   ╷
         js medium (control) ├─┤    │ ├───────────────────────────────────┤
                             ╵ └────┴─┘                                   ╵
                             ╷┌────┬─┐                                  ╷
      js medium (experiment) ├┤    │ ├──────────────────────────────────┤
                             ╵└────┴─┘                                  ╵
                             └                                            ┘
                             6.11 ms           10.27 ms            14.44 ms

summary
  js medium (experiment)
   1.02x faster than js medium (control)

------------------------------------------- -------------------------------
js large (control)             3.12 ms/iter   3.02 ms  █                   
                        (2.25 ms … 9.36 ms)   8.00 ms ██▄                  
                    (308.78 kb …   2.82 mb)   1.45 mb ███▃▃▃▃▂▂▁▂▂▁▂▂▁▁▁▁▁▂

js large (experiment)          2.88 ms/iter   2.73 ms  █                   
                        (2.39 ms … 7.29 ms)   6.00 ms ▄█                   
                    (185.93 kb …   2.68 mb)   1.43 mb ██▇▂▃▂▂▂▁▂▁▁▁▁▁▁▁▁▁▁▂

                             ┌                                            ┐
                             ╷┌─────┬                                     ╷
          js large (control) ├┤     │─────────────────────────────────────┤
                             ╵└─────┴                                     ╵
                              ╷┌──┬                       ╷
       js large (experiment)  ├┤  │───────────────────────┤
                              ╵└──┴                       ╵
                             └                                            ┘
                             2.25 ms            5.12 ms             8.00 ms

summary
  js large (experiment)
   1.08x faster than js large (control)

------------------------------------------- -------------------------------
gjs small (control)            1.25 ms/iter   1.14 ms █                    
                        (1.09 ms … 7.75 ms)   6.40 ms █                    
                    (324.61 kb …   1.66 mb)   1.06 mb █▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

gjs small (experiment)         1.24 ms/iter   1.13 ms █                    
                        (1.08 ms … 7.51 ms)   6.10 ms █                    
                    (251.88 kb …   1.89 mb)   1.06 mb █▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ┌┬                                           ╷
         gjs small (control) ││───────────────────────────────────────────┤
                             └┴                                           ╵
                             ┌┬                                        ╷
      gjs small (experiment) ││────────────────────────────────────────┤
                             └┴                                        ╵
                             └                                            ┘
                             1.08 ms            3.74 ms             6.40 ms

summary
  gjs small (experiment)
   1.01x faster than gjs small (control)

------------------------------------------- -------------------------------
gjs medium (control)         602.51 µs/iter 559.62 µs █                    
                      (534.96 µs … 5.89 ms)   3.23 ms █                    
                    (108.74 kb …   1.26 mb) 541.92 kb █▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

gjs medium (experiment)      595.34 µs/iter 558.44 µs █                    
                      (534.70 µs … 5.17 ms)   1.94 ms █                    
                    ( 66.53 kb …   1.08 mb) 539.91 kb █▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ┌┬                                           ╷
        gjs medium (control) ││───────────────────────────────────────────┤
                             └┴                                           ╵
                             ┌┬                      ╷
     gjs medium (experiment) ││──────────────────────┤
                             └┴                      ╵
                             └                                            ┘
                             534.70 µs           1.88 ms            3.23 ms

summary
  gjs medium (experiment)
   1.01x faster than gjs medium (control)

------------------------------------------- -------------------------------
gjs large (control)          240.31 µs/iter 226.17 µs  █▆                  
                      (213.22 µs … 5.03 ms) 277.54 µs  ██▂                 
                    (138.70 kb … 777.19 kb) 217.02 kb ▄███▅█▅▃▂▂▁▁▁▁▁▁▁▁▁▁▁

gjs large (experiment)       239.30 µs/iter 226.29 µs  ▄█                  
                      (212.74 µs … 4.88 ms) 279.39 µs  ██                  
                    (137.95 kb … 960.73 kb) 216.54 kb ▂███▄█▆▂▁▁▁▁▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ╷  ┌───────────────┬                        ╷
         gjs large (control) ├──┤               │────────────────────────┤
                             ╵  └───────────────┴                        ╵
                             ╷  ┌──────────────┬                          ╷
      gjs large (experiment) ├──┤              │──────────────────────────┤
                             ╵  └──────────────┴                          ╵
                             └                                            ┘
                             212.74 µs         246.07 µs          279.39 µs

summary
  gjs large (experiment)
   1x faster than gjs large (control)

------------------------------------------- -------------------------------
gts small (control)            1.20 ms/iter   1.11 ms █                    
                        (1.09 ms … 6.25 ms)   5.34 ms █                    
                    (197.95 kb …   1.50 mb)   1.06 mb █▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

gts small (experiment)         1.20 ms/iter   1.11 ms █                    
                        (1.08 ms … 6.75 ms)   5.39 ms █                    
                    (195.97 kb …   1.69 mb)   1.05 mb █▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ┌┬                                          ╷
         gts small (control) ││──────────────────────────────────────────┤
                             └┴                                          ╵
                             ┌┬                                           ╷
      gts small (experiment) ││───────────────────────────────────────────┤
                             └┴                                           ╵
                             └                                            ┘
                             1.08 ms            3.23 ms             5.39 ms

summary
  gts small (control)
   1x faster than gts small (experiment)

------------------------------------------- -------------------------------
gts medium (control)         598.52 µs/iter 561.75 µs █                    
                      (535.61 µs … 5.80 ms)   1.60 ms █                    
                    (129.75 kb …   1.26 mb) 541.71 kb █▇▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

gts medium (experiment)      606.19 µs/iter 559.46 µs █                    
                      (535.50 µs … 6.28 ms)   2.91 ms █                    
                    (232.16 kb …   1.08 mb) 540.50 kb █▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ┌┬                  ╷
        gts medium (control) ││──────────────────┤
                             └┴                  ╵
                             ┌┬                                           ╷
     gts medium (experiment) ││───────────────────────────────────────────┤
                             └┴                                           ╵
                             └                                            ┘
                             535.50 µs           1.72 ms            2.91 ms

summary
  gts medium (control)
   1.01x faster than gts medium (experiment)

------------------------------------------- -------------------------------
gts large (control)          240.98 µs/iter 226.59 µs  ▇█                  
                      (213.11 µs … 5.21 ms) 275.65 µs  ██▅                 
                    ( 14.25 kb …   1.07 mb) 216.89 kb ▃███▄▇▇▅▂▁▁▁▁▁▁▁▁▁▁▁▁

gts large (experiment)       244.40 µs/iter 228.52 µs  ██                  
                      (212.62 µs … 5.59 ms) 283.86 µs  ██                  
                    (183.83 kb …   0.99 mb) 216.74 kb ▃███▅█▆▃▂▃▂▁▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ╷  ┌──────────────┬                     ╷
         gts large (control) ├──┤              │─────────────────────┤
                             ╵  └──────────────┴                     ╵
                             ╷  ┌────────────────┬                        ╷
      gts large (experiment) ├──┤                │────────────────────────┤
                             ╵  └────────────────┴                        ╵
                             └                                            ┘
                             212.62 µs         248.24 µs          283.86 µs

summary
  gts large (control)
   1.01x faster than gts large (experiment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants