wip(compiler): generate blocks for v-if

This commit is contained in:
Evan You
2019-10-01 12:25:13 -04:00
parent e31fb3c172
commit 5de744d4e1
21 changed files with 359 additions and 354 deletions

View File

@@ -105,9 +105,11 @@ return function render() {
exports[`compiler: codegen function mode preamble 1`] = `
"const _Vue = Vue
return function render() {
with (this) {
const { helperOne: _helperOne, helperTwo: _helperTwo } = _Vue
return null
}
}"
@@ -137,24 +139,7 @@ exports[`compiler: codegen ifNode 1`] = `
"
return function render() {
with (this) {
return foo
? \\"foo\\"
: (a + b)
? _toString(bye)
: _createVNode(_Comment, 0, \\"foo\\")
}
}"
`;
exports[`compiler: codegen ifNode with no v-else 1`] = `
"
return function render() {
with (this) {
return foo
? \\"foo\\"
: (a + b)
? _toString(bye)
: null
return (foo, bar)
}
}"
`;

View File

@@ -2,17 +2,27 @@
exports[`compiler: integration tests function mode 1`] = `
"const _Vue = Vue
return function render() {
with (this) {
const { createVNode: _createVNode, toString: _toString, renderList: _renderList } = _Vue
const { createVNode: _createVNode, toString: _toString, openBlock: _openBlock, applyDirectives: _applyDirectives, createBlock: _createBlock, Empty: _Empty, Fragment: _Fragment, renderList: _renderList } = _Vue
return _createVNode(\\"div\\", {
id: \\"foo\\",
class: bar.baz
}, [
_toString(world.burn()),
ok
? _createVNode(\\"div\\", null, \\"yes\\")
: \\"no\\",
(_openBlock(), ok
? _createBlock(
\\"div\\",
{ key: 0 },
\\"yes\\"
)
: _createBlock(
_Fragment,
{ key: 1 },
\\"no\\"
)),
_renderList(list, (value, index) => {
return _createVNode(\\"div\\", null, [
_createVNode(\\"span\\", null, _toString(value + index))
@@ -24,7 +34,7 @@ return function render() {
`;
exports[`compiler: integration tests function mode w/ prefixIdentifiers: true 1`] = `
"const { createVNode, toString, renderList } = Vue
"const { createVNode, toString, openBlock, applyDirectives, createBlock, Empty, Fragment, renderList } = Vue
return function render() {
const _ctx = this
@@ -33,9 +43,17 @@ return function render() {
class: _ctx.bar.baz
}, [
toString(_ctx.world.burn()),
(_ctx.ok)
? createVNode(\\"div\\", null, \\"yes\\")
: \\"no\\",
(openBlock(), (_ctx.ok)
? createBlock(
\\"div\\",
{ key: 0 },
\\"yes\\"
)
: createBlock(
Fragment,
{ key: 1 },
\\"no\\"
)),
renderList(_ctx.list, (value, index) => {
return createVNode(\\"div\\", null, [
createVNode(\\"span\\", null, toString(value + index))
@@ -46,7 +64,7 @@ return function render() {
`;
exports[`compiler: integration tests module mode 1`] = `
"import { createVNode, toString, renderList } from \\"vue\\"
"import { createVNode, toString, openBlock, applyDirectives, createBlock, Empty, Fragment, renderList } from \\"vue\\"
export default function render() {
const _ctx = this
@@ -55,9 +73,17 @@ export default function render() {
class: _ctx.bar.baz
}, [
_toString(_ctx.world.burn()),
(_ctx.ok)
? createVNode(\\"div\\", null, \\"yes\\")
: \\"no\\",
(openBlock(), (_ctx.ok)
? createBlock(
\\"div\\",
{ key: 0 },
\\"yes\\"
)
: createBlock(
Fragment,
{ key: 1 },
\\"no\\"
)),
_renderList(_ctx.list, (value, index) => {
return createVNode(\\"div\\", null, [
createVNode(\\"span\\", null, _toString(value + index))

View File

@@ -12,7 +12,8 @@ import {
createArrayExpression,
ElementNode,
createCompoundExpression,
createInterpolation
createInterpolation,
createSequenceExpression
} from '../src'
import {
CREATE_VNODE,
@@ -100,8 +101,7 @@ describe('compiler: codegen', () => {
[
createObjectProperty(
createSimpleExpression(`id`, true, mockLoc),
createSimpleExpression(`foo`, true, mockLoc),
mockLoc
createSimpleExpression(`foo`, true, mockLoc)
)
],
mockLoc
@@ -226,19 +226,16 @@ describe('compiler: codegen', () => {
const { code } = generate(
createRoot({
children: [
createCompoundExpression(
[
`_ctx.`,
createSimpleExpression(`foo`, false, mockLoc),
` + `,
{
type: NodeTypes.INTERPOLATION,
loc: mockLoc,
content: createSimpleExpression(`bar`, false, mockLoc)
}
],
mockLoc
)
createCompoundExpression([
`_ctx.`,
createSimpleExpression(`foo`, false, mockLoc),
` + `,
{
type: NodeTypes.INTERPOLATION,
loc: mockLoc,
content: createSimpleExpression(`bar`, false, mockLoc)
}
])
]
})
)
@@ -253,90 +250,16 @@ describe('compiler: codegen', () => {
{
type: NodeTypes.IF,
loc: mockLoc,
branches: [
{
type: NodeTypes.IF_BRANCH,
condition: createSimpleExpression('foo', false, mockLoc),
loc: mockLoc,
children: [
{
type: NodeTypes.TEXT,
content: 'foo',
isEmpty: false,
loc: mockLoc
}
]
},
{
type: NodeTypes.IF_BRANCH,
condition: createSimpleExpression('a + b', false, mockLoc),
loc: mockLoc,
children: [createInterpolation(`bye`, mockLoc)]
},
{
type: NodeTypes.IF_BRANCH,
condition: undefined,
loc: mockLoc,
children: [
{
type: NodeTypes.COMMENT,
content: 'foo',
loc: mockLoc
}
]
}
]
branches: [],
codegenNode: createSequenceExpression([
createSimpleExpression('foo', false),
createSimpleExpression('bar', false)
])
}
]
})
)
expect(code).toMatch(`
return foo
? "foo"
: (a + b)
? _${TO_STRING}(bye)
: _${CREATE_VNODE}(_${COMMENT}, 0, "foo")`)
expect(code).toMatchSnapshot()
})
test('ifNode with no v-else', () => {
const { code } = generate(
createRoot({
children: [
{
type: NodeTypes.IF,
loc: mockLoc,
branches: [
{
type: NodeTypes.IF_BRANCH,
condition: createSimpleExpression('foo', false, mockLoc),
loc: mockLoc,
children: [
{
type: NodeTypes.TEXT,
content: 'foo',
isEmpty: false,
loc: mockLoc
}
]
},
{
type: NodeTypes.IF_BRANCH,
condition: createSimpleExpression('a + b', false, mockLoc),
loc: mockLoc,
children: [createInterpolation(`bye`, mockLoc)]
}
]
}
]
})
)
expect(code).toMatch(`
return foo
? "foo"
: (a + b)
? _${TO_STRING}(bye)
: null`)
expect(code).toMatch(`return (foo, bar)`)
expect(code).toMatchSnapshot()
})
@@ -570,13 +493,11 @@ describe('compiler: codegen', () => {
[
createObjectProperty(
createSimpleExpression(`id`, true, mockLoc),
createSimpleExpression(`foo`, true, mockLoc),
mockLoc
createSimpleExpression(`foo`, true, mockLoc)
),
createObjectProperty(
createSimpleExpression(`prop`, false, mockLoc),
createSimpleExpression(`bar`, false, mockLoc),
mockLoc
createSimpleExpression(`bar`, false, mockLoc)
),
// compound expression as computed key
createObjectProperty(
@@ -588,8 +509,7 @@ describe('compiler: codegen', () => {
createSimpleExpression(`bar`, false, mockLoc)
]
},
createSimpleExpression(`bar`, false, mockLoc),
mockLoc
createSimpleExpression(`bar`, false, mockLoc)
)
],
mockLoc
@@ -603,8 +523,7 @@ describe('compiler: codegen', () => {
createObjectProperty(
// should quote the key!
createSimpleExpression(`some-key`, true, mockLoc),
createSimpleExpression(`foo`, true, mockLoc),
mockLoc
createSimpleExpression(`foo`, true, mockLoc)
)
],
mockLoc
@@ -641,4 +560,8 @@ describe('compiler: codegen', () => {
])`)
expect(code).toMatchSnapshot()
})
test.todo('SequenceExpression')
test.todo('ConditionalExpression')
})

View File

@@ -50,10 +50,6 @@ describe('compiler: integration tests', () => {
filename: `foo.vue`
})
expect(code).toMatch(
`const { createVNode: _createVNode, toString: _toString, renderList: _renderList } = _Vue`
)
expect(code).toMatchSnapshot()
expect(map!.sources).toEqual([`foo.vue`])
expect(map!.sourcesContent).toEqual([source])
@@ -120,8 +116,6 @@ describe('compiler: integration tests', () => {
prefixIdentifiers: true
})
expect(code).toMatch(`const { createVNode, toString, renderList } = Vue`)
expect(code).toMatchSnapshot()
expect(map!.sources).toEqual([`foo.vue`])
expect(map!.sourcesContent).toEqual([source])
@@ -197,10 +191,6 @@ describe('compiler: integration tests', () => {
filename: `foo.vue`
})
expect(code).toMatch(
`import { createVNode, toString, renderList } from "vue"`
)
expect(code).toMatchSnapshot()
expect(map!.sources).toEqual([`foo.vue`])
expect(map!.sourcesContent).toEqual([source])

View File

@@ -2,9 +2,11 @@
exports[`compiler: optimize interpolation consecutive text 1`] = `
"const _Vue = Vue
return function render() {
with (this) {
const { toString: _toString } = _Vue
return _toString(foo) + \\" bar \\" + _toString(baz)
}
}"
@@ -12,9 +14,11 @@ return function render() {
exports[`compiler: optimize interpolation consecutive text between elements 1`] = `
"const _Vue = Vue
return function render() {
with (this) {
const { createVNode: _createVNode, toString: _toString } = _Vue
return [
_createVNode(\\"div\\"),
_toString(foo) + \\" bar \\" + _toString(baz),
@@ -26,9 +30,11 @@ return function render() {
exports[`compiler: optimize interpolation consecutive text mixed with elements 1`] = `
"const _Vue = Vue
return function render() {
with (this) {
const { createVNode: _createVNode, toString: _toString } = _Vue
return [
_createVNode(\\"div\\"),
_toString(foo) + \\" bar \\" + _toString(baz),
@@ -42,9 +48,11 @@ return function render() {
exports[`compiler: optimize interpolation no consecutive text 1`] = `
"const _Vue = Vue
return function render() {
with (this) {
const { toString: _toString } = _Vue
return _toString(foo)
}
}"

View File

@@ -74,42 +74,25 @@ describe('compiler: element transform', () => {
})
test('static props', () => {
const { root, node } = parseWithElementTransform(
`<div id="foo" class="bar" />`
)
const { node } = parseWithElementTransform(`<div id="foo" class="bar" />`)
expect(node.callee).toBe(`_${CREATE_VNODE}`)
// should hoist the static object
expect(root.hoists).toMatchObject([
expect(node.arguments).toMatchObject([
`"div"`,
createStaticObjectMatcher({
id: 'foo',
class: 'bar'
})
])
expect(node.arguments).toMatchObject([
`"div"`,
{
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_hoisted_1`
}
])
})
test('props + children', () => {
const { root, node } = parseWithElementTransform(
`<div id="foo"><span/></div>`
)
const { node } = parseWithElementTransform(`<div id="foo"><span/></div>`)
expect(node.callee).toBe(`_${CREATE_VNODE}`)
expect(root.hoists).toMatchObject([
createStaticObjectMatcher({
id: 'foo'
})
])
expect(node.arguments).toMatchObject([
`"div"`,
{
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_hoisted_1`
},
createStaticObjectMatcher({
id: 'foo'
}),
[
{
type: NodeTypes.ELEMENT,
@@ -298,7 +281,7 @@ describe('compiler: element transform', () => {
foo(dir) {
_dir = dir
return {
props: createObjectProperty(dir.arg!, dir.exp!, dir.loc),
props: createObjectProperty(dir.arg!, dir.exp!),
needRuntime: false
}
}
@@ -326,7 +309,7 @@ describe('compiler: element transform', () => {
foo(dir) {
_dir = dir
return {
props: [createObjectProperty(dir.arg!, dir.exp!, dir.loc)],
props: [createObjectProperty(dir.arg!, dir.exp!)],
needRuntime: true
}
}

View File

@@ -5,7 +5,6 @@ import {
DirectiveNode,
NodeTypes,
CompilerOptions,
IfNode,
InterpolationNode
} from '../../src'
import { transformIf } from '../../src/transforms/vIf'
@@ -159,14 +158,6 @@ describe('compiler: expression transform', () => {
})
})
test('should prefix v-if condition', () => {
const node = parseWithExpressionTransform(`<div v-if="ok"/>`) as IfNode
expect(node.branches[0].condition).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.ok`
})
})
test('should not prefix whitelisted globals', () => {
const node = parseWithExpressionTransform(
`{{ Math.max(1, 2) }}`

View File

@@ -61,16 +61,6 @@ describe('compiler: transform v-bind', () => {
column: 19
}
}
},
loc: {
start: {
line: 1,
column: 6
},
end: {
line: 1,
column: 20
}
}
})
})

View File

@@ -1,6 +1,7 @@
import { parse } from '../../src/parse'
import { transform } from '../../src/transform'
import { transformIf } from '../../src/transforms/vIf'
import { transformElement } from '../../src/transforms/transformElement'
import {
IfNode,
NodeTypes,
@@ -18,7 +19,10 @@ function parseWithIfTransform(
returnIndex: number = 0
): IfNode {
const node = parse(template, options)
transform(node, { nodeTransforms: [transformIf], ...options })
transform(node, {
nodeTransforms: [transformIf, transformElement],
...options
})
if (!options.onError) {
expect(node.children.length).toBe(1)
expect(node.children[0].type).toBe(NodeTypes.IF)
@@ -153,67 +157,87 @@ describe('compiler: transform v-if', () => {
expect((b3.children[1] as TextNode).content).toBe(`fine`)
})
test('error on v-else missing adjacent v-if', () => {
const onError = jest.fn()
const node1 = parseWithIfTransform(`<div v-else/>`, { onError })
expect(onError.mock.calls[0]).toMatchObject([
{
code: ErrorCodes.X_ELSE_NO_ADJACENT_IF,
loc: node1.loc
}
])
const node2 = parseWithIfTransform(`<div/><div v-else/>`, { onError }, 1)
expect(onError.mock.calls[1]).toMatchObject([
{
code: ErrorCodes.X_ELSE_NO_ADJACENT_IF,
loc: node2.loc
}
])
const node3 = parseWithIfTransform(`<div/>foo<div v-else/>`, { onError }, 2)
expect(onError.mock.calls[2]).toMatchObject([
{
code: ErrorCodes.X_ELSE_NO_ADJACENT_IF,
loc: node3.loc
}
])
test('should prefix v-if condition', () => {
const node = parseWithIfTransform(`<div v-if="ok"/>`, {
prefixIdentifiers: true
}) as IfNode
expect(node.branches[0].condition).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
content: `_ctx.ok`
})
})
test('error on v-else-if missing adjacent v-if', () => {
const onError = jest.fn()
describe('codegen', () => {
// TODO
})
const node1 = parseWithIfTransform(`<div v-else-if="foo"/>`, { onError })
expect(onError.mock.calls[0]).toMatchObject([
{
code: ErrorCodes.X_ELSE_IF_NO_ADJACENT_IF,
loc: node1.loc
}
])
describe('errors', () => {
test('error on v-else missing adjacent v-if', () => {
const onError = jest.fn()
const node2 = parseWithIfTransform(
`<div/><div v-else-if="foo"/>`,
{ onError },
1
)
expect(onError.mock.calls[1]).toMatchObject([
{
code: ErrorCodes.X_ELSE_IF_NO_ADJACENT_IF,
loc: node2.loc
}
])
const node1 = parseWithIfTransform(`<div v-else/>`, { onError })
expect(onError.mock.calls[0]).toMatchObject([
{
code: ErrorCodes.X_ELSE_NO_ADJACENT_IF,
loc: node1.loc
}
])
const node3 = parseWithIfTransform(
`<div/>foo<div v-else-if="foo"/>`,
{ onError },
2
)
expect(onError.mock.calls[2]).toMatchObject([
{
code: ErrorCodes.X_ELSE_IF_NO_ADJACENT_IF,
loc: node3.loc
}
])
const node2 = parseWithIfTransform(`<div/><div v-else/>`, { onError }, 1)
expect(onError.mock.calls[1]).toMatchObject([
{
code: ErrorCodes.X_ELSE_NO_ADJACENT_IF,
loc: node2.loc
}
])
const node3 = parseWithIfTransform(
`<div/>foo<div v-else/>`,
{ onError },
2
)
expect(onError.mock.calls[2]).toMatchObject([
{
code: ErrorCodes.X_ELSE_NO_ADJACENT_IF,
loc: node3.loc
}
])
})
test('error on v-else-if missing adjacent v-if', () => {
const onError = jest.fn()
const node1 = parseWithIfTransform(`<div v-else-if="foo"/>`, { onError })
expect(onError.mock.calls[0]).toMatchObject([
{
code: ErrorCodes.X_ELSE_IF_NO_ADJACENT_IF,
loc: node1.loc
}
])
const node2 = parseWithIfTransform(
`<div/><div v-else-if="foo"/>`,
{ onError },
1
)
expect(onError.mock.calls[1]).toMatchObject([
{
code: ErrorCodes.X_ELSE_IF_NO_ADJACENT_IF,
loc: node2.loc
}
])
const node3 = parseWithIfTransform(
`<div/>foo<div v-else-if="foo"/>`,
{ onError },
2
)
expect(onError.mock.calls[2]).toMatchObject([
{
code: ErrorCodes.X_ELSE_IF_NO_ADJACENT_IF,
loc: node3.loc
}
])
})
})
})

View File

@@ -58,16 +58,6 @@ describe('compiler: transform v-on', () => {
column: 25
}
}
},
loc: {
start: {
line: 1,
column: 6
},
end: {
line: 1,
column: 26
}
}
})
})