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() { | return function render() { | ||||||
|   with (this) { |   with (this) { | ||||||
|     return createVNode(\\"div\\", { |     return _createVNode(\\"div\\", { | ||||||
|       id: \\"foo\\", |       id: \\"foo\\", | ||||||
|       [prop]: bar, |       [prop]: bar, | ||||||
|       [foo + bar]: bar |       [foo + bar]: bar | ||||||
|     }, [ |     }, [ | ||||||
|       createVNode(\\"p\\", { \\"some-key\\": \\"foo\\" }) |       _createVNode(\\"p\\", { \\"some-key\\": \\"foo\\" }) | ||||||
|     ], [ |     ], [ | ||||||
|       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`] = ` | exports[`compiler: codegen comment 1`] = ` | ||||||
| " | " | ||||||
| return function render() { | return function render() { | ||||||
| @ -72,7 +85,7 @@ exports[`compiler: codegen function mode preamble 1`] = ` | |||||||
| 
 | 
 | ||||||
| return function render() { | return function render() { | ||||||
|   with (this) { |   with (this) { | ||||||
|     const { helperOne: _helperOne, helperTwo: _helperTwo } = _Vue |     const { createVNode: _createVNode, resolveDirective: _resolveDirective } = _Vue | ||||||
|      |      | ||||||
|     return null |     return null | ||||||
|   } |   } | ||||||
| @ -80,7 +93,7 @@ return function render() { | |||||||
| `; | `; | ||||||
| 
 | 
 | ||||||
| exports[`compiler: codegen function mode preamble w/ prefixIdentifiers: true 1`] = ` | exports[`compiler: codegen function mode preamble w/ prefixIdentifiers: true 1`] = ` | ||||||
| "const { helperOne, helperTwo } = Vue | "const { createVNode, resolveDirective } = Vue | ||||||
| 
 | 
 | ||||||
| return function render() { | return function render() { | ||||||
|   const _ctx = this |   const _ctx = this | ||||||
| @ -119,7 +132,7 @@ return function render() { | |||||||
| `; | `; | ||||||
| 
 | 
 | ||||||
| exports[`compiler: codegen module mode preamble 1`] = ` | exports[`compiler: codegen module mode preamble 1`] = ` | ||||||
| "import { helperOne, helperTwo } from \\"vue\\" | "import { createVNode, resolveDirective } from \\"vue\\" | ||||||
| 
 | 
 | ||||||
| export default function render() { | export default function render() { | ||||||
|   const _ctx = this |   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`] = ` | exports[`compiler: codegen static text 1`] = ` | ||||||
| " | " | ||||||
| return function render() { | return function render() { | ||||||
|  | |||||||
| @ -56,13 +56,13 @@ export default function render() { | |||||||
|     id: \\"foo\\", |     id: \\"foo\\", | ||||||
|     class: _ctx.bar.baz |     class: _ctx.bar.baz | ||||||
|   }, [ |   }, [ | ||||||
|     _toString(_ctx.world.burn()), |     toString(_ctx.world.burn()), | ||||||
|     (openBlock(), (_ctx.ok) |     (openBlock(), (_ctx.ok) | ||||||
|       ? createBlock(\\"div\\", { key: 0 }, \\"yes\\") |       ? createBlock(\\"div\\", { key: 0 }, \\"yes\\") | ||||||
|       : createBlock(Fragment, { key: 1 }, [\\"no\\"])), |       : createBlock(Fragment, { key: 1 }, [\\"no\\"])), | ||||||
|     (openBlock(), createBlock(Fragment, null, renderList(_ctx.list, (value, index) => { |     (openBlock(), createBlock(Fragment, null, renderList(_ctx.list, (value, index) => { | ||||||
|       return (openBlock(), createBlock(\\"div\\", null, [ |       return (openBlock(), createBlock(\\"div\\", null, [ | ||||||
|         createVNode(\\"span\\", null, _toString(value + index), 1 /* TEXT */) |         createVNode(\\"span\\", null, toString(value + index), 1 /* TEXT */) | ||||||
|       ])) |       ])) | ||||||
|     }), 128 /* UNKEYED_FRAGMENT */)) |     }), 128 /* UNKEYED_FRAGMENT */)) | ||||||
|   ], 2 /* CLASS */)) |   ], 2 /* CLASS */)) | ||||||
|  | |||||||
| @ -13,15 +13,23 @@ import { | |||||||
|   createCallExpression, |   createCallExpression, | ||||||
|   createConditionalExpression |   createConditionalExpression | ||||||
| } from '../src' | } 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' | import { createElementWithCodegen } from './testUtils' | ||||||
| 
 | 
 | ||||||
| function createRoot(options: Partial<RootNode> = {}): RootNode { | function createRoot(options: Partial<RootNode> = {}): RootNode { | ||||||
|   return { |   return { | ||||||
|     type: NodeTypes.ROOT, |     type: NodeTypes.ROOT, | ||||||
|     children: [], |     children: [], | ||||||
|     imports: [], |     helpers: [], | ||||||
|     statements: [], |     components: [], | ||||||
|  |     directives: [], | ||||||
|     hoists: [], |     hoists: [], | ||||||
|     codegenNode: undefined, |     codegenNode: undefined, | ||||||
|     loc: locStub, |     loc: locStub, | ||||||
| @ -32,45 +40,69 @@ function createRoot(options: Partial<RootNode> = {}): RootNode { | |||||||
| describe('compiler: codegen', () => { | describe('compiler: codegen', () => { | ||||||
|   test('module mode preamble', () => { |   test('module mode preamble', () => { | ||||||
|     const root = createRoot({ |     const root = createRoot({ | ||||||
|       imports: [`helperOne`, `helperTwo`] |       helpers: [CREATE_VNODE, RESOLVE_DIRECTIVE] | ||||||
|     }) |     }) | ||||||
|     const { code } = generate(root, { mode: 'module' }) |     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() |     expect(code).toMatchSnapshot() | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   test('function mode preamble', () => { |   test('function mode preamble', () => { | ||||||
|     const root = createRoot({ |     const root = createRoot({ | ||||||
|       imports: [`helperOne`, `helperTwo`] |       helpers: [CREATE_VNODE, RESOLVE_DIRECTIVE] | ||||||
|     }) |     }) | ||||||
|     const { code } = generate(root, { mode: 'function' }) |     const { code } = generate(root, { mode: 'function' }) | ||||||
|     expect(code).toMatch(`const _Vue = Vue`) |     expect(code).toMatch(`const _Vue = Vue`) | ||||||
|     expect(code).toMatch( |     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() |     expect(code).toMatchSnapshot() | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   test('function mode preamble w/ prefixIdentifiers: true', () => { |   test('function mode preamble w/ prefixIdentifiers: true', () => { | ||||||
|     const root = createRoot({ |     const root = createRoot({ | ||||||
|       imports: [`helperOne`, `helperTwo`] |       helpers: [CREATE_VNODE, RESOLVE_DIRECTIVE] | ||||||
|     }) |     }) | ||||||
|     const { code } = generate(root, { |     const { code } = generate(root, { | ||||||
|       mode: 'function', |       mode: 'function', | ||||||
|       prefixIdentifiers: true |       prefixIdentifiers: true | ||||||
|     }) |     }) | ||||||
|     expect(code).not.toMatch(`const _Vue = Vue`) |     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() |     expect(code).toMatchSnapshot() | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   test('statements', () => { |   test('assets', () => { | ||||||
|     const root = createRoot({ |     const root = createRoot({ | ||||||
|       statements: [`const a = 1`, `const b = 2`] |       components: [`Foo`, `bar-baz`], | ||||||
|  |       directives: [`my_dir`] | ||||||
|     }) |     }) | ||||||
|     const { code } = generate(root, { mode: 'function' }) |     const { code } = generate(root, { mode: 'function' }) | ||||||
|     expect(code).toMatch(`const a = 1\n`) |     expect(code).toMatch( | ||||||
|     expect(code).toMatch(`const b = 2\n`) |       `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() |     expect(code).toMatchSnapshot() | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
| @ -122,7 +154,7 @@ describe('compiler: codegen', () => { | |||||||
|         codegenNode: createInterpolation(`hello`, locStub) |         codegenNode: createInterpolation(`hello`, locStub) | ||||||
|       }) |       }) | ||||||
|     ) |     ) | ||||||
|     expect(code).toMatch(`return _${TO_STRING}(hello)`) |     expect(code).toMatch(`return _${helperNameMap[TO_STRING]}(hello)`) | ||||||
|     expect(code).toMatchSnapshot() |     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() |     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() |     expect(code).toMatchSnapshot() | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
| @ -264,15 +300,15 @@ describe('compiler: codegen', () => { | |||||||
|       }) |       }) | ||||||
|     ) |     ) | ||||||
|     expect(code).toMatch(` |     expect(code).toMatch(` | ||||||
|     return ${CREATE_VNODE}("div", { |     return _${helperNameMap[CREATE_VNODE]}("div", { | ||||||
|       id: "foo", |       id: "foo", | ||||||
|       [prop]: bar, |       [prop]: bar, | ||||||
|       [foo + bar]: bar |       [foo + bar]: bar | ||||||
|     }, [ |     }, [ | ||||||
|       ${CREATE_VNODE}("p", { "some-key": "foo" }) |       _${helperNameMap[CREATE_VNODE]}("p", { "some-key": "foo" }) | ||||||
|     ], [ |     ], [ | ||||||
|       foo, |       foo, | ||||||
|       ${CREATE_VNODE}("p") |       _${helperNameMap[CREATE_VNODE]}("p") | ||||||
|     ])`)
 |     ])`)
 | ||||||
|     expect(code).toMatchSnapshot() |     expect(code).toMatchSnapshot() | ||||||
|   }) |   }) | ||||||
|  | |||||||
| @ -6,7 +6,7 @@ import { | |||||||
|   Namespaces, |   Namespaces, | ||||||
|   ElementTypes |   ElementTypes | ||||||
| } from '../src' | } from '../src' | ||||||
| import { CREATE_VNODE } from '../src/runtimeConstants' | import { CREATE_VNODE } from '../src/runtimeHelpers' | ||||||
| import { isString } from '@vue/shared' | import { isString } from '@vue/shared' | ||||||
| 
 | 
 | ||||||
| const leadingBracketRE = /^\[/ | const leadingBracketRE = /^\[/ | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ import { | |||||||
|   CREATE_BLOCK, |   CREATE_BLOCK, | ||||||
|   FRAGMENT, |   FRAGMENT, | ||||||
|   RENDER_SLOT |   RENDER_SLOT | ||||||
| } from '../src/runtimeConstants' | } from '../src/runtimeHelpers' | ||||||
| import { transformIf } from '../src/transforms/vIf' | import { transformIf } from '../src/transforms/vIf' | ||||||
| import { transformFor } from '../src/transforms/vFor' | import { transformFor } from '../src/transforms/vFor' | ||||||
| import { transformElement } from '../src/transforms/transformElement' | import { transformElement } from '../src/transforms/transformElement' | ||||||
| @ -225,14 +225,14 @@ describe('compiler: transform', () => { | |||||||
|   test('should inject toString helper for interpolations', () => { |   test('should inject toString helper for interpolations', () => { | ||||||
|     const ast = parse(`{{ foo }}`) |     const ast = parse(`{{ foo }}`) | ||||||
|     transform(ast, {}) |     transform(ast, {}) | ||||||
|     expect(ast.imports).toContain(TO_STRING) |     expect(ast.helpers).toContain(TO_STRING) | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   test('should inject createVNode and Comment for comments', () => { |   test('should inject createVNode and Comment for comments', () => { | ||||||
|     const ast = parse(`<!--foo-->`) |     const ast = parse(`<!--foo-->`) | ||||||
|     transform(ast, {}) |     transform(ast, {}) | ||||||
|     expect(ast.imports).toContain(CREATE_VNODE) |     expect(ast.helpers).toContain(CREATE_VNODE) | ||||||
|     expect(ast.imports).toContain(COMMENT) |     expect(ast.helpers).toContain(COMMENT) | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   describe('root codegenNode', () => { |   describe('root codegenNode', () => { | ||||||
| @ -256,11 +256,11 @@ describe('compiler: transform', () => { | |||||||
|         expressions: [ |         expressions: [ | ||||||
|           { |           { | ||||||
|             type: NodeTypes.JS_CALL_EXPRESSION, |             type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|             callee: `_${OPEN_BLOCK}` |             callee: OPEN_BLOCK | ||||||
|           }, |           }, | ||||||
|           { |           { | ||||||
|             type: NodeTypes.JS_CALL_EXPRESSION, |             type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|             callee: `_${CREATE_BLOCK}`, |             callee: CREATE_BLOCK, | ||||||
|             arguments: args |             arguments: args | ||||||
|           } |           } | ||||||
|         ] |         ] | ||||||
| @ -277,7 +277,7 @@ describe('compiler: transform', () => { | |||||||
|       expect(ast.codegenNode).toMatchObject({ |       expect(ast.codegenNode).toMatchObject({ | ||||||
|         codegenNode: { |         codegenNode: { | ||||||
|           type: NodeTypes.JS_CALL_EXPRESSION, |           type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|           callee: `_${RENDER_SLOT}` |           callee: RENDER_SLOT | ||||||
|         } |         } | ||||||
|       }) |       }) | ||||||
|     }) |     }) | ||||||
| @ -326,7 +326,7 @@ describe('compiler: transform', () => { | |||||||
|       const ast = transformWithCodegen(`<div/><div/>`) |       const ast = transformWithCodegen(`<div/><div/>`) | ||||||
|       expect(ast.codegenNode).toMatchObject( |       expect(ast.codegenNode).toMatchObject( | ||||||
|         createBlockMatcher([ |         createBlockMatcher([ | ||||||
|           `_${FRAGMENT}`, |           FRAGMENT, | ||||||
|           `null`, |           `null`, | ||||||
|           [ |           [ | ||||||
|             { type: NodeTypes.ELEMENT, tag: `div` }, |             { type: NodeTypes.ELEMENT, tag: `div` }, | ||||||
|  | |||||||
| @ -12,7 +12,7 @@ import { | |||||||
|   RESOLVE_DIRECTIVE, |   RESOLVE_DIRECTIVE, | ||||||
|   APPLY_DIRECTIVES, |   APPLY_DIRECTIVES, | ||||||
|   TO_HANDLERS |   TO_HANDLERS | ||||||
| } from '../../src/runtimeConstants' | } from '../../src/runtimeHelpers' | ||||||
| import { | import { | ||||||
|   CallExpression, |   CallExpression, | ||||||
|   NodeTypes, |   NodeTypes, | ||||||
| @ -52,13 +52,13 @@ function parseWithElementTransform( | |||||||
| describe('compiler: element transform', () => { | describe('compiler: element transform', () => { | ||||||
|   test('import + resolve component', () => { |   test('import + resolve component', () => { | ||||||
|     const { root } = parseWithElementTransform(`<Foo/>`) |     const { root } = parseWithElementTransform(`<Foo/>`) | ||||||
|     expect(root.imports).toContain(RESOLVE_COMPONENT) |     expect(root.helpers).toContain(RESOLVE_COMPONENT) | ||||||
|     expect(root.statements[0]).toMatch(`${RESOLVE_COMPONENT}("Foo")`) |     expect(root.components).toContain(`Foo`) | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   test('static props', () => { |   test('static props', () => { | ||||||
|     const { node } = parseWithElementTransform(`<div id="foo" class="bar" />`) |     const { node } = parseWithElementTransform(`<div id="foo" class="bar" />`) | ||||||
|     expect(node.callee).toBe(`_${CREATE_VNODE}`) |     expect(node.callee).toBe(CREATE_VNODE) | ||||||
|     expect(node.arguments).toMatchObject([ |     expect(node.arguments).toMatchObject([ | ||||||
|       `"div"`, |       `"div"`, | ||||||
|       createObjectMatcher({ |       createObjectMatcher({ | ||||||
| @ -70,7 +70,7 @@ describe('compiler: element transform', () => { | |||||||
| 
 | 
 | ||||||
|   test('props + children', () => { |   test('props + children', () => { | ||||||
|     const { node } = parseWithElementTransform(`<div id="foo"><span/></div>`) |     const { node } = parseWithElementTransform(`<div id="foo"><span/></div>`) | ||||||
|     expect(node.callee).toBe(`_${CREATE_VNODE}`) |     expect(node.callee).toBe(CREATE_VNODE) | ||||||
|     expect(node.arguments).toMatchObject([ |     expect(node.arguments).toMatchObject([ | ||||||
|       `"div"`, |       `"div"`, | ||||||
|       createObjectMatcher({ |       createObjectMatcher({ | ||||||
| @ -81,7 +81,7 @@ describe('compiler: element transform', () => { | |||||||
|           type: NodeTypes.ELEMENT, |           type: NodeTypes.ELEMENT, | ||||||
|           tag: 'span', |           tag: 'span', | ||||||
|           codegenNode: { |           codegenNode: { | ||||||
|             callee: `_${CREATE_VNODE}`, |             callee: CREATE_VNODE, | ||||||
|             arguments: [`"span"`] |             arguments: [`"span"`] | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
| @ -91,7 +91,7 @@ describe('compiler: element transform', () => { | |||||||
| 
 | 
 | ||||||
|   test('0 placeholder for children with no props', () => { |   test('0 placeholder for children with no props', () => { | ||||||
|     const { node } = parseWithElementTransform(`<div><span/></div>`) |     const { node } = parseWithElementTransform(`<div><span/></div>`) | ||||||
|     expect(node.callee).toBe(`_${CREATE_VNODE}`) |     expect(node.callee).toBe(CREATE_VNODE) | ||||||
|     expect(node.arguments).toMatchObject([ |     expect(node.arguments).toMatchObject([ | ||||||
|       `"div"`, |       `"div"`, | ||||||
|       `null`, |       `null`, | ||||||
| @ -100,7 +100,7 @@ describe('compiler: element transform', () => { | |||||||
|           type: NodeTypes.ELEMENT, |           type: NodeTypes.ELEMENT, | ||||||
|           tag: 'span', |           tag: 'span', | ||||||
|           codegenNode: { |           codegenNode: { | ||||||
|             callee: `_${CREATE_VNODE}`, |             callee: CREATE_VNODE, | ||||||
|             arguments: [`"span"`] |             arguments: [`"span"`] | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
| @ -111,8 +111,8 @@ describe('compiler: element transform', () => { | |||||||
|   test('v-bind="obj"', () => { |   test('v-bind="obj"', () => { | ||||||
|     const { root, node } = parseWithElementTransform(`<div v-bind="obj" />`) |     const { root, node } = parseWithElementTransform(`<div v-bind="obj" />`) | ||||||
|     // single v-bind doesn't need mergeProps
 |     // single v-bind doesn't need mergeProps
 | ||||||
|     expect(root.imports).not.toContain(MERGE_PROPS) |     expect(root.helpers).not.toContain(MERGE_PROPS) | ||||||
|     expect(node.callee).toBe(`_${CREATE_VNODE}`) |     expect(node.callee).toBe(CREATE_VNODE) | ||||||
|     // should directly use `obj` in props position
 |     // should directly use `obj` in props position
 | ||||||
|     expect(node.arguments[1]).toMatchObject({ |     expect(node.arguments[1]).toMatchObject({ | ||||||
|       type: NodeTypes.SIMPLE_EXPRESSION, |       type: NodeTypes.SIMPLE_EXPRESSION, | ||||||
| @ -124,11 +124,11 @@ describe('compiler: element transform', () => { | |||||||
|     const { root, node } = parseWithElementTransform( |     const { root, node } = parseWithElementTransform( | ||||||
|       `<div id="foo" v-bind="obj" />` |       `<div id="foo" v-bind="obj" />` | ||||||
|     ) |     ) | ||||||
|     expect(root.imports).toContain(MERGE_PROPS) |     expect(root.helpers).toContain(MERGE_PROPS) | ||||||
|     expect(node.callee).toBe(`_${CREATE_VNODE}`) |     expect(node.callee).toBe(CREATE_VNODE) | ||||||
|     expect(node.arguments[1]).toMatchObject({ |     expect(node.arguments[1]).toMatchObject({ | ||||||
|       type: NodeTypes.JS_CALL_EXPRESSION, |       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|       callee: `_${MERGE_PROPS}`, |       callee: MERGE_PROPS, | ||||||
|       arguments: [ |       arguments: [ | ||||||
|         createObjectMatcher({ |         createObjectMatcher({ | ||||||
|           id: 'foo' |           id: 'foo' | ||||||
| @ -145,11 +145,11 @@ describe('compiler: element transform', () => { | |||||||
|     const { root, node } = parseWithElementTransform( |     const { root, node } = parseWithElementTransform( | ||||||
|       `<div v-bind="obj" id="foo" />` |       `<div v-bind="obj" id="foo" />` | ||||||
|     ) |     ) | ||||||
|     expect(root.imports).toContain(MERGE_PROPS) |     expect(root.helpers).toContain(MERGE_PROPS) | ||||||
|     expect(node.callee).toBe(`_${CREATE_VNODE}`) |     expect(node.callee).toBe(CREATE_VNODE) | ||||||
|     expect(node.arguments[1]).toMatchObject({ |     expect(node.arguments[1]).toMatchObject({ | ||||||
|       type: NodeTypes.JS_CALL_EXPRESSION, |       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|       callee: `_${MERGE_PROPS}`, |       callee: MERGE_PROPS, | ||||||
|       arguments: [ |       arguments: [ | ||||||
|         { |         { | ||||||
|           type: NodeTypes.SIMPLE_EXPRESSION, |           type: NodeTypes.SIMPLE_EXPRESSION, | ||||||
| @ -166,11 +166,11 @@ describe('compiler: element transform', () => { | |||||||
|     const { root, node } = parseWithElementTransform( |     const { root, node } = parseWithElementTransform( | ||||||
|       `<div id="foo" v-bind="obj" class="bar" />` |       `<div id="foo" v-bind="obj" class="bar" />` | ||||||
|     ) |     ) | ||||||
|     expect(root.imports).toContain(MERGE_PROPS) |     expect(root.helpers).toContain(MERGE_PROPS) | ||||||
|     expect(node.callee).toBe(`_${CREATE_VNODE}`) |     expect(node.callee).toBe(CREATE_VNODE) | ||||||
|     expect(node.arguments[1]).toMatchObject({ |     expect(node.arguments[1]).toMatchObject({ | ||||||
|       type: NodeTypes.JS_CALL_EXPRESSION, |       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|       callee: `_${MERGE_PROPS}`, |       callee: MERGE_PROPS, | ||||||
|       arguments: [ |       arguments: [ | ||||||
|         createObjectMatcher({ |         createObjectMatcher({ | ||||||
|           id: 'foo' |           id: 'foo' | ||||||
| @ -190,18 +190,18 @@ describe('compiler: element transform', () => { | |||||||
|     const { root, node } = parseWithElementTransform( |     const { root, node } = parseWithElementTransform( | ||||||
|       `<div id="foo" v-on="obj" class="bar" />` |       `<div id="foo" v-on="obj" class="bar" />` | ||||||
|     ) |     ) | ||||||
|     expect(root.imports).toContain(MERGE_PROPS) |     expect(root.helpers).toContain(MERGE_PROPS) | ||||||
|     expect(node.callee).toBe(`_${CREATE_VNODE}`) |     expect(node.callee).toBe(CREATE_VNODE) | ||||||
|     expect(node.arguments[1]).toMatchObject({ |     expect(node.arguments[1]).toMatchObject({ | ||||||
|       type: NodeTypes.JS_CALL_EXPRESSION, |       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|       callee: `_${MERGE_PROPS}`, |       callee: MERGE_PROPS, | ||||||
|       arguments: [ |       arguments: [ | ||||||
|         createObjectMatcher({ |         createObjectMatcher({ | ||||||
|           id: 'foo' |           id: 'foo' | ||||||
|         }), |         }), | ||||||
|         { |         { | ||||||
|           type: NodeTypes.JS_CALL_EXPRESSION, |           type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|           callee: `_${TO_HANDLERS}`, |           callee: TO_HANDLERS, | ||||||
|           arguments: [ |           arguments: [ | ||||||
|             { |             { | ||||||
|               type: NodeTypes.SIMPLE_EXPRESSION, |               type: NodeTypes.SIMPLE_EXPRESSION, | ||||||
| @ -220,18 +220,18 @@ describe('compiler: element transform', () => { | |||||||
|     const { root, node } = parseWithElementTransform( |     const { root, node } = parseWithElementTransform( | ||||||
|       `<div id="foo" v-on="handlers" v-bind="obj" />` |       `<div id="foo" v-on="handlers" v-bind="obj" />` | ||||||
|     ) |     ) | ||||||
|     expect(root.imports).toContain(MERGE_PROPS) |     expect(root.helpers).toContain(MERGE_PROPS) | ||||||
|     expect(node.callee).toBe(`_${CREATE_VNODE}`) |     expect(node.callee).toBe(CREATE_VNODE) | ||||||
|     expect(node.arguments[1]).toMatchObject({ |     expect(node.arguments[1]).toMatchObject({ | ||||||
|       type: NodeTypes.JS_CALL_EXPRESSION, |       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|       callee: `_${MERGE_PROPS}`, |       callee: MERGE_PROPS, | ||||||
|       arguments: [ |       arguments: [ | ||||||
|         createObjectMatcher({ |         createObjectMatcher({ | ||||||
|           id: 'foo' |           id: 'foo' | ||||||
|         }), |         }), | ||||||
|         { |         { | ||||||
|           type: NodeTypes.JS_CALL_EXPRESSION, |           type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|           callee: `_${TO_HANDLERS}`, |           callee: TO_HANDLERS, | ||||||
|           arguments: [ |           arguments: [ | ||||||
|             { |             { | ||||||
|               type: NodeTypes.SIMPLE_EXPRESSION, |               type: NodeTypes.SIMPLE_EXPRESSION, | ||||||
| @ -249,7 +249,7 @@ describe('compiler: element transform', () => { | |||||||
| 
 | 
 | ||||||
|   test('should handle plain <template> as normal element', () => { |   test('should handle plain <template> as normal element', () => { | ||||||
|     const { node } = parseWithElementTransform(`<template id="foo" />`) |     const { node } = parseWithElementTransform(`<template id="foo" />`) | ||||||
|     expect(node.callee).toBe(`_${CREATE_VNODE}`) |     expect(node.callee).toBe(CREATE_VNODE) | ||||||
|     expect(node.arguments).toMatchObject([ |     expect(node.arguments).toMatchObject([ | ||||||
|       `"template"`, |       `"template"`, | ||||||
|       createObjectMatcher({ |       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({ |     expect(node.arguments[1]).toMatchObject({ | ||||||
|       type: NodeTypes.JS_OBJECT_EXPRESSION, |       type: NodeTypes.JS_OBJECT_EXPRESSION, | ||||||
|       properties: [ |       properties: [ | ||||||
| @ -312,14 +312,14 @@ describe('compiler: element transform', () => { | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     ) |     ) | ||||||
|     expect(root.imports).toContain(RESOLVE_DIRECTIVE) |     expect(root.helpers).toContain(RESOLVE_DIRECTIVE) | ||||||
|     expect(root.statements[0]).toMatch(`${RESOLVE_DIRECTIVE}("foo")`) |     expect(root.directives).toContain(`foo`) | ||||||
| 
 | 
 | ||||||
|     expect(node.callee).toBe(`_${APPLY_DIRECTIVES}`) |     expect(node.callee).toBe(APPLY_DIRECTIVES) | ||||||
|     expect(node.arguments).toMatchObject([ |     expect(node.arguments).toMatchObject([ | ||||||
|       { |       { | ||||||
|         type: NodeTypes.JS_CALL_EXPRESSION, |         type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|         callee: `_${CREATE_VNODE}`, |         callee: CREATE_VNODE, | ||||||
|         arguments: [ |         arguments: [ | ||||||
|           `"div"`, |           `"div"`, | ||||||
|           `null`, |           `null`, | ||||||
| @ -357,12 +357,12 @@ describe('compiler: element transform', () => { | |||||||
|     const { root, node } = parseWithElementTransform( |     const { root, node } = parseWithElementTransform( | ||||||
|       `<div v-foo v-bar="x" v-baz:[arg].mod.mad="y" />` |       `<div v-foo v-bar="x" v-baz:[arg].mod.mad="y" />` | ||||||
|     ) |     ) | ||||||
|     expect(root.imports).toContain(RESOLVE_DIRECTIVE) |     expect(root.helpers).toContain(RESOLVE_DIRECTIVE) | ||||||
|     expect(root.statements[0]).toMatch(`${RESOLVE_DIRECTIVE}("foo")`) |     expect(root.directives).toContain(`foo`) | ||||||
|     expect(root.statements[1]).toMatch(`${RESOLVE_DIRECTIVE}("bar")`) |     expect(root.directives).toContain(`bar`) | ||||||
|     expect(root.statements[2]).toMatch(`${RESOLVE_DIRECTIVE}("baz")`) |     expect(root.directives).toContain(`baz`) | ||||||
| 
 | 
 | ||||||
|     expect(node.callee).toBe(`_${APPLY_DIRECTIVES}`) |     expect(node.callee).toBe(APPLY_DIRECTIVES) | ||||||
|     expect(node.arguments).toMatchObject([ |     expect(node.arguments).toMatchObject([ | ||||||
|       { |       { | ||||||
|         type: NodeTypes.JS_CALL_EXPRESSION |         type: NodeTypes.JS_CALL_EXPRESSION | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ import { transformElement } from '../../src/transforms/transformElement' | |||||||
| import { transformOn } from '../../src/transforms/vOn' | import { transformOn } from '../../src/transforms/vOn' | ||||||
| import { transformBind } from '../../src/transforms/vBind' | import { transformBind } from '../../src/transforms/vBind' | ||||||
| import { transformExpression } from '../../src/transforms/transformExpression' | import { transformExpression } from '../../src/transforms/transformExpression' | ||||||
| import { RENDER_SLOT } from '../../src/runtimeConstants' | import { RENDER_SLOT } from '../../src/runtimeHelpers' | ||||||
| import { transformSlotOutlet } from '../../src/transforms/transformSlotOutlet' | import { transformSlotOutlet } from '../../src/transforms/transformSlotOutlet' | ||||||
| 
 | 
 | ||||||
| function parseWithSlots(template: string, options: CompilerOptions = {}) { | function parseWithSlots(template: string, options: CompilerOptions = {}) { | ||||||
| @ -35,7 +35,7 @@ describe('compiler: transform <slot> outlets', () => { | |||||||
|     const ast = parseWithSlots(`<slot/>`) |     const ast = parseWithSlots(`<slot/>`) | ||||||
|     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ |     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ | ||||||
|       type: NodeTypes.JS_CALL_EXPRESSION, |       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|       callee: `_${RENDER_SLOT}`, |       callee: RENDER_SLOT, | ||||||
|       arguments: [`$slots`, `"default"`] |       arguments: [`$slots`, `"default"`] | ||||||
|     }) |     }) | ||||||
|   }) |   }) | ||||||
| @ -44,7 +44,7 @@ describe('compiler: transform <slot> outlets', () => { | |||||||
|     const ast = parseWithSlots(`<slot name="foo" />`) |     const ast = parseWithSlots(`<slot name="foo" />`) | ||||||
|     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ |     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ | ||||||
|       type: NodeTypes.JS_CALL_EXPRESSION, |       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|       callee: `_${RENDER_SLOT}`, |       callee: RENDER_SLOT, | ||||||
|       arguments: [`$slots`, `"foo"`] |       arguments: [`$slots`, `"foo"`] | ||||||
|     }) |     }) | ||||||
|   }) |   }) | ||||||
| @ -53,7 +53,7 @@ describe('compiler: transform <slot> outlets', () => { | |||||||
|     const ast = parseWithSlots(`<slot :name="foo" />`) |     const ast = parseWithSlots(`<slot :name="foo" />`) | ||||||
|     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ |     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ | ||||||
|       type: NodeTypes.JS_CALL_EXPRESSION, |       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|       callee: `_${RENDER_SLOT}`, |       callee: RENDER_SLOT, | ||||||
|       arguments: [ |       arguments: [ | ||||||
|         `$slots`, |         `$slots`, | ||||||
|         { |         { | ||||||
| @ -98,7 +98,7 @@ describe('compiler: transform <slot> outlets', () => { | |||||||
|     const ast = parseWithSlots(`<slot foo="bar" :baz="qux" />`) |     const ast = parseWithSlots(`<slot foo="bar" :baz="qux" />`) | ||||||
|     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ |     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ | ||||||
|       type: NodeTypes.JS_CALL_EXPRESSION, |       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|       callee: `_${RENDER_SLOT}`, |       callee: RENDER_SLOT, | ||||||
|       arguments: [ |       arguments: [ | ||||||
|         `$slots`, |         `$slots`, | ||||||
|         `"default"`, |         `"default"`, | ||||||
| @ -135,7 +135,7 @@ describe('compiler: transform <slot> outlets', () => { | |||||||
|     const ast = parseWithSlots(`<slot name="foo" foo="bar" :baz="qux" />`) |     const ast = parseWithSlots(`<slot name="foo" foo="bar" :baz="qux" />`) | ||||||
|     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ |     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ | ||||||
|       type: NodeTypes.JS_CALL_EXPRESSION, |       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|       callee: `_${RENDER_SLOT}`, |       callee: RENDER_SLOT, | ||||||
|       arguments: [ |       arguments: [ | ||||||
|         `$slots`, |         `$slots`, | ||||||
|         `"foo"`, |         `"foo"`, | ||||||
| @ -173,7 +173,7 @@ describe('compiler: transform <slot> outlets', () => { | |||||||
|     const ast = parseWithSlots(`<slot :name="foo" foo="bar" :baz="qux" />`) |     const ast = parseWithSlots(`<slot :name="foo" foo="bar" :baz="qux" />`) | ||||||
|     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ |     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ | ||||||
|       type: NodeTypes.JS_CALL_EXPRESSION, |       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|       callee: `_${RENDER_SLOT}`, |       callee: RENDER_SLOT, | ||||||
|       arguments: [ |       arguments: [ | ||||||
|         `$slots`, |         `$slots`, | ||||||
|         { content: `foo`, isStatic: false }, |         { content: `foo`, isStatic: false }, | ||||||
| @ -211,7 +211,7 @@ describe('compiler: transform <slot> outlets', () => { | |||||||
|     const ast = parseWithSlots(`<slot><div/></slot>`) |     const ast = parseWithSlots(`<slot><div/></slot>`) | ||||||
|     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ |     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ | ||||||
|       type: NodeTypes.JS_CALL_EXPRESSION, |       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|       callee: `_${RENDER_SLOT}`, |       callee: RENDER_SLOT, | ||||||
|       arguments: [ |       arguments: [ | ||||||
|         `$slots`, |         `$slots`, | ||||||
|         `"default"`, |         `"default"`, | ||||||
| @ -230,7 +230,7 @@ describe('compiler: transform <slot> outlets', () => { | |||||||
|     const ast = parseWithSlots(`<slot name="foo"><div/></slot>`) |     const ast = parseWithSlots(`<slot name="foo"><div/></slot>`) | ||||||
|     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ |     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ | ||||||
|       type: NodeTypes.JS_CALL_EXPRESSION, |       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|       callee: `_${RENDER_SLOT}`, |       callee: RENDER_SLOT, | ||||||
|       arguments: [ |       arguments: [ | ||||||
|         `$slots`, |         `$slots`, | ||||||
|         `"foo"`, |         `"foo"`, | ||||||
| @ -249,7 +249,7 @@ describe('compiler: transform <slot> outlets', () => { | |||||||
|     const ast = parseWithSlots(`<slot :foo="bar"><div/></slot>`) |     const ast = parseWithSlots(`<slot :foo="bar"><div/></slot>`) | ||||||
|     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ |     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ | ||||||
|       type: NodeTypes.JS_CALL_EXPRESSION, |       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|       callee: `_${RENDER_SLOT}`, |       callee: RENDER_SLOT, | ||||||
|       arguments: [ |       arguments: [ | ||||||
|         `$slots`, |         `$slots`, | ||||||
|         `"default"`, |         `"default"`, | ||||||
| @ -282,7 +282,7 @@ describe('compiler: transform <slot> outlets', () => { | |||||||
|     const ast = parseWithSlots(`<slot name="foo" :foo="bar"><div/></slot>`) |     const ast = parseWithSlots(`<slot name="foo" :foo="bar"><div/></slot>`) | ||||||
|     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ |     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({ | ||||||
|       type: NodeTypes.JS_CALL_EXPRESSION, |       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|       callee: `_${RENDER_SLOT}`, |       callee: RENDER_SLOT, | ||||||
|       arguments: [ |       arguments: [ | ||||||
|         `$slots`, |         `$slots`, | ||||||
|         `"foo"`, |         `"foo"`, | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ import { | |||||||
| } from '../../src' | } from '../../src' | ||||||
| import { transformBind } from '../../src/transforms/vBind' | import { transformBind } from '../../src/transforms/vBind' | ||||||
| import { transformElement } from '../../src/transforms/transformElement' | import { transformElement } from '../../src/transforms/transformElement' | ||||||
| import { CAMELIZE } from '../../src/runtimeConstants' | import { CAMELIZE, helperNameMap } from '../../src/runtimeHelpers' | ||||||
| import { transformExpression } from '../../src/transforms/transformExpression' | import { transformExpression } from '../../src/transforms/transformExpression' | ||||||
| 
 | 
 | ||||||
| function parseWithVBind( | function parseWithVBind( | ||||||
| @ -123,7 +123,7 @@ describe('compiler: transform v-bind', () => { | |||||||
|       .arguments[1] as ObjectExpression |       .arguments[1] as ObjectExpression | ||||||
|     expect(props.properties[0]).toMatchObject({ |     expect(props.properties[0]).toMatchObject({ | ||||||
|       key: { |       key: { | ||||||
|         content: `_${CAMELIZE}(foo)`, |         content: `_${helperNameMap[CAMELIZE]}(foo)`, | ||||||
|         isStatic: false |         isStatic: false | ||||||
|       }, |       }, | ||||||
|       value: { |       value: { | ||||||
| @ -142,7 +142,7 @@ describe('compiler: transform v-bind', () => { | |||||||
|     expect(props.properties[0]).toMatchObject({ |     expect(props.properties[0]).toMatchObject({ | ||||||
|       key: { |       key: { | ||||||
|         children: [ |         children: [ | ||||||
|           `${CAMELIZE}(`, |           `${helperNameMap[CAMELIZE]}(`, | ||||||
|           { content: `_ctx.foo` }, |           { content: `_ctx.foo` }, | ||||||
|           `(`, |           `(`, | ||||||
|           { content: `_ctx.bar` }, |           { content: `_ctx.bar` }, | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ import { | |||||||
|   FRAGMENT, |   FRAGMENT, | ||||||
|   RENDER_LIST, |   RENDER_LIST, | ||||||
|   RENDER_SLOT |   RENDER_SLOT | ||||||
| } from '../../src/runtimeConstants' | } from '../../src/runtimeHelpers' | ||||||
| import { PatchFlags } from '@vue/runtime-dom' | import { PatchFlags } from '@vue/runtime-dom' | ||||||
| import { PatchFlagNames } from '@vue/shared' | import { PatchFlagNames } from '@vue/shared' | ||||||
| import { createObjectMatcher } from '../testUtils' | import { createObjectMatcher } from '../testUtils' | ||||||
| @ -575,17 +575,17 @@ describe('compiler: v-for', () => { | |||||||
|         expressions: [ |         expressions: [ | ||||||
|           { |           { | ||||||
|             type: NodeTypes.JS_CALL_EXPRESSION, |             type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|             callee: `_${OPEN_BLOCK}` |             callee: OPEN_BLOCK | ||||||
|           }, |           }, | ||||||
|           { |           { | ||||||
|             type: NodeTypes.JS_CALL_EXPRESSION, |             type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|             callee: `_${CREATE_BLOCK}`, |             callee: CREATE_BLOCK, | ||||||
|             arguments: [ |             arguments: [ | ||||||
|               `_${FRAGMENT}`, |               FRAGMENT, | ||||||
|               `null`, |               `null`, | ||||||
|               { |               { | ||||||
|                 type: NodeTypes.JS_CALL_EXPRESSION, |                 type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|                 callee: `_${RENDER_LIST}`, |                 callee: RENDER_LIST, | ||||||
|                 arguments: [ |                 arguments: [ | ||||||
|                   {}, // to be asserted by each test
 |                   {}, // to be asserted by each test
 | ||||||
|                   { |                   { | ||||||
| @ -597,11 +597,11 @@ describe('compiler: v-for', () => { | |||||||
|                           expressions: [ |                           expressions: [ | ||||||
|                             { |                             { | ||||||
|                               type: NodeTypes.JS_CALL_EXPRESSION, |                               type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|                               callee: `_${OPEN_BLOCK}` |                               callee: OPEN_BLOCK | ||||||
|                             }, |                             }, | ||||||
|                             { |                             { | ||||||
|                               type: NodeTypes.JS_CALL_EXPRESSION, |                               type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|                               callee: `_${CREATE_BLOCK}` |                               callee: CREATE_BLOCK | ||||||
|                             } |                             } | ||||||
|                           ] |                           ] | ||||||
|                         } |                         } | ||||||
| @ -703,7 +703,7 @@ describe('compiler: v-for', () => { | |||||||
|         source: { content: `items` }, |         source: { content: `items` }, | ||||||
|         params: [{ content: `item` }], |         params: [{ content: `item` }], | ||||||
|         blockArgs: [ |         blockArgs: [ | ||||||
|           `_${FRAGMENT}`, |           FRAGMENT, | ||||||
|           `null`, |           `null`, | ||||||
|           [ |           [ | ||||||
|             { type: NodeTypes.TEXT, content: `hello` }, |             { type: NodeTypes.TEXT, content: `hello` }, | ||||||
| @ -728,7 +728,7 @@ describe('compiler: v-for', () => { | |||||||
|         params: [{ content: `item` }], |         params: [{ content: `item` }], | ||||||
|         returns: { |         returns: { | ||||||
|           type: NodeTypes.JS_CALL_EXPRESSION, |           type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|           callee: `_${RENDER_SLOT}` |           callee: RENDER_SLOT | ||||||
|         } |         } | ||||||
|       }) |       }) | ||||||
|       expect(generate(root).code).toMatchSnapshot() |       expect(generate(root).code).toMatchSnapshot() | ||||||
| @ -746,7 +746,7 @@ describe('compiler: v-for', () => { | |||||||
|         params: [{ content: `item` }], |         params: [{ content: `item` }], | ||||||
|         returns: { |         returns: { | ||||||
|           type: NodeTypes.JS_CALL_EXPRESSION, |           type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|           callee: `_${RENDER_SLOT}` |           callee: RENDER_SLOT | ||||||
|         } |         } | ||||||
|       }) |       }) | ||||||
|       expect(generate(root).code).toMatchSnapshot() |       expect(generate(root).code).toMatchSnapshot() | ||||||
| @ -781,7 +781,7 @@ describe('compiler: v-for', () => { | |||||||
|         source: { content: `items` }, |         source: { content: `items` }, | ||||||
|         params: [{ content: `item` }], |         params: [{ content: `item` }], | ||||||
|         blockArgs: [ |         blockArgs: [ | ||||||
|           `_${FRAGMENT}`, |           FRAGMENT, | ||||||
|           createObjectMatcher({ |           createObjectMatcher({ | ||||||
|             key: `[item]` |             key: `[item]` | ||||||
|           }), |           }), | ||||||
| @ -804,7 +804,7 @@ describe('compiler: v-for', () => { | |||||||
|         expressions: [ |         expressions: [ | ||||||
|           { |           { | ||||||
|             type: NodeTypes.JS_CALL_EXPRESSION, |             type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|             callee: `_${OPEN_BLOCK}`, |             callee: OPEN_BLOCK, | ||||||
|             arguments: [] |             arguments: [] | ||||||
|           }, |           }, | ||||||
|           { |           { | ||||||
| @ -812,14 +812,14 @@ describe('compiler: v-for', () => { | |||||||
|             test: { content: `ok` }, |             test: { content: `ok` }, | ||||||
|             consequent: { |             consequent: { | ||||||
|               type: NodeTypes.JS_CALL_EXPRESSION, |               type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|               callee: `_${CREATE_BLOCK}`, |               callee: CREATE_BLOCK, | ||||||
|               // should optimize v-if + v-for into a single Fragment block
 |               // should optimize v-if + v-for into a single Fragment block
 | ||||||
|               arguments: [ |               arguments: [ | ||||||
|                 `_${FRAGMENT}`, |                 FRAGMENT, | ||||||
|                 createObjectMatcher({ key: `[0]` }), |                 createObjectMatcher({ key: `[0]` }), | ||||||
|                 { |                 { | ||||||
|                   type: NodeTypes.JS_CALL_EXPRESSION, |                   type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|                   callee: `_${RENDER_LIST}`, |                   callee: RENDER_LIST, | ||||||
|                   arguments: [ |                   arguments: [ | ||||||
|                     { content: `list` }, |                     { content: `list` }, | ||||||
|                     { |                     { | ||||||
| @ -830,11 +830,11 @@ describe('compiler: v-for', () => { | |||||||
|                         expressions: [ |                         expressions: [ | ||||||
|                           { |                           { | ||||||
|                             type: NodeTypes.JS_CALL_EXPRESSION, |                             type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|                             callee: `_${OPEN_BLOCK}` |                             callee: OPEN_BLOCK | ||||||
|                           }, |                           }, | ||||||
|                           { |                           { | ||||||
|                             type: NodeTypes.JS_CALL_EXPRESSION, |                             type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|                             callee: `_${CREATE_BLOCK}`, |                             callee: CREATE_BLOCK, | ||||||
|                             arguments: [`"div"`] |                             arguments: [`"div"`] | ||||||
|                           } |                           } | ||||||
|                         ] |                         ] | ||||||
|  | |||||||
| @ -24,7 +24,7 @@ import { | |||||||
|   MERGE_PROPS, |   MERGE_PROPS, | ||||||
|   APPLY_DIRECTIVES, |   APPLY_DIRECTIVES, | ||||||
|   RENDER_SLOT |   RENDER_SLOT | ||||||
| } from '../../src/runtimeConstants' | } from '../../src/runtimeHelpers' | ||||||
| import { createObjectMatcher } from '../testUtils' | import { createObjectMatcher } from '../testUtils' | ||||||
| 
 | 
 | ||||||
| function parseWithIfTransform( | function parseWithIfTransform( | ||||||
| @ -271,7 +271,7 @@ describe('compiler: v-if', () => { | |||||||
|         expressions: [ |         expressions: [ | ||||||
|           { |           { | ||||||
|             type: NodeTypes.JS_CALL_EXPRESSION, |             type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|             callee: `_${OPEN_BLOCK}`, |             callee: OPEN_BLOCK, | ||||||
|             arguments: [] |             arguments: [] | ||||||
|           }, |           }, | ||||||
|           { |           { | ||||||
| @ -281,13 +281,13 @@ describe('compiler: v-if', () => { | |||||||
|             }, |             }, | ||||||
|             consequent: { |             consequent: { | ||||||
|               type: NodeTypes.JS_CALL_EXPRESSION, |               type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|               callee: `_${CREATE_BLOCK}` |               callee: CREATE_BLOCK | ||||||
|             }, |             }, | ||||||
|             alternate: |             alternate: | ||||||
|               depth < 1 |               depth < 1 | ||||||
|                 ? { |                 ? { | ||||||
|                     type: NodeTypes.JS_CALL_EXPRESSION, |                     type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|                     callee: `_${CREATE_BLOCK}` |                     callee: CREATE_BLOCK | ||||||
|                   } |                   } | ||||||
|                 : { |                 : { | ||||||
|                     type: NodeTypes.JS_CONDITIONAL_EXPRESSION, |                     type: NodeTypes.JS_CONDITIONAL_EXPRESSION, | ||||||
| @ -296,11 +296,11 @@ describe('compiler: v-if', () => { | |||||||
|                     }, |                     }, | ||||||
|                     consequent: { |                     consequent: { | ||||||
|                       type: NodeTypes.JS_CALL_EXPRESSION, |                       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|                       callee: `_${CREATE_BLOCK}` |                       callee: CREATE_BLOCK | ||||||
|                     }, |                     }, | ||||||
|                     alternate: { |                     alternate: { | ||||||
|                       type: NodeTypes.JS_CALL_EXPRESSION, |                       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) |       const branch2 = (codegenNode.expressions[1] as ConditionalExpression) | ||||||
|         .alternate as CallExpression |         .alternate as CallExpression | ||||||
|       expect(branch2.arguments).toMatchObject([`_${EMPTY}`]) |       expect(branch2.arguments).toMatchObject([EMPTY]) | ||||||
|       expect(generate(root).code).toMatchSnapshot() |       expect(generate(root).code).toMatchSnapshot() | ||||||
|     }) |     }) | ||||||
| 
 | 
 | ||||||
| @ -335,7 +335,7 @@ describe('compiler: v-if', () => { | |||||||
|       const branch1 = (codegenNode.expressions[1] as ConditionalExpression) |       const branch1 = (codegenNode.expressions[1] as ConditionalExpression) | ||||||
|         .consequent as CallExpression |         .consequent as CallExpression | ||||||
|       expect(branch1.arguments).toMatchObject([ |       expect(branch1.arguments).toMatchObject([ | ||||||
|         `_${FRAGMENT}`, |         FRAGMENT, | ||||||
|         createObjectMatcher({ key: `[0]` }), |         createObjectMatcher({ key: `[0]` }), | ||||||
|         [ |         [ | ||||||
|           { type: NodeTypes.ELEMENT, tag: 'div' }, |           { type: NodeTypes.ELEMENT, tag: 'div' }, | ||||||
| @ -345,7 +345,7 @@ describe('compiler: v-if', () => { | |||||||
|       ]) |       ]) | ||||||
|       const branch2 = (codegenNode.expressions[1] as ConditionalExpression) |       const branch2 = (codegenNode.expressions[1] as ConditionalExpression) | ||||||
|         .alternate as CallExpression |         .alternate as CallExpression | ||||||
|       expect(branch2.arguments).toMatchObject([`_${EMPTY}`]) |       expect(branch2.arguments).toMatchObject([EMPTY]) | ||||||
|       expect(generate(root).code).toMatchSnapshot() |       expect(generate(root).code).toMatchSnapshot() | ||||||
|     }) |     }) | ||||||
| 
 | 
 | ||||||
| @ -359,7 +359,7 @@ describe('compiler: v-if', () => { | |||||||
|         .consequent as CallExpression |         .consequent as CallExpression | ||||||
|       expect(branch1).toMatchObject({ |       expect(branch1).toMatchObject({ | ||||||
|         type: NodeTypes.JS_CALL_EXPRESSION, |         type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|         callee: `_${RENDER_SLOT}`, |         callee: RENDER_SLOT, | ||||||
|         arguments: ['$slots', '"default"', createObjectMatcher({ key: `[0]` })] |         arguments: ['$slots', '"default"', createObjectMatcher({ key: `[0]` })] | ||||||
|       }) |       }) | ||||||
|       expect(generate(root).code).toMatchSnapshot() |       expect(generate(root).code).toMatchSnapshot() | ||||||
| @ -375,7 +375,7 @@ describe('compiler: v-if', () => { | |||||||
|         .consequent as CallExpression |         .consequent as CallExpression | ||||||
|       expect(branch1).toMatchObject({ |       expect(branch1).toMatchObject({ | ||||||
|         type: NodeTypes.JS_CALL_EXPRESSION, |         type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|         callee: `_${RENDER_SLOT}`, |         callee: RENDER_SLOT, | ||||||
|         arguments: ['$slots', '"default"', createObjectMatcher({ key: `[0]` })] |         arguments: ['$slots', '"default"', createObjectMatcher({ key: `[0]` })] | ||||||
|       }) |       }) | ||||||
|       expect(generate(root).code).toMatchSnapshot() |       expect(generate(root).code).toMatchSnapshot() | ||||||
| @ -444,7 +444,7 @@ describe('compiler: v-if', () => { | |||||||
|         createObjectMatcher({ key: `[1]` }) |         createObjectMatcher({ key: `[1]` }) | ||||||
|       ]) |       ]) | ||||||
|       expect((branch2.alternate as CallExpression).arguments).toMatchObject([ |       expect((branch2.alternate as CallExpression).arguments).toMatchObject([ | ||||||
|         `_${FRAGMENT}`, |         FRAGMENT, | ||||||
|         createObjectMatcher({ key: `[2]` }), |         createObjectMatcher({ key: `[2]` }), | ||||||
|         [ |         [ | ||||||
|           { |           { | ||||||
| @ -464,7 +464,7 @@ describe('compiler: v-if', () => { | |||||||
|         .consequent as CallExpression |         .consequent as CallExpression | ||||||
|       expect(branch1.arguments[1]).toMatchObject({ |       expect(branch1.arguments[1]).toMatchObject({ | ||||||
|         type: NodeTypes.JS_CALL_EXPRESSION, |         type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|         callee: `_${MERGE_PROPS}`, |         callee: MERGE_PROPS, | ||||||
|         arguments: [createObjectMatcher({ key: `[0]` }), { content: `obj` }] |         arguments: [createObjectMatcher({ key: `[0]` }), { content: `obj` }] | ||||||
|       }) |       }) | ||||||
|     }) |     }) | ||||||
| @ -477,7 +477,7 @@ describe('compiler: v-if', () => { | |||||||
|         .consequent as CallExpression |         .consequent as CallExpression | ||||||
|       expect(branch1.arguments[1]).toMatchObject({ |       expect(branch1.arguments[1]).toMatchObject({ | ||||||
|         type: NodeTypes.JS_CALL_EXPRESSION, |         type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|         callee: `_${MERGE_PROPS}`, |         callee: MERGE_PROPS, | ||||||
|         arguments: [ |         arguments: [ | ||||||
|           createObjectMatcher({ |           createObjectMatcher({ | ||||||
|             key: '[0]', |             key: '[0]', | ||||||
| @ -496,7 +496,7 @@ describe('compiler: v-if', () => { | |||||||
|         .consequent as CallExpression |         .consequent as CallExpression | ||||||
|       expect(branch1.arguments[1]).toMatchObject({ |       expect(branch1.arguments[1]).toMatchObject({ | ||||||
|         type: NodeTypes.JS_CALL_EXPRESSION, |         type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|         callee: `_${MERGE_PROPS}`, |         callee: MERGE_PROPS, | ||||||
|         arguments: [ |         arguments: [ | ||||||
|           createObjectMatcher({ key: `[0]` }), |           createObjectMatcher({ key: `[0]` }), | ||||||
|           { content: `obj` }, |           { content: `obj` }, | ||||||
| @ -513,7 +513,7 @@ describe('compiler: v-if', () => { | |||||||
|       } = parseWithIfTransform(`<div v-if="ok" v-foo />`) |       } = parseWithIfTransform(`<div v-if="ok" v-foo />`) | ||||||
|       const branch1 = (codegenNode.expressions[1] as ConditionalExpression) |       const branch1 = (codegenNode.expressions[1] as ConditionalExpression) | ||||||
|         .consequent as CallExpression |         .consequent as CallExpression | ||||||
|       expect(branch1.callee).toBe(`_${APPLY_DIRECTIVES}`) |       expect(branch1.callee).toBe(APPLY_DIRECTIVES) | ||||||
|       const realBranch = branch1.arguments[0] as CallExpression |       const realBranch = branch1.arguments[0] as CallExpression | ||||||
|       expect(realBranch.arguments[1]).toMatchObject( |       expect(realBranch.arguments[1]).toMatchObject( | ||||||
|         createObjectMatcher({ key: `[0]` }) |         createObjectMatcher({ key: `[0]` }) | ||||||
|  | |||||||
| @ -17,7 +17,7 @@ import { | |||||||
|   trackSlotScopes, |   trackSlotScopes, | ||||||
|   trackVForSlotScopes |   trackVForSlotScopes | ||||||
| } from '../../src/transforms/vSlot' | } 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 { createObjectMatcher } from '../testUtils' | ||||||
| import { PatchFlags, PatchFlagNames } from '@vue/shared' | import { PatchFlags, PatchFlagNames } from '@vue/shared' | ||||||
| import { transformFor } from '../../src/transforms/vFor' | import { transformFor } from '../../src/transforms/vFor' | ||||||
| @ -360,7 +360,7 @@ describe('compiler: transform component slots', () => { | |||||||
|     ) |     ) | ||||||
|     expect(slots).toMatchObject({ |     expect(slots).toMatchObject({ | ||||||
|       type: NodeTypes.JS_CALL_EXPRESSION, |       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|       callee: `_${CREATE_SLOTS}`, |       callee: CREATE_SLOTS, | ||||||
|       arguments: [ |       arguments: [ | ||||||
|         createObjectMatcher({ |         createObjectMatcher({ | ||||||
|           _compiled: `[true]` |           _compiled: `[true]` | ||||||
| @ -451,7 +451,7 @@ describe('compiler: transform component slots', () => { | |||||||
|     ) |     ) | ||||||
|     expect(slots).toMatchObject({ |     expect(slots).toMatchObject({ | ||||||
|       type: NodeTypes.JS_CALL_EXPRESSION, |       type: NodeTypes.JS_CALL_EXPRESSION, | ||||||
|       callee: `_${CREATE_SLOTS}`, |       callee: CREATE_SLOTS, | ||||||
|       arguments: [ |       arguments: [ | ||||||
|         createObjectMatcher({ |         createObjectMatcher({ | ||||||
|           _compiled: `[true]` |           _compiled: `[true]` | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| import { isString } from '@vue/shared' | import { isString } from '@vue/shared' | ||||||
| import { ForParseResult } from './transforms/vFor' | import { ForParseResult } from './transforms/vFor' | ||||||
|  | import { CREATE_VNODE, RuntimeHelper } from './runtimeHelpers' | ||||||
| 
 | 
 | ||||||
| // Vue template is a platform-agnostic superset of HTML (syntax only).
 | // Vue template is a platform-agnostic superset of HTML (syntax only).
 | ||||||
| // More namespaces like SVG and MathML are declared by platform specific
 | // More namespaces like SVG and MathML are declared by platform specific
 | ||||||
| @ -76,8 +77,9 @@ export type TemplateChildNode = | |||||||
| export interface RootNode extends Node { | export interface RootNode extends Node { | ||||||
|   type: NodeTypes.ROOT |   type: NodeTypes.ROOT | ||||||
|   children: TemplateChildNode[] |   children: TemplateChildNode[] | ||||||
|   imports: string[] |   helpers: RuntimeHelper[] | ||||||
|   statements: string[] |   components: string[] | ||||||
|  |   directives: string[] | ||||||
|   hoists: JSChildNode[] |   hoists: JSChildNode[] | ||||||
|   codegenNode: TemplateChildNode | JSChildNode | undefined |   codegenNode: TemplateChildNode | JSChildNode | undefined | ||||||
| } | } | ||||||
| @ -93,6 +95,29 @@ export interface ElementNode extends Node { | |||||||
|   codegenNode: CallExpression | SimpleExpressionNode | 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 { | export interface TextNode extends Node { | ||||||
|   type: NodeTypes.TEXT |   type: NodeTypes.TEXT | ||||||
|   content: string |   content: string | ||||||
| @ -137,7 +162,12 @@ export interface InterpolationNode extends Node { | |||||||
| // always dynamic
 | // always dynamic
 | ||||||
| export interface CompoundExpressionNode extends Node { | export interface CompoundExpressionNode extends Node { | ||||||
|   type: NodeTypes.COMPOUND_EXPRESSION |   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
 |   // an expression parsed as the params of a function will track
 | ||||||
|   // the identifiers declared inside the function body.
 |   // the identifiers declared inside the function body.
 | ||||||
|   identifiers?: string[] |   identifiers?: string[] | ||||||
| @ -146,9 +176,11 @@ export interface CompoundExpressionNode extends Node { | |||||||
| export interface IfNode extends Node { | export interface IfNode extends Node { | ||||||
|   type: NodeTypes.IF |   type: NodeTypes.IF | ||||||
|   branches: IfBranchNode[] |   branches: IfBranchNode[] | ||||||
|   codegenNode: SequenceExpression |   codegenNode: IfCodegenNode | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export interface IfCodegenNode extends SequenceExpression {} | ||||||
|  | 
 | ||||||
| export interface IfBranchNode extends Node { | export interface IfBranchNode extends Node { | ||||||
|   type: NodeTypes.IF_BRANCH |   type: NodeTypes.IF_BRANCH | ||||||
|   condition: ExpressionNode | undefined // else
 |   condition: ExpressionNode | undefined // else
 | ||||||
| @ -162,9 +194,11 @@ export interface ForNode extends Node { | |||||||
|   keyAlias: ExpressionNode | undefined |   keyAlias: ExpressionNode | undefined | ||||||
|   objectIndexAlias: ExpressionNode | undefined |   objectIndexAlias: ExpressionNode | undefined | ||||||
|   children: TemplateChildNode[] |   children: TemplateChildNode[] | ||||||
|   codegenNode: SequenceExpression |   codegenNode: ForCodegenNode | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export interface ForCodegenNode extends SequenceExpression {} | ||||||
|  | 
 | ||||||
| // We also include a number of JavaScript AST nodes for code generation.
 | // 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
 | // The AST is an intentionally minimal subset just to meet the exact needs of
 | ||||||
| // Vue render function generation.
 | // Vue render function generation.
 | ||||||
| @ -179,8 +213,13 @@ export type JSChildNode = | |||||||
| 
 | 
 | ||||||
| export interface CallExpression extends Node { | export interface CallExpression extends Node { | ||||||
|   type: NodeTypes.JS_CALL_EXPRESSION |   type: NodeTypes.JS_CALL_EXPRESSION | ||||||
|   callee: string |   callee: string | RuntimeHelper | ||||||
|   arguments: (string | JSChildNode | TemplateChildNode | TemplateChildNode[])[] |   arguments: ( | ||||||
|  |     | string | ||||||
|  |     | RuntimeHelper | ||||||
|  |     | JSChildNode | ||||||
|  |     | TemplateChildNode | ||||||
|  |     | TemplateChildNode[])[] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface ObjectExpression extends Node { | export interface ObjectExpression extends Node { | ||||||
|  | |||||||
| @ -23,10 +23,19 @@ import { | |||||||
|   advancePositionWithMutation, |   advancePositionWithMutation, | ||||||
|   assert, |   assert, | ||||||
|   isSimpleIdentifier, |   isSimpleIdentifier, | ||||||
|   loadDep |   loadDep, | ||||||
|  |   toValidAssetId | ||||||
| } from './utils' | } from './utils' | ||||||
| import { isString, isArray } from '@vue/shared' | import { isString, isArray, isSymbol } from '@vue/shared' | ||||||
| import { TO_STRING, CREATE_VNODE, COMMENT } from './runtimeConstants' | import { | ||||||
|  |   TO_STRING, | ||||||
|  |   CREATE_VNODE, | ||||||
|  |   COMMENT, | ||||||
|  |   helperNameMap, | ||||||
|  |   RESOLVE_COMPONENT, | ||||||
|  |   RESOLVE_DIRECTIVE, | ||||||
|  |   RuntimeHelper | ||||||
|  | } from './runtimeHelpers' | ||||||
| 
 | 
 | ||||||
| type CodegenNode = TemplateChildNode | JSChildNode | type CodegenNode = TemplateChildNode | JSChildNode | ||||||
| 
 | 
 | ||||||
| @ -65,7 +74,7 @@ export interface CodegenContext extends Required<CodegenOptions> { | |||||||
|   offset: number |   offset: number | ||||||
|   indentLevel: number |   indentLevel: number | ||||||
|   map?: SourceMapGenerator |   map?: SourceMapGenerator | ||||||
|   helper(name: string): string |   helper(key: RuntimeHelper): string | ||||||
|   push(code: string, node?: CodegenNode, openOnly?: boolean): void |   push(code: string, node?: CodegenNode, openOnly?: boolean): void | ||||||
|   resetMapping(loc: SourceLocation): void |   resetMapping(loc: SourceLocation): void | ||||||
|   indent(): void |   indent(): void | ||||||
| @ -77,7 +86,7 @@ function createCodegenContext( | |||||||
|   ast: RootNode, |   ast: RootNode, | ||||||
|   { |   { | ||||||
|     mode = 'function', |     mode = 'function', | ||||||
|     prefixIdentifiers = false, |     prefixIdentifiers = mode === 'module', | ||||||
|     sourceMap = false, |     sourceMap = false, | ||||||
|     filename = `template.vue.html` |     filename = `template.vue.html` | ||||||
|   }: CodegenOptions |   }: CodegenOptions | ||||||
| @ -100,7 +109,8 @@ function createCodegenContext( | |||||||
|         ? undefined |         ? undefined | ||||||
|         : new (loadDep('source-map')).SourceMapGenerator(), |         : new (loadDep('source-map')).SourceMapGenerator(), | ||||||
| 
 | 
 | ||||||
|     helper(name) { |     helper(key) { | ||||||
|  |       const name = helperNameMap[key] | ||||||
|       return prefixIdentifiers ? name : `_${name}` |       return prefixIdentifiers ? name : `_${name}` | ||||||
|     }, |     }, | ||||||
|     push(code, node, openOnly) { |     push(code, node, openOnly) { | ||||||
| @ -172,8 +182,16 @@ export function generate( | |||||||
|   options: CodegenOptions = {} |   options: CodegenOptions = {} | ||||||
| ): CodegenResult { | ): CodegenResult { | ||||||
|   const context = createCodegenContext(ast, options) |   const context = createCodegenContext(ast, options) | ||||||
|   const { mode, push, prefixIdentifiers, indent, deindent, newline } = context |   const { | ||||||
|   const hasImports = ast.imports.length |     mode, | ||||||
|  |     push, | ||||||
|  |     helper, | ||||||
|  |     prefixIdentifiers, | ||||||
|  |     indent, | ||||||
|  |     deindent, | ||||||
|  |     newline | ||||||
|  |   } = context | ||||||
|  |   const hasHelpers = ast.helpers.length > 0 | ||||||
|   const useWithBlock = !prefixIdentifiers && mode !== 'module' |   const useWithBlock = !prefixIdentifiers && mode !== 'module' | ||||||
| 
 | 
 | ||||||
|   // preambles
 |   // preambles
 | ||||||
| @ -182,9 +200,9 @@ export function generate( | |||||||
|     // In prefix mode, we place the const declaration at top so it's done
 |     // 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
 |     // 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.
 |     // with block so it doesn't incur the `in` check cost for every helper access.
 | ||||||
|     if (hasImports) { |     if (hasHelpers) { | ||||||
|       if (prefixIdentifiers) { |       if (prefixIdentifiers) { | ||||||
|         push(`const { ${ast.imports.join(', ')} } = Vue\n`) |         push(`const { ${ast.helpers.map(helper).join(', ')} } = Vue\n`) | ||||||
|       } else { |       } else { | ||||||
|         // "with" mode.
 |         // "with" mode.
 | ||||||
|         // save Vue in a separate variable to avoid collision
 |         // 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
 |         // has check cost, but hoists are lifted out of the function - we need
 | ||||||
|         // to provide the helper here.
 |         // to provide the helper here.
 | ||||||
|         if (ast.hoists.length) { |         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 `) |     push(`return `) | ||||||
|   } else { |   } else { | ||||||
|     // generate import statements for helpers
 |     // generate import statements for helpers
 | ||||||
|     if (hasImports) { |     if (hasHelpers) { | ||||||
|       push(`import { ${ast.imports.join(', ')} } from "vue"\n`) |       push(`import { ${ast.helpers.map(helper).join(', ')} } from "vue"\n`) | ||||||
|     } |     } | ||||||
|     genHoists(ast.hoists, context) |     genHoists(ast.hoists, context) | ||||||
|     context.newline() |     context.newline() | ||||||
| @ -219,8 +237,12 @@ export function generate( | |||||||
|     indent() |     indent() | ||||||
|     // function mode const declarations should be inside with block
 |     // function mode const declarations should be inside with block
 | ||||||
|     // also they should be renamed to avoid collision with user properties
 |     // also they should be renamed to avoid collision with user properties
 | ||||||
|     if (hasImports) { |     if (hasHelpers) { | ||||||
|       push(`const { ${ast.imports.map(n => `${n}: _${n}`).join(', ')} } = _Vue`) |       push( | ||||||
|  |         `const { ${ast.helpers | ||||||
|  |           .map(s => `${helperNameMap[s]}: _${helperNameMap[s]}`) | ||||||
|  |           .join(', ')} } = _Vue` | ||||||
|  |       ) | ||||||
|       newline() |       newline() | ||||||
|       newline() |       newline() | ||||||
|     } |     } | ||||||
| @ -230,11 +252,13 @@ export function generate( | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // generate asset resolution statements
 |   // generate asset resolution statements
 | ||||||
|   if (ast.statements.length) { |   if (ast.components.length) { | ||||||
|     ast.statements.forEach(s => { |     genAssets(ast.components, 'component', context) | ||||||
|       push(s) |   } | ||||||
|       newline() |   if (ast.directives.length) { | ||||||
|     }) |     genAssets(ast.directives, 'directive', context) | ||||||
|  |   } | ||||||
|  |   if (ast.components.length || ast.directives.length) { | ||||||
|     newline() |     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) { | function genHoists(hoists: JSChildNode[], context: CodegenContext) { | ||||||
|   if (!hoists.length) { |   if (!hoists.length) { | ||||||
|     return |     return | ||||||
| @ -297,7 +338,7 @@ function genNodeListAsArray( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function genNodeList( | function genNodeList( | ||||||
|   nodes: (string | CodegenNode | TemplateChildNode[])[], |   nodes: (string | RuntimeHelper | CodegenNode | TemplateChildNode[])[], | ||||||
|   context: CodegenContext, |   context: CodegenContext, | ||||||
|   multilines: boolean = false |   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)) { |   if (isString(node)) { | ||||||
|     context.push(node) |     context.push(node) | ||||||
|     return |     return | ||||||
|   } |   } | ||||||
|  |   if (isSymbol(node)) { | ||||||
|  |     context.push(context.helper(node)) | ||||||
|  |     return | ||||||
|  |   } | ||||||
|   switch (node.type) { |   switch (node.type) { | ||||||
|     case NodeTypes.ELEMENT: |     case NodeTypes.ELEMENT: | ||||||
|     case NodeTypes.IF: |     case NodeTypes.IF: | ||||||
| @ -450,7 +498,10 @@ function genComment(node: CommentNode, context: CodegenContext) { | |||||||
| 
 | 
 | ||||||
| // JavaScript
 | // JavaScript
 | ||||||
| function genCallExpression(node: CallExpression, context: CodegenContext) { | 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) |   genNodeList(node.arguments, context) | ||||||
|   context.push(`)`) |   context.push(`)`) | ||||||
| } | } | ||||||
|  | |||||||
| @ -64,7 +64,10 @@ export function baseCompile( | |||||||
|     } |     } | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   return generate(ast, options) |   return generate(ast, { | ||||||
|  |     ...options, | ||||||
|  |     prefixIdentifiers | ||||||
|  |   }) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Also expose lower level APIs & types
 | // 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' | } from './ast' | ||||||
| import { isString, isArray } from '@vue/shared' | import { isString, isArray } from '@vue/shared' | ||||||
| import { CompilerError, defaultOnError } from './errors' | 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 { isVSlot, createBlockExpression, isSlotOutlet } from './utils' | ||||||
| import { hoistStatic } from './transforms/hoistStatic' | import { hoistStatic } from './transforms/hoistStatic' | ||||||
| 
 | 
 | ||||||
| @ -57,8 +64,9 @@ export interface TransformOptions { | |||||||
| 
 | 
 | ||||||
| export interface TransformContext extends Required<TransformOptions> { | export interface TransformContext extends Required<TransformOptions> { | ||||||
|   root: RootNode |   root: RootNode | ||||||
|   imports: Set<string> |   helpers: Set<RuntimeHelper> | ||||||
|   statements: Set<string> |   components: Set<string> | ||||||
|  |   directives: Set<string> | ||||||
|   hoists: JSChildNode[] |   hoists: JSChildNode[] | ||||||
|   identifiers: { [name: string]: number | undefined } |   identifiers: { [name: string]: number | undefined } | ||||||
|   scopes: { |   scopes: { | ||||||
| @ -70,7 +78,8 @@ export interface TransformContext extends Required<TransformOptions> { | |||||||
|   parent: ParentNode | null |   parent: ParentNode | null | ||||||
|   childIndex: number |   childIndex: number | ||||||
|   currentNode: RootNode | TemplateChildNode | null |   currentNode: RootNode | TemplateChildNode | null | ||||||
|   helper(name: string): string |   helper<T extends RuntimeHelper>(name: T): T | ||||||
|  |   helperString(name: RuntimeHelper): string | ||||||
|   replaceNode(node: TemplateChildNode): void |   replaceNode(node: TemplateChildNode): void | ||||||
|   removeNode(node?: TemplateChildNode): void |   removeNode(node?: TemplateChildNode): void | ||||||
|   onNodeRemoved: () => void |   onNodeRemoved: () => void | ||||||
| @ -91,8 +100,9 @@ function createTransformContext( | |||||||
| ): TransformContext { | ): TransformContext { | ||||||
|   const context: TransformContext = { |   const context: TransformContext = { | ||||||
|     root, |     root, | ||||||
|     imports: new Set(), |     helpers: new Set(), | ||||||
|     statements: new Set(), |     components: new Set(), | ||||||
|  |     directives: new Set(), | ||||||
|     hoists: [], |     hoists: [], | ||||||
|     identifiers: {}, |     identifiers: {}, | ||||||
|     scopes: { |     scopes: { | ||||||
| @ -110,8 +120,14 @@ function createTransformContext( | |||||||
|     currentNode: root, |     currentNode: root, | ||||||
|     childIndex: 0, |     childIndex: 0, | ||||||
|     helper(name) { |     helper(name) { | ||||||
|       context.imports.add(name) |       context.helpers.add(name) | ||||||
|       return prefixIdentifiers ? name : `_${name}` |       return name | ||||||
|  |     }, | ||||||
|  |     helperString(name) { | ||||||
|  |       return ( | ||||||
|  |         (context.prefixIdentifiers ? `` : `_`) + | ||||||
|  |         helperNameMap[context.helper(name)] | ||||||
|  |       ) | ||||||
|     }, |     }, | ||||||
|     replaceNode(node) { |     replaceNode(node) { | ||||||
|       /* istanbul ignore if */ |       /* istanbul ignore if */ | ||||||
| @ -242,8 +258,9 @@ function finalizeRoot(root: RootNode, context: TransformContext) { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // finalize meta information
 |   // finalize meta information
 | ||||||
|   root.imports = [...context.imports] |   root.helpers = [...context.helpers] | ||||||
|   root.statements = [...context.statements] |   root.components = [...context.components] | ||||||
|  |   root.directives = [...context.directives] | ||||||
|   root.hoists = context.hoists |   root.hoists = context.hoists | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ import { | |||||||
|   ElementTypes |   ElementTypes | ||||||
| } from '../ast' | } from '../ast' | ||||||
| import { TransformContext } from '../transform' | import { TransformContext } from '../transform' | ||||||
| import { APPLY_DIRECTIVES } from '../runtimeConstants' | import { APPLY_DIRECTIVES } from '../runtimeHelpers' | ||||||
| import { PropsExpression } from './transformElement' | import { PropsExpression } from './transformElement' | ||||||
| import { PatchFlags } from '@vue/shared' | import { PatchFlags } from '@vue/shared' | ||||||
| 
 | 
 | ||||||
| @ -41,7 +41,7 @@ function walk( | |||||||
|           flag === PatchFlags.TEXT |           flag === PatchFlags.TEXT | ||||||
|         ) { |         ) { | ||||||
|           let codegenNode = child.codegenNode as CallExpression |           let codegenNode = child.codegenNode as CallExpression | ||||||
|           if (codegenNode.callee.includes(APPLY_DIRECTIVES)) { |           if (codegenNode.callee === APPLY_DIRECTIVES) { | ||||||
|             codegenNode = codegenNode.arguments[0] as CallExpression |             codegenNode = codegenNode.arguments[0] as CallExpression | ||||||
|           } |           } | ||||||
|           const props = codegenNode.arguments[1] as |           const props = codegenNode.arguments[1] as | ||||||
| @ -68,7 +68,7 @@ function walk( | |||||||
| 
 | 
 | ||||||
| function getPatchFlag(node: ElementNode): number | undefined { | function getPatchFlag(node: ElementNode): number | undefined { | ||||||
|   let codegenNode = node.codegenNode as CallExpression |   let codegenNode = node.codegenNode as CallExpression | ||||||
|   if (codegenNode.callee.includes(APPLY_DIRECTIVES)) { |   if (codegenNode.callee === APPLY_DIRECTIVES) { | ||||||
|     codegenNode = codegenNode.arguments[0] as CallExpression |     codegenNode = codegenNode.arguments[0] as CallExpression | ||||||
|   } |   } | ||||||
|   const flag = codegenNode.arguments[3] |   const flag = codegenNode.arguments[3] | ||||||
|  | |||||||
| @ -25,12 +25,10 @@ import { | |||||||
|   RESOLVE_COMPONENT, |   RESOLVE_COMPONENT, | ||||||
|   MERGE_PROPS, |   MERGE_PROPS, | ||||||
|   TO_HANDLERS |   TO_HANDLERS | ||||||
| } from '../runtimeConstants' | } from '../runtimeHelpers' | ||||||
| import { getInnerRange, isVSlot } from '../utils' | import { getInnerRange, isVSlot, toValidAssetId } from '../utils' | ||||||
| import { buildSlots } from './vSlot' | import { buildSlots } from './vSlot' | ||||||
| 
 | 
 | ||||||
| const toValidId = (str: string): string => str.replace(/[^\w]/g, '') |  | ||||||
| 
 |  | ||||||
| // generate a JavaScript AST for this element's codegen
 | // generate a JavaScript AST for this element's codegen
 | ||||||
| export const transformElement: NodeTransform = (node, context) => { | export const transformElement: NodeTransform = (node, context) => { | ||||||
|   if (node.type === NodeTypes.ELEMENT) { |   if (node.type === NodeTypes.ELEMENT) { | ||||||
| @ -50,19 +48,14 @@ export const transformElement: NodeTransform = (node, context) => { | |||||||
|         let patchFlag: number = 0 |         let patchFlag: number = 0 | ||||||
|         let runtimeDirectives: DirectiveNode[] | undefined |         let runtimeDirectives: DirectiveNode[] | undefined | ||||||
|         let dynamicPropNames: string[] | undefined |         let dynamicPropNames: string[] | undefined | ||||||
|         let componentIdentifier: string | undefined |  | ||||||
| 
 | 
 | ||||||
|         if (isComponent) { |         if (isComponent) { | ||||||
|           componentIdentifier = `_component_${toValidId(node.tag)}` |           context.helper(RESOLVE_COMPONENT) | ||||||
|           context.statements.add( |           context.components.add(node.tag) | ||||||
|             `const ${componentIdentifier} = ${context.helper( |  | ||||||
|               RESOLVE_COMPONENT |  | ||||||
|             )}(${JSON.stringify(node.tag)})` |  | ||||||
|           ) |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const args: CallExpression['arguments'] = [ |         const args: CallExpression['arguments'] = [ | ||||||
|           isComponent ? componentIdentifier! : `"${node.tag}"` |           isComponent ? toValidAssetId(node.tag, `component`) : `"${node.tag}"` | ||||||
|         ] |         ] | ||||||
|         // props
 |         // props
 | ||||||
|         if (hasProps) { |         if (hasProps) { | ||||||
| @ -402,13 +395,11 @@ function createDirectiveArgs( | |||||||
|   context: TransformContext |   context: TransformContext | ||||||
| ): ArrayExpression { | ): ArrayExpression { | ||||||
|   // inject statement for resolving directive
 |   // inject statement for resolving directive
 | ||||||
|   const dirIdentifier = `_directive_${toValidId(dir.name)}` |   context.helper(RESOLVE_DIRECTIVE) | ||||||
|   context.statements.add( |   context.directives.add(dir.name) | ||||||
|     `const ${dirIdentifier} = ${context.helper( |   const dirArgs: ArrayExpression['elements'] = [ | ||||||
|       RESOLVE_DIRECTIVE |     toValidAssetId(dir.name, `directive`) | ||||||
|     )}(${JSON.stringify(dir.name)})` |   ] | ||||||
|   ) |  | ||||||
|   const dirArgs: ArrayExpression['elements'] = [dirIdentifier] |  | ||||||
|   const { loc } = dir |   const { loc } = dir | ||||||
|   if (dir.exp) dirArgs.push(dir.exp) |   if (dir.exp) dirArgs.push(dir.exp) | ||||||
|   if (dir.arg) dirArgs.push(dir.arg) |   if (dir.arg) dirArgs.push(dir.arg) | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ import { | |||||||
| import { isSlotOutlet } from '../utils' | import { isSlotOutlet } from '../utils' | ||||||
| import { buildProps } from './transformElement' | import { buildProps } from './transformElement' | ||||||
| import { createCompilerError, ErrorCodes } from '../errors' | import { createCompilerError, ErrorCodes } from '../errors' | ||||||
| import { RENDER_SLOT } from '../runtimeConstants' | import { RENDER_SLOT } from '../runtimeHelpers' | ||||||
| 
 | 
 | ||||||
| export const transformSlotOutlet: NodeTransform = (node, context) => { | export const transformSlotOutlet: NodeTransform = (node, context) => { | ||||||
|   if (isSlotOutlet(node)) { |   if (isSlotOutlet(node)) { | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ import { DirectiveTransform } from '../transform' | |||||||
| import { createObjectProperty, createSimpleExpression, NodeTypes } from '../ast' | import { createObjectProperty, createSimpleExpression, NodeTypes } from '../ast' | ||||||
| import { createCompilerError, ErrorCodes } from '../errors' | import { createCompilerError, ErrorCodes } from '../errors' | ||||||
| import { camelize } from '@vue/shared' | 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
 | // 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
 | // 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) { |       if (arg.isStatic) { | ||||||
|         arg.content = camelize(arg.content) |         arg.content = camelize(arg.content) | ||||||
|       } else { |       } else { | ||||||
|         arg.content = `${context.helper(CAMELIZE)}(${arg.content})` |         arg.content = `${context.helperString(CAMELIZE)}(${arg.content})` | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       arg.children.unshift(`${context.helper(CAMELIZE)}(`) |       arg.children.unshift(`${context.helperString(CAMELIZE)}(`) | ||||||
|       arg.children.push(`)`) |       arg.children.push(`)`) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -30,7 +30,7 @@ import { | |||||||
|   OPEN_BLOCK, |   OPEN_BLOCK, | ||||||
|   CREATE_BLOCK, |   CREATE_BLOCK, | ||||||
|   FRAGMENT |   FRAGMENT | ||||||
| } from '../runtimeConstants' | } from '../runtimeHelpers' | ||||||
| import { processExpression } from './transformExpression' | import { processExpression } from './transformExpression' | ||||||
| import { PatchFlags, PatchFlagNames } from '@vue/shared' | import { PatchFlags, PatchFlagNames } from '@vue/shared' | ||||||
| import { PropsExpression } from './transformElement' | import { PropsExpression } from './transformElement' | ||||||
|  | |||||||
| @ -29,7 +29,7 @@ import { | |||||||
|   APPLY_DIRECTIVES, |   APPLY_DIRECTIVES, | ||||||
|   CREATE_VNODE, |   CREATE_VNODE, | ||||||
|   RENDER_SLOT |   RENDER_SLOT | ||||||
| } from '../runtimeConstants' | } from '../runtimeHelpers' | ||||||
| import { injectProp } from '../utils' | import { injectProp } from '../utils' | ||||||
| import { PropsExpression } from './transformElement' | import { PropsExpression } from './transformElement' | ||||||
| 
 | 
 | ||||||
| @ -184,18 +184,18 @@ function createChildrenCodegenNode( | |||||||
|     const childCodegen = (child as ElementNode).codegenNode as CallExpression |     const childCodegen = (child as ElementNode).codegenNode as CallExpression | ||||||
|     let vnodeCall = childCodegen |     let vnodeCall = childCodegen | ||||||
|     // Element with custom directives. Locate the actual createVNode() call.
 |     // 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 |       vnodeCall = vnodeCall.arguments[0] as CallExpression | ||||||
|     } |     } | ||||||
|     // Change createVNode to createBlock.
 |     // Change createVNode to createBlock.
 | ||||||
|     if (vnodeCall.callee.includes(CREATE_VNODE)) { |     if (vnodeCall.callee === CREATE_VNODE) { | ||||||
|       vnodeCall.callee = helper(CREATE_BLOCK) |       vnodeCall.callee = helper(CREATE_BLOCK) | ||||||
|     } |     } | ||||||
|     // It's possible to have renderSlot() here as well - which already produces
 |     // 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 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
 |     // a different arg index so make sure to check for so that the key injection
 | ||||||
|     // logic below works for it too.
 |     // 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
 |     // inject branch key
 | ||||||
|     const existingProps = vnodeCall.arguments[propsIndex] as |     const existingProps = vnodeCall.arguments[propsIndex] as | ||||||
|       | PropsExpression |       | PropsExpression | ||||||
|  | |||||||
| @ -24,7 +24,7 @@ import { | |||||||
| import { TransformContext, NodeTransform } from '../transform' | import { TransformContext, NodeTransform } from '../transform' | ||||||
| import { createCompilerError, ErrorCodes } from '../errors' | import { createCompilerError, ErrorCodes } from '../errors' | ||||||
| import { findDir, isTemplateNode, assert, isVSlot } from '../utils' | 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' | import { parseForExpression, createForLoopParams } from './vFor' | ||||||
| 
 | 
 | ||||||
| const isStaticExp = (p: JSChildNode): p is SimpleExpressionNode => | const isStaticExp = (p: JSChildNode): p is SimpleExpressionNode => | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ import { | |||||||
| import { parse } from 'acorn' | import { parse } from 'acorn' | ||||||
| import { walk } from 'estree-walker' | import { walk } from 'estree-walker' | ||||||
| import { TransformContext } from './transform' | 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 { isString, isFunction } from '@vue/shared' | ||||||
| import { PropsExpression } from './transforms/transformElement' | 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 => | export const isFunction = (val: any): val is Function => | ||||||
|   typeof val === 'function' |   typeof val === 'function' | ||||||
| export const isString = (val: any): val is string => typeof val === 'string' | 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> => | export const isObject = (val: any): val is Record<any, any> => | ||||||
|   val !== null && typeof val === 'object' |   val !== null && typeof val === 'object' | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user