@@ -359,46 +359,42 @@ class AstSerializer {
359
359
// Has <* webc:root> (has to be a root child, not script/style)
360
360
let tops = this . getTopLevelNodes ( component ) ;
361
361
for ( let child of tops ) {
362
- let tagName = this . getTagName ( child ) ;
363
- if ( tagName === "script" || tagName === "style" ) {
364
- continue ;
365
- }
366
-
367
- if ( this . hasAttribute ( child , AstSerializer . attrs . ROOT ) ) {
368
- // ignore if webc:root and webc:keep
369
- if ( this . hasAttribute ( child , AstSerializer . attrs . KEEP ) ) {
362
+ let rootNodeMode = this . getRootNodeMode ( child ) ;
363
+ if ( rootNodeMode ) {
364
+ // do not use parent tag if webc:root="override"
365
+ if ( rootNodeMode === "override" ) {
370
366
return true ;
371
367
}
372
368
373
- // do not ignore if webc:root (but not webc:keep )
369
+ // use parent tag if webc:root (and not webc:root="override" )
374
370
return false ;
375
371
}
376
372
}
377
373
378
- // do not ignore if <style> or <script> in component definition (unless <style webc:root> or <script webc:root>)
374
+ // use parent tag if <style> or <script> in component definition (unless <style webc:root> or <script webc:root>)
379
375
for ( let child of tops ) {
380
376
let tagName = this . getTagName ( child ) ;
381
- if ( tagName !== "script" && tagName !== "style" || this . hasAttribute ( child , AstSerializer . attrs . ROOT ) ) {
377
+ if ( tagName !== "script" && tagName !== "style" ) {
382
378
continue ;
383
379
}
384
380
385
381
if ( this . hasTextContent ( child ) ) {
386
- return false ;
382
+ return false ; // use parent tag if script/style has non-empty values
387
383
}
388
384
389
385
// <script src=""> or <link rel="stylesheet" href="">
390
386
if ( this . getExternalSource ( tagName , child ) ) {
391
- return false ;
387
+ return false ; // use parent tag if script/link have external file refs
392
388
}
393
389
}
394
390
395
-
396
- // Has <template shadowroot> (can be anywhere in the component body)
391
+ // Use parent tag if has <template shadowroot> (can be anywhere in the component body)
397
392
let shadowroot = this . findElement ( component , "template" , [ "shadowroot" ] ) ;
398
393
if ( shadowroot ) {
399
394
return false ;
400
395
}
401
396
397
+ // Do not use parent tag
402
398
return true ;
403
399
}
404
400
@@ -427,16 +423,16 @@ class AstSerializer {
427
423
isTagIgnored ( node , component , renderingMode , options ) {
428
424
let tagName = this . getTagName ( node ) ;
429
425
430
- if ( this . shouldKeepNode ( node ) ) {
426
+ if ( this . shouldKeepNode ( node ) ) { // webc:keep
431
427
return false ; // do not ignore
432
428
}
433
429
434
- if ( this . hasAttribute ( node , AstSerializer . attrs . ROOT ) ) {
430
+ // must come after webc:keep (webc:keep takes precedence)
431
+ if ( this . hasAttribute ( node , AstSerializer . attrs . NOKEEP ) ) {
435
432
return true ;
436
433
}
437
434
438
- // must come after webc:keep (webc:keep takes precedence)
439
- if ( this . hasAttribute ( node , AstSerializer . attrs . NOKEEP ) ) {
435
+ if ( this . getRootNodeMode ( node ) === "merge" ) { // has webc:root but is not webc:root="override"
440
436
return true ;
441
437
}
442
438
@@ -659,6 +655,19 @@ class AstSerializer {
659
655
return str ;
660
656
}
661
657
658
+ getRootNodeMode ( node ) {
659
+ // override is when child component definitions override the host component tag
660
+ let rootAttributeValue = this . getAttributeValue ( node , AstSerializer . attrs . ROOT ) ;
661
+ if ( rootAttributeValue ) {
662
+ return rootAttributeValue ;
663
+ }
664
+ // merge is when webc:root attributes flow up to the host component (and the child component tag is ignored)
665
+ if ( rootAttributeValue === "" ) {
666
+ return "merge" ;
667
+ }
668
+ return false ;
669
+ }
670
+
662
671
async renderStartTag ( node , tagName , component , renderingMode , options ) {
663
672
let content = "" ;
664
673
@@ -674,8 +683,8 @@ class AstSerializer {
674
683
let attrs = this . getAttributes ( node , component , options ) ;
675
684
let parentComponent = this . components [ options . closestParentComponent ] ;
676
685
677
- // webc:keep webc: root should use the style hash class name and host attributes since they won’t be added to the host component
678
- if ( parentComponent && parentComponent . ignoreRootTag && this . hasAttribute ( node , AstSerializer . attrs . ROOT ) && this . hasAttribute ( node , AstSerializer . attrs . KEEP ) ) {
686
+ // webc:root="override" should use the style hash class name and host attributes since they won’t be added to the host component
687
+ if ( parentComponent && parentComponent . ignoreRootTag && this . getRootNodeMode ( node ) === "override" ) {
679
688
if ( parentComponent . scopedStyleHash ) {
680
689
attrs . push ( { name : "class" , value : parentComponent . scopedStyleHash } ) ;
681
690
}
@@ -850,7 +859,7 @@ class AstSerializer {
850
859
851
860
// Processes `<template webc:root>` as WebC (including slot resolution)
852
861
// Processes `<template>` in raw mode (for plain template, shadowroots, webc:keep, etc).
853
- if ( ! this . hasAttribute ( node , AstSerializer . attrs . ROOT ) ) {
862
+ if ( ! this . hasAttribute ( node , AstSerializer . attrs . ROOT ) ) { // TODO is this too much magic?
854
863
templateOptions . rawMode = true ;
855
864
}
856
865
@@ -923,7 +932,7 @@ class AstSerializer {
923
932
return Array . from ( types ) ;
924
933
}
925
934
926
- addComponentDependency ( component , tagName , options ) {
935
+ addComponentDependency ( component , node , tagName , options ) {
927
936
let componentFilePath = Path . normalizePath ( component . filePath ) ;
928
937
if ( ! options . components . hasNode ( componentFilePath ) ) {
929
938
options . components . addNode ( componentFilePath ) ;
@@ -1135,12 +1144,29 @@ class AstSerializer {
1135
1144
return rawContent ;
1136
1145
}
1137
1146
1147
+ addImpliedWebCAttributes ( node ) {
1148
+ if ( this . getAttributeValue ( node , AstSerializer . attrs . TYPE ) === AstSerializer . transformTypes . JS ) {
1149
+ // this check is perhaps unnecessary since KEEP has a higher precedence than NOKEEP
1150
+ if ( ! this . hasAttribute ( node , AstSerializer . attrs . KEEP ) ) {
1151
+ node . attrs . push ( { name : AstSerializer . attrs . NOKEEP , value : "" } ) ;
1152
+ }
1153
+
1154
+ if ( ! this . hasAttribute ( node , AstSerializer . attrs . IS ) ) {
1155
+ node . attrs . push ( { name : AstSerializer . attrs . IS , value : "template" } ) ;
1156
+ }
1157
+ }
1158
+ }
1159
+
1138
1160
async compileNode ( node , slots = { } , options = { } , streamEnabled = true ) {
1139
1161
options = Object . assign ( { } , options ) ;
1140
1162
1163
+ this . addImpliedWebCAttributes ( node ) ;
1164
+
1141
1165
let tagName = this . getTagName ( node ) ;
1142
1166
let content = "" ;
1143
1167
1168
+ // webc:type="js" has an implied webc:is="template" webc:nokeep
1169
+
1144
1170
let transformTypes = this . getTransformTypes ( node ) ;
1145
1171
if ( transformTypes . length ) {
1146
1172
options . currentTransformTypes = transformTypes ;
@@ -1185,11 +1211,16 @@ class AstSerializer {
1185
1211
}
1186
1212
1187
1213
let component ;
1188
- let importSource = this . getAttributeValue ( node , AstSerializer . attrs . IMPORT ) ;
1189
- if ( importSource ) {
1190
- component = await this . importComponent ( importSource , options . closestParentComponent , tagName ) ;
1191
- } else {
1192
- component = this . getComponent ( tagName ) ;
1214
+
1215
+ // This allows use of <img webc:root> inside of an <img> component definition without circular reference errors
1216
+ let rootNodeMode = this . getRootNodeMode ( node ) ;
1217
+ if ( ! rootNodeMode ) {
1218
+ let importSource = this . getAttributeValue ( node , AstSerializer . attrs . IMPORT ) ;
1219
+ if ( importSource ) {
1220
+ component = await this . importComponent ( importSource , options . closestParentComponent , tagName ) ;
1221
+ } else {
1222
+ component = this . getComponent ( tagName ) ;
1223
+ }
1193
1224
}
1194
1225
1195
1226
if ( component ) {
@@ -1259,10 +1290,12 @@ class AstSerializer {
1259
1290
1260
1291
// Component content (foreshadow dom)
1261
1292
if ( ! options . rawMode && component ) {
1262
- this . addComponentDependency ( component , tagName , options ) ;
1293
+ this . addComponentDependency ( component , node , tagName , options ) ;
1263
1294
1295
+ // for attribute sharing
1264
1296
options . hostComponentNode = node ;
1265
1297
1298
+
1266
1299
let evaluatedAttributes = await AttributeSerializer . evaluateAttributesArray ( node . attrs , nodeData ) ;
1267
1300
options . hostComponentData = AttributeSerializer . mergeAttributes ( evaluatedAttributes ) ;
1268
1301
0 commit comments