@@ -202,6 +202,43 @@ describe('compiler: v-for', () => {
202
202
expect ( forNode . valueAlias ) . toBeUndefined ( )
203
203
expect ( ( forNode . source as SimpleExpressionNode ) . content ) . toBe ( 'items' )
204
204
} )
205
+
206
+ test ( 'no whitespace around (in|of) with simple expression' , ( ) => {
207
+ const { node : forNode } = parseWithForTransform (
208
+ '<span v-for="(item)in[items]" />'
209
+ )
210
+
211
+ expect ( forNode . keyAlias ) . toBeUndefined ( )
212
+ expect ( forNode . objectIndexAlias ) . toBeUndefined ( )
213
+ expect ( ( forNode . valueAlias as SimpleExpressionNode ) . content ) . toBe ( 'item' )
214
+ expect ( ( forNode . source as SimpleExpressionNode ) . content ) . toBe ( '[items]' )
215
+ } )
216
+
217
+ test ( 'no whitespace around (in|of) with object de-structured value' , ( ) => {
218
+ const { node : forNode } = parseWithForTransform (
219
+ '<span v-for="{ id, value }in[item]" />'
220
+ )
221
+
222
+ expect ( forNode . keyAlias ) . toBeUndefined ( )
223
+ expect ( forNode . objectIndexAlias ) . toBeUndefined ( )
224
+ expect ( ( forNode . valueAlias as SimpleExpressionNode ) . content ) . toBe (
225
+ '{ id, value }'
226
+ )
227
+ expect ( ( forNode . source as SimpleExpressionNode ) . content ) . toBe ( '[item]' )
228
+ } )
229
+
230
+ test ( 'no whitespace around (in|of) with array de-structured value' , ( ) => {
231
+ const { node : forNode } = parseWithForTransform (
232
+ '<span v-for="[ id ]in[item]" />'
233
+ )
234
+
235
+ expect ( forNode . keyAlias ) . toBeUndefined ( )
236
+ expect ( forNode . objectIndexAlias ) . toBeUndefined ( )
237
+ expect ( ( forNode . valueAlias as SimpleExpressionNode ) . content ) . toBe (
238
+ '[ id ]'
239
+ )
240
+ expect ( ( forNode . source as SimpleExpressionNode ) . content ) . toBe ( '[item]' )
241
+ } )
205
242
} )
206
243
207
244
describe ( 'errors' , ( ) => {
@@ -241,6 +278,18 @@ describe('compiler: v-for', () => {
241
278
)
242
279
} )
243
280
281
+ test ( 'invalid expression containing (in|of)' , ( ) => {
282
+ const onError = vi . fn ( )
283
+ parseWithForTransform ( '<span v-for="fooinbar" />' , { onError } )
284
+
285
+ expect ( onError ) . toHaveBeenCalledTimes ( 1 )
286
+ expect ( onError ) . toHaveBeenCalledWith (
287
+ expect . objectContaining ( {
288
+ code : ErrorCodes . X_V_FOR_MALFORMED_EXPRESSION
289
+ } )
290
+ )
291
+ } )
292
+
244
293
test ( 'missing source' , ( ) => {
245
294
const onError = vi . fn ( )
246
295
parseWithForTransform ( '<span v-for="item in" />' , { onError } )
@@ -265,6 +314,18 @@ describe('compiler: v-for', () => {
265
314
)
266
315
} )
267
316
317
+ test ( 'missing source and value' , ( ) => {
318
+ const onError = vi . fn ( )
319
+ parseWithForTransform ( '<span v-for=" in " />' , { onError } )
320
+
321
+ expect ( onError ) . toHaveBeenCalledTimes ( 1 )
322
+ expect ( onError ) . toHaveBeenCalledWith (
323
+ expect . objectContaining ( {
324
+ code : ErrorCodes . X_V_FOR_MALFORMED_EXPRESSION
325
+ } )
326
+ )
327
+ } )
328
+
268
329
test ( '<template v-for> key placement' , ( ) => {
269
330
const onError = vi . fn ( )
270
331
parseWithForTransform (
@@ -409,6 +470,48 @@ describe('compiler: v-for', () => {
409
470
)
410
471
} )
411
472
473
+ test ( 'no whitespace around (in|of) with bracketed value, key, index' , ( ) => {
474
+ const source = '<span v-for="( item, key, index )in[items]" />'
475
+ const { node : forNode } = parseWithForTransform ( source )
476
+
477
+ const itemOffset = source . indexOf ( 'item' )
478
+ const value = forNode . valueAlias as SimpleExpressionNode
479
+ expect ( value . content ) . toBe ( 'item' )
480
+ expect ( value . loc . start . offset ) . toBe ( itemOffset )
481
+ expect ( value . loc . start . line ) . toBe ( 1 )
482
+ expect ( value . loc . start . column ) . toBe ( itemOffset + 1 )
483
+ expect ( value . loc . end . line ) . toBe ( 1 )
484
+ expect ( value . loc . end . column ) . toBe ( itemOffset + 1 + `item` . length )
485
+
486
+ const keyOffset = source . indexOf ( 'key' )
487
+ const key = forNode . keyAlias as SimpleExpressionNode
488
+ expect ( key . content ) . toBe ( 'key' )
489
+ expect ( key . loc . start . offset ) . toBe ( keyOffset )
490
+ expect ( key . loc . start . line ) . toBe ( 1 )
491
+ expect ( key . loc . start . column ) . toBe ( keyOffset + 1 )
492
+ expect ( key . loc . end . line ) . toBe ( 1 )
493
+ expect ( key . loc . end . column ) . toBe ( keyOffset + 1 + `key` . length )
494
+
495
+ const indexOffset = source . indexOf ( 'index' )
496
+ const index = forNode . objectIndexAlias as SimpleExpressionNode
497
+ expect ( index . content ) . toBe ( 'index' )
498
+ expect ( index . loc . start . offset ) . toBe ( indexOffset )
499
+ expect ( index . loc . start . line ) . toBe ( 1 )
500
+ expect ( index . loc . start . column ) . toBe ( indexOffset + 1 )
501
+ expect ( index . loc . end . line ) . toBe ( 1 )
502
+ expect ( index . loc . end . column ) . toBe ( indexOffset + 1 + `index` . length )
503
+
504
+ const itemsOffset = source . indexOf ( '[items]' )
505
+ expect ( ( forNode . source as SimpleExpressionNode ) . content ) . toBe ( '[items]' )
506
+ expect ( forNode . source . loc . start . offset ) . toBe ( itemsOffset )
507
+ expect ( forNode . source . loc . start . line ) . toBe ( 1 )
508
+ expect ( forNode . source . loc . start . column ) . toBe ( itemsOffset + 1 )
509
+ expect ( forNode . source . loc . end . line ) . toBe ( 1 )
510
+ expect ( forNode . source . loc . end . column ) . toBe (
511
+ itemsOffset + 1 + `[items]` . length
512
+ )
513
+ } )
514
+
412
515
test ( 'skipped key' , ( ) => {
413
516
const source = '<span v-for="( item,, index ) in items" />'
414
517
const { node : forNode } = parseWithForTransform ( source )
@@ -717,6 +820,21 @@ describe('compiler: v-for', () => {
717
820
expect ( generate ( root ) . code ) . toMatchSnapshot ( )
718
821
} )
719
822
823
+ test ( 'no whitespace around (in|of) with basic v-for' , ( ) => {
824
+ const {
825
+ root,
826
+ node : { codegenNode }
827
+ } = parseWithForTransform ( '<span v-for="(item)in[items]" />' )
828
+ expect ( assertSharedCodegen ( codegenNode ) ) . toMatchObject ( {
829
+ source : { content : `[items]` } ,
830
+ params : [ { content : `item` } ] ,
831
+ innerVNodeCall : {
832
+ tag : `"span"`
833
+ }
834
+ } )
835
+ expect ( generate ( root ) . code ) . toMatchSnapshot ( )
836
+ } )
837
+
720
838
test ( 'value + key + index' , ( ) => {
721
839
const {
722
840
root,
0 commit comments