wip(compiler): generate blocks for v-if
This commit is contained in:
parent
e31fb3c172
commit
5de744d4e1
@ -105,9 +105,11 @@ return function render() {
|
|||||||
|
|
||||||
exports[`compiler: codegen function mode preamble 1`] = `
|
exports[`compiler: codegen function mode preamble 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
|
|
||||||
return function render() {
|
return function render() {
|
||||||
with (this) {
|
with (this) {
|
||||||
const { helperOne: _helperOne, helperTwo: _helperTwo } = _Vue
|
const { helperOne: _helperOne, helperTwo: _helperTwo } = _Vue
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@ -137,24 +139,7 @@ exports[`compiler: codegen ifNode 1`] = `
|
|||||||
"
|
"
|
||||||
return function render() {
|
return function render() {
|
||||||
with (this) {
|
with (this) {
|
||||||
return foo
|
return (foo, bar)
|
||||||
? \\"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
|
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
@ -2,17 +2,27 @@
|
|||||||
|
|
||||||
exports[`compiler: integration tests function mode 1`] = `
|
exports[`compiler: integration tests function mode 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
|
|
||||||
return function render() {
|
return function render() {
|
||||||
with (this) {
|
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\\", {
|
return _createVNode(\\"div\\", {
|
||||||
id: \\"foo\\",
|
id: \\"foo\\",
|
||||||
class: bar.baz
|
class: bar.baz
|
||||||
}, [
|
}, [
|
||||||
_toString(world.burn()),
|
_toString(world.burn()),
|
||||||
ok
|
(_openBlock(), ok
|
||||||
? _createVNode(\\"div\\", null, \\"yes\\")
|
? _createBlock(
|
||||||
: \\"no\\",
|
\\"div\\",
|
||||||
|
{ key: 0 },
|
||||||
|
\\"yes\\"
|
||||||
|
)
|
||||||
|
: _createBlock(
|
||||||
|
_Fragment,
|
||||||
|
{ key: 1 },
|
||||||
|
\\"no\\"
|
||||||
|
)),
|
||||||
_renderList(list, (value, index) => {
|
_renderList(list, (value, index) => {
|
||||||
return _createVNode(\\"div\\", null, [
|
return _createVNode(\\"div\\", null, [
|
||||||
_createVNode(\\"span\\", null, _toString(value + index))
|
_createVNode(\\"span\\", null, _toString(value + index))
|
||||||
@ -24,7 +34,7 @@ return function render() {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: integration tests function mode w/ prefixIdentifiers: true 1`] = `
|
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() {
|
return function render() {
|
||||||
const _ctx = this
|
const _ctx = this
|
||||||
@ -33,9 +43,17 @@ return function render() {
|
|||||||
class: _ctx.bar.baz
|
class: _ctx.bar.baz
|
||||||
}, [
|
}, [
|
||||||
toString(_ctx.world.burn()),
|
toString(_ctx.world.burn()),
|
||||||
(_ctx.ok)
|
(openBlock(), (_ctx.ok)
|
||||||
? createVNode(\\"div\\", null, \\"yes\\")
|
? createBlock(
|
||||||
: \\"no\\",
|
\\"div\\",
|
||||||
|
{ key: 0 },
|
||||||
|
\\"yes\\"
|
||||||
|
)
|
||||||
|
: createBlock(
|
||||||
|
Fragment,
|
||||||
|
{ key: 1 },
|
||||||
|
\\"no\\"
|
||||||
|
)),
|
||||||
renderList(_ctx.list, (value, index) => {
|
renderList(_ctx.list, (value, index) => {
|
||||||
return createVNode(\\"div\\", null, [
|
return createVNode(\\"div\\", null, [
|
||||||
createVNode(\\"span\\", null, toString(value + index))
|
createVNode(\\"span\\", null, toString(value + index))
|
||||||
@ -46,7 +64,7 @@ return function render() {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: integration tests module mode 1`] = `
|
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() {
|
export default function render() {
|
||||||
const _ctx = this
|
const _ctx = this
|
||||||
@ -55,9 +73,17 @@ export default function render() {
|
|||||||
class: _ctx.bar.baz
|
class: _ctx.bar.baz
|
||||||
}, [
|
}, [
|
||||||
_toString(_ctx.world.burn()),
|
_toString(_ctx.world.burn()),
|
||||||
(_ctx.ok)
|
(openBlock(), (_ctx.ok)
|
||||||
? createVNode(\\"div\\", null, \\"yes\\")
|
? createBlock(
|
||||||
: \\"no\\",
|
\\"div\\",
|
||||||
|
{ key: 0 },
|
||||||
|
\\"yes\\"
|
||||||
|
)
|
||||||
|
: createBlock(
|
||||||
|
Fragment,
|
||||||
|
{ key: 1 },
|
||||||
|
\\"no\\"
|
||||||
|
)),
|
||||||
_renderList(_ctx.list, (value, index) => {
|
_renderList(_ctx.list, (value, index) => {
|
||||||
return createVNode(\\"div\\", null, [
|
return createVNode(\\"div\\", null, [
|
||||||
createVNode(\\"span\\", null, _toString(value + index))
|
createVNode(\\"span\\", null, _toString(value + index))
|
||||||
|
@ -12,7 +12,8 @@ import {
|
|||||||
createArrayExpression,
|
createArrayExpression,
|
||||||
ElementNode,
|
ElementNode,
|
||||||
createCompoundExpression,
|
createCompoundExpression,
|
||||||
createInterpolation
|
createInterpolation,
|
||||||
|
createSequenceExpression
|
||||||
} from '../src'
|
} from '../src'
|
||||||
import {
|
import {
|
||||||
CREATE_VNODE,
|
CREATE_VNODE,
|
||||||
@ -100,8 +101,7 @@ describe('compiler: codegen', () => {
|
|||||||
[
|
[
|
||||||
createObjectProperty(
|
createObjectProperty(
|
||||||
createSimpleExpression(`id`, true, mockLoc),
|
createSimpleExpression(`id`, true, mockLoc),
|
||||||
createSimpleExpression(`foo`, true, mockLoc),
|
createSimpleExpression(`foo`, true, mockLoc)
|
||||||
mockLoc
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
mockLoc
|
mockLoc
|
||||||
@ -226,8 +226,7 @@ describe('compiler: codegen', () => {
|
|||||||
const { code } = generate(
|
const { code } = generate(
|
||||||
createRoot({
|
createRoot({
|
||||||
children: [
|
children: [
|
||||||
createCompoundExpression(
|
createCompoundExpression([
|
||||||
[
|
|
||||||
`_ctx.`,
|
`_ctx.`,
|
||||||
createSimpleExpression(`foo`, false, mockLoc),
|
createSimpleExpression(`foo`, false, mockLoc),
|
||||||
` + `,
|
` + `,
|
||||||
@ -236,9 +235,7 @@ describe('compiler: codegen', () => {
|
|||||||
loc: mockLoc,
|
loc: mockLoc,
|
||||||
content: createSimpleExpression(`bar`, false, mockLoc)
|
content: createSimpleExpression(`bar`, false, mockLoc)
|
||||||
}
|
}
|
||||||
],
|
])
|
||||||
mockLoc
|
|
||||||
)
|
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@ -253,90 +250,16 @@ describe('compiler: codegen', () => {
|
|||||||
{
|
{
|
||||||
type: NodeTypes.IF,
|
type: NodeTypes.IF,
|
||||||
loc: mockLoc,
|
loc: mockLoc,
|
||||||
branches: [
|
branches: [],
|
||||||
{
|
codegenNode: createSequenceExpression([
|
||||||
type: NodeTypes.IF_BRANCH,
|
createSimpleExpression('foo', false),
|
||||||
condition: createSimpleExpression('foo', false, mockLoc),
|
createSimpleExpression('bar', false)
|
||||||
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
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
expect(code).toMatch(`
|
expect(code).toMatch(`return (foo, bar)`)
|
||||||
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).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -570,13 +493,11 @@ describe('compiler: codegen', () => {
|
|||||||
[
|
[
|
||||||
createObjectProperty(
|
createObjectProperty(
|
||||||
createSimpleExpression(`id`, true, mockLoc),
|
createSimpleExpression(`id`, true, mockLoc),
|
||||||
createSimpleExpression(`foo`, true, mockLoc),
|
createSimpleExpression(`foo`, true, mockLoc)
|
||||||
mockLoc
|
|
||||||
),
|
),
|
||||||
createObjectProperty(
|
createObjectProperty(
|
||||||
createSimpleExpression(`prop`, false, mockLoc),
|
createSimpleExpression(`prop`, false, mockLoc),
|
||||||
createSimpleExpression(`bar`, false, mockLoc),
|
createSimpleExpression(`bar`, false, mockLoc)
|
||||||
mockLoc
|
|
||||||
),
|
),
|
||||||
// compound expression as computed key
|
// compound expression as computed key
|
||||||
createObjectProperty(
|
createObjectProperty(
|
||||||
@ -588,8 +509,7 @@ describe('compiler: codegen', () => {
|
|||||||
createSimpleExpression(`bar`, false, mockLoc)
|
createSimpleExpression(`bar`, false, mockLoc)
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
createSimpleExpression(`bar`, false, mockLoc),
|
createSimpleExpression(`bar`, false, mockLoc)
|
||||||
mockLoc
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
mockLoc
|
mockLoc
|
||||||
@ -603,8 +523,7 @@ describe('compiler: codegen', () => {
|
|||||||
createObjectProperty(
|
createObjectProperty(
|
||||||
// should quote the key!
|
// should quote the key!
|
||||||
createSimpleExpression(`some-key`, true, mockLoc),
|
createSimpleExpression(`some-key`, true, mockLoc),
|
||||||
createSimpleExpression(`foo`, true, mockLoc),
|
createSimpleExpression(`foo`, true, mockLoc)
|
||||||
mockLoc
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
mockLoc
|
mockLoc
|
||||||
@ -641,4 +560,8 @@ describe('compiler: codegen', () => {
|
|||||||
])`)
|
])`)
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test.todo('SequenceExpression')
|
||||||
|
|
||||||
|
test.todo('ConditionalExpression')
|
||||||
})
|
})
|
||||||
|
@ -50,10 +50,6 @@ describe('compiler: integration tests', () => {
|
|||||||
filename: `foo.vue`
|
filename: `foo.vue`
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(code).toMatch(
|
|
||||||
`const { createVNode: _createVNode, toString: _toString, renderList: _renderList } = _Vue`
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
expect(map!.sources).toEqual([`foo.vue`])
|
expect(map!.sources).toEqual([`foo.vue`])
|
||||||
expect(map!.sourcesContent).toEqual([source])
|
expect(map!.sourcesContent).toEqual([source])
|
||||||
@ -120,8 +116,6 @@ describe('compiler: integration tests', () => {
|
|||||||
prefixIdentifiers: true
|
prefixIdentifiers: true
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(code).toMatch(`const { createVNode, toString, renderList } = Vue`)
|
|
||||||
|
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
expect(map!.sources).toEqual([`foo.vue`])
|
expect(map!.sources).toEqual([`foo.vue`])
|
||||||
expect(map!.sourcesContent).toEqual([source])
|
expect(map!.sourcesContent).toEqual([source])
|
||||||
@ -197,10 +191,6 @@ describe('compiler: integration tests', () => {
|
|||||||
filename: `foo.vue`
|
filename: `foo.vue`
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(code).toMatch(
|
|
||||||
`import { createVNode, toString, renderList } from "vue"`
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
expect(map!.sources).toEqual([`foo.vue`])
|
expect(map!.sources).toEqual([`foo.vue`])
|
||||||
expect(map!.sourcesContent).toEqual([source])
|
expect(map!.sourcesContent).toEqual([source])
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
exports[`compiler: optimize interpolation consecutive text 1`] = `
|
exports[`compiler: optimize interpolation consecutive text 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
|
|
||||||
return function render() {
|
return function render() {
|
||||||
with (this) {
|
with (this) {
|
||||||
const { toString: _toString } = _Vue
|
const { toString: _toString } = _Vue
|
||||||
|
|
||||||
return _toString(foo) + \\" bar \\" + _toString(baz)
|
return _toString(foo) + \\" bar \\" + _toString(baz)
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@ -12,9 +14,11 @@ return function render() {
|
|||||||
|
|
||||||
exports[`compiler: optimize interpolation consecutive text between elements 1`] = `
|
exports[`compiler: optimize interpolation consecutive text between elements 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
|
|
||||||
return function render() {
|
return function render() {
|
||||||
with (this) {
|
with (this) {
|
||||||
const { createVNode: _createVNode, toString: _toString } = _Vue
|
const { createVNode: _createVNode, toString: _toString } = _Vue
|
||||||
|
|
||||||
return [
|
return [
|
||||||
_createVNode(\\"div\\"),
|
_createVNode(\\"div\\"),
|
||||||
_toString(foo) + \\" bar \\" + _toString(baz),
|
_toString(foo) + \\" bar \\" + _toString(baz),
|
||||||
@ -26,9 +30,11 @@ return function render() {
|
|||||||
|
|
||||||
exports[`compiler: optimize interpolation consecutive text mixed with elements 1`] = `
|
exports[`compiler: optimize interpolation consecutive text mixed with elements 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
|
|
||||||
return function render() {
|
return function render() {
|
||||||
with (this) {
|
with (this) {
|
||||||
const { createVNode: _createVNode, toString: _toString } = _Vue
|
const { createVNode: _createVNode, toString: _toString } = _Vue
|
||||||
|
|
||||||
return [
|
return [
|
||||||
_createVNode(\\"div\\"),
|
_createVNode(\\"div\\"),
|
||||||
_toString(foo) + \\" bar \\" + _toString(baz),
|
_toString(foo) + \\" bar \\" + _toString(baz),
|
||||||
@ -42,9 +48,11 @@ return function render() {
|
|||||||
|
|
||||||
exports[`compiler: optimize interpolation no consecutive text 1`] = `
|
exports[`compiler: optimize interpolation no consecutive text 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
|
|
||||||
return function render() {
|
return function render() {
|
||||||
with (this) {
|
with (this) {
|
||||||
const { toString: _toString } = _Vue
|
const { toString: _toString } = _Vue
|
||||||
|
|
||||||
return _toString(foo)
|
return _toString(foo)
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
|
@ -74,42 +74,25 @@ describe('compiler: element transform', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('static props', () => {
|
test('static props', () => {
|
||||||
const { root, node } = parseWithElementTransform(
|
const { node } = parseWithElementTransform(`<div id="foo" class="bar" />`)
|
||||||
`<div id="foo" class="bar" />`
|
|
||||||
)
|
|
||||||
expect(node.callee).toBe(`_${CREATE_VNODE}`)
|
expect(node.callee).toBe(`_${CREATE_VNODE}`)
|
||||||
// should hoist the static object
|
expect(node.arguments).toMatchObject([
|
||||||
expect(root.hoists).toMatchObject([
|
`"div"`,
|
||||||
createStaticObjectMatcher({
|
createStaticObjectMatcher({
|
||||||
id: 'foo',
|
id: 'foo',
|
||||||
class: 'bar'
|
class: 'bar'
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
expect(node.arguments).toMatchObject([
|
|
||||||
`"div"`,
|
|
||||||
{
|
|
||||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
|
||||||
content: `_hoisted_1`
|
|
||||||
}
|
|
||||||
])
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('props + children', () => {
|
test('props + children', () => {
|
||||||
const { root, node } = parseWithElementTransform(
|
const { node } = parseWithElementTransform(`<div id="foo"><span/></div>`)
|
||||||
`<div id="foo"><span/></div>`
|
|
||||||
)
|
|
||||||
expect(node.callee).toBe(`_${CREATE_VNODE}`)
|
expect(node.callee).toBe(`_${CREATE_VNODE}`)
|
||||||
expect(root.hoists).toMatchObject([
|
|
||||||
createStaticObjectMatcher({
|
|
||||||
id: 'foo'
|
|
||||||
})
|
|
||||||
])
|
|
||||||
expect(node.arguments).toMatchObject([
|
expect(node.arguments).toMatchObject([
|
||||||
`"div"`,
|
`"div"`,
|
||||||
{
|
createStaticObjectMatcher({
|
||||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
id: 'foo'
|
||||||
content: `_hoisted_1`
|
}),
|
||||||
},
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
type: NodeTypes.ELEMENT,
|
type: NodeTypes.ELEMENT,
|
||||||
@ -298,7 +281,7 @@ describe('compiler: element transform', () => {
|
|||||||
foo(dir) {
|
foo(dir) {
|
||||||
_dir = dir
|
_dir = dir
|
||||||
return {
|
return {
|
||||||
props: createObjectProperty(dir.arg!, dir.exp!, dir.loc),
|
props: createObjectProperty(dir.arg!, dir.exp!),
|
||||||
needRuntime: false
|
needRuntime: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -326,7 +309,7 @@ describe('compiler: element transform', () => {
|
|||||||
foo(dir) {
|
foo(dir) {
|
||||||
_dir = dir
|
_dir = dir
|
||||||
return {
|
return {
|
||||||
props: [createObjectProperty(dir.arg!, dir.exp!, dir.loc)],
|
props: [createObjectProperty(dir.arg!, dir.exp!)],
|
||||||
needRuntime: true
|
needRuntime: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import {
|
|||||||
DirectiveNode,
|
DirectiveNode,
|
||||||
NodeTypes,
|
NodeTypes,
|
||||||
CompilerOptions,
|
CompilerOptions,
|
||||||
IfNode,
|
|
||||||
InterpolationNode
|
InterpolationNode
|
||||||
} from '../../src'
|
} from '../../src'
|
||||||
import { transformIf } from '../../src/transforms/vIf'
|
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', () => {
|
test('should not prefix whitelisted globals', () => {
|
||||||
const node = parseWithExpressionTransform(
|
const node = parseWithExpressionTransform(
|
||||||
`{{ Math.max(1, 2) }}`
|
`{{ Math.max(1, 2) }}`
|
||||||
|
@ -61,16 +61,6 @@ describe('compiler: transform v-bind', () => {
|
|||||||
column: 19
|
column: 19
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
loc: {
|
|
||||||
start: {
|
|
||||||
line: 1,
|
|
||||||
column: 6
|
|
||||||
},
|
|
||||||
end: {
|
|
||||||
line: 1,
|
|
||||||
column: 20
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
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 { transformIf } from '../../src/transforms/vIf'
|
||||||
|
import { transformElement } from '../../src/transforms/transformElement'
|
||||||
import {
|
import {
|
||||||
IfNode,
|
IfNode,
|
||||||
NodeTypes,
|
NodeTypes,
|
||||||
@ -18,7 +19,10 @@ function parseWithIfTransform(
|
|||||||
returnIndex: number = 0
|
returnIndex: number = 0
|
||||||
): IfNode {
|
): IfNode {
|
||||||
const node = parse(template, options)
|
const node = parse(template, options)
|
||||||
transform(node, { nodeTransforms: [transformIf], ...options })
|
transform(node, {
|
||||||
|
nodeTransforms: [transformIf, transformElement],
|
||||||
|
...options
|
||||||
|
})
|
||||||
if (!options.onError) {
|
if (!options.onError) {
|
||||||
expect(node.children.length).toBe(1)
|
expect(node.children.length).toBe(1)
|
||||||
expect(node.children[0].type).toBe(NodeTypes.IF)
|
expect(node.children[0].type).toBe(NodeTypes.IF)
|
||||||
@ -153,6 +157,21 @@ describe('compiler: transform v-if', () => {
|
|||||||
expect((b3.children[1] as TextNode).content).toBe(`fine`)
|
expect((b3.children[1] as TextNode).content).toBe(`fine`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
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`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('codegen', () => {
|
||||||
|
// TODO
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('errors', () => {
|
||||||
test('error on v-else missing adjacent v-if', () => {
|
test('error on v-else missing adjacent v-if', () => {
|
||||||
const onError = jest.fn()
|
const onError = jest.fn()
|
||||||
|
|
||||||
@ -172,7 +191,11 @@ describe('compiler: transform v-if', () => {
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
const node3 = parseWithIfTransform(`<div/>foo<div v-else/>`, { onError }, 2)
|
const node3 = parseWithIfTransform(
|
||||||
|
`<div/>foo<div v-else/>`,
|
||||||
|
{ onError },
|
||||||
|
2
|
||||||
|
)
|
||||||
expect(onError.mock.calls[2]).toMatchObject([
|
expect(onError.mock.calls[2]).toMatchObject([
|
||||||
{
|
{
|
||||||
code: ErrorCodes.X_ELSE_NO_ADJACENT_IF,
|
code: ErrorCodes.X_ELSE_NO_ADJACENT_IF,
|
||||||
@ -216,4 +239,5 @@ describe('compiler: transform v-if', () => {
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -58,16 +58,6 @@ describe('compiler: transform v-on', () => {
|
|||||||
column: 25
|
column: 25
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
loc: {
|
|
||||||
start: {
|
|
||||||
line: 1,
|
|
||||||
column: 6
|
|
||||||
},
|
|
||||||
end: {
|
|
||||||
line: 1,
|
|
||||||
column: 26
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -142,7 +142,7 @@ export interface CompoundExpressionNode extends Node {
|
|||||||
export interface IfNode extends Node {
|
export interface IfNode extends Node {
|
||||||
type: NodeTypes.IF
|
type: NodeTypes.IF
|
||||||
branches: IfBranchNode[]
|
branches: IfBranchNode[]
|
||||||
codegenNode: JSChildNode | undefined
|
codegenNode: SequenceExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IfBranchNode extends Node {
|
export interface IfBranchNode extends Node {
|
||||||
@ -212,9 +212,20 @@ export interface ConditionalExpression extends Node {
|
|||||||
alternate: JSChildNode
|
alternate: JSChildNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AST Utilities ---------------------------------------------------------------
|
||||||
|
|
||||||
|
// Some expressions, e.g. sequence and conditional expressions, are never
|
||||||
|
// associated with template nodes, so their source locations are just a stub.
|
||||||
|
// Container types like CompoundExpression also don't need a real location.
|
||||||
|
const locStub: SourceLocation = {
|
||||||
|
source: '',
|
||||||
|
start: { line: 1, column: 1, offset: 0 },
|
||||||
|
end: { line: 1, column: 1, offset: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
export function createArrayExpression(
|
export function createArrayExpression(
|
||||||
elements: ArrayExpression['elements'],
|
elements: ArrayExpression['elements'],
|
||||||
loc: SourceLocation
|
loc: SourceLocation = locStub
|
||||||
): ArrayExpression {
|
): ArrayExpression {
|
||||||
return {
|
return {
|
||||||
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
||||||
@ -225,7 +236,7 @@ export function createArrayExpression(
|
|||||||
|
|
||||||
export function createObjectExpression(
|
export function createObjectExpression(
|
||||||
properties: Property[],
|
properties: Property[],
|
||||||
loc: SourceLocation
|
loc: SourceLocation = locStub
|
||||||
): ObjectExpression {
|
): ObjectExpression {
|
||||||
return {
|
return {
|
||||||
type: NodeTypes.JS_OBJECT_EXPRESSION,
|
type: NodeTypes.JS_OBJECT_EXPRESSION,
|
||||||
@ -236,12 +247,11 @@ export function createObjectExpression(
|
|||||||
|
|
||||||
export function createObjectProperty(
|
export function createObjectProperty(
|
||||||
key: ExpressionNode,
|
key: ExpressionNode,
|
||||||
value: JSChildNode,
|
value: JSChildNode
|
||||||
loc: SourceLocation
|
|
||||||
): Property {
|
): Property {
|
||||||
return {
|
return {
|
||||||
type: NodeTypes.JS_PROPERTY,
|
type: NodeTypes.JS_PROPERTY,
|
||||||
loc,
|
loc: locStub,
|
||||||
key,
|
key,
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
@ -250,7 +260,7 @@ export function createObjectProperty(
|
|||||||
export function createSimpleExpression(
|
export function createSimpleExpression(
|
||||||
content: string,
|
content: string,
|
||||||
isStatic: boolean,
|
isStatic: boolean,
|
||||||
loc: SourceLocation
|
loc: SourceLocation = locStub
|
||||||
): SimpleExpressionNode {
|
): SimpleExpressionNode {
|
||||||
return {
|
return {
|
||||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
@ -274,20 +284,19 @@ export function createInterpolation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createCompoundExpression(
|
export function createCompoundExpression(
|
||||||
children: CompoundExpressionNode['children'],
|
children: CompoundExpressionNode['children']
|
||||||
loc: SourceLocation
|
|
||||||
): CompoundExpressionNode {
|
): CompoundExpressionNode {
|
||||||
return {
|
return {
|
||||||
type: NodeTypes.COMPOUND_EXPRESSION,
|
type: NodeTypes.COMPOUND_EXPRESSION,
|
||||||
loc,
|
loc: locStub,
|
||||||
children
|
children
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createCallExpression(
|
export function createCallExpression(
|
||||||
callee: string,
|
callee: string,
|
||||||
args: CallExpression['arguments'],
|
args: CallExpression['arguments'] = [],
|
||||||
loc: SourceLocation
|
loc: SourceLocation = locStub
|
||||||
): CallExpression {
|
): CallExpression {
|
||||||
return {
|
return {
|
||||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||||
@ -300,7 +309,7 @@ export function createCallExpression(
|
|||||||
export function createFunctionExpression(
|
export function createFunctionExpression(
|
||||||
params: ExpressionNode | undefined,
|
params: ExpressionNode | undefined,
|
||||||
returns: TemplateChildNode[],
|
returns: TemplateChildNode[],
|
||||||
loc: SourceLocation
|
loc: SourceLocation = locStub
|
||||||
): SlotFunctionExpression {
|
): SlotFunctionExpression {
|
||||||
return {
|
return {
|
||||||
type: NodeTypes.JS_SLOT_FUNCTION,
|
type: NodeTypes.JS_SLOT_FUNCTION,
|
||||||
@ -310,15 +319,9 @@ export function createFunctionExpression(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sequence and conditional expressions are never associated with template nodes,
|
export function createSequenceExpression(
|
||||||
// so their source locations are just a stub.
|
expressions: JSChildNode[]
|
||||||
const locStub: SourceLocation = {
|
): SequenceExpression {
|
||||||
source: '',
|
|
||||||
start: { line: 1, column: 1, offset: 0 },
|
|
||||||
end: { line: 1, column: 1, offset: 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createSequenceExpression(expressions: JSChildNode[]) {
|
|
||||||
return {
|
return {
|
||||||
type: NodeTypes.JS_SEQUENCE_EXPRESSION,
|
type: NodeTypes.JS_SEQUENCE_EXPRESSION,
|
||||||
expressions,
|
expressions,
|
||||||
@ -330,7 +333,7 @@ export function createConditionalExpression(
|
|||||||
test: ExpressionNode,
|
test: ExpressionNode,
|
||||||
consequent: JSChildNode,
|
consequent: JSChildNode,
|
||||||
alternate: JSChildNode
|
alternate: JSChildNode
|
||||||
) {
|
): ConditionalExpression {
|
||||||
return {
|
return {
|
||||||
type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
|
type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
|
||||||
test,
|
test,
|
||||||
|
@ -12,7 +12,6 @@ import {
|
|||||||
CallExpression,
|
CallExpression,
|
||||||
ArrayExpression,
|
ArrayExpression,
|
||||||
ObjectExpression,
|
ObjectExpression,
|
||||||
IfBranchNode,
|
|
||||||
SourceLocation,
|
SourceLocation,
|
||||||
Position,
|
Position,
|
||||||
InterpolationNode,
|
InterpolationNode,
|
||||||
@ -196,7 +195,7 @@ export function generate(
|
|||||||
push(`const { ${ast.imports.join(', ')} } = Vue\n`)
|
push(`const { ${ast.imports.join(', ')} } = Vue\n`)
|
||||||
} else {
|
} else {
|
||||||
// save Vue in a separate variable to avoid collision
|
// save Vue in a separate variable to avoid collision
|
||||||
push(`const _Vue = Vue`)
|
push(`const _Vue = Vue\n`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
genHoists(ast.hoists, context)
|
genHoists(ast.hoists, context)
|
||||||
@ -222,6 +221,7 @@ export function generate(
|
|||||||
if (hasImports) {
|
if (hasImports) {
|
||||||
push(`const { ${ast.imports.map(n => `${n}: _${n}`).join(', ')} } = _Vue`)
|
push(`const { ${ast.imports.map(n => `${n}: _${n}`).join(', ')} } = _Vue`)
|
||||||
newline()
|
newline()
|
||||||
|
newline()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
push(`const _ctx = this`)
|
push(`const _ctx = this`)
|
||||||
@ -471,44 +471,7 @@ function genComment(node: CommentNode, context: CodegenContext) {
|
|||||||
|
|
||||||
// control flow
|
// control flow
|
||||||
function genIf(node: IfNode, context: CodegenContext) {
|
function genIf(node: IfNode, context: CodegenContext) {
|
||||||
genIfBranch(node.branches[0], node.branches, 1, context)
|
genNode(node.codegenNode, context)
|
||||||
}
|
|
||||||
|
|
||||||
function genIfBranch(
|
|
||||||
{ condition, children }: IfBranchNode,
|
|
||||||
branches: IfBranchNode[],
|
|
||||||
nextIndex: number,
|
|
||||||
context: CodegenContext
|
|
||||||
) {
|
|
||||||
if (condition) {
|
|
||||||
// v-if or v-else-if
|
|
||||||
const { push, indent, deindent, newline } = context
|
|
||||||
if (condition.type === NodeTypes.SIMPLE_EXPRESSION) {
|
|
||||||
const needsQuote = !isSimpleIdentifier(condition.content)
|
|
||||||
needsQuote && push(`(`)
|
|
||||||
genExpression(condition, context)
|
|
||||||
needsQuote && push(`)`)
|
|
||||||
} else {
|
|
||||||
genCompoundExpression(condition, context)
|
|
||||||
}
|
|
||||||
indent()
|
|
||||||
context.indentLevel++
|
|
||||||
push(`? `)
|
|
||||||
genChildren(children, context, true)
|
|
||||||
context.indentLevel--
|
|
||||||
newline()
|
|
||||||
push(`: `)
|
|
||||||
if (nextIndex < branches.length) {
|
|
||||||
genIfBranch(branches[nextIndex], branches, nextIndex + 1, context)
|
|
||||||
} else {
|
|
||||||
context.push(`null`)
|
|
||||||
}
|
|
||||||
deindent(true /* without newline */)
|
|
||||||
} else {
|
|
||||||
// v-else
|
|
||||||
__DEV__ && assert(nextIndex === branches.length)
|
|
||||||
genChildren(children, context, true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function genFor(node: ForNode, context: CodegenContext) {
|
function genFor(node: ForNode, context: CodegenContext) {
|
||||||
@ -623,7 +586,14 @@ function genConditionalExpression(
|
|||||||
context.indentLevel--
|
context.indentLevel--
|
||||||
newline()
|
newline()
|
||||||
push(`: `)
|
push(`: `)
|
||||||
|
const isNested = alternate.type === NodeTypes.JS_CONDITIONAL_EXPRESSION
|
||||||
|
if (!isNested) {
|
||||||
|
context.indentLevel++
|
||||||
|
}
|
||||||
genNode(alternate, context)
|
genNode(alternate, context)
|
||||||
|
if (!isNested) {
|
||||||
|
context.indentLevel--
|
||||||
|
}
|
||||||
deindent(true /* without newline */)
|
deindent(true /* without newline */)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ export const enum ErrorCodes {
|
|||||||
X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END,
|
X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END,
|
||||||
|
|
||||||
// transform errors
|
// transform errors
|
||||||
|
X_IF_NO_EXPRESSION,
|
||||||
X_ELSE_IF_NO_ADJACENT_IF,
|
X_ELSE_IF_NO_ADJACENT_IF,
|
||||||
X_ELSE_NO_ADJACENT_IF,
|
X_ELSE_NO_ADJACENT_IF,
|
||||||
X_FOR_NO_EXPRESSION,
|
X_FOR_NO_EXPRESSION,
|
||||||
@ -138,9 +139,10 @@ export const errorMessages: { [code: number]: string } = {
|
|||||||
'Note that dynamic directive argument connot contain spaces.',
|
'Note that dynamic directive argument connot contain spaces.',
|
||||||
|
|
||||||
// transform errors
|
// transform errors
|
||||||
|
[ErrorCodes.X_IF_NO_EXPRESSION]: `v-if/v-else-if is missing expression.`,
|
||||||
[ErrorCodes.X_ELSE_IF_NO_ADJACENT_IF]: `v-else-if has no adjacent v-if.`,
|
[ErrorCodes.X_ELSE_IF_NO_ADJACENT_IF]: `v-else-if has no adjacent v-if.`,
|
||||||
[ErrorCodes.X_ELSE_NO_ADJACENT_IF]: `v-else has no adjacent v-if.`,
|
[ErrorCodes.X_ELSE_NO_ADJACENT_IF]: `v-else has no adjacent v-if.`,
|
||||||
[ErrorCodes.X_FOR_NO_EXPRESSION]: `v-for has no expression.`,
|
[ErrorCodes.X_FOR_NO_EXPRESSION]: `v-for is missing expression.`,
|
||||||
[ErrorCodes.X_FOR_MALFORMED_EXPRESSION]: `v-for has invalid expression.`,
|
[ErrorCodes.X_FOR_MALFORMED_EXPRESSION]: `v-for has invalid expression.`,
|
||||||
[ErrorCodes.X_V_BIND_NO_EXPRESSION]: `v-bind is missing expression.`,
|
[ErrorCodes.X_V_BIND_NO_EXPRESSION]: `v-bind is missing expression.`,
|
||||||
[ErrorCodes.X_V_ON_NO_EXPRESSION]: `v-on is missing expression.`,
|
[ErrorCodes.X_V_ON_NO_EXPRESSION]: `v-on is missing expression.`,
|
||||||
|
@ -5,6 +5,9 @@ export const PORTAL = `Portal`
|
|||||||
export const COMMENT = `Comment`
|
export const COMMENT = `Comment`
|
||||||
export const TEXT = `Text`
|
export const TEXT = `Text`
|
||||||
export const SUSPENSE = `Suspense`
|
export const SUSPENSE = `Suspense`
|
||||||
|
export const EMPTY = `Empty`
|
||||||
|
export const OPEN_BLOCK = `openBlock`
|
||||||
|
export const CREATE_BLOCK = `createBlock`
|
||||||
export const CREATE_VNODE = `createVNode`
|
export const CREATE_VNODE = `createVNode`
|
||||||
export const RESOLVE_COMPONENT = `resolveComponent`
|
export const RESOLVE_COMPONENT = `resolveComponent`
|
||||||
export const RESOLVE_DIRECTIVE = `resolveDirective`
|
export const RESOLVE_DIRECTIVE = `resolveDirective`
|
||||||
|
@ -148,7 +148,6 @@ export function buildProps(
|
|||||||
patchFlag: number
|
patchFlag: number
|
||||||
dynamicPropNames: string[]
|
dynamicPropNames: string[]
|
||||||
} {
|
} {
|
||||||
let isStatic = true
|
|
||||||
let properties: ObjectExpression['properties'] = []
|
let properties: ObjectExpression['properties'] = []
|
||||||
const mergeArgs: PropsExpression[] = []
|
const mergeArgs: PropsExpression[] = []
|
||||||
const runtimeDirectives: DirectiveNode[] = []
|
const runtimeDirectives: DirectiveNode[] = []
|
||||||
@ -180,13 +179,11 @@ export function buildProps(
|
|||||||
value ? value.content : '',
|
value ? value.content : '',
|
||||||
true,
|
true,
|
||||||
value ? value.loc : loc
|
value ? value.loc : loc
|
||||||
),
|
)
|
||||||
loc
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// directives
|
// directives
|
||||||
isStatic = false
|
|
||||||
const { name, arg, exp, loc } = prop
|
const { name, arg, exp, loc } = prop
|
||||||
|
|
||||||
// skip v-slot - it is handled by its dedicated transform.
|
// skip v-slot - it is handled by its dedicated transform.
|
||||||
@ -297,11 +294,6 @@ export function buildProps(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hoist the object if it's fully static
|
|
||||||
if (isStatic && propsExpression) {
|
|
||||||
propsExpression = context.hoist(propsExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine the flags to add
|
// determine the flags to add
|
||||||
if (hasDynammicKeys) {
|
if (hasDynammicKeys) {
|
||||||
patchFlag |= PatchFlags.FULL_PROPS
|
patchFlag |= PatchFlags.FULL_PROPS
|
||||||
@ -391,8 +383,7 @@ function createDirectiveArgs(
|
|||||||
dir.modifiers.map(modifier =>
|
dir.modifiers.map(modifier =>
|
||||||
createObjectProperty(
|
createObjectProperty(
|
||||||
createSimpleExpression(modifier, true, loc),
|
createSimpleExpression(modifier, true, loc),
|
||||||
createSimpleExpression(`true`, false, loc),
|
createSimpleExpression(`true`, false, loc)
|
||||||
loc
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
loc
|
loc
|
||||||
|
@ -192,7 +192,7 @@ export function processExpression(
|
|||||||
|
|
||||||
let ret
|
let ret
|
||||||
if (children.length) {
|
if (children.length) {
|
||||||
ret = createCompoundExpression(children, node.loc)
|
ret = createCompoundExpression(children)
|
||||||
} else {
|
} else {
|
||||||
ret = node
|
ret = node
|
||||||
}
|
}
|
||||||
|
@ -43,16 +43,13 @@ export const transformSlotOutlet: NodeTransform = (node, context) => {
|
|||||||
arg.content === `name`
|
arg.content === `name`
|
||||||
) {
|
) {
|
||||||
// dynamic :name="xxx"
|
// dynamic :name="xxx"
|
||||||
slot = createCompoundExpression(
|
slot = createCompoundExpression([
|
||||||
[
|
|
||||||
$slots + `[`,
|
$slots + `[`,
|
||||||
...(exp.type === NodeTypes.SIMPLE_EXPRESSION
|
...(exp.type === NodeTypes.SIMPLE_EXPRESSION
|
||||||
? [exp]
|
? [exp]
|
||||||
: exp.children),
|
: exp.children),
|
||||||
`]`
|
`]`
|
||||||
],
|
])
|
||||||
loc
|
|
||||||
)
|
|
||||||
nameIndex = i
|
nameIndex = i
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,7 @@ export const transformBind: DirectiveTransform = (dir, context) => {
|
|||||||
return {
|
return {
|
||||||
props: createObjectProperty(
|
props: createObjectProperty(
|
||||||
arg!,
|
arg!,
|
||||||
exp || createSimpleExpression('', true, loc),
|
exp || createSimpleExpression('', true, loc)
|
||||||
loc
|
|
||||||
),
|
),
|
||||||
needRuntime: false
|
needRuntime: false
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
createStructuralDirectiveTransform,
|
createStructuralDirectiveTransform,
|
||||||
traverseChildren
|
traverseChildren,
|
||||||
|
TransformContext
|
||||||
} from '../transform'
|
} from '../transform'
|
||||||
import {
|
import {
|
||||||
NodeTypes,
|
NodeTypes,
|
||||||
@ -8,25 +9,66 @@ import {
|
|||||||
ElementNode,
|
ElementNode,
|
||||||
DirectiveNode,
|
DirectiveNode,
|
||||||
IfBranchNode,
|
IfBranchNode,
|
||||||
SimpleExpressionNode
|
SimpleExpressionNode,
|
||||||
|
createSequenceExpression,
|
||||||
|
createCallExpression,
|
||||||
|
createConditionalExpression,
|
||||||
|
ConditionalExpression,
|
||||||
|
CallExpression,
|
||||||
|
createSimpleExpression,
|
||||||
|
JSChildNode,
|
||||||
|
ObjectExpression,
|
||||||
|
createObjectProperty,
|
||||||
|
Property
|
||||||
} from '../ast'
|
} from '../ast'
|
||||||
import { createCompilerError, ErrorCodes } from '../errors'
|
import { createCompilerError, ErrorCodes } from '../errors'
|
||||||
import { processExpression } from './transformExpression'
|
import { processExpression } from './transformExpression'
|
||||||
|
import {
|
||||||
|
OPEN_BLOCK,
|
||||||
|
CREATE_BLOCK,
|
||||||
|
EMPTY,
|
||||||
|
FRAGMENT,
|
||||||
|
APPLY_DIRECTIVES
|
||||||
|
} from '../runtimeConstants'
|
||||||
|
import { isString } from '@vue/shared'
|
||||||
|
|
||||||
export const transformIf = createStructuralDirectiveTransform(
|
export const transformIf = createStructuralDirectiveTransform(
|
||||||
/^(if|else|else-if)$/,
|
/^(if|else|else-if)$/,
|
||||||
(node, dir, context) => {
|
(node, dir, context) => {
|
||||||
|
if (
|
||||||
|
dir.name !== 'else' &&
|
||||||
|
(!dir.exp || !(dir.exp as SimpleExpressionNode).content.trim())
|
||||||
|
) {
|
||||||
|
const loc = dir.exp ? dir.exp.loc : node.loc
|
||||||
|
context.onError(createCompilerError(ErrorCodes.X_IF_NO_EXPRESSION, loc))
|
||||||
|
dir.exp = createSimpleExpression(`true`, false, loc)
|
||||||
|
}
|
||||||
|
|
||||||
if (!__BROWSER__ && context.prefixIdentifiers && dir.exp) {
|
if (!__BROWSER__ && context.prefixIdentifiers && dir.exp) {
|
||||||
// dir.exp can only be simple expression because vIf transform is applied
|
// dir.exp can only be simple expression because vIf transform is applied
|
||||||
// before expression transform.
|
// before expression transform.
|
||||||
processExpression(dir.exp as SimpleExpressionNode, context)
|
dir.exp = processExpression(dir.exp as SimpleExpressionNode, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dir.name === 'if') {
|
if (dir.name === 'if') {
|
||||||
|
const codegenNode = createSequenceExpression([
|
||||||
|
createCallExpression(context.helper(OPEN_BLOCK))
|
||||||
|
])
|
||||||
|
|
||||||
context.replaceNode({
|
context.replaceNode({
|
||||||
type: NodeTypes.IF,
|
type: NodeTypes.IF,
|
||||||
loc: node.loc,
|
loc: node.loc,
|
||||||
branches: [createIfBranch(node, dir)]
|
branches: [createIfBranch(node, dir)],
|
||||||
|
codegenNode
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Exit callback. Complete the codegenNode when all children have been
|
||||||
|
// transformed.
|
||||||
|
return () => {
|
||||||
|
codegenNode.expressions.push(
|
||||||
|
createCodegenNodeForBranch(node, dir, 0, context)
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// locate the adjacent v-if
|
// locate the adjacent v-if
|
||||||
const siblings = context.parent!.children
|
const siblings = context.parent!.children
|
||||||
@ -50,6 +92,25 @@ export const transformIf = createStructuralDirectiveTransform(
|
|||||||
// since the branch was removed, it will not be traversed.
|
// since the branch was removed, it will not be traversed.
|
||||||
// make sure to traverse here.
|
// make sure to traverse here.
|
||||||
traverseChildren(branch, context)
|
traverseChildren(branch, context)
|
||||||
|
// attach this branch's codegen node to the v-if root.
|
||||||
|
let parentCondition = sibling.codegenNode
|
||||||
|
.expressions[1] as ConditionalExpression
|
||||||
|
while (true) {
|
||||||
|
if (
|
||||||
|
parentCondition.alternate.type ===
|
||||||
|
NodeTypes.JS_CONDITIONAL_EXPRESSION
|
||||||
|
) {
|
||||||
|
parentCondition = parentCondition.alternate
|
||||||
|
} else {
|
||||||
|
parentCondition.alternate = createCodegenNodeForBranch(
|
||||||
|
node,
|
||||||
|
dir,
|
||||||
|
sibling.branches.length - 1,
|
||||||
|
context
|
||||||
|
)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
context.onError(
|
context.onError(
|
||||||
createCompilerError(
|
createCompilerError(
|
||||||
@ -74,3 +135,74 @@ function createIfBranch(node: ElementNode, dir: DirectiveNode): IfBranchNode {
|
|||||||
children: node.tagType === ElementTypes.TEMPLATE ? node.children : [node]
|
children: node.tagType === ElementTypes.TEMPLATE ? node.children : [node]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createCodegenNodeForBranch(
|
||||||
|
node: ElementNode,
|
||||||
|
dir: DirectiveNode,
|
||||||
|
index: number,
|
||||||
|
context: TransformContext
|
||||||
|
): ConditionalExpression | CallExpression {
|
||||||
|
if (dir.exp) {
|
||||||
|
return createConditionalExpression(
|
||||||
|
dir.exp,
|
||||||
|
createChildrenCodegenNode(node, index, context),
|
||||||
|
createCallExpression(context.helper(CREATE_BLOCK), [
|
||||||
|
context.helper(EMPTY)
|
||||||
|
])
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return createChildrenCodegenNode(node, index, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createChildrenCodegenNode(
|
||||||
|
node: ElementNode,
|
||||||
|
index: number,
|
||||||
|
{ helper }: TransformContext
|
||||||
|
): CallExpression {
|
||||||
|
const isTemplate = node.tagType === ElementTypes.TEMPLATE
|
||||||
|
const keyExp = `{ key: ${index} }`
|
||||||
|
if (isTemplate) {
|
||||||
|
return createCallExpression(helper(CREATE_BLOCK), [
|
||||||
|
helper(FRAGMENT),
|
||||||
|
keyExp,
|
||||||
|
node.children
|
||||||
|
])
|
||||||
|
} else {
|
||||||
|
let childCodegen = node.codegenNode!
|
||||||
|
if (childCodegen.callee === helper(APPLY_DIRECTIVES)) {
|
||||||
|
childCodegen = childCodegen.arguments[0] as CallExpression
|
||||||
|
}
|
||||||
|
// change child to a block
|
||||||
|
childCodegen.callee = helper(CREATE_BLOCK)
|
||||||
|
// branch key
|
||||||
|
const existingProps = childCodegen.arguments[1]
|
||||||
|
if (!existingProps || existingProps === `null`) {
|
||||||
|
childCodegen.arguments[1] = keyExp
|
||||||
|
} else {
|
||||||
|
// inject branch key if not already have a key
|
||||||
|
const props = existingProps as CallExpression | ObjectExpression
|
||||||
|
if (props.type === NodeTypes.JS_CALL_EXPRESSION) {
|
||||||
|
// merged props... add ours
|
||||||
|
// only inject key to object literal if it's the first argument so that
|
||||||
|
// if doesn't override user provided keys
|
||||||
|
const first = props.arguments[0] as string | JSChildNode
|
||||||
|
if (!isString(first) && first.type === NodeTypes.JS_OBJECT_EXPRESSION) {
|
||||||
|
first.properties.unshift(createKeyProperty(index))
|
||||||
|
} else {
|
||||||
|
props.arguments.unshift(keyExp)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
props.properties.unshift(createKeyProperty(index))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return childCodegen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createKeyProperty(index: number): Property {
|
||||||
|
return createObjectProperty(
|
||||||
|
createSimpleExpression(`key`, true),
|
||||||
|
createSimpleExpression(index + '', false)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -27,7 +27,7 @@ export const transformOn: DirectiveTransform = (dir, context) => {
|
|||||||
arg.loc
|
arg.loc
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
eventName = createCompoundExpression([`"on" + (`, arg, `)`], arg.loc)
|
eventName = createCompoundExpression([`"on" + (`, arg, `)`])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// already a compound epxression.
|
// already a compound epxression.
|
||||||
@ -40,8 +40,7 @@ export const transformOn: DirectiveTransform = (dir, context) => {
|
|||||||
return {
|
return {
|
||||||
props: createObjectProperty(
|
props: createObjectProperty(
|
||||||
eventName,
|
eventName,
|
||||||
exp || createSimpleExpression(`() => {}`, false, loc),
|
exp || createSimpleExpression(`() => {}`, false, loc)
|
||||||
loc
|
|
||||||
),
|
),
|
||||||
needRuntime: false
|
needRuntime: false
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,6 @@ function buildSlot(
|
|||||||
slotProps,
|
slotProps,
|
||||||
children,
|
children,
|
||||||
children.length ? children[0].loc : loc
|
children.length ? children[0].loc : loc
|
||||||
),
|
)
|
||||||
loc
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user