test(compiler): tests for v-for codegen w/ block optimization

This commit is contained in:
Evan You 2019-10-01 21:00:55 -04:00
parent 65661b5ec0
commit 07955e6c96
3 changed files with 354 additions and 55 deletions

View File

@ -0,0 +1,104 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`compiler: v-for codegen basic v-for 1`] = `
"const _Vue = Vue
return function render() {
with (this) {
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Fragment: _Fragment, renderList: _renderList } = _Vue
return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (item) => {
return _createVNode(\\"span\\")
})))
}
}"
`;
exports[`compiler: v-for codegen skipped key 1`] = `
"const _Vue = Vue
return function render() {
with (this) {
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Fragment: _Fragment, renderList: _renderList } = _Vue
return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (value, __, index) => {
return _createVNode(\\"span\\")
})))
}
}"
`;
exports[`compiler: v-for codegen skipped value & key 1`] = `
"const _Vue = Vue
return function render() {
with (this) {
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Fragment: _Fragment, renderList: _renderList } = _Vue
return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (_, __, index) => {
return _createVNode(\\"span\\")
})))
}
}"
`;
exports[`compiler: v-for codegen skipped value 1`] = `
"const _Vue = Vue
return function render() {
with (this) {
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Fragment: _Fragment, renderList: _renderList } = _Vue
return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (_, key, index) => {
return _createVNode(\\"span\\")
})))
}
}"
`;
exports[`compiler: v-for codegen template v-for 1`] = `
"const _Vue = Vue
return function render() {
with (this) {
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Fragment: _Fragment, renderList: _renderList } = _Vue
return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (item) => {
return [
\\"hello\\",
_createVNode(\\"span\\")
]
})))
}
}"
`;
exports[`compiler: v-for codegen v-if + v-for 1`] = `
"const _Vue = Vue
return function render() {
with (this) {
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Fragment: _Fragment, renderList: _renderList, Empty: _Empty } = _Vue
return (_openBlock(), ok
? _createBlock(_Fragment, { key: 0 }, _renderList(list, (i) => {
return _createVNode(\\"div\\")
}))
: _createBlock(_Empty))
}
}"
`;
exports[`compiler: v-for codegen value + key + index 1`] = `
"const _Vue = Vue
return function render() {
with (this) {
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Fragment: _Fragment, renderList: _renderList } = _Vue
return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (item, key, index) => {
return _createVNode(\\"span\\")
})))
}
}"
`;

View File

