refactor(compiler): use symbols for runtime helpers
This commit is contained in:
		
							parent
							
								
									7c4eea6048
								
							
						
					
					
						commit
						bfecf2cdce
					
				| @ -17,15 +17,15 @@ exports[`compiler: codegen Element (callExpression + objectExpression + arrayExp | ||||
| " | ||||
| 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\\") | ||||
|     ]) | ||||
|   } | ||||
| }" | ||||
| @ -40,6 +40,19 @@ return function render() { | ||||
| }" | ||||
| `; | ||||
| 
 | ||||
| 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() { | ||||
| @ -72,7 +85,7 @@ exports[`compiler: codegen function mode preamble 1`] = ` | ||||
| 
 | ||||
| return function render() { | ||||
|   with (this) { | ||||
|     const { helperOne: _helperOne, helperTwo: _helperTwo } = _Vue | ||||
|     const { createVNode: _createVNode, resolveDirective: _resolveDirective } = _Vue | ||||
|      | ||||
|     return null | ||||
|   } | ||||
| @ -80,7 +93,7 @@ return function render() { | ||||
| `; | ||||
| 
 | ||||
| exports[`compiler: codegen function mode preamble w/ prefixIdentifiers: true 1`] = ` | ||||
| "const { helperOne, helperTwo } = Vue | ||||
| "const { createVNode, resolveDirective } = Vue | ||||
| 
 | ||||
| return function render() { | ||||
|   const _ctx = this | ||||
| @ -119,7 +132,7 @@ return function render() { | ||||
| `; | ||||
| 
 | ||||
| exports[`compiler: codegen module mode preamble 1`] = ` | ||||
| "import { helperOne, helperTwo } from \\"vue\\" | ||||
| "import { createVNode, resolveDirective } from \\"vue\\" | ||||
| 
 | ||||
| export default function render() { | ||||
|   const _ctx = this | ||||
| @ -135,18 +148,6 @@ return function render() { | ||||
| }" | ||||
| `; | ||||
| 
 | ||||
| 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() { | ||||
|  | ||||
| @ -56,13 +56,13 @@ export default 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 */)) | ||||
|  | ||||
| @ -13,15 +13,23 @@ import { | ||||
|   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, | ||||
| @ -32,45 +40,69 @@ function createRoot(options: Partial<RootNode> = {}): RootNode { | ||||
| 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() | ||||
|   }) | ||||
| 
 | ||||
| @ -122,7 +154,7 @@ describe('compiler: codegen', () => { | ||||
|         codegenNode: createInterpolation(`hello`, locStub) | ||||
|       }) | ||||
|     ) | ||||
|     expect(code).toMatch(`return _${TO_STRING}(hello)`) | ||||
|     expect(code).toMatch(`return _${helperNameMap[TO_STRING]}(hello)`) | ||||
|     expect(code).toMatchSnapshot() | ||||
|   }) | ||||
| 
 | ||||
| @ -136,7 +168,11 @@ describe('compiler: codegen', () => { | ||||
|         } | ||||
|       }) | ||||
|     ) | ||||
|     expect(code).toMatch(`return _${CREATE_VNODE}(_${COMMENT}, 0, "foo")`) | ||||
|     expect(code).toMatch( | ||||
|       `return _${helperNameMap[CREATE_VNODE]}(_${ | ||||
|         helperNameMap[COMMENT] | ||||
|       }, 0, "foo")` | ||||
|     ) | ||||
|     expect(code).toMatchSnapshot() | ||||
|   }) | ||||
| 
 | ||||
| @ -155,7 +191,7 @@ describe('compiler: codegen', () => { | ||||
|         ]) | ||||
|       }) | ||||
|     ) | ||||
|     expect(code).toMatch(`return _ctx.foo + _${TO_STRING}(bar)`) | ||||
|     expect(code).toMatch(`return _ctx.foo + _${helperNameMap[TO_STRING]}(bar)`) | ||||
|     expect(code).toMatchSnapshot() | ||||
|   }) | ||||
| 
 | ||||
