@@ -125,13 +125,16 @@ function walk (opts, nodes) {
125125
126126 // parse loops
127127 if ( node . tag === loops [ 0 ] ) {
128+ // handle syntax error
128129 if ( ! ( node . attrs && node . attrs . loop ) ) {
129130 throw new Error ( `the "${ conditionals [ 1 ] } " tag must have a "loop" attribute` )
130131 }
132+
131133 // parse the "loop" param
132134 const loopParams = parseLoopStatement ( node . attrs . loop )
133135 const target = vm . runInContext ( loopParams . expression , ctx )
134136
137+ // handle additional syntax errors
135138 if ( typeof target !== 'object' ) {
136139 throw new Error ( 'You must provide an array or object to loop through' )
137140 }
@@ -140,41 +143,19 @@ function walk (opts, nodes) {
140143 throw new Error ( 'You must provide at least one loop argument' )
141144 }
142145
146+ // run the loop, different types of loops for arrays and objects
143147 if ( Array . isArray ( target ) ) {
144148 for ( let index = 0 ; index < target . length ; index ++ ) {
145- const value = target [ index ]
146- // add value and optional index loop locals
147- const scopedLocals = { }
148- scopedLocals [ loopParams . keys [ 0 ] ] = value
149- if ( loopParams . keys [ 1 ] ) scopedLocals [ loopParams . keys [ 1 ] ] = index
150- // merge nondestructively into existing locals
151- const scopedOptions = merge ( opts , { locals : scopedLocals } )
152- // provide the modified options to the content evaluation
153- // we need to clone the node because the normal operation modifies
154- // the node directly
155- const content = cloneDeep ( node . content )
156- const res = walk ( scopedOptions , content )
157- m . push ( res )
149+ m . push ( executeLoop ( loopParams . keys , target [ index ] , index , node , opts ) )
158150 }
159- return m
160151 } else {
161152 for ( let key in target ) {
162- const value = target [ key ]
163- // add item and optional index loop locals
164- const scopedLocals = { }
165- scopedLocals [ loopParams . keys [ 0 ] ] = key
166- if ( loopParams . keys [ 1 ] ) scopedLocals [ loopParams . keys [ 1 ] ] = value
167- // merge nondestructively into existing locals
168- const scopedOptions = merge ( opts , { locals : scopedLocals } )
169- // provide the modified options to the content evaluation
170- // we need to clone the node because the normal operation modifies
171- // the node directly
172- const content = cloneDeep ( node . content )
173- const res = walk ( scopedOptions , content )
174- m . push ( res )
153+ m . push ( executeLoop ( loopParams . keys , target [ key ] , key , node , opts ) )
175154 }
176- return m
177155 }
156+
157+ // return directly out of the loop, which will skip the "each" tag
158+ return m
178159 }
179160
180161 // return the node
@@ -196,6 +177,10 @@ function getNextTag (nodes, i, nodeCount) {
196177 return [ i , { tag : undefined } ]
197178}
198179
180+ /**
181+ * Given a "loop" parameter from an "each" tag, parses out the param names and
182+ * expression to be looped through using a mini text parser.
183+ */
199184function parseLoopStatement ( input ) {
200185 let current = 0
201186 let char = input [ current ]
@@ -250,3 +235,22 @@ function parseLoopStatement (input) {
250235 return res
251236 }
252237}
238+
239+ /**
240+ * Creates a set of local variables within the loop, and evaluates all nodes
241+ * within the loop, returning their contents
242+ */
243+ function executeLoop ( loopParams , p1 , p2 , node , opts ) {
244+ // two loop locals are allowed
245+ // - for arrays it's the current value and the index
246+ // - for objects, it's the value and the key
247+ const scopedLocals = { }
248+ scopedLocals [ loopParams [ 0 ] ] = p1
249+ if ( loopParams [ 1 ] ) scopedLocals [ loopParams [ 1 ] ] = p2
250+ // merge nondestructively into existing locals
251+ const scopedOptions = merge ( opts , { locals : scopedLocals } )
252+ // walk through the contents and run replacements with modified options
253+ // we need to clone the node because the normal operation modifies
254+ // the node directly
255+ return walk ( scopedOptions , cloneDeep ( node . content ) )
256+ }
0 commit comments