feat(compiler): handle complex destructure expressions in v-for

This commit is contained in:
Evan You
2019-09-28 16:02:08 -04:00
parent 798a9cbe9b
commit 389a07835c
9 changed files with 388 additions and 278 deletions

View File

@@ -4,13 +4,11 @@ import {
ElementNode,
DirectiveNode,
NodeTypes,
ForNode,
CompilerOptions,
IfNode,
InterpolationNode
} from '../../src'
import { transformIf } from '../../src/transforms/vIf'
import { transformFor } from '../../src/transforms/vFor'
import { transformExpression } from '../../src/transforms/transformExpression'
function parseWithExpressionTransform(
@@ -20,7 +18,7 @@ function parseWithExpressionTransform(
const ast = parse(template)
transform(ast, {
prefixIdentifiers: true,
nodeTransforms: [transformIf, transformFor, transformExpression],
nodeTransforms: [transformIf, transformExpression],
...options
})
return ast.children[0]
@@ -169,103 +167,6 @@ describe('compiler: expression transform', () => {
})
})
test('should prefix v-for source', () => {
const node = parseWithExpressionTransform(
`<div v-for="i in list"/>`
) as ForNode
expect(node.source).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.list`
})
})
test('should prefix v-for source w/ complex expression', () => {
const node = parseWithExpressionTransform(
`<div v-for="i in list.concat([foo])"/>`
) as ForNode
expect(node.source).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: [
{ content: `_ctx.list` },
`.`,
{ content: `concat` },
`([`,
{ content: `_ctx.foo` },
`])`
]
})
})
test('should not prefix v-for alias', () => {
const node = parseWithExpressionTransform(
`<div v-for="i in list">{{ i }}{{ j }}</div>`
) as ForNode
const div = node.children[0] as ElementNode
expect((div.children[0] as InterpolationNode).content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `i`
})
expect((div.children[1] as InterpolationNode).content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.j`
})
})
test('should not prefix v-for aliases (multiple)', () => {
const node = parseWithExpressionTransform(
`<div v-for="(i, j, k) in list">{{ i + j + k }}{{ l }}</div>`
) as ForNode
const div = node.children[0] as ElementNode
expect((div.children[0] as InterpolationNode).content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: [
{ content: `i` },
` + `,
{ content: `j` },
` + `,
{ content: `k` }
]
})
expect((div.children[1] as InterpolationNode).content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.l`
})
})
test('should prefix id outside of v-for', () => {
const node = parseWithExpressionTransform(
`<div><div v-for="i in list" />{{ i }}</div>`
) as ElementNode
expect((node.children[1] as InterpolationNode).content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.i`
})
})
test('nested v-for', () => {
const node = parseWithExpressionTransform(
`<div v-for="i in list">
<div v-for="i in list">{{ i + j }}</div>{{ i }}
</div>`
) as ForNode
const outerDiv = node.children[0] as ElementNode
const innerFor = outerDiv.children[0] as ForNode
const innerExp = (innerFor.children[0] as ElementNode)
.children[0] as InterpolationNode
expect(innerExp.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: [{ content: 'i' }, ` + `, { content: `_ctx.j` }]
})
// when an inner v-for shadows a variable of an outer v-for and exit,
// it should not cause the outer v-for's alias to be removed from known ids
const outerExp = outerDiv.children[1] as InterpolationNode
expect(outerExp.content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `i`
})
})
test('should not prefix whitelisted globals', () => {
const node = parseWithExpressionTransform(
`{{ Math.max(1, 2) }}`
@@ -334,7 +235,9 @@ describe('compiler: expression transform', () => {
expect(node.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: [
`({ foo }) => `,
`({ `,
{ content: `foo` },
` }) => `,
{ content: `foo` },
` + `,
{ content: `_ctx.bar` }

View File

@@ -1,148 +1,185 @@
import { parse } from '../../src/parse'
import { transform } from '../../src/transform'
import { transformFor } from '../../src/transforms/vFor'
import { ForNode, NodeTypes, SimpleExpressionNode } from '../../src/ast'
import {
ForNode,
NodeTypes,
SimpleExpressionNode,
ElementNode,
InterpolationNode
} from '../../src/ast'
import { ErrorCodes } from '../../src/errors'
import { CompilerOptions } from '../../src'
import { transformExpression } from '../../src/transforms/transformExpression'
function parseWithForTransform(
template: string,
options: CompilerOptions = {}
): ForNode {
) {
const node = parse(template, options)
transform(node, { nodeTransforms: [transformFor], ...options })
if (!options.onError) {
expect(node.children.length).toBe(1)
expect(node.children[0].type).toBe(NodeTypes.FOR)
}
return node.children[0] as ForNode
transform(node, {
nodeTransforms: [
transformFor,
...(options.prefixIdentifiers ? [transformExpression] : [])
],
...options
})
return node.children[0]
}
describe('compiler: transform v-for', () => {
test('number expression', () => {
const forNode = parseWithForTransform('<span v-for="index in 5" />')
const forNode = parseWithForTransform(
'<span v-for="index in 5" />'
) as ForNode
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined()
expect(forNode.valueAlias!.content).toBe('index')
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('index')
expect((forNode.source as SimpleExpressionNode).content).toBe('5')
})
test('value', () => {
const forNode = parseWithForTransform('<span v-for="(item) in items" />')
const forNode = parseWithForTransform(
'<span v-for="(item) in items" />'
) as ForNode
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined()
expect(forNode.valueAlias!.content).toBe('item')
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('item')
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
})
test('object de-structured value', () => {
const forNode = parseWithForTransform(
'<span v-for="({ id, value }) in items" />'
)
) as ForNode
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined()
expect(forNode.valueAlias!.content).toBe('{ id, value }')
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe(
'{ id, value }'
)
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
})
test('array de-structured value', () => {
const forNode = parseWithForTransform(
'<span v-for="([ id, value ]) in items" />'
)
) as ForNode
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined()
expect(forNode.valueAlias!.content).toBe('[ id, value ]')
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe(
'[ id, value ]'
)
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
})
test('value and key', () => {
const forNode = parseWithForTransform(
'<span v-for="(item, key) in items" />'
)
) as ForNode
expect(forNode.keyAlias).not.toBeUndefined()
expect(forNode.keyAlias!.content).toBe('key')
expect((forNode.keyAlias as SimpleExpressionNode).content).toBe('key')
expect(forNode.objectIndexAlias).toBeUndefined()
expect(forNode.valueAlias!.content).toBe('item')
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('item')
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
})
test('value, key and index', () => {
const forNode = parseWithForTransform(
'<span v-for="(value, key, index) in items" />'
)
) as ForNode
expect(forNode.keyAlias).not.toBeUndefined()
expect(forNode.keyAlias!.content).toBe('key')
expect((forNode.keyAlias as SimpleExpressionNode).content).toBe('key')
expect(forNode.objectIndexAlias).not.toBeUndefined()
expect(forNode.objectIndexAlias!.content).toBe('index')
expect(forNode.valueAlias!.content).toBe('value')
expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe(
'index'
)
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('value')
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
})
test('skipped key', () => {
const forNode = parseWithForTransform(
'<span v-for="(value,,index) in items" />'
)
) as ForNode
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).not.toBeUndefined()
expect(forNode.objectIndexAlias!.content).toBe('index')
expect(forNode.valueAlias!.content).toBe('value')
expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe(
'index'
)
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('value')
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
})
test('skipped value and key', () => {
const forNode = parseWithForTransform('<span v-for="(,,index) in items" />')
const forNode = parseWithForTransform(
'<span v-for="(,,index) in items" />'
) as ForNode
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).not.toBeUndefined()
expect(forNode.objectIndexAlias!.content).toBe('index')
expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe(
'index'
)
expect(forNode.valueAlias).toBeUndefined()
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
})
test('unbracketed value', () => {
const forNode = parseWithForTransform('<span v-for="item in items" />')
const forNode = parseWithForTransform(
'<span v-for="item in items" />'
) as ForNode
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined()
expect(forNode.valueAlias!.content).toBe('item')
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('item')
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
})
test('unbracketed value and key', () => {
const forNode = parseWithForTransform('<span v-for="item, key in items" />')
const forNode = parseWithForTransform(
'<span v-for="item, key in items" />'
) as ForNode
expect(forNode.keyAlias).not.toBeUndefined()
expect(forNode.keyAlias!.content).toBe('key')
expect((forNode.keyAlias as SimpleExpressionNode).content).toBe('key')
expect(forNode.objectIndexAlias).toBeUndefined()
expect(forNode.valueAlias!.content).toBe('item')
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('item')
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
})
test('unbracketed value, key and index', () => {
const forNode = parseWithForTransform(
'<span v-for="value, key, index in items" />'
)
) as ForNode
expect(forNode.keyAlias).not.toBeUndefined()
expect(forNode.keyAlias!.content).toBe('key')
expect((forNode.keyAlias as SimpleExpressionNode).content).toBe('key')
expect(forNode.objectIndexAlias).not.toBeUndefined()
expect(forNode.objectIndexAlias!.content).toBe('index')
expect(forNode.valueAlias!.content).toBe('value')
expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe(
'index'
)
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('value')
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
})
test('unbracketed skipped key', () => {
const forNode = parseWithForTransform(
'<span v-for="value, , index in items" />'
)
) as ForNode
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).not.toBeUndefined()
expect(forNode.objectIndexAlias!.content).toBe('index')
expect(forNode.valueAlias!.content).toBe('value')
expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe(
'index'
)
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('value')
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
})
test('unbracketed skipped value and key', () => {
const forNode = parseWithForTransform('<span v-for=", , index in items" />')
const forNode = parseWithForTransform(
'<span v-for=", , index in items" />'
) as ForNode
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).not.toBeUndefined()
expect(forNode.objectIndexAlias!.content).toBe('index')
expect((forNode.objectIndexAlias as SimpleExpressionNode).content).toBe(
'index'
)
expect(forNode.valueAlias).toBeUndefined()
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
})
@@ -210,17 +247,16 @@ describe('compiler: transform v-for', () => {
describe('source location', () => {
test('value & source', () => {
const source = '<span v-for="item in items" />'
const forNode = parseWithForTransform(source)
const forNode = parseWithForTransform(source) as ForNode
const itemOffset = source.indexOf('item')
expect(forNode.valueAlias!.content).toBe('item')
expect(forNode.valueAlias!.loc.start.offset).toBe(itemOffset)
expect(forNode.valueAlias!.loc.start.line).toBe(1)
expect(forNode.valueAlias!.loc.start.column).toBe(itemOffset + 1)
expect(forNode.valueAlias!.loc.end.line).toBe(1)
expect(forNode.valueAlias!.loc.end.column).toBe(
itemOffset + 1 + `item`.length
)
const value = forNode.valueAlias as SimpleExpressionNode
expect((forNode.valueAlias as SimpleExpressionNode).content).toBe('item')
expect(value.loc.start.offset).toBe(itemOffset)
expect(value.loc.start.line).toBe(1)
expect(value.loc.start.column).toBe(itemOffset + 1)
expect(value.loc.end.line).toBe(1)
expect(value.loc.end.column).toBe(itemOffset + 1 + `item`.length)
const itemsOffset = source.indexOf('items')
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
@@ -235,17 +271,16 @@ describe('compiler: transform v-for', () => {
test('bracketed value', () => {
const source = '<span v-for="( item ) in items" />'
const forNode = parseWithForTransform(source)
const forNode = parseWithForTransform(source) as ForNode
const itemOffset = source.indexOf('item')
expect(forNode.valueAlias!.content).toBe('item')
expect(forNode.valueAlias!.loc.start.offset).toBe(itemOffset)
expect(forNode.valueAlias!.loc.start.line).toBe(1)
expect(forNode.valueAlias!.loc.start.column).toBe(itemOffset + 1)
expect(forNode.valueAlias!.loc.end.line).toBe(1)
expect(forNode.valueAlias!.loc.end.column).toBe(
itemOffset + 1 + `item`.length
)
const value = forNode.valueAlias as SimpleExpressionNode
expect(value.content).toBe('item')
expect(value.loc.start.offset).toBe(itemOffset)
expect(value.loc.start.line).toBe(1)
expect(value.loc.start.column).toBe(itemOffset + 1)
expect(value.loc.end.line).toBe(1)
expect(value.loc.end.column).toBe(itemOffset + 1 + `item`.length)
const itemsOffset = source.indexOf('items')
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
@@ -260,17 +295,16 @@ describe('compiler: transform v-for', () => {
test('de-structured value', () => {
const source = '<span v-for="( { id, key }) in items" />'
const forNode = parseWithForTransform(source)
const forNode = parseWithForTransform(source) as ForNode
const value = forNode.valueAlias as SimpleExpressionNode
const valueIndex = source.indexOf('{ id, key }')
expect(forNode.valueAlias!.content).toBe('{ id, key }')
expect(forNode.valueAlias!.loc.start.offset).toBe(valueIndex)
expect(forNode.valueAlias!.loc.start.line).toBe(1)
expect(forNode.valueAlias!.loc.start.column).toBe(valueIndex + 1)
expect(forNode.valueAlias!.loc.end.line).toBe(1)
expect(forNode.valueAlias!.loc.end.column).toBe(
valueIndex + 1 + '{ id, key }'.length
)
expect(value.content).toBe('{ id, key }')
expect(value.loc.start.offset).toBe(valueIndex)
expect(value.loc.start.line).toBe(1)
expect(value.loc.start.column).toBe(valueIndex + 1)
expect(value.loc.end.line).toBe(1)
expect(value.loc.end.column).toBe(valueIndex + 1 + '{ id, key }'.length)
const itemsOffset = source.indexOf('items')
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
@@ -285,37 +319,34 @@ describe('compiler: transform v-for', () => {
test('bracketed value, key, index', () => {
const source = '<span v-for="( item, key, index ) in items" />'
const forNode = parseWithForTransform(source)
const forNode = parseWithForTransform(source) as ForNode
const itemOffset = source.indexOf('item')
expect(forNode.valueAlias!.content).toBe('item')
expect(forNode.valueAlias!.loc.start.offset).toBe(itemOffset)
expect(forNode.valueAlias!.loc.start.line).toBe(1)
expect(forNode.valueAlias!.loc.start.column).toBe(itemOffset + 1)
expect(forNode.valueAlias!.loc.end.line).toBe(1)
expect(forNode.valueAlias!.loc.end.column).toBe(
itemOffset + 1 + `item`.length
)
const value = forNode.valueAlias as SimpleExpressionNode
expect(value.content).toBe('item')
expect(value.loc.start.offset).toBe(itemOffset)
expect(value.loc.start.line).toBe(1)
expect(value.loc.start.column).toBe(itemOffset + 1)
expect(value.loc.end.line).toBe(1)
expect(value.loc.end.column).toBe(itemOffset + 1 + `item`.length)
const keyOffset = source.indexOf('key')
expect(forNode.keyAlias!.content).toBe('key')
expect(forNode.keyAlias!.loc.start.offset).toBe(keyOffset)
expect(forNode.keyAlias!.loc.start.line).toBe(1)
expect(forNode.keyAlias!.loc.start.column).toBe(keyOffset + 1)
expect(forNode.keyAlias!.loc.end.line).toBe(1)
expect(forNode.keyAlias!.loc.end.column).toBe(
keyOffset + 1 + `key`.length
)
const key = forNode.keyAlias as SimpleExpressionNode
expect(key.content).toBe('key')
expect(key.loc.start.offset).toBe(keyOffset)
expect(key.loc.start.line).toBe(1)
expect(key.loc.start.column).toBe(keyOffset + 1)
expect(key.loc.end.line).toBe(1)
expect(key.loc.end.column).toBe(keyOffset + 1 + `key`.length)
const indexOffset = source.indexOf('index')
expect(forNode.objectIndexAlias!.content).toBe('index')
expect(forNode.objectIndexAlias!.loc.start.offset).toBe(indexOffset)
expect(forNode.objectIndexAlias!.loc.start.line).toBe(1)
expect(forNode.objectIndexAlias!.loc.start.column).toBe(indexOffset + 1)
expect(forNode.objectIndexAlias!.loc.end.line).toBe(1)
expect(forNode.objectIndexAlias!.loc.end.column).toBe(
indexOffset + 1 + `index`.length
)
const index = forNode.objectIndexAlias as SimpleExpressionNode
expect(index.content).toBe('index')
expect(index.loc.start.offset).toBe(indexOffset)
expect(index.loc.start.line).toBe(1)
expect(index.loc.start.column).toBe(indexOffset + 1)
expect(index.loc.end.line).toBe(1)
expect(index.loc.end.column).toBe(indexOffset + 1 + `index`.length)
const itemsOffset = source.indexOf('items')
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
@@ -330,27 +361,25 @@ describe('compiler: transform v-for', () => {
test('skipped key', () => {
const source = '<span v-for="( item,, index ) in items" />'
const forNode = parseWithForTransform(source)
const forNode = parseWithForTransform(source) as ForNode
const itemOffset = source.indexOf('item')
expect(forNode.valueAlias!.content).toBe('item')
expect(forNode.valueAlias!.loc.start.offset).toBe(itemOffset)
expect(forNode.valueAlias!.loc.start.line).toBe(1)
expect(forNode.valueAlias!.loc.start.column).toBe(itemOffset + 1)
expect(forNode.valueAlias!.loc.end.line).toBe(1)
expect(forNode.valueAlias!.loc.end.column).toBe(
itemOffset + 1 + `item`.length
)
const value = forNode.valueAlias as SimpleExpressionNode
expect(value.content).toBe('item')
expect(value.loc.start.offset).toBe(itemOffset)
expect(value.loc.start.line).toBe(1)
expect(value.loc.start.column).toBe(itemOffset + 1)
expect(value.loc.end.line).toBe(1)
expect(value.loc.end.column).toBe(itemOffset + 1 + `item`.length)
const indexOffset = source.indexOf('index')
expect(forNode.objectIndexAlias!.content).toBe('index')
expect(forNode.objectIndexAlias!.loc.start.offset).toBe(indexOffset)
expect(forNode.objectIndexAlias!.loc.start.line).toBe(1)
expect(forNode.objectIndexAlias!.loc.start.column).toBe(indexOffset + 1)
expect(forNode.objectIndexAlias!.loc.end.line).toBe(1)
expect(forNode.objectIndexAlias!.loc.end.column).toBe(
indexOffset + 1 + `index`.length
)
const index = forNode.objectIndexAlias as SimpleExpressionNode
expect(index.content).toBe('index')
expect(index.loc.start.offset).toBe(indexOffset)
expect(index.loc.start.line).toBe(1)
expect(index.loc.start.column).toBe(indexOffset + 1)
expect(index.loc.end.line).toBe(1)
expect(index.loc.end.column).toBe(indexOffset + 1 + `index`.length)
const itemsOffset = source.indexOf('items')
expect((forNode.source as SimpleExpressionNode).content).toBe('items')
@@ -363,4 +392,146 @@ describe('compiler: transform v-for', () => {
)
})
})
describe('prefixIdentifiers: true', () => {
test('should prefix v-for source', () => {
const node = parseWithForTransform(`<div v-for="i in list"/>`, {
prefixIdentifiers: true
}) as ForNode
expect(node.source).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.list`
})
})
test('should prefix v-for source w/ complex expression', () => {
const node = parseWithForTransform(
`<div v-for="i in list.concat([foo])"/>`,
{ prefixIdentifiers: true }
) as ForNode
expect(node.source).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: [
{ content: `_ctx.list` },
`.`,
{ content: `concat` },
`([`,
{ content: `_ctx.foo` },
`])`
]
})
})
test('should not prefix v-for alias', () => {
const node = parseWithForTransform(
`<div v-for="i in list">{{ i }}{{ j }}</div>`,
{ prefixIdentifiers: true }
) as ForNode
const div = node.children[0] as ElementNode
expect((div.children[0] as InterpolationNode).content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `i`
})
expect((div.children[1] as InterpolationNode).content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.j`
})
})
test('should not prefix v-for aliases (multiple)', () => {
const node = parseWithForTransform(
`<div v-for="(i, j, k) in list">{{ i + j + k }}{{ l }}</div>`,
{ prefixIdentifiers: true }
) as ForNode
const div = node.children[0] as ElementNode
expect((div.children[0] as InterpolationNode).content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: [
{ content: `i` },
` + `,
{ content: `j` },
` + `,
{ content: `k` }
]
})
expect((div.children[1] as InterpolationNode).content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.l`
})
})
test('should prefix id outside of v-for', () => {
const node = parseWithForTransform(
`<div><div v-for="i in list" />{{ i }}</div>`,
{ prefixIdentifiers: true }
) as ElementNode
expect((node.children[1] as InterpolationNode).content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.i`
})
})
test('nested v-for', () => {
const node = parseWithForTransform(
`<div v-for="i in list">
<div v-for="i in list">{{ i + j }}</div>{{ i }}
</div>`,
{ prefixIdentifiers: true }
) as ForNode
const outerDiv = node.children[0] as ElementNode
const innerFor = outerDiv.children[0] as ForNode
const innerExp = (innerFor.children[0] as ElementNode)
.children[0] as InterpolationNode
expect(innerExp.content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: [{ content: 'i' }, ` + `, { content: `_ctx.j` }]
})
// when an inner v-for shadows a variable of an outer v-for and exit,
// it should not cause the outer v-for's alias to be removed from known ids
const outerExp = outerDiv.children[1] as InterpolationNode
expect(outerExp.content).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `i`
})
})
test('v-for aliases w/ complex expressions', () => {
const node = parseWithForTransform(
`<div v-for="({ foo = bar, baz: [qux = quux] }) in list">
{{ foo + bar + baz + qux + quux }}
</div>`,
{ prefixIdentifiers: true }
) as ForNode
expect(node.valueAlias!).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: [
`{ `,
{ content: `foo` },
` = `,
{ content: `_ctx.bar` },
`, baz: [`,
{ content: `qux` },
` = `,
{ content: `_ctx.quux` },
`] }`
]
})
const div = node.children[0] as ElementNode
expect((div.children[0] as InterpolationNode).content).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: [
{ content: `foo` },
` + `,
{ content: `_ctx.bar` },
` + `,
{ content: `_ctx.baz` },
` + `,
{ content: `qux` },
` + `,
{ content: `_ctx.quux` }
]
})
})
})
})

View File

@@ -83,9 +83,8 @@ describe('compiler: transform component slots', () => {
default: {
type: NodeTypes.JS_SLOT_FUNCTION,
params: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `{ foo }`,
isStatic: false
type: NodeTypes.COMPOUND_EXPRESSION,
children: [`{ `, { content: `foo` }, ` }`]
},
returns: [
{
@@ -266,9 +265,8 @@ describe('compiler: transform component slots', () => {
default: {
type: NodeTypes.JS_SLOT_FUNCTION,
params: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `{ bar }`,
isStatic: false
type: NodeTypes.COMPOUND_EXPRESSION,
children: [`{ `, { content: `bar` }, ` }`]
},
returns: [
{