@ -1,38 +1,53 @@
import { parse } from '../../src/parse' import { parse } from '../../src/parse'
import { transform } from '../../src/transform' import { transform } from '../../src/transform'
import { transformIf } from '../../src/transforms/vIf'
import { transformFor } from '../../src/transforms/vFor' import { transformFor } from '../../src/transforms/vFor'
import { transformElement } from '../../src/transforms/transformElement'
import { import {
ForNode, ForNode,
NodeTypes, NodeTypes,
SimpleExpressionNode, SimpleExpressionNode,
ElementNode, ElementNode,
InterpolationNode InterpolationNode,
SequenceExpression,
CallExpression
} from '../../src/ast' } from '../../src/ast'
import { ErrorCodes } from '../../src/errors' import { ErrorCodes } from '../../src/errors'
import { CompilerOptions } from '../../src' import { CompilerOptions, generate } from '../../src'
import { transformExpression } from '../../src/transforms/transformExpression' import { transformExpression } from '../../src/transforms/transformExpression'
import {
OPEN_BLOCK,
CREATE_BLOCK,
FRAGMENT,
RENDER_LIST
} from '../../src/runtimeConstants'
function parseWithForTransform( function parseWithForTransform(
template: string, template: string,
options: CompilerOptions = {} options: CompilerOptions = {}
) { ) {
const node = parse(template, options) const ast = parse(template, options)
transform(node, { transform(ast, {
nodeTransforms: [ nodeTransforms: [
transformIf,
transformFor, transformFor,
...(options.prefixIdentifiers ? [transformExpression] : []) ...(options.prefixIdentifiers ? [transformExpression] : []),
transformElement
], ],
...options ...options
}) })
return node.children[0] return {
root: ast,
node: ast.children[0] as ForNode
}
} }
describe('compiler: v-for', () => { describe('compiler: v-for', () => {
describe('transform', () => { describe('transform', () => {
test('number expression', () => { test('number expression', () => {
const forNode = parseWithForTransform( const { node: forNode } = parseWithForTransform(
'<span v-for="index in 5" />' '<span v-for="index in 5" />'
) as ForNode )
expect(forNode.keyAlias).toBeUndefined() expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined() expect(forNode.objectIndexAlias).toBeUndefined()
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('index') expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('index')
@ -40,9 +55,9 @@ describe('compiler: v-for', () => {
}) })
test('value', () => { test('value', () => {
const forNode = parseWithForTransform( const { node: forNode } = parseWithForTransform(
'<span v-for="(item) in items" />' '<span v-for="(item) in items" />'
) as ForNode )
expect(forNode.keyAlias).toBeUndefined() expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined() expect(forNode.objectIndexAlias).toBeUndefined()
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('item') expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('item')
@ -50,9 +65,9 @@ describe('compiler: v-for', () => {
}) })
test('object de-structured value', () => { test('object de-structured value', () => {
const forNode = parseWithForTransform( const { node: forNode } = parseWithForTransform(
'<span v-for="({ id, value }) in items" />' '<span v-for="({ id, value }) in items" />'
) as ForNode )
expect(forNode.keyAlias).toBeUndefined() expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined() expect(forNode.objectIndexAlias).toBeUndefined()
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe( expect((forNode.valueAlias as SimpleExpressionNode).content).toBe(
@ -62,9 +77,9 @@ describe('compiler: v-for', () => {
}) })
test('array de-structured value', () => { test('array de-structured value', () => {
const forNode = parseWithForTransform( const { node: forNode } = parseWithForTransform(
'<span v-for="([ id, value ]) in items" />' '<span v-for="([ id, value ]) in items" />'
) as ForNode )
expect(forNode.keyAlias).toBeUndefined() expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined() expect(forNode.objectIndexAlias).toBeUndefined()
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe( expect((forNode.valueAlias as SimpleExpressionNode).content).toBe(
@ -74,9 +89,9 @@ describe('compiler: v-for', () => {
}) })
test('value and key', () => { test('value and key', () => {
const forNode = parseWithForTransform( const { node: forNode } = parseWithForTransform(
'<span v-for="(item, key) in items" />' '<span v-for="(item, key) in items" />'
) as ForNode )
expect(forNode.keyAlias).not.toBeUndefined() expect(forNode.keyAlias).not.toBeUndefined()
expect((forNode.keyAlias as SimpleExpressionNode).content).toBe('key') expect((forNode.keyAlias as SimpleExpressionNode).content).toBe('key')
expect(forNode.objectIndexAlias).toBeUndefined() expect(forNode.objectIndexAlias).toBeUndefined()
@ -85,9 +100,9 @@ describe('compiler: v-for', () => {
}) })
test('value, key and index', () => { test('value, key and index', () => {
const forNode = parseWithForTransform( const { node: forNode } = parseWithForTransform(
'<span v-for="(value, key, index) in items" />' '<span v-for="(value, key, index) in items" />'
) as ForNode )
expect(forNode.keyAlias).not.toBeUndefined() expect(forNode.keyAlias).not.toBeUndefined()
expect((forNode.keyAlias as SimpleExpressionNode).content).toBe('key') expect((forNode.keyAlias as SimpleExpressionNode).content).toBe('key')
expect(forNode.objectIndexAlias).not.toBeUndefined() expect(forNode.objectIndexAlias).not.toBeUndefined()
@ -99,9 +114,9 @@ describe('compiler: v-for', () => {
}) })
test('skipped key', () => { test('skipped key', () => {
const forNode = parseWithForTransform( const { node: forNode } = parseWithForTransform(
'<span v-for="(value,,index) in items" />' '<span v-for="(value,,index) in items" />'
) as ForNode )
expect(forNode.keyAlias).toBeUndefined() expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).not.toBeUndefined() expect(forNode.objectIndexAlias).not.toBeUndefined()
expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe( expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe(
@ -112,9 +127,9 @@ describe('compiler: v-for', () => {
}) })
test('skipped value and key', () => { test('skipped value and key', () => {
const forNode = parseWithForTransform( const { node: forNode } = parseWithForTransform(
'<span v-for="(,,index) in items" />' '<span v-for="(,,index) in items" />'
) as ForNode )
expect(forNode.keyAlias).toBeUndefined() expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).not.toBeUndefined() expect(forNode.objectIndexAlias).not.toBeUndefined()
expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe( expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe(
@ -125,9 +140,9 @@ describe('compiler: v-for', () => {
}) })
test('unbracketed value', () => { test('unbracketed value', () => {
const forNode = parseWithForTransform( const { node: forNode } = parseWithForTransform(
'<span v-for="item in items" />' '<span v-for="item in items" />'
) as ForNode )
expect(forNode.keyAlias).toBeUndefined() expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined() expect(forNode.objectIndexAlias).toBeUndefined()
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('item') expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('item')
@ -135,9 +150,9 @@ describe('compiler: v-for', () => {
}) })
test('unbracketed value and key', () => { test('unbracketed value and key', () => {
const forNode = parseWithForTransform( const { node: forNode } = parseWithForTransform(
'<span v-for="item, key in items" />' '<span v-for="item, key in items" />'
) as ForNode )
expect(forNode.keyAlias).not.toBeUndefined() expect(forNode.keyAlias).not.toBeUndefined()
expect((forNode.keyAlias as SimpleExpressionNode).content).toBe('key') expect((forNode.keyAlias as SimpleExpressionNode).content).toBe('key')
expect(forNode.objectIndexAlias).toBeUndefined() expect(forNode.objectIndexAlias).toBeUndefined()
@ -146,9 +161,9 @@ describe('compiler: v-for', () => {
}) })
test('unbracketed value, key and index', () => { test('unbracketed value, key and index', () => {
const forNode = parseWithForTransform( const { node: forNode } = parseWithForTransform(
'<span v-for="value, key, index in items" />' '<span v-for="value, key, index in items" />'
) as ForNode )
expect(forNode.keyAlias).not.toBeUndefined() expect(forNode.keyAlias).not.toBeUndefined()
expect((forNode.keyAlias as SimpleExpressionNode).content).toBe('key') expect((forNode.keyAlias as SimpleExpressionNode).content).toBe('key')
expect(forNode.objectIndexAlias).not.toBeUndefined() expect(forNode.objectIndexAlias).not.toBeUndefined()
@ -160,9 +175,9 @@ describe('compiler: v-for', () => {
}) })
test('unbracketed skipped key', () => { test('unbracketed skipped key', () => {
const forNode = parseWithForTransform( const { node: forNode } = parseWithForTransform(
'<span v-for="value, , index in items" />' '<span v-for="value, , index in items" />'
) as ForNode )
expect(forNode.keyAlias).toBeUndefined() expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).not.toBeUndefined() expect(forNode.objectIndexAlias).not.toBeUndefined()
expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe( expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe(
@ -173,9 +188,9 @@ describe('compiler: v-for', () => {
}) })
test('unbracketed skipped value and key', () => { test('unbracketed skipped value and key', () => {
const forNode = parseWithForTransform( const { node: forNode } = parseWithForTransform(
'<span v-for=", , index in items" />' '<span v-for=", , index in items" />'
) as ForNode )
expect(forNode.keyAlias).toBeUndefined() expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).not.toBeUndefined() expect(forNode.objectIndexAlias).not.toBeUndefined()
expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe( expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe(
@ -251,7 +266,7 @@ describe('compiler: v-for', () => {
describe('source location', () => { describe('source location', () => {
test('value & source', () => { test('value & source', () => {
const source = '<span v-for="item in items" />' const source = '<span v-for="item in items" />'
const forNode = parseWithForTransform(source) as ForNode const { node: forNode } = parseWithForTransform(source)
const itemOffset = source.indexOf('item') const itemOffset = source.indexOf('item')
const value = forNode.valueAlias as SimpleExpressionNode const value = forNode.valueAlias as SimpleExpressionNode
@ -275,7 +290,7 @@ describe('compiler: v-for', () => {
test('bracketed value', () => { test('bracketed value', () => {
const source = '<span v-for="( item ) in items" />' const source = '<span v-for="( item ) in items" />'
const forNode = parseWithForTransform(source) as ForNode const { node: forNode } = parseWithForTransform(source)
const itemOffset = source.indexOf('item') const itemOffset = source.indexOf('item')
const value = forNode.valueAlias as SimpleExpressionNode const value = forNode.valueAlias as SimpleExpressionNode
@ -299,7 +314,7 @@ describe('compiler: v-for', () => {
test('de-structured value', () => { test('de-structured value', () => {
const source = '<span v-for="( { id, key }) in items" />' const source = '<span v-for="( { id, key }) in items" />'
const forNode = parseWithForTransform(source) as ForNode const { node: forNode } = parseWithForTransform(source)
const value = forNode.valueAlias as SimpleExpressionNode const value = forNode.valueAlias as SimpleExpressionNode
const valueIndex = source.indexOf('{ id, key }') const valueIndex = source.indexOf('{ id, key }')
@ -323,7 +338,7 @@ describe('compiler: v-for', () => {
test('bracketed value, key, index', () => { test('bracketed value, key, index', () => {
const source = '<span v-for="( item, key, index ) in items" />' const source = '<span v-for="( item, key, index ) in items" />'
const forNode = parseWithForTransform(source) as ForNode const { node: forNode } = parseWithForTransform(source)
const itemOffset = source.indexOf('item') const itemOffset = source.indexOf('item')
const value = forNode.valueAlias as SimpleExpressionNode const value = forNode.valueAlias as SimpleExpressionNode
@ -365,7 +380,7 @@ describe('compiler: v-for', () => {
test('skipped key', () => { test('skipped key', () => {
const source = '<span v-for="( item,, index ) in items" />' const source = '<span v-for="( item,, index ) in items" />'
const forNode = parseWithForTransform(source) as ForNode const { node: forNode } = parseWithForTransform(source)
const itemOffset = source.indexOf('item') const itemOffset = source.indexOf('item')
const value = forNode.valueAlias as SimpleExpressionNode const value = forNode.valueAlias as SimpleExpressionNode
@ -399,9 +414,9 @@ describe('compiler: v-for', () => {
describe('prefixIdentifiers: true', () => { describe('prefixIdentifiers: true', () => {
test('should prefix v-for source', () => { test('should prefix v-for source', () => {
const node = parseWithForTransform(`<div v-for="i in list"/>`, { const { node } = parseWithForTransform(`<div v-for="i in list"/>`, {
prefixIdentifiers: true prefixIdentifiers: true
}) as ForNode })
expect(node.source).toMatchObject({ expect(node.source).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION, type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.list` content: `_ctx.list`
@ -409,10 +424,10 @@ describe('compiler: v-for', () => {
}) })
test('should prefix v-for source w/ complex expression', () => { test('should prefix v-for source w/ complex expression', () => {
const node = parseWithForTransform( const { node } = parseWithForTransform(
`<div v-for="i in list.concat([foo])"/>`, `<div v-for="i in list.concat([foo])"/>`,
{ prefixIdentifiers: true } { prefixIdentifiers: true }
) as ForNode )
expect(node.source).toMatchObject({ expect(node.source).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION, type: NodeTypes.COMPOUND_EXPRESSION,
children: [ children: [
@ -427,10 +442,10 @@ describe('compiler: v-for', () => {
}) })
test('should not prefix v-for alias', () => { test('should not prefix v-for alias', () => {
const node = parseWithForTransform( const { node } = parseWithForTransform(
`<div v-for="i in list">{{ i }}{{ j }}</div>`, `<div v-for="i in list">{{ i }}{{ j }}</div>`,
{ prefixIdentifiers: true } { prefixIdentifiers: true }
) as ForNode )
const div = node.children[0] as ElementNode const div = node.children[0] as ElementNode
expect((div.children[0] as InterpolationNode).content).toMatchObject({ expect((div.children[0] as InterpolationNode).content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION, type: NodeTypes.SIMPLE_EXPRESSION,
@ -443,10 +458,10 @@ describe('compiler: v-for', () => {
}) })
test('should not prefix v-for aliases (multiple)', () => { test('should not prefix v-for aliases (multiple)', () => {
const node = parseWithForTransform( const { node } = parseWithForTransform(
`<div v-for="(i, j, k) in list">{{ i + j + k }}{{ l }}</div>`, `<div v-for="(i, j, k) in list">{{ i + j + k }}{{ l }}</div>`,
{ prefixIdentifiers: true } { prefixIdentifiers: true }
) as ForNode )
const div = node.children[0] as ElementNode const div = node.children[0] as ElementNode
expect((div.children[0] as InterpolationNode).content).toMatchObject({ expect((div.children[0] as InterpolationNode).content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION, type: NodeTypes.COMPOUND_EXPRESSION,
@ -465,10 +480,10 @@ describe('compiler: v-for', () => {
}) })
test('should prefix id outside of v-for', () => { test('should prefix id outside of v-for', () => {
const node = parseWithForTransform( const { node } = parseWithForTransform(
`<div><div v-for="i in list" />{{ i }}</div>`, `<div><div v-for="i in list" />{{ i }}</div>`,
{ prefixIdentifiers: true } { prefixIdentifiers: true }
) as ElementNode )
expect((node.children[1] as InterpolationNode).content).toMatchObject({ expect((node.children[1] as InterpolationNode).content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION, type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.i` content: `_ctx.i`
@ -476,12 +491,12 @@ describe('compiler: v-for', () => {
}) })
test('nested v-for', () => { test('nested v-for', () => {
const node = parseWithForTransform( const { node } = parseWithForTransform(
`<div v-for="i in list"> `<div v-for="i in list">
<div v-for="i in list">{{ i + j }}</div>{{ i }} <div v-for="i in list">{{ i + j }}</div>{{ i }}
</div>`, </div>`,
{ prefixIdentifiers: true } { prefixIdentifiers: true }
) as ForNode )
const outerDiv = node.children[0] as ElementNode const outerDiv = node.children[0] as ElementNode
const innerFor = outerDiv.children[0] as ForNode const innerFor = outerDiv.children[0] as ForNode
const innerExp = (innerFor.children[0] as ElementNode) const innerExp = (innerFor.children[0] as ElementNode)
@ -501,12 +516,12 @@ describe('compiler: v-for', () => {
}) })
test('v-for aliases w/ complex expressions', () => { test('v-for aliases w/ complex expressions', () => {
const node = parseWithForTransform( const { node } = parseWithForTransform(
`<div v-for="({ foo = bar, baz: [qux = quux] }) in list"> `<div v-for="({ foo = bar, baz: [qux = quux] }) in list">
{{ foo + bar + baz + qux + quux }} {{ foo + bar + baz + qux + quux }}
</div>`, </div>`,
{ prefixIdentifiers: true } { prefixIdentifiers: true }
) as ForNode )
expect(node.valueAlias!).toMatchObject({ expect(node.valueAlias!).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION, type: NodeTypes.COMPOUND_EXPRESSION,
children: [ children: [
@ -540,8 +555,185 @@ describe('compiler: v-for', () => {
}) })
describe('codegen', () => { describe('codegen', () => {
test('basic v-for', () => {}) function assertSharedCodegen(node: SequenceExpression) {
expect(node).toMatchObject({
type: NodeTypes.JS_SEQUENCE_EXPRESSION,
expressions: [
{
type: NodeTypes.JS_CALL_EXPRESSION,
callee: `_${OPEN_BLOCK}`,
arguments: []
},
{
type: NodeTypes.JS_CALL_EXPRESSION,
callee: `_${CREATE_BLOCK}`,
arguments: [
`_${FRAGMENT}`,
`null`,
{
type: NodeTypes.JS_CALL_EXPRESSION,
callee: `_${RENDER_LIST}`
}
]
}
]
})
return (node.expressions[1] as CallExpression)
.arguments[2] as CallExpression
}
test('', () => {}) test('basic v-for', () => {
const {
root,
node: { codegenNode }
} = parseWithForTransform('<span v-for="(item) in items" />')
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
{ content: `items` },
{
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: [{ content: `item` }],
returns: {
type: NodeTypes.ELEMENT,
tag: `span`
}
}
])
expect(generate(root).code).toMatchSnapshot()
})
test('value + key + index', () => {
const {
root,
node: { codegenNode }
} = parseWithForTransform('<span v-for="(item, key, index) in items" />')
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
{ content: `items` },
{
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: [
{ content: `item` },
{ content: `key` },
{ content: `index` }
]
}
])
expect(generate(root).code).toMatchSnapshot()
})
test('skipped value', () => {
const {
root,
node: { codegenNode }
} = parseWithForTransform('<span v-for="(,key,index) in items" />')
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
{ content: `items` },
{
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: [{ content: `_` }, { content: `key` }, { content: `index` }]
}
])
expect(generate(root).code).toMatchSnapshot()
})
test('skipped key', () => {
const {
root,
node: { codegenNode }
} = parseWithForTransform('<span v-for="(value,,index) in items" />')
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
{ content: `items` },
{
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: [
{ content: `value` },
{ content: `__` },
{ content: `index` }
]
}
])
expect(generate(root).code).toMatchSnapshot()
})
test('skipped value & key', () => {
const {
root,
node: { codegenNode }
} = parseWithForTransform('<span v-for="(,,index) in items" />')
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
{ content: `items` },
{
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: [{ content: `_` }, { content: `__` }, { content: `index` }]
}
])
expect(generate(root).code).toMatchSnapshot()
})
test('template v-for', () => {
const {
root,
node: { codegenNode }
} = parseWithForTransform(
'<template v-for="item in items">hello<span/></template>'
)
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
{ content: `items` },
{
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: [{ content: `item` }],
returns: [
{ type: NodeTypes.TEXT, content: `hello` },
{ type: NodeTypes.ELEMENT, tag: `span` }
]
}
])
expect(generate(root).code).toMatchSnapshot()
})
test('v-if + v-for', () => {
const {
root,
node: { codegenNode }
} = parseWithForTransform(`<div v-if="ok" v-for="i in list"/>`)
expect(codegenNode).toMatchObject({
type: NodeTypes.JS_SEQUENCE_EXPRESSION,
expressions: [
{
type: NodeTypes.JS_CALL_EXPRESSION,
callee: `_${OPEN_BLOCK}`,
arguments: []
},
{
type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
test: { content: `ok` },
consequent: {
type: NodeTypes.JS_CALL_EXPRESSION,
callee: `_${CREATE_BLOCK}`,
// should optimize v-if + v-for into a single Fragment block
arguments: [
`_${FRAGMENT}`,
`{ key: 0 }`,
{
type: NodeTypes.JS_CALL_EXPRESSION,
callee: `_${RENDER_LIST}`,
arguments: [
{ content: `list` },
{
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: [{ content: `i` }],
returns: {
type: NodeTypes.ELEMENT,
tag: `div`
}
}
]
}
]
}
}
]
})
expect(generate(root).code).toMatchSnapshot()
})
}) })
}) })

View File

@ -54,7 +54,7 @@ export const transformFor = createStructuralDirectiveTransform(
codegenNode codegenNode
}) })
if (!__BROWSER__) { if (!__BROWSER__ && context.prefixIdentifiers) {
// scope management // scope management
// inject identifiers to context // inject identifiers to context
value && addIdentifiers(value) value && addIdentifiers(value)
@ -75,6 +75,9 @@ export const transformFor = createStructuralDirectiveTransform(
} }
if (index) { if (index) {
if (!key) { if (!key) {
if (!value) {
params.push(createSimpleExpression(`_`, false))
}
params.push(createSimpleExpression(`__`, false)) params.push(createSimpleExpression(`__`, false))
} }
params.push(index) params.push(index)
@ -95,7 +98,7 @@ export const transformFor = createStructuralDirectiveTransform(
]) ])
) )
if (!__BROWSER__) { if (!__BROWSER__ && context.prefixIdentifiers) {
value && removeIdentifiers(value) value && removeIdentifiers(value)
key && removeIdentifiers(key) key && removeIdentifiers(key)
index && removeIdentifiers(index) index && removeIdentifiers(index)