wip(compiler): codegen node w/ block optimization for v-for
This commit is contained in:
parent
aa134e7a4f
commit
e5bc17967d
@ -22,19 +22,6 @@ return function render() {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: codegen SlotFunctionExpression 1`] = `
|
||||
"
|
||||
return function render() {
|
||||
with (this) {
|
||||
return _createVNode(Comp, 0, {
|
||||
default: ({ foo }) => [
|
||||
_toString(foo)
|
||||
]
|
||||
})
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: codegen callExpression + objectExpression + arrayExpression 1`] = `
|
||||
"
|
||||
return function render() {
|
||||
@ -71,60 +58,6 @@ return function render() {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: codegen forNode 1`] = `
|
||||
"
|
||||
return function render() {
|
||||
with (this) {
|
||||
return _renderList(list, (v, k, i) => {
|
||||
return _toString(v)
|
||||
})
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: codegen forNode w/ prefixIdentifiers: true 1`] = `
|
||||
"
|
||||
return function render() {
|
||||
const _ctx = this
|
||||
return renderList(list, (v, k, i) => {
|
||||
return toString(v)
|
||||
})
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: codegen forNode w/ skipped key alias 1`] = `
|
||||
"
|
||||
return function render() {
|
||||
with (this) {
|
||||
return _renderList(list, (v, __key, i) => {
|
||||
return _toString(v)
|
||||
})
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: codegen forNode w/ skipped value alias 1`] = `
|
||||
"
|
||||
return function render() {
|
||||
with (this) {
|
||||
return _renderList(list, (__value, k, i) => {
|
||||
return _toString(v)
|
||||
})
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: codegen forNode w/ skipped value and key aliases 1`] = `
|
||||
"
|
||||
return function render() {
|
||||
with (this) {
|
||||
return _renderList(list, (__value, __key, i) => {
|
||||
return _toString(v)
|
||||
})
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: codegen function mode preamble 1`] = `
|
||||
"const _Vue = Vue
|
||||
|
||||
|
@ -15,11 +15,11 @@ return function render() {
|
||||
(_openBlock(), ok
|
||||
? _createBlock(\\"div\\", { key: 0 }, \\"yes\\")
|
||||
: _createBlock(_Fragment, { key: 1 }, \\"no\\")),
|
||||
_renderList(list, (value, index) => {
|
||||
(_openBlock(), _createBlock(_Fragment, null, _renderList(list, (value, index) => {
|
||||
return _createVNode(\\"div\\", null, [
|
||||
_createVNode(\\"span\\", null, _toString(value + index))
|
||||
])
|
||||
})
|
||||
})))
|
||||
], 2)
|
||||
}
|
||||
}"
|
||||
@ -38,11 +38,11 @@ return function render() {
|
||||
(openBlock(), (_ctx.ok)
|
||||
? createBlock(\\"div\\", { key: 0 }, \\"yes\\")
|
||||
: createBlock(Fragment, { key: 1 }, \\"no\\")),
|
||||
renderList(_ctx.list, (value, index) => {
|
||||
(openBlock(), createBlock(Fragment, null, renderList(_ctx.list, (value, index) => {
|
||||
return createVNode(\\"div\\", null, [
|
||||
createVNode(\\"span\\", null, toString(value + index))
|
||||
])
|
||||
})
|
||||
})))
|
||||
], 2)
|
||||
}"
|
||||
`;
|
||||
@ -60,11 +60,11 @@ export default function render() {
|
||||
(openBlock(), (_ctx.ok)
|
||||
? createBlock(\\"div\\", { key: 0 }, \\"yes\\")
|
||||
: createBlock(Fragment, { key: 1 }, \\"no\\")),
|
||||
_renderList(_ctx.list, (value, index) => {
|
||||
(openBlock(), createBlock(Fragment, null, renderList(_ctx.list, (value, index) => {
|
||||
return createVNode(\\"div\\", null, [
|
||||
createVNode(\\"span\\", null, _toString(value + index))
|
||||
])
|
||||
})
|
||||
})))
|
||||
], 2)
|
||||
}"
|
||||
`;
|
||||
|
@ -4,8 +4,6 @@ import {
|
||||
NodeTypes,
|
||||
RootNode,
|
||||
createSimpleExpression,
|
||||
Namespaces,
|
||||
ElementTypes,
|
||||
createObjectExpression,
|
||||
createObjectProperty,
|
||||
createArrayExpression,
|
||||
@ -15,12 +13,7 @@ import {
|
||||
createCallExpression,
|
||||
createConditionalExpression
|
||||
} from '../src'
|
||||
import {
|
||||
CREATE_VNODE,
|
||||
COMMENT,
|
||||
TO_STRING,
|
||||
RENDER_LIST
|
||||
} from '../src/runtimeConstants'
|
||||
import { CREATE_VNODE, COMMENT, TO_STRING } from '../src/runtimeConstants'
|
||||
import { createElementWithCodegen } from './testUtils'
|
||||
|
||||
function createRoot(options: Partial<RootNode> = {}): RootNode {
|
||||
@ -250,202 +243,202 @@ describe('compiler: codegen', () => {
|
||||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('forNode', () => {
|
||||
const { code } = generate(
|
||||
createRoot({
|
||||
children: [
|
||||
{
|
||||
type: NodeTypes.FOR,
|
||||
loc: locStub,
|
||||
source: createSimpleExpression(`list`, false, locStub),
|
||||
valueAlias: createSimpleExpression(`v`, false, locStub),
|
||||
keyAlias: createSimpleExpression(`k`, false, locStub),
|
||||
objectIndexAlias: createSimpleExpression(`i`, false, locStub),
|
||||
children: [createInterpolation(`v`, locStub)]
|
||||
}
|
||||
]
|
||||
})
|
||||
)
|
||||
expect(code).toMatch(
|
||||
`return _${RENDER_LIST}(list, (v, k, i) => {
|
||||
return _${TO_STRING}(v)
|
||||
})`
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
// test('forNode', () => {
|
||||
// const { code } = generate(
|
||||
// createRoot({
|
||||
// children: [
|
||||
// {
|
||||
// type: NodeTypes.FOR,
|
||||
// loc: locStub,
|
||||
// source: createSimpleExpression(`list`, false, locStub),
|
||||
// valueAlias: createSimpleExpression(`v`, false, locStub),
|
||||
// keyAlias: createSimpleExpression(`k`, false, locStub),
|
||||
// objectIndexAlias: createSimpleExpression(`i`, false, locStub),
|
||||
// children: [createInterpolation(`v`, locStub)]
|
||||
// }
|
||||
// ]
|
||||
// })
|
||||
// )
|
||||
// expect(code).toMatch(
|
||||
// `return _${RENDER_LIST}(list, (v, k, i) => {
|
||||
// return _${TO_STRING}(v)
|
||||
// })`
|
||||
// )
|
||||
// expect(code).toMatchSnapshot()
|
||||
// })
|
||||
|
||||
test('forNode w/ prefixIdentifiers: true', () => {
|
||||
const { code } = generate(
|
||||
createRoot({
|
||||
children: [
|
||||
{
|
||||
type: NodeTypes.FOR,
|
||||
loc: locStub,
|
||||
source: createSimpleExpression(`list`, false, locStub),
|
||||
valueAlias: createSimpleExpression(`v`, false, locStub),
|
||||
keyAlias: createSimpleExpression(`k`, false, locStub),
|
||||
objectIndexAlias: createSimpleExpression(`i`, false, locStub),
|
||||
children: [createInterpolation(`v`, locStub)]
|
||||
}
|
||||
]
|
||||
}),
|
||||
{
|
||||
prefixIdentifiers: true
|
||||
}
|
||||
)
|
||||
expect(code).toMatch(
|
||||
`return ${RENDER_LIST}(list, (v, k, i) => {
|
||||
return ${TO_STRING}(v)
|
||||
})`
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
// test('forNode w/ prefixIdentifiers: true', () => {
|
||||
// const { code } = generate(
|
||||
// createRoot({
|
||||
// children: [
|
||||
// {
|
||||
// type: NodeTypes.FOR,
|
||||
// loc: locStub,
|
||||
// source: createSimpleExpression(`list`, false, locStub),
|
||||
// valueAlias: createSimpleExpression(`v`, false, locStub),
|
||||
// keyAlias: createSimpleExpression(`k`, false, locStub),
|
||||
// objectIndexAlias: createSimpleExpression(`i`, false, locStub),
|
||||
// children: [createInterpolation(`v`, locStub)]
|
||||
// }
|
||||
// ]
|
||||
// }),
|
||||
// {
|
||||
// prefixIdentifiers: true
|
||||
// }
|
||||
// )
|
||||
// expect(code).toMatch(
|
||||
// `return ${RENDER_LIST}(list, (v, k, i) => {
|
||||
// return ${TO_STRING}(v)
|
||||
// })`
|
||||
// )
|
||||
// expect(code).toMatchSnapshot()
|
||||
// })
|
||||
|
||||
test('forNode w/ skipped value alias', () => {
|
||||
const { code } = generate(
|
||||
createRoot({
|
||||
children: [
|
||||
{
|
||||
type: NodeTypes.FOR,
|
||||
loc: locStub,
|
||||
source: createSimpleExpression(`list`, false, locStub),
|
||||
valueAlias: undefined,
|
||||
keyAlias: createSimpleExpression(`k`, false, locStub),
|
||||
objectIndexAlias: createSimpleExpression(`i`, false, locStub),
|
||||
children: [createInterpolation(`v`, locStub)]
|
||||
}
|
||||
]
|
||||
})
|
||||
)
|
||||
expect(code).toMatch(
|
||||
`return _${RENDER_LIST}(list, (__value, k, i) => {
|
||||
return _${TO_STRING}(v)
|
||||
})`
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
// test('forNode w/ skipped value alias', () => {
|
||||
// const { code } = generate(
|
||||
// createRoot({
|
||||
// children: [
|
||||
// {
|
||||
// type: NodeTypes.FOR,
|
||||
// loc: locStub,
|
||||
// source: createSimpleExpression(`list`, false, locStub),
|
||||
// valueAlias: undefined,
|
||||
// keyAlias: createSimpleExpression(`k`, false, locStub),
|
||||
// objectIndexAlias: createSimpleExpression(`i`, false, locStub),
|
||||
// children: [createInterpolation(`v`, locStub)]
|
||||
// }
|
||||
// ]
|
||||
// })
|
||||
// )
|
||||
// expect(code).toMatch(
|
||||
// `return _${RENDER_LIST}(list, (__value, k, i) => {
|
||||
// return _${TO_STRING}(v)
|
||||
// })`
|
||||
// )
|
||||
// expect(code).toMatchSnapshot()
|
||||
// })
|
||||
|
||||
test('forNode w/ skipped key alias', () => {
|
||||
const { code } = generate(
|
||||
createRoot({
|
||||
children: [
|
||||
{
|
||||
type: NodeTypes.FOR,
|
||||
loc: locStub,
|
||||
source: createSimpleExpression(`list`, false, locStub),
|
||||
valueAlias: createSimpleExpression(`v`, false, locStub),
|
||||
keyAlias: undefined,
|
||||
objectIndexAlias: createSimpleExpression(`i`, false, locStub),
|
||||
children: [createInterpolation(`v`, locStub)]
|
||||
}
|
||||
]
|
||||
})
|
||||
)
|
||||
expect(code).toMatch(
|
||||
`return _${RENDER_LIST}(list, (v, __key, i) => {
|
||||
return _${TO_STRING}(v)
|
||||
})`
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
// test('forNode w/ skipped key alias', () => {
|
||||
// const { code } = generate(
|
||||
// createRoot({
|
||||
// children: [
|
||||
// {
|
||||
// type: NodeTypes.FOR,
|
||||
// loc: locStub,
|
||||
// source: createSimpleExpression(`list`, false, locStub),
|
||||
// valueAlias: createSimpleExpression(`v`, false, locStub),
|
||||
// keyAlias: undefined,
|
||||
// objectIndexAlias: createSimpleExpression(`i`, false, locStub),
|
||||
// children: [createInterpolation(`v`, locStub)]
|
||||
// }
|
||||
// ]
|
||||
// })
|
||||
// )
|
||||
// expect(code).toMatch(
|
||||
// `return _${RENDER_LIST}(list, (v, __key, i) => {
|
||||
// return _${TO_STRING}(v)
|
||||
// })`
|
||||
// )
|
||||
// expect(code).toMatchSnapshot()
|
||||
// })
|
||||
|
||||
test('forNode w/ skipped value and key aliases', () => {
|
||||
const { code } = generate(
|
||||
createRoot({
|
||||
children: [
|
||||
{
|
||||
type: NodeTypes.FOR,
|
||||
loc: locStub,
|
||||
source: createSimpleExpression(`list`, false, locStub),
|
||||
valueAlias: undefined,
|
||||
keyAlias: undefined,
|
||||
objectIndexAlias: createSimpleExpression(`i`, false, locStub),
|
||||
children: [createInterpolation(`v`, locStub)]
|
||||
}
|
||||
]
|
||||
})
|
||||
)
|
||||
expect(code).toMatch(
|
||||
`return _${RENDER_LIST}(list, (__value, __key, i) => {
|
||||
return _${TO_STRING}(v)
|
||||
})`
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
// test('forNode w/ skipped value and key aliases', () => {
|
||||
// const { code } = generate(
|
||||
// createRoot({
|
||||
// children: [
|
||||
// {
|
||||
// type: NodeTypes.FOR,
|
||||
// loc: locStub,
|
||||
// source: createSimpleExpression(`list`, false, locStub),
|
||||
// valueAlias: undefined,
|
||||
// keyAlias: undefined,
|
||||
// objectIndexAlias: createSimpleExpression(`i`, false, locStub),
|
||||
// children: [createInterpolation(`v`, locStub)]
|
||||
// }
|
||||
// ]
|
||||
// })
|
||||
// )
|
||||
// expect(code).toMatch(
|
||||
// `return _${RENDER_LIST}(list, (__value, __key, i) => {
|
||||
// return _${TO_STRING}(v)
|
||||
// })`
|
||||
// )
|
||||
// expect(code).toMatchSnapshot()
|
||||
// })
|
||||
|
||||
test('SlotFunctionExpression', () => {
|
||||
const { code } = generate(
|
||||
createRoot({
|
||||
children: [
|
||||
{
|
||||
type: NodeTypes.ELEMENT,
|
||||
tagType: ElementTypes.COMPONENT,
|
||||
ns: Namespaces.HTML,
|
||||
isSelfClosing: false,
|
||||
tag: `Comp`,
|
||||
loc: locStub,
|
||||
props: [],
|
||||
children: [],
|
||||
codegenNode: {
|
||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||
loc: locStub,
|
||||
callee: `_${CREATE_VNODE}`,
|
||||
arguments: [
|
||||
`Comp`,
|
||||
`0`,
|
||||
{
|
||||
type: NodeTypes.JS_OBJECT_EXPRESSION,
|
||||
loc: locStub,
|
||||
properties: [
|
||||
{
|
||||
type: NodeTypes.JS_PROPERTY,
|
||||
loc: locStub,
|
||||
key: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
isStatic: true,
|
||||
content: `default`,
|
||||
loc: locStub
|
||||
},
|
||||
value: {
|
||||
type: NodeTypes.JS_SLOT_FUNCTION,
|
||||
loc: locStub,
|
||||
params: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
isStatic: false,
|
||||
content: `{ foo }`,
|
||||
loc: locStub
|
||||
},
|
||||
returns: [
|
||||
{
|
||||
type: NodeTypes.INTERPOLATION,
|
||||
loc: locStub,
|
||||
content: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
isStatic: false,
|
||||
content: `foo`,
|
||||
loc: locStub
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
)
|
||||
expect(code).toMatch(
|
||||
`return _createVNode(Comp, 0, {
|
||||
default: ({ foo }) => [
|
||||
_toString(foo)
|
||||
]
|
||||
})`
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
// test('SlotFunctionExpression', () => {
|
||||
// const { code } = generate(
|
||||
// createRoot({
|
||||
// children: [
|
||||
// {
|
||||
// type: NodeTypes.ELEMENT,
|
||||
// tagType: ElementTypes.COMPONENT,
|
||||
// ns: Namespaces.HTML,
|
||||
// isSelfClosing: false,
|
||||
// tag: `Comp`,
|
||||
// loc: locStub,
|
||||
// props: [],
|
||||
// children: [],
|
||||
// codegenNode: {
|
||||
// type: NodeTypes.JS_CALL_EXPRESSION,
|
||||
// loc: locStub,
|
||||
// callee: `_${CREATE_VNODE}`,
|
||||
// arguments: [
|
||||
// `Comp`,
|
||||
// `0`,
|
||||
// {
|
||||
// type: NodeTypes.JS_OBJECT_EXPRESSION,
|
||||
// loc: locStub,
|
||||
// properties: [
|
||||
// {
|
||||
// type: NodeTypes.JS_PROPERTY,
|
||||
// loc: locStub,
|
||||
// key: {
|
||||
// type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
// isStatic: true,
|
||||
// content: `default`,
|
||||
// loc: locStub
|
||||
// },
|
||||
// value: {
|
||||
// type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
// loc: locStub,
|
||||
// params: {
|
||||
// type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
// isStatic: false,
|
||||
// content: `{ foo }`,
|
||||
// loc: locStub
|
||||
// },
|
||||
// returns: [
|
||||
// {
|
||||
// type: NodeTypes.INTERPOLATION,
|
||||
// loc: locStub,
|
||||
// content: {
|
||||
// type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
// isStatic: false,
|
||||
// content: `foo`,
|
||||
// loc: locStub
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// })
|
||||
// )
|
||||
// expect(code).toMatch(
|
||||
// `return _createVNode(Comp, 0, {
|
||||
// default: ({ foo }) => [
|
||||
// _toString(foo)
|
||||
// ]
|
||||
// })`
|
||||
// )
|
||||
// expect(code).toMatchSnapshot()
|
||||
// })
|
||||
|
||||
test('callExpression + objectExpression + arrayExpression', () => {
|
||||
const { code } = generate(
|
||||
|
@ -59,7 +59,7 @@ describe('compiler: transform component slots', () => {
|
||||
expect(slots).toMatchObject(
|
||||
createSlotMatcher({
|
||||
default: {
|
||||
type: NodeTypes.JS_SLOT_FUNCTION,
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
params: undefined,
|
||||
returns: [
|
||||
{
|
||||
@ -81,7 +81,7 @@ describe('compiler: transform component slots', () => {
|
||||
expect(slots).toMatchObject(
|
||||
createSlotMatcher({
|
||||
default: {
|
||||
type: NodeTypes.JS_SLOT_FUNCTION,
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
params: {
|
||||
type: NodeTypes.COMPOUND_EXPRESSION,
|
||||
children: [`{ `, { content: `foo` }, ` }`]
|
||||
@ -121,7 +121,7 @@ describe('compiler: transform component slots', () => {
|
||||
expect(slots).toMatchObject(
|
||||
createSlotMatcher({
|
||||
one: {
|
||||
type: NodeTypes.JS_SLOT_FUNCTION,
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
params: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: `{ foo }`,
|
||||
@ -143,7 +143,7 @@ describe('compiler: transform component slots', () => {
|
||||
]
|
||||
},
|
||||
two: {
|
||||
type: NodeTypes.JS_SLOT_FUNCTION,
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
params: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: `{ bar }`,
|
||||
@ -184,7 +184,7 @@ describe('compiler: transform component slots', () => {
|
||||
expect(slots).toMatchObject(
|
||||
createSlotMatcher({
|
||||
'[_ctx.one]': {
|
||||
type: NodeTypes.JS_SLOT_FUNCTION,
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
params: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: `{ foo }`,
|
||||
@ -206,7 +206,7 @@ describe('compiler: transform component slots', () => {
|
||||
]
|
||||
},
|
||||
'[_ctx.two]': {
|
||||
type: NodeTypes.JS_SLOT_FUNCTION,
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
params: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: `{ bar }`,
|
||||
@ -247,7 +247,7 @@ describe('compiler: transform component slots', () => {
|
||||
expect(slots).toMatchObject(
|
||||
createSlotMatcher({
|
||||
default: {
|
||||
type: NodeTypes.JS_SLOT_FUNCTION,
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
params: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: `{ foo }`,
|
||||
@ -263,7 +263,7 @@ describe('compiler: transform component slots', () => {
|
||||
`null`,
|
||||
createSlotMatcher({
|
||||
default: {
|
||||
type: NodeTypes.JS_SLOT_FUNCTION,
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
params: {
|
||||
type: NodeTypes.COMPOUND_EXPRESSION,
|
||||
children: [`{ `, { content: `bar` }, ` }`]
|
||||
|
@ -28,7 +28,7 @@ export const enum NodeTypes {
|
||||
JS_OBJECT_EXPRESSION,
|
||||
JS_PROPERTY,
|
||||
JS_ARRAY_EXPRESSION,
|
||||
JS_SLOT_FUNCTION,
|
||||
JS_FUNCTION_EXPRESSION,
|
||||
JS_SEQUENCE_EXPRESSION,
|
||||
JS_CONDITIONAL_EXPRESSION
|
||||
}
|
||||
@ -158,6 +158,7 @@ export interface ForNode extends Node {
|
||||
keyAlias: ExpressionNode | undefined
|
||||
objectIndexAlias: ExpressionNode | undefined
|
||||
children: TemplateChildNode[]
|
||||
codegenNode: SequenceExpression
|
||||
}
|
||||
|
||||
// We also include a number of JavaScript AST nodes for code generation.
|
||||
@ -168,7 +169,7 @@ export type JSChildNode =
|
||||
| ObjectExpression
|
||||
| ArrayExpression
|
||||
| ExpressionNode
|
||||
| SlotFunctionExpression
|
||||
| FunctionExpression
|
||||
| ConditionalExpression
|
||||
| SequenceExpression
|
||||
|
||||
@ -194,10 +195,11 @@ export interface ArrayExpression extends Node {
|
||||
elements: Array<string | JSChildNode>
|
||||
}
|
||||
|
||||
export interface SlotFunctionExpression extends Node {
|
||||
type: NodeTypes.JS_SLOT_FUNCTION
|
||||
params: ExpressionNode | undefined
|
||||
returns: TemplateChildNode[]
|
||||
export interface FunctionExpression extends Node {
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION
|
||||
params: ExpressionNode | ExpressionNode[] | undefined
|
||||
returns: TemplateChildNode | TemplateChildNode[]
|
||||
newline: boolean
|
||||
}
|
||||
|
||||
export interface SequenceExpression extends Node {
|
||||
@ -235,7 +237,7 @@ export function createArrayExpression(
|
||||
}
|
||||
|
||||
export function createObjectExpression(
|
||||
properties: Property[],
|
||||
properties: ObjectExpression['properties'],
|
||||
loc: SourceLocation = locStub
|
||||
): ObjectExpression {
|
||||
return {
|
||||
@ -246,8 +248,8 @@ export function createObjectExpression(
|
||||
}
|
||||
|
||||
export function createObjectProperty(
|
||||
key: ExpressionNode,
|
||||
value: JSChildNode
|
||||
key: Property['key'],
|
||||
value: Property['value']
|
||||
): Property {
|
||||
return {
|
||||
type: NodeTypes.JS_PROPERTY,
|
||||
@ -258,8 +260,8 @@ export function createObjectProperty(
|
||||
}
|
||||
|
||||
export function createSimpleExpression(
|
||||
content: string,
|
||||
isStatic: boolean,
|
||||
content: SimpleExpressionNode['content'],
|
||||
isStatic: SimpleExpressionNode['isStatic'],
|
||||
loc: SourceLocation = locStub
|
||||
): SimpleExpressionNode {
|
||||
return {
|
||||
@ -271,7 +273,7 @@ export function createSimpleExpression(
|
||||
}
|
||||
|
||||
export function createInterpolation(
|
||||
content: string | CompoundExpressionNode,
|
||||
content: InterpolationNode['content'] | string,
|
||||
loc: SourceLocation
|
||||
): InterpolationNode {
|
||||
return {
|
||||
@ -294,7 +296,7 @@ export function createCompoundExpression(
|
||||
}
|
||||
|
||||
export function createCallExpression(
|
||||
callee: string,
|
||||
callee: CallExpression['callee'],
|
||||
args: CallExpression['arguments'] = [],
|
||||
loc: SourceLocation = locStub
|
||||
): CallExpression {
|
||||
@ -307,20 +309,22 @@ export function createCallExpression(
|
||||
}
|
||||
|
||||
export function createFunctionExpression(
|
||||
params: ExpressionNode | undefined,
|
||||
returns: TemplateChildNode[],
|
||||
params: FunctionExpression['params'],
|
||||
returns: FunctionExpression['returns'],
|
||||
newline: boolean = false,
|
||||
loc: SourceLocation = locStub
|
||||
): SlotFunctionExpression {
|
||||
): FunctionExpression {
|
||||
return {
|
||||
type: NodeTypes.JS_SLOT_FUNCTION,
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
params,
|
||||
returns,
|
||||
newline,
|
||||
loc
|
||||
}
|
||||
}
|
||||
|
||||
export function createSequenceExpression(
|
||||
expressions: JSChildNode[]
|
||||
expressions: SequenceExpression['expressions']
|
||||
): SequenceExpression {
|
||||
return {
|
||||
type: NodeTypes.JS_SEQUENCE_EXPRESSION,
|
||||
@ -330,9 +334,9 @@ export function createSequenceExpression(
|
||||
}
|
||||
|
||||
export function createConditionalExpression(
|
||||
test: ExpressionNode,
|
||||
consequent: JSChildNode,
|
||||
alternate: JSChildNode
|
||||
test: ConditionalExpression['test'],
|
||||
consequent: ConditionalExpression['consequent'],
|
||||
alternate: ConditionalExpression['alternate']
|
||||
): ConditionalExpression {
|
||||
return {
|
||||
type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
|
||||
|
@ -2,8 +2,6 @@ import {
|
||||
RootNode,
|
||||
TemplateChildNode,
|
||||
ElementNode,
|
||||
IfNode,
|
||||
ForNode,
|
||||
TextNode,
|
||||
CommentNode,
|
||||
ExpressionNode,
|
||||
@ -18,7 +16,7 @@ import {
|
||||
CompoundExpressionNode,
|
||||
SimpleExpressionNode,
|
||||
ElementTypes,
|
||||
SlotFunctionExpression,
|
||||
FunctionExpression,
|
||||
SequenceExpression,
|
||||
ConditionalExpression
|
||||
} from './ast'
|
||||
@ -29,12 +27,7 @@ import {
|
||||
isSimpleIdentifier
|
||||
} from './utils'
|
||||
import { isString, isArray } from '@vue/shared'
|
||||
import {
|
||||
RENDER_LIST,
|
||||
TO_STRING,
|
||||
CREATE_VNODE,
|
||||
COMMENT
|
||||
} from './runtimeConstants'
|
||||
import { TO_STRING, CREATE_VNODE, COMMENT } from './runtimeConstants'
|
||||
|
||||
type CodegenNode = TemplateChildNode | JSChildNode
|
||||
|
||||
@ -342,7 +335,15 @@ function genNodeList(
|
||||
function genNode(node: CodegenNode, context: CodegenContext) {
|
||||
switch (node.type) {
|
||||
case NodeTypes.ELEMENT:
|
||||
genElement(node, context)
|
||||
case NodeTypes.IF:
|
||||
case NodeTypes.FOR:
|
||||
__DEV__ &&
|
||||
assert(
|
||||
node.codegenNode != null,
|
||||
`Codegen node is missing for element/if/for node. ` +
|
||||
`Apply appropriate transforms first.`
|
||||
)
|
||||
genNode(node.codegenNode!, context)
|
||||
break
|
||||
case NodeTypes.TEXT:
|
||||
genText(node, context)
|
||||
@ -359,12 +360,6 @@ function genNode(node: CodegenNode, context: CodegenContext) {
|
||||
case NodeTypes.COMMENT:
|
||||
genComment(node, context)
|
||||
break
|
||||
case NodeTypes.IF:
|
||||
genIf(node, context)
|
||||
break
|
||||
case NodeTypes.FOR:
|
||||
genFor(node, context)
|
||||
break
|
||||
case NodeTypes.JS_CALL_EXPRESSION:
|
||||
genCallExpression(node, context)
|
||||
break
|
||||
@ -374,8 +369,8 @@ function genNode(node: CodegenNode, context: CodegenContext) {
|
||||
case NodeTypes.JS_ARRAY_EXPRESSION:
|
||||
genArrayExpression(node, context)
|
||||
break
|
||||
case NodeTypes.JS_SLOT_FUNCTION:
|
||||
genSlotFunction(node, context)
|
||||
case NodeTypes.JS_FUNCTION_EXPRESSION:
|
||||
genFunctionExpression(node, context)
|
||||
break
|
||||
case NodeTypes.JS_SEQUENCE_EXPRESSION:
|
||||
genSequenceExpression(node, context)
|
||||
@ -394,16 +389,6 @@ function genNode(node: CodegenNode, context: CodegenContext) {
|
||||
}
|
||||
}
|
||||
|
||||
function genElement(node: ElementNode, context: CodegenContext) {
|
||||
__DEV__ &&
|
||||
assert(
|
||||
node.codegenNode != null,
|
||||
`AST is not transformed for codegen. ` +
|
||||
`Apply appropriate transforms first.`
|
||||
)
|
||||
genCallExpression(node.codegenNode!, context, false)
|
||||
}
|
||||
|
||||
function genText(
|
||||
node: TextNode | SimpleExpressionNode,
|
||||
context: CodegenContext
|
||||
@ -469,56 +454,10 @@ function genComment(node: CommentNode, context: CodegenContext) {
|
||||
}
|
||||
}
|
||||
|
||||
// control flow
|
||||
function genIf(node: IfNode, context: CodegenContext) {
|
||||
genNode(node.codegenNode, context)
|
||||
}
|
||||
|
||||
function genFor(node: ForNode, context: CodegenContext) {
|
||||
const { push, helper, indent, deindent } = context
|
||||
const { source, keyAlias, valueAlias, objectIndexAlias, children } = node
|
||||
push(`${helper(RENDER_LIST)}(`, node, true)
|
||||
genNode(source, context)
|
||||
push(`, (`)
|
||||
if (valueAlias) {
|
||||
genNode(valueAlias, context)
|
||||
}
|
||||
if (keyAlias) {
|
||||
if (!valueAlias) {
|
||||
push(`__value`)
|
||||
}
|
||||
push(`, `)
|
||||
genNode(keyAlias, context)
|
||||
}
|
||||
if (objectIndexAlias) {
|
||||
if (!keyAlias) {
|
||||
if (!valueAlias) {
|
||||
push(`__value, __key`)
|
||||
} else {
|
||||
push(`, __key`)
|
||||
}
|
||||
}
|
||||
push(`, `)
|
||||
genNode(objectIndexAlias, context)
|
||||
}
|
||||
push(`) => {`)
|
||||
indent()
|
||||
push(`return `)
|
||||
genChildren(children, context, true)
|
||||
deindent()
|
||||
push(`})`)
|
||||
}
|
||||
|
||||
// JavaScript
|
||||
function genCallExpression(
|
||||
node: CallExpression,
|
||||
context: CodegenContext,
|
||||
multilines = false
|
||||
) {
|
||||
function genCallExpression(node: CallExpression, context: CodegenContext) {
|
||||
context.push(node.callee + `(`, node, true)
|
||||
multilines && context.indent()
|
||||
genNodeList(node.arguments, context, multilines)
|
||||
multilines && context.deindent()
|
||||
genNodeList(node.arguments, context)
|
||||
context.push(`)`)
|
||||
}
|
||||
|
||||
@ -554,15 +493,33 @@ function genArrayExpression(node: ArrayExpression, context: CodegenContext) {
|
||||
genNodeListAsArray(node.elements, context)
|
||||
}
|
||||
|
||||
function genSlotFunction(
|
||||
node: SlotFunctionExpression,
|
||||
function genFunctionExpression(
|
||||
node: FunctionExpression,
|
||||
context: CodegenContext
|
||||
) {
|
||||
context.push(`(`, node)
|
||||
if (node.params) genNode(node.params, context)
|
||||
context.push(`) => `)
|
||||
// pre-normalized slots should always return arrays
|
||||
genNodeListAsArray(node.returns, context)
|
||||
const { push, indent, deindent } = context
|
||||
const { params, returns, newline } = node
|
||||
push(`(`, node)
|
||||
if (isArray(params)) {
|
||||
genNodeList(params, context)
|
||||
} else if (params) {
|
||||
genNode(params, context)
|
||||
}
|
||||
push(`) => `)
|
||||
if (newline) {
|
||||
push(`{`)
|
||||
indent()
|
||||
push(`return `)
|
||||
}
|
||||
if (isArray(returns)) {
|
||||
genNodeListAsArray(returns, context)
|
||||
} else {
|
||||
genNode(returns, context)
|
||||
}
|
||||
if (newline) {
|
||||
deindent()
|
||||
push(`}`)
|
||||
}
|
||||
}
|
||||
|
||||
function genConditionalExpression(
|
||||
|
@ -7,11 +7,20 @@ import {
|
||||
ExpressionNode,
|
||||
createSimpleExpression,
|
||||
SourceLocation,
|
||||
SimpleExpressionNode
|
||||
SimpleExpressionNode,
|
||||
createSequenceExpression,
|
||||
createCallExpression,
|
||||
createFunctionExpression,
|
||||
ElementTypes
|
||||
} from '../ast'
|
||||
import { createCompilerError, ErrorCodes } from '../errors'
|
||||
import { getInnerRange } from '../utils'
|
||||
import { RENDER_LIST } from '../runtimeConstants'
|
||||
import {
|
||||
RENDER_LIST,
|
||||
OPEN_BLOCK,
|
||||
CREATE_BLOCK,
|
||||
FRAGMENT
|
||||
} from '../runtimeConstants'
|
||||
import { processExpression } from './transformExpression'
|
||||
|
||||
export const transformFor = createStructuralDirectiveTransform(
|
||||
@ -26,9 +35,14 @@ export const transformFor = createStructuralDirectiveTransform(
|
||||
)
|
||||
|
||||
if (parseResult) {
|
||||
context.helper(RENDER_LIST)
|
||||
const { helper, addIdentifiers, removeIdentifiers } = context
|
||||
const { source, value, key, index } = parseResult
|
||||
|
||||
const codegenNode = createSequenceExpression([
|
||||
createCallExpression(helper(OPEN_BLOCK))
|
||||
// to be filled in on exit after children traverse
|
||||
])
|
||||
|
||||
context.replaceNode({
|
||||
type: NodeTypes.FOR,
|
||||
loc: dir.loc,
|
||||
@ -36,19 +50,52 @@ export const transformFor = createStructuralDirectiveTransform(
|
||||
valueAlias: value,
|
||||
keyAlias: key,
|
||||
objectIndexAlias: index,
|
||||
children: [node]
|
||||
children: [node],
|
||||
codegenNode
|
||||
})
|
||||
|
||||
if (!__BROWSER__) {
|
||||
// scope management
|
||||
const { addIdentifiers, removeIdentifiers } = context
|
||||
|
||||
// inject identifiers to context
|
||||
value && addIdentifiers(value)
|
||||
key && addIdentifiers(key)
|
||||
index && addIdentifiers(index)
|
||||
}
|
||||
|
||||
return () => {
|
||||
const params: ExpressionNode[] = []
|
||||
if (value) {
|
||||
params.push(value)
|
||||
}
|
||||
if (key) {
|
||||
if (!value) {
|
||||
params.push(createSimpleExpression(`_`, false))
|
||||
}
|
||||
params.push(key)
|
||||
}
|
||||
if (index) {
|
||||
if (!key) {
|
||||
params.push(createSimpleExpression(`__`, false))
|
||||
}
|
||||
params.push(index)
|
||||
}
|
||||
|
||||
codegenNode.expressions.push(
|
||||
createCallExpression(helper(CREATE_BLOCK), [
|
||||
helper(FRAGMENT),
|
||||
`null`,
|
||||
createCallExpression(helper(RENDER_LIST), [
|
||||
source,
|
||||
createFunctionExpression(
|
||||
params,
|
||||
node.tagType === ElementTypes.TEMPLATE ? node.children : node,
|
||||
true /* force newline to make it more readable */
|
||||
)
|
||||
])
|
||||
])
|
||||
)
|
||||
|
||||
if (!__BROWSER__) {
|
||||
value && removeIdentifiers(value)
|
||||
key && removeIdentifiers(key)
|
||||
index && removeIdentifiers(index)
|
||||
|
@ -20,7 +20,9 @@ import {
|
||||
ObjectExpression,
|
||||
createObjectProperty,
|
||||
Property,
|
||||
ExpressionNode
|
||||
ExpressionNode,
|
||||
TemplateChildNode,
|
||||
FunctionExpression
|
||||
} from '../ast'
|
||||
import { createCompilerError, ErrorCodes } from '../errors'
|
||||
import { processExpression } from './transformExpression'
|
||||
@ -68,7 +70,7 @@ export const transformIf = createStructuralDirectiveTransform(
|
||||
// transformed.
|
||||
return () => {
|
||||
codegenNode.expressions.push(
|
||||
createCodegenNodeForBranch(node, branch, 0, context)
|
||||
createCodegenNodeForBranch(branch, 0, context)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@ -105,7 +107,6 @@ export const transformIf = createStructuralDirectiveTransform(
|
||||
parentCondition = parentCondition.alternate
|
||||
} else {
|
||||
parentCondition.alternate = createCodegenNodeForBranch(
|
||||
node,
|
||||
branch,
|
||||
sibling.branches.length - 1,
|
||||
context
|
||||
@ -139,7 +140,6 @@ function createIfBranch(node: ElementNode, dir: DirectiveNode): IfBranchNode {
|
||||
}
|
||||
|
||||
function createCodegenNodeForBranch(
|
||||
node: ElementNode,
|
||||
branch: IfBranchNode,
|
||||
index: number,
|
||||
context: TransformContext
|
||||
@ -147,41 +147,50 @@ function createCodegenNodeForBranch(
|
||||
if (branch.condition) {
|
||||
return createConditionalExpression(
|
||||
branch.condition,
|
||||
createChildrenCodegenNode(node, branch, index, context),
|
||||
createChildrenCodegenNode(branch, index, context),
|
||||
createCallExpression(context.helper(CREATE_BLOCK), [
|
||||
context.helper(EMPTY)
|
||||
])
|
||||
)
|
||||
} else {
|
||||
return createChildrenCodegenNode(node, branch, index, context)
|
||||
return createChildrenCodegenNode(branch, index, context)
|
||||
}
|
||||
}
|
||||
|
||||
function createChildrenCodegenNode(
|
||||
node: ElementNode,
|
||||
branch: IfBranchNode,
|
||||
index: number,
|
||||
{ helper }: TransformContext
|
||||
): CallExpression {
|
||||
const isTemplate = node.tagType === ElementTypes.TEMPLATE
|
||||
const keyExp = `{ key: ${index} }`
|
||||
if (isTemplate) {
|
||||
const { children } = branch
|
||||
const child = children[0]
|
||||
const needFragmentWrapper =
|
||||
children.length > 1 || child.type !== NodeTypes.ELEMENT
|
||||
if (needFragmentWrapper) {
|
||||
let fragmentChildren: TemplateChildNode[] | FunctionExpression = children
|
||||
// optimize away nested fragments when child is a ForNode
|
||||
if (children.length === 1 && child.type === NodeTypes.FOR) {
|
||||
fragmentChildren = (child.codegenNode.expressions[1] as CallExpression)
|
||||
.arguments[2] as FunctionExpression
|
||||
}
|
||||
return createCallExpression(helper(CREATE_BLOCK), [
|
||||
helper(FRAGMENT),
|
||||
keyExp,
|
||||
branch.children
|
||||
fragmentChildren
|
||||
])
|
||||
} else {
|
||||
let childCodegen = node.codegenNode!
|
||||
if (childCodegen.callee.includes(APPLY_DIRECTIVES)) {
|
||||
childCodegen = childCodegen.arguments[0] as CallExpression
|
||||
const childCodegen = (child as ElementNode).codegenNode!
|
||||
let vnodeCall = childCodegen
|
||||
if (vnodeCall.callee.includes(APPLY_DIRECTIVES)) {
|
||||
vnodeCall = vnodeCall.arguments[0] as CallExpression
|
||||
}
|
||||
// change child to a block
|
||||
childCodegen.callee = helper(CREATE_BLOCK)
|
||||
vnodeCall.callee = helper(CREATE_BLOCK)
|
||||
// branch key
|
||||
const existingProps = childCodegen.arguments[1]
|
||||
const existingProps = vnodeCall.arguments[1]
|
||||
if (!existingProps || existingProps === `null`) {
|
||||
childCodegen.arguments[1] = keyExp
|
||||
vnodeCall.arguments[1] = keyExp
|
||||
} else {
|
||||
// inject branch key if not already have a key
|
||||
const props = existingProps as
|
||||
@ -202,13 +211,13 @@ function createChildrenCodegenNode(
|
||||
props.properties.unshift(createKeyProperty(index))
|
||||
} else {
|
||||
// single v-bind with expression
|
||||
childCodegen.arguments[1] = createCallExpression(helper(MERGE_PROPS), [
|
||||
vnodeCall.arguments[1] = createCallExpression(helper(MERGE_PROPS), [
|
||||
keyExp,
|
||||
props
|
||||
])
|
||||
}
|
||||
}
|
||||
return node.codegenNode!
|
||||
return childCodegen
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,6 +143,7 @@ function buildSlot(
|
||||
createFunctionExpression(
|
||||
slotProps,
|
||||
children,
|
||||
false,
|
||||
children.length ? children[0].loc : loc
|
||||
)
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user