1+ const IGNORABLE_TYPES = new Set ( [ 'GlimmerTextNode' , 'GlimmerMustacheCommentStatement' ] ) ;
2+
3+ function isBareYield ( node ) {
4+ return (
5+ node . type === 'GlimmerMustacheStatement' &&
6+ node . path &&
7+ node . path . type === 'GlimmerPathExpression' &&
8+ node . path . original === 'yield' &&
9+ ( ! node . params || node . params . length === 0 ) &&
10+ ( ! node . hash || ! node . hash . pairs || node . hash . pairs . length === 0 )
11+ ) ;
12+ }
13+
14+ function isMeaningfulContent ( node ) {
15+ if ( node . type === 'GlimmerTextNode' ) {
16+ return node . chars && node . chars . trim ( ) . length > 0 ;
17+ }
18+ return ! IGNORABLE_TYPES . has ( node . type ) ;
19+ }
20+
121/** @type {import('eslint').Rule.RuleModule } */
222module . exports = {
323 meta : {
@@ -23,56 +43,35 @@ module.exports = {
2343 } ,
2444
2545 create ( context ) {
26- return {
27- // eslint-disable-next-line complexity
28- GlimmerTemplate ( node ) {
29- // The template body contains a GlimmerElementNode for <template>
30- // The actual content is in its children
31- if ( ! node . body || node . body . length === 0 ) {
32- return ;
33- }
46+ function checkChildren ( children ) {
47+ let yieldNode = null ;
3448
35- const templateElement = node . body [ 0 ] ;
36- if ( ! templateElement || templateElement . type !== 'GlimmerElementNode' ) {
49+ for ( const child of children ) {
50+ if ( isBareYield ( child ) ) {
51+ yieldNode = child ;
52+ } else if ( isMeaningfulContent ( child ) ) {
3753 return ;
3854 }
55+ }
3956
40- const children = templateElement . children || [ ] ;
41-
42- let hasYield = false ;
43- let yieldNode = null ;
44- let hasOtherContent = false ;
57+ if ( yieldNode ) {
58+ context . report ( { node : yieldNode , messageId : 'noYieldOnly' } ) ;
59+ }
60+ }
4561
46- for ( const child of children ) {
47- if ( child . type === 'GlimmerMustacheStatement' ) {
48- if (
49- child . path &&
50- child . path . type === 'GlimmerPathExpression' &&
51- child . path . original === 'yield' &&
52- ( ! child . params || child . params . length === 0 ) &&
53- ( ! child . hash || ! child . hash . pairs || child . hash . pairs . length === 0 )
54- ) {
55- hasYield = true ;
56- yieldNode = child ;
57- } else {
58- hasOtherContent = true ;
59- }
60- } else if ( child . type === 'GlimmerElementNode' ) {
61- hasOtherContent = true ;
62- } else if (
63- child . type === 'GlimmerTextNode' &&
64- child . chars &&
65- child . chars . trim ( ) . length > 0
66- ) {
67- hasOtherContent = true ;
68- }
62+ return {
63+ GlimmerTemplate ( node ) {
64+ if ( ! node . body || node . body . length === 0 ) {
65+ return ;
6966 }
7067
71- if ( hasYield && ! hasOtherContent && yieldNode ) {
72- context . report ( {
73- node : yieldNode ,
74- messageId : 'noYieldOnly' ,
75- } ) ;
68+ const firstChild = node . body [ 0 ] ;
69+ if ( firstChild && firstChild . type === 'GlimmerElementNode' ) {
70+ // gjs/gts: body[0] is the <template> element, check its children
71+ checkChildren ( firstChild . children || [ ] ) ;
72+ } else {
73+ // hbs: body directly contains the template nodes
74+ checkChildren ( node . body ) ;
7675 }
7776 } ,
7877 } ;
0 commit comments