@@ -5,8 +5,10 @@ import { DepGraph } from "dependency-graph";
5
5
import { WebC } from "../webc.js" ;
6
6
import { Path } from "./path.js" ;
7
7
import { AstQuery } from "./astQuery.js" ;
8
+ import { AstModify } from "./astModify.js" ;
8
9
import { AssetManager } from "./assetManager.js" ;
9
10
import { CssPrefixer } from "./css.js" ;
11
+ import { Looping } from "./looping.js" ;
10
12
import { AttributeSerializer } from "./attributeSerializer.js" ;
11
13
import { ModuleScript } from "./moduleScript.cjs" ;
12
14
import { Streams } from "./streams.js" ;
@@ -138,7 +140,8 @@ class AstSerializer {
138
140
TEXT : "@text" ,
139
141
ATTRIBUTES : "@attributes" ,
140
142
SETUP : "webc:setup" ,
141
- IGNORE : "webc:ignore" , // ignore this node
143
+ IGNORE : "webc:ignore" , // ignore the node
144
+ LOOP : "webc:for" ,
142
145
} ;
143
146
144
147
static transformTypes = {
@@ -401,7 +404,7 @@ class AstSerializer {
401
404
}
402
405
}
403
406
404
- let nodeData = this . dataCascade . getData ( options . componentProps , options . hostComponentData , parentComponent ?. setupScript ) ;
407
+ let nodeData = this . dataCascade . getData ( options . componentProps , options . hostComponentData , parentComponent ?. setupScript , options . injectedData ) ;
405
408
let evaluatedAttributes = await AttributeSerializer . evaluateAttributesArray ( attrs , nodeData , options . closestParentComponent ) ;
406
409
let finalAttributesObject = AttributeSerializer . mergeAttributes ( evaluatedAttributes ) ;
407
410
@@ -458,7 +461,7 @@ class AstSerializer {
458
461
slotsText . default = this . getPreparsedRawTextContent ( o . hostComponentNode , o ) ;
459
462
}
460
463
461
- let context = this . dataCascade . getData ( options . componentProps , options . currentTagAttributes , parentComponent ?. setupScript , {
464
+ let context = this . dataCascade . getData ( options . componentProps , options . currentTagAttributes , parentComponent ?. setupScript , options . injectedData , {
462
465
// Ideally these would be under `webc.*`
463
466
filePath : this . filePath ,
464
467
slots : {
@@ -719,7 +722,7 @@ class AstSerializer {
719
722
// Used for @html and webc:if
720
723
async evaluateAttribute ( name , attrContent , options ) {
721
724
let parentComponent = this . componentManager . get ( options . closestParentComponent ) ;
722
- let data = this . dataCascade . getData ( options . componentProps , parentComponent ?. setupScript ) ;
725
+ let data = this . dataCascade . getData ( options . componentProps , parentComponent ?. setupScript , options . injectedData ) ;
723
726
724
727
let { returns } = await ModuleScript . evaluateScriptInline ( attrContent , data , `Check the dynamic attribute: \`${ name } ="${ attrContent } "\`.` , options . closestParentComponent ) ;
725
728
return returns ;
@@ -804,18 +807,18 @@ class AstSerializer {
804
807
addImpliedWebCAttributes ( node ) {
805
808
// if(AstQuery.getTagName(node) === "template") {
806
809
if ( AstQuery . isDeclarativeShadowDomNode ( node ) ) {
807
- node . attrs . push ( { name : AstSerializer . attrs . RAW , value : "" } ) ;
810
+ AstModify . addAttribute ( node , AstSerializer . attrs . RAW , "" ) ;
808
811
}
809
812
810
813
// webc:type="js" (WebC v0.9.0+) has implied webc:is="template" webc:nokeep
811
814
if ( AstQuery . getAttributeValue ( node , AstSerializer . attrs . TYPE ) === AstSerializer . transformTypes . JS ) {
812
815
// this check is perhaps unnecessary since KEEP has a higher precedence than NOKEEP
813
816
if ( ! AstQuery . hasAttribute ( node , AstSerializer . attrs . KEEP ) ) {
814
- node . attrs . push ( { name : AstSerializer . attrs . NOKEEP , value : "" } ) ;
817
+ AstModify . addAttribute ( node , AstSerializer . attrs . NOKEEP , "" ) ;
815
818
}
816
819
817
820
if ( ! AstQuery . hasAttribute ( node , AstSerializer . attrs . IS ) ) {
818
- node . attrs . push ( { name : AstSerializer . attrs . IS , value : "template" } ) ;
821
+ AstModify . addAttribute ( node , AstSerializer . attrs . IS , "template" ) ;
819
822
}
820
823
}
821
824
}
@@ -839,12 +842,62 @@ class AstSerializer {
839
842
}
840
843
}
841
844
845
+
846
+ async runLoop ( node , slots = { } , options = { } , streamEnabled = true ) {
847
+ let loopAttrValue = AstQuery . getAttributeValue ( node , AstSerializer . attrs . LOOP ) ;
848
+ if ( ! loopAttrValue ) {
849
+ AstModify . removeAttribute ( node , AstSerializer . attrs . LOOP ) ;
850
+ return { html : "" } ;
851
+ }
852
+
853
+ let { keys, type, content } = Looping . parse ( loopAttrValue ) ;
854
+ let loopContent = await this . evaluateAttribute ( AstSerializer . attrs . LOOP , content , options ) ;
855
+
856
+ AstModify . removeAttribute ( node , AstSerializer . attrs . LOOP ) ;
857
+
858
+ // if falsy, skip
859
+ if ( ! loopContent ) {
860
+ return { html : "" } ;
861
+ }
862
+
863
+ let promises = [ ] ;
864
+
865
+ if ( type === "Object" ) {
866
+ let index = 0 ;
867
+ for ( let loopKey in loopContent ) {
868
+ options . injectedData = {
869
+ [ keys . key ] : loopKey ,
870
+ [ keys . value ] : loopContent [ loopKey ] ,
871
+ [ keys . index ] : index ++ ,
872
+ } ;
873
+ promises . push ( this . compileNode ( node , slots , options , streamEnabled ) ) ;
874
+ }
875
+ } else if ( type === "Array" ) {
876
+ promises = loopContent . map ( ( ( loopValue , index ) => {
877
+ options . injectedData = {
878
+ [ keys . index ] : index ,
879
+ [ keys . value ] : loopValue
880
+ } ;
881
+
882
+ return this . compileNode ( node , slots , options , streamEnabled ) ;
883
+ } ) ) ;
884
+ }
885
+
886
+ // Whitespace normalizer
887
+ let html = ( await Promise . all ( promises ) ) . map ( entry => entry . html ) . filter ( entry => entry ) . join ( "\n" ) ;
888
+
889
+ return { html } ;
890
+ }
891
+
842
892
async compileNode ( node , slots = { } , options = { } , streamEnabled = true ) {
843
893
options = Object . assign ( { } , options ) ;
844
894
845
895
if ( AstQuery . hasAnyAttribute ( node , [ AstSerializer . attrs . IGNORE , AstSerializer . attrs . SETUP ] ) ) {
846
896
return { html : "" } ;
847
897
}
898
+ if ( AstQuery . hasAttribute ( node , AstSerializer . attrs . LOOP ) ) {
899
+ return this . runLoop ( node , slots , options , streamEnabled ) ;
900
+ }
848
901
849
902
this . addImpliedWebCAttributes ( node ) ;
850
903
0 commit comments