| @ -264,15 +300,15 @@ describe('compiler: codegen', () => { | ||||
|       }) | ||||
|     ) | ||||
|     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() | ||||
|   }) | ||||
|  | ||||
| @ -6,7 +6,7 @@ import { | ||||
|   Namespaces, | ||||
|   ElementTypes | ||||
| } from '../src' | ||||
| import { CREATE_VNODE } from '../src/runtimeConstants' | ||||
| import { CREATE_VNODE } from '../src/runtimeHelpers' | ||||
| import { isString } from '@vue/shared' | ||||
| 
 | ||||
| const leadingBracketRE = /^\[/ | ||||
|  | ||||
| @ -15,7 +15,7 @@ import { | ||||
|   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' | ||||
| @ -225,14 +225,14 @@ describe('compiler: transform', () => { | ||||
|   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', () => { | ||||
| @ -256,11 +256,11 @@ describe('compiler: transform', () => { | ||||
|         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 | ||||
|           } | ||||
|         ] | ||||
| @ -277,7 +277,7 @@ describe('compiler: transform', () => { | ||||
|       expect(ast.codegenNode).toMatchObject({ | ||||
|         codegenNode: { | ||||
|           type: NodeTypes.JS_CALL_EXPRESSION, | ||||
|           callee: `_${RENDER_SLOT}` | ||||
|           callee: RENDER_SLOT | ||||
|         } | ||||
|       }) | ||||
|     }) | ||||
| @ -326,7 +326,7 @@ describe('compiler: transform', () => { | ||||
|       const ast = transformWithCodegen(`<div/><div/>`) | ||||
|       expect(ast.codegenNode).toMatchObject( | ||||
|         createBlockMatcher([ | ||||
|           `_${FRAGMENT}`, | ||||
|           FRAGMENT, | ||||
|           `null`, | ||||
|           [ | ||||
|             { type: NodeTypes.ELEMENT, tag: `div` }, | ||||
|  | ||||
| @ -12,7 +12,7 @@ import { | ||||
|   RESOLVE_DIRECTIVE, | ||||
|   APPLY_DIRECTIVES, | ||||
|   TO_HANDLERS | ||||
| } from '../../src/runtimeConstants' | ||||
| } from '../../src/runtimeHelpers' | ||||
| import { | ||||
|   CallExpression, | ||||
|   NodeTypes, | ||||
| @ -52,13 +52,13 @@ function parseWithElementTransform( | ||||
| 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({ | ||||
| @ -70,7 +70,7 @@ describe('compiler: element transform', () => { | ||||
| 
 | ||||
|   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({ | ||||
| @ -81,7 +81,7 @@ describe('compiler: element transform', () => { | ||||
|           type: NodeTypes.ELEMENT, | ||||
|           tag: 'span', | ||||
|           codegenNode: { | ||||
|             callee: `_${CREATE_VNODE}`, | ||||
|             callee: CREATE_VNODE, | ||||
|             arguments: [`"span"`] | ||||
|           } | ||||
|         } | ||||
| @ -91,7 +91,7 @@ describe('compiler: element transform', () => { | ||||
| 
 | ||||
|   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`, | ||||
| @ -100,7 +100,7 @@ describe('compiler: element transform', () => { | ||||
|           type: NodeTypes.ELEMENT, | ||||
|           tag: 'span', | ||||
|           codegenNode: { | ||||
|             callee: `_${CREATE_VNODE}`, | ||||
|             callee: CREATE_VNODE, | ||||
|             arguments: [`"span"`] | ||||
|           } | ||||
|         } | ||||
| @ -111,8 +111,8 @@ describe('compiler: element transform', () => { | ||||
|   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, | ||||
| @ -124,11 +124,11 @@ describe('compiler: element transform', () => { | ||||
|     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' | ||||
| @ -145,11 +145,11 @@ describe('compiler: element transform', () => { | ||||
|     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, | ||||
| @ -166,11 +166,11 @@ describe('compiler: element transform', () => { | ||||
|     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' | ||||
| @ -190,18 +190,18 @@ describe('compiler: element transform', () => { | ||||
|     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, | ||||
| @ -220,18 +220,18 @@ describe('compiler: element transform', () => { | ||||
|     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, | ||||
| @ -249,7 +249,7 @@ describe('compiler: element transform', () => { | ||||
| 
 | ||||
|   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({ | ||||
| @ -281,7 +281,7 @@ describe('compiler: element transform', () => { | ||||
|         } | ||||
|       } | ||||
|     }) | ||||
|     expect(node.callee).toBe(`_${CREATE_VNODE}`) | ||||
|     expect(node.callee).toBe(CREATE_VNODE) | ||||
|     expect(node.arguments[1]).toMatchObject({ | ||||
|       type: NodeTypes.JS_OBJECT_EXPRESSION, | ||||
|       properties: [ | ||||
| @ -312,14 +312,14 @@ describe('compiler: element transform', () => { | ||||
|         } | ||||
|       } | ||||
|     ) | ||||
|     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`, | ||||
| @ -357,12 +357,12 @@ describe('compiler: element transform', () => { | ||||
|     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 | ||||
|  | ||||
| @ -10,7 +10,7 @@ import { transformElement } from '../../src/transforms/transformElement' | ||||
| 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 = {}) { | ||||
| @ -35,7 +35,7 @@ describe('compiler: transform <slot> outlets', () => { | ||||
|     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"`] | ||||
|     }) | ||||
|   }) | ||||
| @ -44,7 +44,7 @@ describe('compiler: transform <slot> outlets', () => { | ||||
|     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"`] | ||||
|     }) | ||||
|   }) | ||||
| @ -53,7 +53,7 @@ describe('compiler: transform <slot> outlets', () => { | ||||
|     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`, | ||||
|         { | ||||
| @ -98,7 +98,7 @@ describe('compiler: transform <slot> outlets', () => { | ||||
|     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"`, | ||||
| @ -135,7 +135,7 @@ describe('compiler: transform <slot> outlets', () => { | ||||
|     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"`, | ||||
| @ -173,7 +173,7 @@ describe('compiler: transform <slot> outlets', () => { | ||||
|     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 }, | ||||
| @ -211,7 +211,7 @@ describe('compiler: transform <slot> outlets', () => { | ||||
|     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"`, | ||||
| @ -230,7 +230,7 @@ describe('compiler: transform <slot> outlets', () => { | ||||
|     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"`, | ||||
| @ -249,7 +249,7 @@ describe('compiler: transform <slot> outlets', () => { | ||||
|     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"`, | ||||
| @ -282,7 +282,7 @@ describe('compiler: transform <slot> outlets', () => { | ||||
|     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"`, | ||||
|  | ||||
| @ -9,7 +9,7 @@ import { | ||||
| } 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( | ||||
| @ -123,7 +123,7 @@ describe('compiler: transform v-bind', () => { | ||||
|       .arguments[1] as ObjectExpression | ||||
|     expect(props.properties[0]).toMatchObject({ | ||||
|       key: { | ||||
|         content: `_${CAMELIZE}(foo)`, | ||||
|         content: `_${helperNameMap[CAMELIZE]}(foo)`, | ||||
|         isStatic: false | ||||
|       }, | ||||
|       value: { | ||||
| @ -142,7 +142,7 @@ describe('compiler: transform v-bind', () => { | ||||
|     expect(props.properties[0]).toMatchObject({ | ||||
|       key: { | ||||
|         children: [ | ||||
|           `${CAMELIZE}(`, | ||||
|           `${helperNameMap[CAMELIZE]}(`, | ||||
|           { content: `_ctx.foo` }, | ||||
|           `(`, | ||||
|           { content: `_ctx.bar` }, | ||||
|  | ||||
| @ -23,7 +23,7 @@ import { | ||||
|   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' | ||||
| @ -575,17 +575,17 @@ describe('compiler: v-for', () => { | ||||
|         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
 | ||||
|                   { | ||||
| @ -597,11 +597,11 @@ describe('compiler: v-for', () => { | ||||
|                           expressions: [ | ||||
|                             { | ||||
|                               type: NodeTypes.JS_CALL_EXPRESSION, | ||||
|                               callee: `_${OPEN_BLOCK}` | ||||
|                               callee: OPEN_BLOCK | ||||
|                             }, | ||||
|                             { | ||||
|                               type: NodeTypes.JS_CALL_EXPRESSION, | ||||
|                               callee: `_${CREATE_BLOCK}` | ||||
|                               callee: CREATE_BLOCK | ||||
|                             } | ||||
|                           ] | ||||
|                         } | ||||
| @ -703,7 +703,7 @@ describe('compiler: v-for', () => { | ||||
|         source: { content: `items` }, | ||||
|         params: [{ content: `item` }], | ||||
|         blockArgs: [ | ||||
|           `_${FRAGMENT}`, | ||||
|           FRAGMENT, | ||||
|           `null`, | ||||
|           [ | ||||
|             { type: NodeTypes.TEXT, content: `hello` }, | ||||
| @ -728,7 +728,7 @@ describe('compiler: v-for', () => { | ||||
|         params: [{ content: `item` }], | ||||
|         returns: { | ||||
|           type: NodeTypes.JS_CALL_EXPRESSION, | ||||
|           callee: `_${RENDER_SLOT}` | ||||
|           callee: RENDER_SLOT | ||||
|         } | ||||
|       }) | ||||
|       expect(generate(root).code).toMatchSnapshot() | ||||
| @ -746,7 +746,7 @@ describe('compiler: v-for', () => { | ||||
|         params: [{ content: `item` }], | ||||
|         returns: { | ||||
|           type: NodeTypes.JS_CALL_EXPRESSION, | ||||
|           callee: `_${RENDER_SLOT}` | ||||
|           callee: RENDER_SLOT | ||||
|         } | ||||
|       }) | ||||
|       expect(generate(root).code).toMatchSnapshot() | ||||
| @ -781,7 +781,7 @@ describe('compiler: v-for', () => { | ||||
|         source: { content: `items` }, | ||||
|         params: [{ content: `item` }], | ||||
|         blockArgs: [ | ||||
|           `_${FRAGMENT}`, | ||||
|           FRAGMENT, | ||||
|           createObjectMatcher({ | ||||
|             key: `[item]` | ||||
|           }), | ||||
| @ -804,7 +804,7 @@ describe('compiler: v-for', () => { | ||||
|         expressions: [ | ||||
|           { | ||||
|             type: NodeTypes.JS_CALL_EXPRESSION, | ||||
|             callee: `_${OPEN_BLOCK}`, | ||||
|             callee: OPEN_BLOCK, | ||||
|             arguments: [] | ||||
|           }, | ||||
|           { | ||||
| @ -812,14 +812,14 @@ describe('compiler: v-for', () => { | ||||
|             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` }, | ||||
|                     { | ||||
| @ -830,11 +830,11 @@ describe('compiler: v-for', () => { | ||||
|                         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"`] | ||||
|                           } | ||||
|                         ] | ||||
|  | ||||
| @ -24,7 +24,7 @@ import { | ||||
|   MERGE_PROPS, | ||||
|   APPLY_DIRECTIVES, | ||||
|   RENDER_SLOT | ||||
| } from '../../src/runtimeConstants' | ||||
| } from '../../src/runtimeHelpers' | ||||
| import { createObjectMatcher } from '../testUtils' | ||||
| 
 | ||||
| function parseWithIfTransform( | ||||
| @ -271,7 +271,7 @@ describe('compiler: v-if', () => { | ||||
|         expressions: [ | ||||
|           { | ||||
|             type: NodeTypes.JS_CALL_EXPRESSION, | ||||
|             callee: `_${OPEN_BLOCK}`, | ||||
|             callee: OPEN_BLOCK, | ||||
|             arguments: [] | ||||
|           }, | ||||
|           { | ||||
| @ -281,13 +281,13 @@ describe('compiler: v-if', () => { | ||||
|             }, | ||||
|             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, | ||||
| @ -296,11 +296,11 @@ describe('compiler: v-if', () => { | ||||
|                     }, | ||||
|                     consequent: { | ||||
|                       type: NodeTypes.JS_CALL_EXPRESSION, | ||||
|                       callee: `_${CREATE_BLOCK}` | ||||
|                       callee: CREATE_BLOCK | ||||
|                     }, | ||||
|                     alternate: { | ||||
|                       type: NodeTypes.JS_CALL_EXPRESSION, | ||||
|                       callee: `_${CREATE_BLOCK}` | ||||
|                       callee: CREATE_BLOCK | ||||
|                     } | ||||
|                   } | ||||
|           } | ||||
| @ -322,7 +322,7 @@ describe('compiler: v-if', () => { | ||||
|       ]) | ||||
|       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() | ||||
|     }) | ||||
| 
 | ||||
| @ -335,7 +335,7 @@ describe('compiler: v-if', () => { | ||||
|       const branch1 = (codegenNode.expressions[1] as ConditionalExpression) | ||||
|         .consequent as CallExpression | ||||
|       expect(branch1.arguments).toMatchObject([ | ||||
|         `_${FRAGMENT}`, | ||||
|         FRAGMENT, | ||||
|         createObjectMatcher({ key: `[0]` }), | ||||
|         [ | ||||
|           { type: NodeTypes.ELEMENT, tag: 'div' }, | ||||
| @ -345,7 +345,7 @@ describe('compiler: v-if', () => { | ||||
|       ]) | ||||
|       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() | ||||
|     }) | ||||
| 
 | ||||
| @ -359,7 +359,7 @@ describe('compiler: v-if', () => { | ||||
|         .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() | ||||
| @ -375,7 +375,7 @@ describe('compiler: v-if', () => { | ||||
|         .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() | ||||
| @ -444,7 +444,7 @@ describe('compiler: v-if', () => { | ||||
|         createObjectMatcher({ key: `[1]` }) | ||||
|       ]) | ||||
|       expect((branch2.alternate as CallExpression).arguments).toMatchObject([ | ||||
|         `_${FRAGMENT}`, | ||||
|         FRAGMENT, | ||||
|         createObjectMatcher({ key: `[2]` }), | ||||
|         [ | ||||
|           { | ||||
| @ -464,7 +464,7 @@ describe('compiler: v-if', () => { | ||||
|         .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` }] | ||||
|       }) | ||||
|     }) | ||||
| @ -477,7 +477,7 @@ describe('compiler: v-if', () => { | ||||
|         .consequent as CallExpression | ||||
|       expect(branch1.arguments[1]).toMatchObject({ | ||||
|         type: NodeTypes.JS_CALL_EXPRESSION, | ||||
|         callee: `_${MERGE_PROPS}`, | ||||
|         callee: MERGE_PROPS, | ||||
|         arguments: [ | ||||
|           createObjectMatcher({ | ||||
|             key: '[0]', | ||||
| @ -496,7 +496,7 @@ describe('compiler: v-if', () => { | ||||
|         .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` }, | ||||
| @ -513,7 +513,7 @@ describe('compiler: v-if', () => { | ||||
|       } = 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]` }) | ||||
|  | ||||
| @ -17,7 +17,7 @@ import { | ||||
|   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' | ||||
| @ -360,7 +360,7 @@ describe('compiler: transform component slots', () => { | ||||
|     ) | ||||
|     expect(slots).toMatchObject({ | ||||
|       type: NodeTypes.JS_CALL_EXPRESSION, | ||||
|       callee: `_${CREATE_SLOTS}`, | ||||
|       callee: CREATE_SLOTS, | ||||
|       arguments: [ | ||||
|         createObjectMatcher({ | ||||
|           _compiled: `[true]` | ||||
| @ -451,7 +451,7 @@ describe('compiler: transform component slots', () => { | ||||
|     ) | ||||
|     expect(slots).toMatchObject({ | ||||
|       type: NodeTypes.JS_CALL_EXPRESSION, | ||||
|       callee: `_${CREATE_SLOTS}`, | ||||
|       callee: CREATE_SLOTS, | ||||
|       arguments: [ | ||||
|         createObjectMatcher({ | ||||
|           _compiled: `[true]` | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| 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
 | ||||
| @ -76,8 +77,9 @@ export type TemplateChildNode = | ||||
| 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 | ||||
| } | ||||
| @ -93,6 +95,29 @@ export interface ElementNode extends Node { | ||||
|   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 | ||||
| @ -137,7 +162,12 @@ export interface InterpolationNode extends Node { | ||||
| // 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[] | ||||
| @ -146,9 +176,11 @@ export interface CompoundExpressionNode extends Node { | ||||
| 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
 | ||||
| @ -162,9 +194,11 @@ export interface ForNode extends Node { | ||||
|   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.
 | ||||
| @ -179,8 +213,13 @@ export type JSChildNode = | ||||
| 
 | ||||
| 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 { | ||||
|  | ||||
| @ -23,10 +23,19 @@ import { | ||||
|   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 | ||||
| 
 | ||||
| @ -65,7 +74,7 @@ export interface CodegenContext extends Required<CodegenOptions> { | ||||
|   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 | ||||
| @ -77,7 +86,7 @@ function createCodegenContext( | ||||
|   ast: RootNode, | ||||
|   { | ||||
|     mode = 'function', | ||||
|     prefixIdentifiers = false, | ||||
|     prefixIdentifiers = mode === 'module', | ||||
|     sourceMap = false, | ||||
|     filename = `template.vue.html` | ||||
|   }: CodegenOptions | ||||
| @ -100,7 +109,8 @@ function createCodegenContext( | ||||
|         ? undefined | ||||
|         : new (loadDep('source-map')).SourceMapGenerator(), | ||||
| 
 | ||||
|     helper(name) { | ||||
|     helper(key) { | ||||
|       const name = helperNameMap[key] | ||||
|       return prefixIdentifiers ? name : `_${name}` | ||||
|     }, | ||||
|     push(code, node, openOnly) { | ||||
| @ -172,8 +182,16 @@ export function generate( | ||||
|   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
 | ||||
| @ -182,9 +200,9 @@ export function generate( | ||||
|     // 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
 | ||||
| @ -193,7 +211,7 @@ export function generate( | ||||
|         // 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`) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| @ -202,8 +220,8 @@ export function generate( | ||||
|     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() | ||||
| @ -219,8 +237,12 @@ export function generate( | ||||
|     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() | ||||
|     } | ||||
| @ -230,11 +252,13 @@ export function generate( | ||||
|   } | ||||
| 
 | ||||
|   // 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() | ||||
|   } | ||||
| 
 | ||||
| @ -260,6 +284,23 @@ export function generate( | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 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 | ||||
| @ -297,7 +338,7 @@ function genNodeListAsArray( | ||||
| } | ||||
| 
 | ||||
| function genNodeList( | ||||
|   nodes: (string | CodegenNode | TemplateChildNode[])[], | ||||
|   nodes: (string | RuntimeHelper | CodegenNode | TemplateChildNode[])[], | ||||
|   context: CodegenContext, | ||||
|   multilines: boolean = false | ||||
| ) { | ||||
| @ -322,11 +363,18 @@ function genNodeList( | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 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: | ||||
| @ -450,7 +498,10 @@ function genComment(node: CommentNode, context: CodegenContext) { | ||||
| 
 | ||||
| // 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(`)`) | ||||
| } | ||||
|  | ||||
| @ -64,7 +64,10 @@ export function baseCompile( | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   return generate(ast, options) | ||||
|   return generate(ast, { | ||||
|     ...options, | ||||
|     prefixIdentifiers | ||||
|   }) | ||||
| } | ||||
| 
 | ||||
| // Also expose lower level APIs & types
 | ||||
|  | ||||
| @ -1,21 +0,0 @@ | ||||
| // 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` | ||||
							
								
								
									
										64
									
								
								packages/compiler-core/src/runtimeHelpers.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								packages/compiler-core/src/runtimeHelpers.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | ||||
| 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` | ||||
| } | ||||
| @ -14,7 +14,14 @@ import { | ||||
| } 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' | ||||
| 
 | ||||
| @ -57,8 +64,9 @@ export interface TransformOptions { | ||||
| 
 | ||||
| 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: { | ||||
| @ -70,7 +78,8 @@ export interface TransformContext extends Required<TransformOptions> { | ||||
|   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 | ||||
| @ -91,8 +100,9 @@ function createTransformContext( | ||||
| ): TransformContext { | ||||
|   const context: TransformContext = { | ||||
|     root, | ||||
|     imports: new Set(), | ||||
|     statements: new Set(), | ||||
|     helpers: new Set(), | ||||
|     components: new Set(), | ||||
|     directives: new Set(), | ||||
|     hoists: [], | ||||
|     identifiers: {}, | ||||
|     scopes: { | ||||
| @ -110,8 +120,14 @@ function createTransformContext( | ||||
|     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 */ | ||||
| @ -242,8 +258,9 @@ function finalizeRoot(root: RootNode, context: TransformContext) { | ||||
|   } | ||||
| 
 | ||||
|   // 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 | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -7,7 +7,7 @@ import { | ||||
|   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' | ||||
| 
 | ||||
| @ -41,7 +41,7 @@ function walk( | ||||
|           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 | ||||
| @ -68,7 +68,7 @@ function walk( | ||||
| 
 | ||||
| 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] | ||||
|  | ||||
| @ -25,12 +25,10 @@ import { | ||||
|   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) { | ||||
| @ -50,19 +48,14 @@ export const transformElement: NodeTransform = (node, context) => { | ||||
|         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) { | ||||
| @ -402,13 +395,11 @@ function createDirectiveArgs( | ||||
|   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) | ||||
|  | ||||
| @ -8,7 +8,7 @@ import { | ||||
| 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)) { | ||||
|  | ||||
| @ -2,7 +2,7 @@ import { DirectiveTransform } from '../transform' | ||||
| 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
 | ||||
| @ -20,10 +20,10 @@ export const transformBind: DirectiveTransform = (dir, context) => { | ||||
|       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(`)`) | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @ -30,7 +30,7 @@ import { | ||||
|   OPEN_BLOCK, | ||||
|   CREATE_BLOCK, | ||||
|   FRAGMENT | ||||
| } from '../runtimeConstants' | ||||
| } from '../runtimeHelpers' | ||||
| import { processExpression } from './transformExpression' | ||||
| import { PatchFlags, PatchFlagNames } from '@vue/shared' | ||||
| import { PropsExpression } from './transformElement' | ||||
|  | ||||
| @ -29,7 +29,7 @@ import { | ||||
|   APPLY_DIRECTIVES, | ||||
|   CREATE_VNODE, | ||||
|   RENDER_SLOT | ||||
| } from '../runtimeConstants' | ||||
| } from '../runtimeHelpers' | ||||
| import { injectProp } from '../utils' | ||||
| import { PropsExpression } from './transformElement' | ||||
| 
 | ||||
| @ -184,18 +184,18 @@ function createChildrenCodegenNode( | ||||
|     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 | ||||
|  | ||||
| @ -24,7 +24,7 @@ import { | ||||
| 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 => | ||||
|  | ||||
| @ -19,7 +19,7 @@ import { | ||||
| 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' | ||||
| 
 | ||||
| @ -217,3 +217,10 @@ export function injectProp( | ||||
|     ]) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export function toValidAssetId( | ||||
|   name: string, | ||||
|   type: 'component' | 'directive' | ||||
| ): string { | ||||
|   return `_${type}_${name.replace(/[^\w]/g, '')}` | ||||
| } | ||||
|  | ||||
| @ -30,6 +30,7 @@ export const isArray = Array.isArray | ||||
| 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' | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user