"
return function render() {
with (this) {
- return createVNode(\\"div\\", {
+ return _createVNode(\\"div\\", {
id: \\"foo\\",
[prop]: bar,
[foo + bar]: bar
}, [
- createVNode(\\"p\\", { \\"some-key\\": \\"foo\\" })
+ _createVNode(\\"p\\", { \\"some-key\\": \\"foo\\" })
], [
foo,
- createVNode(\\"p\\")
+ _createVNode(\\"p\\")
])
}
}"
}"
`;
+exports[`compiler: codegen assets 1`] = `
+"
+return function render() {
+ with (this) {
+ const _component_Foo = _resolveComponent(\\"Foo\\")
+ const _component_barbaz = _resolveComponent(\\"bar-baz\\")
+ const _directive_my_dir = _resolveDirective(\\"my_dir\\")
+
+ return null
+ }
+}"
+`;
+
exports[`compiler: codegen comment 1`] = `
"
return function render() {
return function render() {
with (this) {
- const { helperOne: _helperOne, helperTwo: _helperTwo } = _Vue
+ const { createVNode: _createVNode, resolveDirective: _resolveDirective } = _Vue
return null
}
`;
exports[`compiler: codegen function mode preamble w/ prefixIdentifiers: true 1`] = `
-"const { helperOne, helperTwo } = Vue
+"const { createVNode, resolveDirective } = Vue
return function render() {
const _ctx = this
`;
exports[`compiler: codegen module mode preamble 1`] = `
-"import { helperOne, helperTwo } from \\"vue\\"
+"import { createVNode, resolveDirective } from \\"vue\\"
export default function render() {
const _ctx = this
}"
`;
-exports[`compiler: codegen statements 1`] = `
-"
-return function render() {
- with (this) {
- const a = 1
- const b = 2
-
- return null
- }
-}"
-`;
-
exports[`compiler: codegen static text 1`] = `
"
return function render() {
id: \\"foo\\",
class: _ctx.bar.baz
}, [
- _toString(_ctx.world.burn()),
+ toString(_ctx.world.burn()),
(openBlock(), (_ctx.ok)
? createBlock(\\"div\\", { key: 0 }, \\"yes\\")
: createBlock(Fragment, { key: 1 }, [\\"no\\"])),
(openBlock(), createBlock(Fragment, null, renderList(_ctx.list, (value, index) => {
return (openBlock(), createBlock(\\"div\\", null, [
- createVNode(\\"span\\", null, _toString(value + index), 1 /* TEXT */)
+ createVNode(\\"span\\", null, toString(value + index), 1 /* TEXT */)
]))
}), 128 /* UNKEYED_FRAGMENT */))
], 2 /* CLASS */))
createCallExpression,
createConditionalExpression
} from '../src'
-import { CREATE_VNODE, COMMENT, TO_STRING } from '../src/runtimeConstants'
+import {
+ CREATE_VNODE,
+ COMMENT,
+ TO_STRING,
+ RESOLVE_DIRECTIVE,
+ helperNameMap,
+ RESOLVE_COMPONENT
+} from '../src/runtimeHelpers'
import { createElementWithCodegen } from './testUtils'
function createRoot(options: Partial<RootNode> = {}): RootNode {
return {
type: NodeTypes.ROOT,
children: [],
- imports: [],
- statements: [],
+ helpers: [],
+ components: [],
+ directives: [],
hoists: [],
codegenNode: undefined,
loc: locStub,
describe('compiler: codegen', () => {
test('module mode preamble', () => {
const root = createRoot({
- imports: [`helperOne`, `helperTwo`]
+ helpers: [CREATE_VNODE, RESOLVE_DIRECTIVE]
})
const { code } = generate(root, { mode: 'module' })
- expect(code).toMatch(`import { helperOne, helperTwo } from "vue"`)
+ expect(code).toMatch(
+ `import { ${helperNameMap[CREATE_VNODE]}, ${
+ helperNameMap[RESOLVE_DIRECTIVE]
+ } } from "vue"`
+ )
expect(code).toMatchSnapshot()
})
test('function mode preamble', () => {
const root = createRoot({
- imports: [`helperOne`, `helperTwo`]
+ helpers: [CREATE_VNODE, RESOLVE_DIRECTIVE]
})
const { code } = generate(root, { mode: 'function' })
expect(code).toMatch(`const _Vue = Vue`)
expect(code).toMatch(
- `const { helperOne: _helperOne, helperTwo: _helperTwo } = _Vue`
+ `const { ${helperNameMap[CREATE_VNODE]}: _${
+ helperNameMap[CREATE_VNODE]
+ }, ${helperNameMap[RESOLVE_DIRECTIVE]}: _${
+ helperNameMap[RESOLVE_DIRECTIVE]
+ } } = _Vue`
)
expect(code).toMatchSnapshot()
})
test('function mode preamble w/ prefixIdentifiers: true', () => {
const root = createRoot({
- imports: [`helperOne`, `helperTwo`]
+ helpers: [CREATE_VNODE, RESOLVE_DIRECTIVE]
})
const { code } = generate(root, {
mode: 'function',
prefixIdentifiers: true
})
expect(code).not.toMatch(`const _Vue = Vue`)
- expect(code).toMatch(`const { helperOne, helperTwo } = Vue`)
+ expect(code).toMatch(
+ `const { ${helperNameMap[CREATE_VNODE]}, ${
+ helperNameMap[RESOLVE_DIRECTIVE]
+ } } = Vue`
+ )
expect(code).toMatchSnapshot()
})
- test('statements', () => {
+ test('assets', () => {
const root = createRoot({
- statements: [`const a = 1`, `const b = 2`]
+ components: [`Foo`, `bar-baz`],
+ directives: [`my_dir`]
})
const { code } = generate(root, { mode: 'function' })
- expect(code).toMatch(`const a = 1\n`)
- expect(code).toMatch(`const b = 2\n`)
+ expect(code).toMatch(
+ `const _component_Foo = _${helperNameMap[RESOLVE_COMPONENT]}("Foo")\n`
+ )
+ expect(code).toMatch(
+ `const _component_barbaz = _${
+ helperNameMap[RESOLVE_COMPONENT]
+ }("bar-baz")\n`
+ )
+ expect(code).toMatch(
+ `const _directive_my_dir = _${
+ helperNameMap[RESOLVE_DIRECTIVE]
+ }("my_dir")\n`
+ )
expect(code).toMatchSnapshot()
})
codegenNode: createInterpolation(`hello`, locStub)
})
)
- expect(code).toMatch(`return _${TO_STRING}(hello)`)
+ expect(code).toMatch(`return _${helperNameMap[TO_STRING]}(hello)`)
expect(code).toMatchSnapshot()
})
}
})
)
- expect(code).toMatch(`return _${CREATE_VNODE}(_${COMMENT}, 0, "foo")`)
+ expect(code).toMatch(
+ `return _${helperNameMap[CREATE_VNODE]}(_${
+ helperNameMap[COMMENT]
+ }, 0, "foo")`
+ )
expect(code).toMatchSnapshot()
})
])
})
)
- expect(code).toMatch(`return _ctx.foo + _${TO_STRING}(bar)`)
+ expect(code).toMatch(`return _ctx.foo + _${helperNameMap[TO_STRING]}(bar)`)
expect(code).toMatchSnapshot()
})
})
)
expect(code).toMatch(`
- return ${CREATE_VNODE}("div", {
+ return _${helperNameMap[CREATE_VNODE]}("div", {
id: "foo",
[prop]: bar,
[foo + bar]: bar
}, [
- ${CREATE_VNODE}("p", { "some-key": "foo" })
+ _${helperNameMap[CREATE_VNODE]}("p", { "some-key": "foo" })
], [
foo,
- ${CREATE_VNODE}("p")
+ _${helperNameMap[CREATE_VNODE]}("p")
])`)
expect(code).toMatchSnapshot()
})
Namespaces,
ElementTypes
} from '../src'
-import { CREATE_VNODE } from '../src/runtimeConstants'
+import { CREATE_VNODE } from '../src/runtimeHelpers'
import { isString } from '@vue/shared'
const leadingBracketRE = /^\[/
CREATE_BLOCK,
FRAGMENT,
RENDER_SLOT
-} from '../src/runtimeConstants'
+} from '../src/runtimeHelpers'
import { transformIf } from '../src/transforms/vIf'
import { transformFor } from '../src/transforms/vFor'
import { transformElement } from '../src/transforms/transformElement'
test('should inject toString helper for interpolations', () => {
const ast = parse(`{{ foo }}`)
transform(ast, {})
- expect(ast.imports).toContain(TO_STRING)
+ expect(ast.helpers).toContain(TO_STRING)
})
test('should inject createVNode and Comment for comments', () => {
const ast = parse(`<!--foo-->`)
transform(ast, {})
- expect(ast.imports).toContain(CREATE_VNODE)
- expect(ast.imports).toContain(COMMENT)
+ expect(ast.helpers).toContain(CREATE_VNODE)
+ expect(ast.helpers).toContain(COMMENT)
})
describe('root codegenNode', () => {
expressions: [
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${OPEN_BLOCK}`
+ callee: OPEN_BLOCK
},
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${CREATE_BLOCK}`,
+ callee: CREATE_BLOCK,
arguments: args
}
]
expect(ast.codegenNode).toMatchObject({
codegenNode: {
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${RENDER_SLOT}`
+ callee: RENDER_SLOT
}
})
})
const ast = transformWithCodegen(`<div/><div/>`)
expect(ast.codegenNode).toMatchObject(
createBlockMatcher([
- `_${FRAGMENT}`,
+ FRAGMENT,
`null`,
[
{ type: NodeTypes.ELEMENT, tag: `div` },
RESOLVE_DIRECTIVE,
APPLY_DIRECTIVES,
TO_HANDLERS
-} from '../../src/runtimeConstants'
+} from '../../src/runtimeHelpers'
import {
CallExpression,
NodeTypes,
describe('compiler: element transform', () => {
test('import + resolve component', () => {
const { root } = parseWithElementTransform(`<Foo/>`)
- expect(root.imports).toContain(RESOLVE_COMPONENT)
- expect(root.statements[0]).toMatch(`${RESOLVE_COMPONENT}("Foo")`)
+ expect(root.helpers).toContain(RESOLVE_COMPONENT)
+ expect(root.components).toContain(`Foo`)
})
test('static props', () => {
const { node } = parseWithElementTransform(`<div id="foo" class="bar" />`)
- expect(node.callee).toBe(`_${CREATE_VNODE}`)
+ expect(node.callee).toBe(CREATE_VNODE)
expect(node.arguments).toMatchObject([
`"div"`,
createObjectMatcher({
test('props + children', () => {
const { node } = parseWithElementTransform(`<div id="foo"><span/></div>`)
- expect(node.callee).toBe(`_${CREATE_VNODE}`)
+ expect(node.callee).toBe(CREATE_VNODE)
expect(node.arguments).toMatchObject([
`"div"`,
createObjectMatcher({
type: NodeTypes.ELEMENT,
tag: 'span',
codegenNode: {
- callee: `_${CREATE_VNODE}`,
+ callee: CREATE_VNODE,
arguments: [`"span"`]
}
}
test('0 placeholder for children with no props', () => {
const { node } = parseWithElementTransform(`<div><span/></div>`)
- expect(node.callee).toBe(`_${CREATE_VNODE}`)
+ expect(node.callee).toBe(CREATE_VNODE)
expect(node.arguments).toMatchObject([
`"div"`,
`null`,
type: NodeTypes.ELEMENT,
tag: 'span',
codegenNode: {
- callee: `_${CREATE_VNODE}`,
+ callee: CREATE_VNODE,
arguments: [`"span"`]
}
}
test('v-bind="obj"', () => {
const { root, node } = parseWithElementTransform(`<div v-bind="obj" />`)
// single v-bind doesn't need mergeProps
- expect(root.imports).not.toContain(MERGE_PROPS)
- expect(node.callee).toBe(`_${CREATE_VNODE}`)
+ expect(root.helpers).not.toContain(MERGE_PROPS)
+ expect(node.callee).toBe(CREATE_VNODE)
// should directly use `obj` in props position
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.SIMPLE_EXPRESSION,
const { root, node } = parseWithElementTransform(
`<div id="foo" v-bind="obj" />`
)
- expect(root.imports).toContain(MERGE_PROPS)
- expect(node.callee).toBe(`_${CREATE_VNODE}`)
+ expect(root.helpers).toContain(MERGE_PROPS)
+ expect(node.callee).toBe(CREATE_VNODE)
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${MERGE_PROPS}`,
+ callee: MERGE_PROPS,
arguments: [
createObjectMatcher({
id: 'foo'
const { root, node } = parseWithElementTransform(
`<div v-bind="obj" id="foo" />`
)
- expect(root.imports).toContain(MERGE_PROPS)
- expect(node.callee).toBe(`_${CREATE_VNODE}`)
+ expect(root.helpers).toContain(MERGE_PROPS)
+ expect(node.callee).toBe(CREATE_VNODE)
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${MERGE_PROPS}`,
+ callee: MERGE_PROPS,
arguments: [
{
type: NodeTypes.SIMPLE_EXPRESSION,
const { root, node } = parseWithElementTransform(
`<div id="foo" v-bind="obj" class="bar" />`
)
- expect(root.imports).toContain(MERGE_PROPS)
- expect(node.callee).toBe(`_${CREATE_VNODE}`)
+ expect(root.helpers).toContain(MERGE_PROPS)
+ expect(node.callee).toBe(CREATE_VNODE)
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${MERGE_PROPS}`,
+ callee: MERGE_PROPS,
arguments: [
createObjectMatcher({
id: 'foo'
const { root, node } = parseWithElementTransform(
`<div id="foo" v-on="obj" class="bar" />`
)
- expect(root.imports).toContain(MERGE_PROPS)
- expect(node.callee).toBe(`_${CREATE_VNODE}`)
+ expect(root.helpers).toContain(MERGE_PROPS)
+ expect(node.callee).toBe(CREATE_VNODE)
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${MERGE_PROPS}`,
+ callee: MERGE_PROPS,
arguments: [
createObjectMatcher({
id: 'foo'
}),
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${TO_HANDLERS}`,
+ callee: TO_HANDLERS,
arguments: [
{
type: NodeTypes.SIMPLE_EXPRESSION,
const { root, node } = parseWithElementTransform(
`<div id="foo" v-on="handlers" v-bind="obj" />`
)
- expect(root.imports).toContain(MERGE_PROPS)
- expect(node.callee).toBe(`_${CREATE_VNODE}`)
+ expect(root.helpers).toContain(MERGE_PROPS)
+ expect(node.callee).toBe(CREATE_VNODE)
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${MERGE_PROPS}`,
+ callee: MERGE_PROPS,
arguments: [
createObjectMatcher({
id: 'foo'
}),
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${TO_HANDLERS}`,
+ callee: TO_HANDLERS,
arguments: [
{
type: NodeTypes.SIMPLE_EXPRESSION,
test('should handle plain <template> as normal element', () => {
const { node } = parseWithElementTransform(`<template id="foo" />`)
- expect(node.callee).toBe(`_${CREATE_VNODE}`)
+ expect(node.callee).toBe(CREATE_VNODE)
expect(node.arguments).toMatchObject([
`"template"`,
createObjectMatcher({
}
}
})
- expect(node.callee).toBe(`_${CREATE_VNODE}`)
+ expect(node.callee).toBe(CREATE_VNODE)
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.JS_OBJECT_EXPRESSION,
properties: [
}
}
)
- expect(root.imports).toContain(RESOLVE_DIRECTIVE)
- expect(root.statements[0]).toMatch(`${RESOLVE_DIRECTIVE}("foo")`)
+ expect(root.helpers).toContain(RESOLVE_DIRECTIVE)
+ expect(root.directives).toContain(`foo`)
- expect(node.callee).toBe(`_${APPLY_DIRECTIVES}`)
+ expect(node.callee).toBe(APPLY_DIRECTIVES)
expect(node.arguments).toMatchObject([
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${CREATE_VNODE}`,
+ callee: CREATE_VNODE,
arguments: [
`"div"`,
`null`,
const { root, node } = parseWithElementTransform(
`<div v-foo v-bar="x" v-baz:[arg].mod.mad="y" />`
)
- expect(root.imports).toContain(RESOLVE_DIRECTIVE)
- expect(root.statements[0]).toMatch(`${RESOLVE_DIRECTIVE}("foo")`)
- expect(root.statements[1]).toMatch(`${RESOLVE_DIRECTIVE}("bar")`)
- expect(root.statements[2]).toMatch(`${RESOLVE_DIRECTIVE}("baz")`)
+ expect(root.helpers).toContain(RESOLVE_DIRECTIVE)
+ expect(root.directives).toContain(`foo`)
+ expect(root.directives).toContain(`bar`)
+ expect(root.directives).toContain(`baz`)
- expect(node.callee).toBe(`_${APPLY_DIRECTIVES}`)
+ expect(node.callee).toBe(APPLY_DIRECTIVES)
expect(node.arguments).toMatchObject([
{
type: NodeTypes.JS_CALL_EXPRESSION
import { transformOn } from '../../src/transforms/vOn'
import { transformBind } from '../../src/transforms/vBind'
import { transformExpression } from '../../src/transforms/transformExpression'
-import { RENDER_SLOT } from '../../src/runtimeConstants'
+import { RENDER_SLOT } from '../../src/runtimeHelpers'
import { transformSlotOutlet } from '../../src/transforms/transformSlotOutlet'
function parseWithSlots(template: string, options: CompilerOptions = {}) {
const ast = parseWithSlots(`<slot/>`)
expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${RENDER_SLOT}`,
+ callee: RENDER_SLOT,
arguments: [`$slots`, `"default"`]
})
})
const ast = parseWithSlots(`<slot name="foo" />`)
expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${RENDER_SLOT}`,
+ callee: RENDER_SLOT,
arguments: [`$slots`, `"foo"`]
})
})
const ast = parseWithSlots(`<slot :name="foo" />`)
expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${RENDER_SLOT}`,
+ callee: RENDER_SLOT,
arguments: [
`$slots`,
{
const ast = parseWithSlots(`<slot foo="bar" :baz="qux" />`)
expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${RENDER_SLOT}`,
+ callee: RENDER_SLOT,
arguments: [
`$slots`,
`"default"`,
const ast = parseWithSlots(`<slot name="foo" foo="bar" :baz="qux" />`)
expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${RENDER_SLOT}`,
+ callee: RENDER_SLOT,
arguments: [
`$slots`,
`"foo"`,
const ast = parseWithSlots(`<slot :name="foo" foo="bar" :baz="qux" />`)
expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${RENDER_SLOT}`,
+ callee: RENDER_SLOT,
arguments: [
`$slots`,
{ content: `foo`, isStatic: false },
const ast = parseWithSlots(`<slot><div/></slot>`)
expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${RENDER_SLOT}`,
+ callee: RENDER_SLOT,
arguments: [
`$slots`,
`"default"`,
const ast = parseWithSlots(`<slot name="foo"><div/></slot>`)
expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${RENDER_SLOT}`,
+ callee: RENDER_SLOT,
arguments: [
`$slots`,
`"foo"`,
const ast = parseWithSlots(`<slot :foo="bar"><div/></slot>`)
expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${RENDER_SLOT}`,
+ callee: RENDER_SLOT,
arguments: [
`$slots`,
`"default"`,
const ast = parseWithSlots(`<slot name="foo" :foo="bar"><div/></slot>`)
expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${RENDER_SLOT}`,
+ callee: RENDER_SLOT,
arguments: [
`$slots`,
`"foo"`,
} from '../../src'
import { transformBind } from '../../src/transforms/vBind'
import { transformElement } from '../../src/transforms/transformElement'
-import { CAMELIZE } from '../../src/runtimeConstants'
+import { CAMELIZE, helperNameMap } from '../../src/runtimeHelpers'
import { transformExpression } from '../../src/transforms/transformExpression'
function parseWithVBind(
.arguments[1] as ObjectExpression
expect(props.properties[0]).toMatchObject({
key: {
- content: `_${CAMELIZE}(foo)`,
+ content: `_${helperNameMap[CAMELIZE]}(foo)`,
isStatic: false
},
value: {
expect(props.properties[0]).toMatchObject({
key: {
children: [
- `${CAMELIZE}(`,
+ `${helperNameMap[CAMELIZE]}(`,
{ content: `_ctx.foo` },
`(`,
{ content: `_ctx.bar` },
FRAGMENT,
RENDER_LIST,
RENDER_SLOT
-} from '../../src/runtimeConstants'
+} from '../../src/runtimeHelpers'
import { PatchFlags } from '@vue/runtime-dom'
import { PatchFlagNames } from '@vue/shared'
import { createObjectMatcher } from '../testUtils'
expressions: [
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${OPEN_BLOCK}`
+ callee: OPEN_BLOCK
},
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${CREATE_BLOCK}`,
+ callee: CREATE_BLOCK,
arguments: [
- `_${FRAGMENT}`,
+ FRAGMENT,
`null`,
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${RENDER_LIST}`,
+ callee: RENDER_LIST,
arguments: [
{}, // to be asserted by each test
{
expressions: [
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${OPEN_BLOCK}`
+ callee: OPEN_BLOCK
},
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${CREATE_BLOCK}`
+ callee: CREATE_BLOCK
}
]
}
source: { content: `items` },
params: [{ content: `item` }],
blockArgs: [
- `_${FRAGMENT}`,
+ FRAGMENT,
`null`,
[
{ type: NodeTypes.TEXT, content: `hello` },
params: [{ content: `item` }],
returns: {
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${RENDER_SLOT}`
+ callee: RENDER_SLOT
}
})
expect(generate(root).code).toMatchSnapshot()
params: [{ content: `item` }],
returns: {
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${RENDER_SLOT}`
+ callee: RENDER_SLOT
}
})
expect(generate(root).code).toMatchSnapshot()
source: { content: `items` },
params: [{ content: `item` }],
blockArgs: [
- `_${FRAGMENT}`,
+ FRAGMENT,
createObjectMatcher({
key: `[item]`
}),
expressions: [
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${OPEN_BLOCK}`,
+ callee: OPEN_BLOCK,
arguments: []
},
{
test: { content: `ok` },
consequent: {
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${CREATE_BLOCK}`,
+ callee: CREATE_BLOCK,
// should optimize v-if + v-for into a single Fragment block
arguments: [
- `_${FRAGMENT}`,
+ FRAGMENT,
createObjectMatcher({ key: `[0]` }),
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${RENDER_LIST}`,
+ callee: RENDER_LIST,
arguments: [
{ content: `list` },
{
expressions: [
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${OPEN_BLOCK}`
+ callee: OPEN_BLOCK
},
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${CREATE_BLOCK}`,
+ callee: CREATE_BLOCK,
arguments: [`"div"`]
}
]
MERGE_PROPS,
APPLY_DIRECTIVES,
RENDER_SLOT
-} from '../../src/runtimeConstants'
+} from '../../src/runtimeHelpers'
import { createObjectMatcher } from '../testUtils'
function parseWithIfTransform(
expressions: [
{
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${OPEN_BLOCK}`,
+ callee: OPEN_BLOCK,
arguments: []
},
{
},
consequent: {
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${CREATE_BLOCK}`
+ callee: CREATE_BLOCK
},
alternate:
depth < 1
? {
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${CREATE_BLOCK}`
+ callee: CREATE_BLOCK
}
: {
type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
},
consequent: {
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${CREATE_BLOCK}`
+ callee: CREATE_BLOCK
},
alternate: {
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${CREATE_BLOCK}`
+ callee: CREATE_BLOCK
}
}
}
])
const branch2 = (codegenNode.expressions[1] as ConditionalExpression)
.alternate as CallExpression
- expect(branch2.arguments).toMatchObject([`_${EMPTY}`])
+ expect(branch2.arguments).toMatchObject([EMPTY])
expect(generate(root).code).toMatchSnapshot()
})
const branch1 = (codegenNode.expressions[1] as ConditionalExpression)
.consequent as CallExpression
expect(branch1.arguments).toMatchObject([
- `_${FRAGMENT}`,
+ FRAGMENT,
createObjectMatcher({ key: `[0]` }),
[
{ type: NodeTypes.ELEMENT, tag: 'div' },
])
const branch2 = (codegenNode.expressions[1] as ConditionalExpression)
.alternate as CallExpression
- expect(branch2.arguments).toMatchObject([`_${EMPTY}`])
+ expect(branch2.arguments).toMatchObject([EMPTY])
expect(generate(root).code).toMatchSnapshot()
})
.consequent as CallExpression
expect(branch1).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${RENDER_SLOT}`,
+ callee: RENDER_SLOT,
arguments: ['$slots', '"default"', createObjectMatcher({ key: `[0]` })]
})
expect(generate(root).code).toMatchSnapshot()
.consequent as CallExpression
expect(branch1).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${RENDER_SLOT}`,
+ callee: RENDER_SLOT,
arguments: ['$slots', '"default"', createObjectMatcher({ key: `[0]` })]
})
expect(generate(root).code).toMatchSnapshot()
createObjectMatcher({ key: `[1]` })
])
expect((branch2.alternate as CallExpression).arguments).toMatchObject([
- `_${FRAGMENT}`,
+ FRAGMENT,
createObjectMatcher({ key: `[2]` }),
[
{
.consequent as CallExpression
expect(branch1.arguments[1]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${MERGE_PROPS}`,
+ callee: MERGE_PROPS,
arguments: [createObjectMatcher({ key: `[0]` }), { content: `obj` }]
})
})
.consequent as CallExpression
expect(branch1.arguments[1]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${MERGE_PROPS}`,
+ callee: MERGE_PROPS,
arguments: [
createObjectMatcher({
key: '[0]',
.consequent as CallExpression
expect(branch1.arguments[1]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${MERGE_PROPS}`,
+ callee: MERGE_PROPS,
arguments: [
createObjectMatcher({ key: `[0]` }),
{ content: `obj` },
} = parseWithIfTransform(`<div v-if="ok" v-foo />`)
const branch1 = (codegenNode.expressions[1] as ConditionalExpression)
.consequent as CallExpression
- expect(branch1.callee).toBe(`_${APPLY_DIRECTIVES}`)
+ expect(branch1.callee).toBe(APPLY_DIRECTIVES)
const realBranch = branch1.arguments[0] as CallExpression
expect(realBranch.arguments[1]).toMatchObject(
createObjectMatcher({ key: `[0]` })
trackSlotScopes,
trackVForSlotScopes
} from '../../src/transforms/vSlot'
-import { CREATE_SLOTS, RENDER_LIST } from '../../src/runtimeConstants'
+import { CREATE_SLOTS, RENDER_LIST } from '../../src/runtimeHelpers'
import { createObjectMatcher } from '../testUtils'
import { PatchFlags, PatchFlagNames } from '@vue/shared'
import { transformFor } from '../../src/transforms/vFor'
)
expect(slots).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${CREATE_SLOTS}`,
+ callee: CREATE_SLOTS,
arguments: [
createObjectMatcher({
_compiled: `[true]`
)
expect(slots).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
- callee: `_${CREATE_SLOTS}`,
+ callee: CREATE_SLOTS,
arguments: [
createObjectMatcher({
_compiled: `[true]`
import { isString } from '@vue/shared'
import { ForParseResult } from './transforms/vFor'
+import { CREATE_VNODE, RuntimeHelper } from './runtimeHelpers'
// Vue template is a platform-agnostic superset of HTML (syntax only).
// More namespaces like SVG and MathML are declared by platform specific
export interface RootNode extends Node {
type: NodeTypes.ROOT
children: TemplateChildNode[]
- imports: string[]
- statements: string[]
+ helpers: RuntimeHelper[]
+ components: string[]
+ directives: string[]
hoists: JSChildNode[]
codegenNode: TemplateChildNode | JSChildNode | undefined
}
codegenNode: CallExpression | SimpleExpressionNode | undefined
}
+export interface PlainElementNode extends ElementNode {
+ tagType: ElementTypes.ELEMENT
+ codegenNode: VNodeCodegenNode | VNodeWithDirectiveCodegenNode
+}
+
+export interface ComponentNode extends ElementNode {
+ tagType: ElementTypes.COMPONENT
+ codegenNode: VNodeCodegenNode | VNodeWithDirectiveCodegenNode
+}
+
+export interface SlotOutletNode extends ElementNode {
+ tagType: ElementTypes.SLOT
+ codegenNode: SlotOutletCodegenNode
+}
+
+export interface VNodeCodegenNode extends CallExpression {
+ callee: typeof CREATE_VNODE
+}
+
+export interface VNodeWithDirectiveCodegenNode extends CallExpression {}
+
+export interface SlotOutletCodegenNode extends CallExpression {}
+
export interface TextNode extends Node {
type: NodeTypes.TEXT
content: string
// always dynamic
export interface CompoundExpressionNode extends Node {
type: NodeTypes.COMPOUND_EXPRESSION
- children: (SimpleExpressionNode | InterpolationNode | TextNode | string)[]
+ children: (
+ | SimpleExpressionNode
+ | InterpolationNode
+ | TextNode
+ | string
+ | RuntimeHelper)[]
// an expression parsed as the params of a function will track
// the identifiers declared inside the function body.
identifiers?: string[]
export interface IfNode extends Node {
type: NodeTypes.IF
branches: IfBranchNode[]
- codegenNode: SequenceExpression
+ codegenNode: IfCodegenNode
}
+export interface IfCodegenNode extends SequenceExpression {}
+
export interface IfBranchNode extends Node {
type: NodeTypes.IF_BRANCH
condition: ExpressionNode | undefined // else
keyAlias: ExpressionNode | undefined
objectIndexAlias: ExpressionNode | undefined
children: TemplateChildNode[]
- codegenNode: SequenceExpression
+ codegenNode: ForCodegenNode
}
+export interface ForCodegenNode extends SequenceExpression {}
+
// We also include a number of JavaScript AST nodes for code generation.
// The AST is an intentionally minimal subset just to meet the exact needs of
// Vue render function generation.
export interface CallExpression extends Node {
type: NodeTypes.JS_CALL_EXPRESSION
- callee: string
- arguments: (string | JSChildNode | TemplateChildNode | TemplateChildNode[])[]
+ callee: string | RuntimeHelper
+ arguments: (
+ | string
+ | RuntimeHelper
+ | JSChildNode
+ | TemplateChildNode
+ | TemplateChildNode[])[]
}
export interface ObjectExpression extends Node {
advancePositionWithMutation,
assert,
isSimpleIdentifier,
- loadDep
+ loadDep,
+ toValidAssetId
} from './utils'
-import { isString, isArray } from '@vue/shared'
-import { TO_STRING, CREATE_VNODE, COMMENT } from './runtimeConstants'
+import { isString, isArray, isSymbol } from '@vue/shared'
+import {
+ TO_STRING,
+ CREATE_VNODE,
+ COMMENT,
+ helperNameMap,
+ RESOLVE_COMPONENT,
+ RESOLVE_DIRECTIVE,
+ RuntimeHelper
+} from './runtimeHelpers'
type CodegenNode = TemplateChildNode | JSChildNode
offset: number
indentLevel: number
map?: SourceMapGenerator
- helper(name: string): string
+ helper(key: RuntimeHelper): string
push(code: string, node?: CodegenNode, openOnly?: boolean): void
resetMapping(loc: SourceLocation): void
indent(): void
ast: RootNode,
{
mode = 'function',
- prefixIdentifiers = false,
+ prefixIdentifiers = mode === 'module',
sourceMap = false,
filename = `template.vue.html`
}: CodegenOptions
? undefined
: new (loadDep('source-map')).SourceMapGenerator(),
- helper(name) {
+ helper(key) {
+ const name = helperNameMap[key]
return prefixIdentifiers ? name : `_${name}`
},
push(code, node, openOnly) {
options: CodegenOptions = {}
): CodegenResult {
const context = createCodegenContext(ast, options)
- const { mode, push, prefixIdentifiers, indent, deindent, newline } = context
- const hasImports = ast.imports.length
+ const {
+ mode,
+ push,
+ helper,
+ prefixIdentifiers,
+ indent,
+ deindent,
+ newline
+ } = context
+ const hasHelpers = ast.helpers.length > 0
const useWithBlock = !prefixIdentifiers && mode !== 'module'
// preambles
// In prefix mode, we place the const declaration at top so it's done
// only once; But if we not prefixing, we place the declaration inside the
// with block so it doesn't incur the `in` check cost for every helper access.
- if (hasImports) {
+ if (hasHelpers) {
if (prefixIdentifiers) {
- push(`const { ${ast.imports.join(', ')} } = Vue\n`)
+ push(`const { ${ast.helpers.map(helper).join(', ')} } = Vue\n`)
} else {
// "with" mode.
// save Vue in a separate variable to avoid collision
// has check cost, but hoists are lifted out of the function - we need
// to provide the helper here.
if (ast.hoists.length) {
- push(`const _${CREATE_VNODE} = Vue.createVNode\n`)
+ push(`const _${helperNameMap[CREATE_VNODE]} = Vue.createVNode\n`)
}
}
}
push(`return `)
} else {
// generate import statements for helpers
- if (hasImports) {
- push(`import { ${ast.imports.join(', ')} } from "vue"\n`)
+ if (hasHelpers) {
+ push(`import { ${ast.helpers.map(helper).join(', ')} } from "vue"\n`)
}
genHoists(ast.hoists, context)
context.newline()
indent()
// function mode const declarations should be inside with block
// also they should be renamed to avoid collision with user properties
- if (hasImports) {
- push(`const { ${ast.imports.map(n => `${n}: _${n}`).join(', ')} } = _Vue`)
+ if (hasHelpers) {
+ push(
+ `const { ${ast.helpers
+ .map(s => `${helperNameMap[s]}: _${helperNameMap[s]}`)
+ .join(', ')} } = _Vue`
+ )
newline()
newline()
}
}
// generate asset resolution statements
- if (ast.statements.length) {
- ast.statements.forEach(s => {
- push(s)
- newline()
- })
+ if (ast.components.length) {
+ genAssets(ast.components, 'component', context)
+ }
+ if (ast.directives.length) {
+ genAssets(ast.directives, 'directive', context)
+ }
+ if (ast.components.length || ast.directives.length) {
newline()
}
}
}
+function genAssets(
+ assets: string[],
+ type: 'component' | 'directive',
+ context: CodegenContext
+) {
+ const resolver = context.helper(
+ type === 'component' ? RESOLVE_COMPONENT : RESOLVE_DIRECTIVE
+ )
+ for (let i = 0; i < assets.length; i++) {
+ const id = assets[i]
+ context.push(
+ `const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)})`
+ )
+ context.newline()
+ }
+}
+
function genHoists(hoists: JSChildNode[], context: CodegenContext) {
if (!hoists.length) {
return
}
function genNodeList(
- nodes: (string | CodegenNode | TemplateChildNode[])[],
+ nodes: (string | RuntimeHelper | CodegenNode | TemplateChildNode[])[],
context: CodegenContext,
multilines: boolean = false
) {
}
}
-function genNode(node: CodegenNode | string, context: CodegenContext) {
+function genNode(
+ node: CodegenNode | RuntimeHelper | string,
+ context: CodegenContext
+) {
if (isString(node)) {
context.push(node)
return
}
+ if (isSymbol(node)) {
+ context.push(context.helper(node))
+ return
+ }
switch (node.type) {
case NodeTypes.ELEMENT:
case NodeTypes.IF:
// JavaScript
function genCallExpression(node: CallExpression, context: CodegenContext) {
- context.push(node.callee + `(`, node, true)
+ const callee = isString(node.callee)
+ ? node.callee
+ : context.helper(node.callee)
+ context.push(callee + `(`, node, true)
genNodeList(node.arguments, context)
context.push(`)`)
}
}
})
- return generate(ast, options)
+ return generate(ast, {
+ ...options,
+ prefixIdentifiers
+ })
}
// Also expose lower level APIs & types
+++ /dev/null
-// Name mapping constants for runtime helpers that need to be imported in
-// generated code. Make sure these are correctly exported in the runtime!
-export const FRAGMENT = `Fragment`
-export const PORTAL = `Portal`
-export const COMMENT = `Comment`
-export const TEXT = `Text`
-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 RESOLVE_COMPONENT = `resolveComponent`
-export const RESOLVE_DIRECTIVE = `resolveDirective`
-export const APPLY_DIRECTIVES = `applyDirectives`
-export const RENDER_LIST = `renderList`
-export const RENDER_SLOT = `renderSlot`
-export const CREATE_SLOTS = `createSlots`
-export const TO_STRING = `toString`
-export const MERGE_PROPS = `mergeProps`
-export const TO_HANDLERS = `toHandlers`
-export const CAMELIZE = `camelize`
--- /dev/null
+export const FRAGMENT = Symbol()
+export const PORTAL = Symbol()
+export const COMMENT = Symbol()
+export const TEXT = Symbol()
+export const SUSPENSE = Symbol()
+export const EMPTY = Symbol()
+export const OPEN_BLOCK = Symbol()
+export const CREATE_BLOCK = Symbol()
+export const CREATE_VNODE = Symbol()
+export const RESOLVE_COMPONENT = Symbol()
+export const RESOLVE_DIRECTIVE = Symbol()
+export const APPLY_DIRECTIVES = Symbol()
+export const RENDER_LIST = Symbol()
+export const RENDER_SLOT = Symbol()
+export const CREATE_SLOTS = Symbol()
+export const TO_STRING = Symbol()
+export const MERGE_PROPS = Symbol()
+export const TO_HANDLERS = Symbol()
+export const CAMELIZE = Symbol()
+
+export type RuntimeHelper =
+ | typeof FRAGMENT
+ | typeof PORTAL
+ | typeof COMMENT
+ | typeof TEXT
+ | typeof SUSPENSE
+ | typeof EMPTY
+ | typeof OPEN_BLOCK
+ | typeof CREATE_BLOCK
+ | typeof CREATE_VNODE
+ | typeof RESOLVE_COMPONENT
+ | typeof RESOLVE_DIRECTIVE
+ | typeof APPLY_DIRECTIVES
+ | typeof RENDER_LIST
+ | typeof RENDER_SLOT
+ | typeof CREATE_SLOTS
+ | typeof TO_STRING
+ | typeof MERGE_PROPS
+ | typeof TO_HANDLERS
+ | typeof CAMELIZE
+
+// Name mapping for runtime helpers that need to be imported from 'vue' in
+// generated code. Make sure these are correctly exported in the runtime!
+export const helperNameMap = {
+ [FRAGMENT]: `Fragment`,
+ [PORTAL]: `Portal`,
+ [COMMENT]: `Comment`,
+ [TEXT]: `Text`,
+ [SUSPENSE]: `Suspense`,
+ [EMPTY]: `Empty`,
+ [OPEN_BLOCK]: `openBlock`,
+ [CREATE_BLOCK]: `createBlock`,
+ [CREATE_VNODE]: `createVNode`,
+ [RESOLVE_COMPONENT]: `resolveComponent`,
+ [RESOLVE_DIRECTIVE]: `resolveDirective`,
+ [APPLY_DIRECTIVES]: `applyDirectives`,
+ [RENDER_LIST]: `renderList`,
+ [RENDER_SLOT]: `renderSlot`,
+ [CREATE_SLOTS]: `createSlots`,
+ [TO_STRING]: `toString`,
+ [MERGE_PROPS]: `mergeProps`,
+ [TO_HANDLERS]: `toHandlers`,
+ [CAMELIZE]: `camelize`
+}
} from './ast'
import { isString, isArray } from '@vue/shared'
import { CompilerError, defaultOnError } from './errors'
-import { TO_STRING, COMMENT, CREATE_VNODE, FRAGMENT } from './runtimeConstants'
+import {
+ TO_STRING,
+ COMMENT,
+ CREATE_VNODE,
+ FRAGMENT,
+ RuntimeHelper,
+ helperNameMap
+} from './runtimeHelpers'
import { isVSlot, createBlockExpression, isSlotOutlet } from './utils'
import { hoistStatic } from './transforms/hoistStatic'
export interface TransformContext extends Required<TransformOptions> {
root: RootNode
- imports: Set<string>
- statements: Set<string>
+ helpers: Set<RuntimeHelper>
+ components: Set<string>
+ directives: Set<string>
hoists: JSChildNode[]
identifiers: { [name: string]: number | undefined }
scopes: {
parent: ParentNode | null
childIndex: number
currentNode: RootNode | TemplateChildNode | null
- helper(name: string): string
+ helper<T extends RuntimeHelper>(name: T): T
+ helperString(name: RuntimeHelper): string
replaceNode(node: TemplateChildNode): void
removeNode(node?: TemplateChildNode): void
onNodeRemoved: () => void
): TransformContext {
const context: TransformContext = {
root,
- imports: new Set(),
- statements: new Set(),
+ helpers: new Set(),
+ components: new Set(),
+ directives: new Set(),
hoists: [],
identifiers: {},
scopes: {
currentNode: root,
childIndex: 0,
helper(name) {
- context.imports.add(name)
- return prefixIdentifiers ? name : `_${name}`
+ context.helpers.add(name)
+ return name
+ },
+ helperString(name) {
+ return (
+ (context.prefixIdentifiers ? `` : `_`) +
+ helperNameMap[context.helper(name)]
+ )
},
replaceNode(node) {
/* istanbul ignore if */
}
// finalize meta information
- root.imports = [...context.imports]
- root.statements = [...context.statements]
+ root.helpers = [...context.helpers]
+ root.components = [...context.components]
+ root.directives = [...context.directives]
root.hoists = context.hoists
}
ElementTypes
} from '../ast'
import { TransformContext } from '../transform'
-import { APPLY_DIRECTIVES } from '../runtimeConstants'
+import { APPLY_DIRECTIVES } from '../runtimeHelpers'
import { PropsExpression } from './transformElement'
import { PatchFlags } from '@vue/shared'
flag === PatchFlags.TEXT
) {
let codegenNode = child.codegenNode as CallExpression
- if (codegenNode.callee.includes(APPLY_DIRECTIVES)) {
+ if (codegenNode.callee === APPLY_DIRECTIVES) {
codegenNode = codegenNode.arguments[0] as CallExpression
}
const props = codegenNode.arguments[1] as
function getPatchFlag(node: ElementNode): number | undefined {
let codegenNode = node.codegenNode as CallExpression
- if (codegenNode.callee.includes(APPLY_DIRECTIVES)) {
+ if (codegenNode.callee === APPLY_DIRECTIVES) {
codegenNode = codegenNode.arguments[0] as CallExpression
}
const flag = codegenNode.arguments[3]
RESOLVE_COMPONENT,
MERGE_PROPS,
TO_HANDLERS
-} from '../runtimeConstants'
-import { getInnerRange, isVSlot } from '../utils'
+} from '../runtimeHelpers'
+import { getInnerRange, isVSlot, toValidAssetId } from '../utils'
import { buildSlots } from './vSlot'
-const toValidId = (str: string): string => str.replace(/[^\w]/g, '')
-
// generate a JavaScript AST for this element's codegen
export const transformElement: NodeTransform = (node, context) => {
if (node.type === NodeTypes.ELEMENT) {
let patchFlag: number = 0
let runtimeDirectives: DirectiveNode[] | undefined
let dynamicPropNames: string[] | undefined
- let componentIdentifier: string | undefined
if (isComponent) {
- componentIdentifier = `_component_${toValidId(node.tag)}`
- context.statements.add(
- `const ${componentIdentifier} = ${context.helper(
- RESOLVE_COMPONENT
- )}(${JSON.stringify(node.tag)})`
- )
+ context.helper(RESOLVE_COMPONENT)
+ context.components.add(node.tag)
}
const args: CallExpression['arguments'] = [
- isComponent ? componentIdentifier! : `"${node.tag}"`
+ isComponent ? toValidAssetId(node.tag, `component`) : `"${node.tag}"`
]
// props
if (hasProps) {
context: TransformContext
): ArrayExpression {
// inject statement for resolving directive
- const dirIdentifier = `_directive_${toValidId(dir.name)}`
- context.statements.add(
- `const ${dirIdentifier} = ${context.helper(
- RESOLVE_DIRECTIVE
- )}(${JSON.stringify(dir.name)})`
- )
- const dirArgs: ArrayExpression['elements'] = [dirIdentifier]
+ context.helper(RESOLVE_DIRECTIVE)
+ context.directives.add(dir.name)
+ const dirArgs: ArrayExpression['elements'] = [
+ toValidAssetId(dir.name, `directive`)
+ ]
const { loc } = dir
if (dir.exp) dirArgs.push(dir.exp)
if (dir.arg) dirArgs.push(dir.arg)
import { isSlotOutlet } from '../utils'
import { buildProps } from './transformElement'
import { createCompilerError, ErrorCodes } from '../errors'
-import { RENDER_SLOT } from '../runtimeConstants'
+import { RENDER_SLOT } from '../runtimeHelpers'
export const transformSlotOutlet: NodeTransform = (node, context) => {
if (isSlotOutlet(node)) {
import { createObjectProperty, createSimpleExpression, NodeTypes } from '../ast'
import { createCompilerError, ErrorCodes } from '../errors'
import { camelize } from '@vue/shared'
-import { CAMELIZE } from '../runtimeConstants'
+import { CAMELIZE } from '../runtimeHelpers'
// v-bind without arg is handled directly in ./element.ts due to it affecting
// codegen for the entire props object. This transform here is only for v-bind
if (arg.isStatic) {
arg.content = camelize(arg.content)
} else {
- arg.content = `${context.helper(CAMELIZE)}(${arg.content})`
+ arg.content = `${context.helperString(CAMELIZE)}(${arg.content})`
}
} else {
- arg.children.unshift(`${context.helper(CAMELIZE)}(`)
+ arg.children.unshift(`${context.helperString(CAMELIZE)}(`)
arg.children.push(`)`)
}
}
OPEN_BLOCK,
CREATE_BLOCK,
FRAGMENT
-} from '../runtimeConstants'
+} from '../runtimeHelpers'
import { processExpression } from './transformExpression'
import { PatchFlags, PatchFlagNames } from '@vue/shared'
import { PropsExpression } from './transformElement'
APPLY_DIRECTIVES,
CREATE_VNODE,
RENDER_SLOT
-} from '../runtimeConstants'
+} from '../runtimeHelpers'
import { injectProp } from '../utils'
import { PropsExpression } from './transformElement'
const childCodegen = (child as ElementNode).codegenNode as CallExpression
let vnodeCall = childCodegen
// Element with custom directives. Locate the actual createVNode() call.
- if (vnodeCall.callee.includes(APPLY_DIRECTIVES)) {
+ if (vnodeCall.callee === APPLY_DIRECTIVES) {
vnodeCall = vnodeCall.arguments[0] as CallExpression
}
// Change createVNode to createBlock.
- if (vnodeCall.callee.includes(CREATE_VNODE)) {
+ if (vnodeCall.callee === CREATE_VNODE) {
vnodeCall.callee = helper(CREATE_BLOCK)
}
// It's possible to have renderSlot() here as well - which already produces
// a block, so no need to change the callee. However it accepts props at
// a different arg index so make sure to check for so that the key injection
// logic below works for it too.
- const propsIndex = vnodeCall.callee.includes(RENDER_SLOT) ? 2 : 1
+ const propsIndex = vnodeCall.callee === RENDER_SLOT ? 2 : 1
// inject branch key
const existingProps = vnodeCall.arguments[propsIndex] as
| PropsExpression
import { TransformContext, NodeTransform } from '../transform'
import { createCompilerError, ErrorCodes } from '../errors'
import { findDir, isTemplateNode, assert, isVSlot } from '../utils'
-import { CREATE_SLOTS, RENDER_LIST } from '../runtimeConstants'
+import { CREATE_SLOTS, RENDER_LIST } from '../runtimeHelpers'
import { parseForExpression, createForLoopParams } from './vFor'
const isStaticExp = (p: JSChildNode): p is SimpleExpressionNode =>
import { parse } from 'acorn'
import { walk } from 'estree-walker'
import { TransformContext } from './transform'
-import { OPEN_BLOCK, CREATE_BLOCK, MERGE_PROPS } from './runtimeConstants'
+import { OPEN_BLOCK, CREATE_BLOCK, MERGE_PROPS } from './runtimeHelpers'
import { isString, isFunction } from '@vue/shared'
import { PropsExpression } from './transforms/transformElement'
])
}
}
+
+export function toValidAssetId(
+ name: string,
+ type: 'component' | 'directive'
+): string {
+ return `_${type}_${name.replace(/[^\w]/g, '')}`
+}
export const isFunction = (val: any): val is Function =>
typeof val === 'function'
export const isString = (val: any): val is string => typeof val === 'string'
+export const isSymbol = (val: any): val is symbol => typeof val === 'symbol'
export const isObject = (val: any): val is Record<any, any> =>
val !== null && typeof val === 'object'