diff --git a/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap b/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap index 4acc91a94..533252b6b 100644 --- a/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap @@ -33,16 +33,20 @@ export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") const _directive_hello = _resolveDirective("hello") const _directive_test = _resolveDirective("test") - const n4 = _createComponent(_component_Comp, null, { default: () => { - const n0 = _createIf(() => (true), () => { - const n3 = t0() - const n2 = _createComponent(_component_Bar) - _withDirectives(n2, [[_directive_hello, void 0, void 0, { world: true }]]) - _insert(n2, n3) - return n3 - }) - return n0 - } }, null, true) + const n4 = _createComponent(_component_Comp, null, [ + { + default: () => { + const n0 = _createIf(() => (true), () => { + const n3 = t0() + const n2 = _createComponent(_component_Bar) + _withDirectives(n2, [[_directive_hello, void 0, void 0, { world: true }]]) + _insert(n2, n3) + return n3 + }) + return n0 + } + } + ], true) _withDirectives(n4, [[_directive_test]]) return n4 }" diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap index 2d3bc2f23..0bd845763 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap @@ -5,7 +5,7 @@ exports[`compiler: element transform > component > do not resolve component from export function render(_ctx) { const _component_Example = _resolveComponent("Example") - const n0 = _createComponent(_component_Example, null, null, null, true) + const n0 = _createComponent(_component_Example, null, null, true) return n0 }" `; @@ -25,7 +25,7 @@ exports[`compiler: element transform > component > generate single root componen "import { createComponent as _createComponent } from 'vue/vapor'; export function render(_ctx) { - const n0 = _createComponent(_ctx.Comp, null, null, null, true) + const n0 = _createComponent(_ctx.Comp, null, null, true) return n0 }" `; @@ -35,21 +35,21 @@ exports[`compiler: element transform > component > import + resolve component 1` export function render(_ctx) { const _component_Foo = _resolveComponent("Foo") - const n0 = _createComponent(_component_Foo, null, null, null, true) + const n0 = _createComponent(_component_Foo, null, null, true) return n0 }" `; exports[`compiler: element transform > component > resolve component from setup bindings (inline const) 1`] = ` "(() => { - const n0 = _createComponent(Example, null, null, null, true) + const n0 = _createComponent(Example, null, null, true) return n0 })()" `; exports[`compiler: element transform > component > resolve component from setup bindings (inline) 1`] = ` "(() => { - const n0 = _createComponent(_unref(Example), null, null, null, true) + const n0 = _createComponent(_unref(Example), null, null, true) return n0 })()" `; @@ -58,14 +58,14 @@ exports[`compiler: element transform > component > resolve component from setup "import { createComponent as _createComponent } from 'vue/vapor'; export function render(_ctx) { - const n0 = _createComponent(_ctx.Example, null, null, null, true) + const n0 = _createComponent(_ctx.Example, null, null, true) return n0 }" `; exports[`compiler: element transform > component > resolve namespaced component from props bindings (inline) 1`] = ` "(() => { - const n0 = _createComponent(Foo.Example, null, null, null, true) + const n0 = _createComponent(Foo.Example, null, null, true) return n0 })()" `; @@ -74,14 +74,14 @@ exports[`compiler: element transform > component > resolve namespaced component "import { createComponent as _createComponent } from 'vue/vapor'; export function render(_ctx) { - const n0 = _createComponent(_ctx.Foo.Example, null, null, null, true) + const n0 = _createComponent(_ctx.Foo.Example, null, null, true) return n0 }" `; exports[`compiler: element transform > component > resolve namespaced component from setup bindings (inline const) 1`] = ` "(() => { - const n0 = _createComponent(Foo.Example, null, null, null, true) + const n0 = _createComponent(Foo.Example, null, null, true) return n0 })()" `; @@ -90,7 +90,7 @@ exports[`compiler: element transform > component > resolve namespaced component "import { createComponent as _createComponent } from 'vue/vapor'; export function render(_ctx) { - const n0 = _createComponent(_ctx.Foo.Example, null, null, null, true) + const n0 = _createComponent(_ctx.Foo.Example, null, null, true) return n0 }" `; @@ -102,7 +102,7 @@ export function render(_ctx) { const _component_Foo = _resolveComponent("Foo") const n0 = _createComponent(_component_Foo, [ { onBar: () => $event => (_ctx.handleBar($event)) } - ], null, null, true) + ], null, true) return n0 }" `; @@ -117,7 +117,7 @@ export function render(_ctx) { id: () => ("foo"), class: () => ("bar") } - ], null, null, true) + ], null, true) return n0 }" `; @@ -129,7 +129,7 @@ export function render(_ctx) { const _component_Foo = _resolveComponent("Foo") const n0 = _createComponent(_component_Foo, [ () => (_ctx.obj) - ], null, null, true) + ], null, true) return n0 }" `; @@ -142,7 +142,7 @@ export function render(_ctx) { const n0 = _createComponent(_component_Foo, [ { id: () => ("foo") }, () => (_ctx.obj) - ], null, null, true) + ], null, true) return n0 }" `; @@ -155,7 +155,7 @@ export function render(_ctx) { const n0 = _createComponent(_component_Foo, [ () => (_ctx.obj), { id: () => ("foo") } - ], null, null, true) + ], null, true) return n0 }" `; @@ -169,7 +169,7 @@ export function render(_ctx) { { id: () => ("foo") }, () => (_ctx.obj), { class: () => ("bar") } - ], null, null, true) + ], null, true) return n0 }" `; @@ -181,7 +181,7 @@ export function render(_ctx) { const _component_Foo = _resolveComponent("Foo") const n0 = _createComponent(_component_Foo, [ () => (_toHandlers(_ctx.obj)) - ], null, null, true) + ], null, true) return n0 }" `; @@ -195,7 +195,7 @@ export function render(_ctx) { const n0 = _createComponent(_component_Foo, [ () => ({ [_toHandlerKey(_ctx.foo-_ctx.bar)]: () => _ctx.bar }), () => ({ [_toHandlerKey(_ctx.baz)]: () => _ctx.qux }) - ], null, null, true) + ], null, true) return n0 }" `; @@ -208,7 +208,7 @@ export function render(_ctx) { const n0 = _createComponent(_component_Foo, [ () => ({ [_ctx.foo-_ctx.bar]: _ctx.bar }), () => ({ [_ctx.baz]: _ctx.qux }) - ], null, null, true) + ], null, true) return n0 }" `; diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap index 62e0ece59..ee8fcf62d 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap @@ -9,7 +9,7 @@ export function render(_ctx) { { modelValue: () => (_ctx.foo), "onUpdate:modelValue": () => $event => (_ctx.foo = $event), modelModifiers: () => ({ trim: true, "bar-baz": true }) } - ], null, null, true) + ], null, true) return n0 }" `; @@ -22,7 +22,7 @@ export function render(_ctx) { const n0 = _createComponent(_component_Comp, [ { modelValue: () => (_ctx.foo), "onUpdate:modelValue": () => $event => (_ctx.foo = $event) } - ], null, null, true) + ], null, true) return n0 }" `; @@ -41,7 +41,7 @@ export function render(_ctx) { "onUpdate:bar": () => $event => (_ctx.bar = $event), barModifiers: () => ({ number: true }) } - ], null, null, true) + ], null, true) return n0 }" `; @@ -54,7 +54,7 @@ export function render(_ctx) { const n0 = _createComponent(_component_Comp, [ { bar: () => (_ctx.foo), "onUpdate:bar": () => $event => (_ctx.foo = $event) } - ], null, null, true) + ], null, true) return n0 }" `; @@ -71,7 +71,7 @@ export function render(_ctx) { () => ({ [_ctx.bar]: _ctx.bar, ["onUpdate:" + _ctx.bar]: () => $event => (_ctx.bar = $event), [_ctx.bar + "Modifiers"]: () => ({ number: true }) }) - ], null, null, true) + ], null, true) return n0 }" `; @@ -84,7 +84,7 @@ export function render(_ctx) { const n0 = _createComponent(_component_Comp, [ () => ({ [_ctx.arg]: _ctx.foo, ["onUpdate:" + _ctx.arg]: () => $event => (_ctx.foo = $event) }) - ], null, null, true) + ], null, true) return n0 }" `; diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap index f4e42a895..68fe53dd8 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap @@ -44,7 +44,7 @@ export function render(_ctx) { const n1 = t0() const n0 = _createComponent(_component_Comp, [ { id: () => (_ctx.foo) } - ], null, null, null, true) + ], null, null, true) _insert(n0, n1) return n1 }" diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap index 8ac1e71f6..518b4408b 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap @@ -6,82 +6,90 @@ const t0 = _template("foo") export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n2 = _createComponent(_component_Comp, null, null, [() => ({ - name: _ctx.name, - fn: () => { - const n0 = t0() - return n0 - } - })], true) + const n2 = _createComponent(_component_Comp, null, [ + () => ({ + name: _ctx.name, + fn: () => { + const n0 = t0() + return n0 + } + }) + ], true) return n2 }" `; exports[`compiler: transform slot > dynamic slots name w/ v-for 1`] = ` -"import { resolveComponent as _resolveComponent, createComponent as _createComponent, withDestructure as _withDestructure, createForSlots as _createForSlots, template as _template } from 'vue/vapor'; +"import { resolveComponent as _resolveComponent, withDestructure as _withDestructure, createForSlots as _createForSlots, createComponent as _createComponent, template as _template } from 'vue/vapor'; const t0 = _template("foo") export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n2 = _createComponent(_component_Comp, null, null, [() => (_createForSlots(_ctx.list, (item) => ({ - name: item, - fn: _withDestructure(({ bar }) => [bar], (_ctx0) => { - const n0 = t0() - return n0 - }) - })))], true) + const n2 = _createComponent(_component_Comp, null, [ + () => (_createForSlots(_ctx.list, (item) => ({ + name: item, + fn: _withDestructure(({ bar }) => [bar], (_ctx0) => { + const n0 = t0() + return n0 + }) + }))) + ], true) return n2 }" `; exports[`compiler: transform slot > dynamic slots name w/ v-for and provide absent key 1`] = ` -"import { resolveComponent as _resolveComponent, createComponent as _createComponent, createForSlots as _createForSlots, template as _template } from 'vue/vapor'; +"import { resolveComponent as _resolveComponent, createForSlots as _createForSlots, createComponent as _createComponent, template as _template } from 'vue/vapor'; const t0 = _template("foo") export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n2 = _createComponent(_component_Comp, null, null, [() => (_createForSlots(_ctx.list, (_, __, index) => ({ - name: index, - fn: () => { - const n0 = t0() - return n0 - } - })))], true) + const n2 = _createComponent(_component_Comp, null, [ + () => (_createForSlots(_ctx.list, (_, __, index) => ({ + name: index, + fn: () => { + const n0 = t0() + return n0 + } + }))) + ], true) return n2 }" `; exports[`compiler: transform slot > dynamic slots name w/ v-if / v-else[-if] 1`] = ` -"import { resolveComponent as _resolveComponent, createComponent as _createComponent, withDestructure as _withDestructure, template as _template } from 'vue/vapor'; +"import { resolveComponent as _resolveComponent, withDestructure as _withDestructure, createComponent as _createComponent, template as _template } from 'vue/vapor'; const t0 = _template("condition slot") const t1 = _template("another condition") const t2 = _template("else condition") export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n6 = _createComponent(_component_Comp, null, null, [() => (_ctx.condition - ? { - name: "condition", - fn: () => { - const n0 = t0() - return n0 - } - } - : _ctx.anotherCondition + const n6 = _createComponent(_component_Comp, null, [ + () => (_ctx.condition ? { - name: "condition", - fn: _withDestructure(({ foo, bar }) => [foo, bar], (_ctx0) => { - const n2 = t1() - return n2 - }) - } - : { name: "condition", fn: () => { - const n4 = t2() - return n4 + const n0 = t0() + return n0 } - })], true) + } + : _ctx.anotherCondition + ? { + name: "condition", + fn: _withDestructure(({ foo, bar }) => [foo, bar], (_ctx0) => { + const n2 = t1() + return n2 + }) + } + : { + name: "condition", + fn: () => { + const n4 = t2() + return n4 + } + }) + ], true) return n6 }" `; @@ -92,10 +100,14 @@ const t0 = _template("
") export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n1 = _createComponent(_component_Comp, null, { default: () => { - const n0 = t0() - return n0 - } }, null, true) + const n1 = _createComponent(_component_Comp, null, [ + { + default: () => { + const n0 = t0() + return n0 + } + } + ], true) return n1 }" `; @@ -108,79 +120,99 @@ const t2 = _template("") export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n4 = _createComponent(_component_Comp, null, { - one: () => { - const n0 = t0() - return n0 - }, - default: () => { - const n2 = t1() - const n3 = t2() - return [n2, n3] + const n4 = _createComponent(_component_Comp, null, [ + { + one: () => { + const n0 = t0() + return n0 + }, + default: () => { + const n2 = t1() + const n3 = t2() + return [n2, n3] + } } - }, null, true) + ], true) return n4 }" `; exports[`compiler: transform slot > nested slots scoping 1`] = ` -"import { resolveComponent as _resolveComponent, createComponent as _createComponent, createTextNode as _createTextNode, withDestructure as _withDestructure, template as _template } from 'vue/vapor'; +"import { resolveComponent as _resolveComponent, createTextNode as _createTextNode, withDestructure as _withDestructure, createComponent as _createComponent, template as _template } from 'vue/vapor'; const t0 = _template(" ") export function render(_ctx) { const _component_Inner = _resolveComponent("Inner") const _component_Comp = _resolveComponent("Comp") - const n5 = _createComponent(_component_Comp, null, { default: _withDestructure(({ foo }) => [foo], (_ctx0) => { - const n2 = t0() - const n1 = _createComponent(_component_Inner, null, { default: _withDestructure(({ bar }) => [bar], (_ctx1) => { - const n0 = _createTextNode(() => [_ctx0[0] + _ctx1[0] + _ctx.baz]) - return n0 - }) }) - const n3 = _createTextNode(() => [_ctx0[0] + _ctx.bar + _ctx.baz]) - return [n1, n2, n3] - }) }, null, true) + const n5 = _createComponent(_component_Comp, null, [ + { + default: _withDestructure(({ foo }) => [foo], (_ctx0) => { + const n2 = t0() + const n1 = _createComponent(_component_Inner, null, [ + { + default: _withDestructure(({ bar }) => [bar], (_ctx1) => { + const n0 = _createTextNode(() => [_ctx0[0] + _ctx1[0] + _ctx.baz]) + return n0 + }) + } + ]) + const n3 = _createTextNode(() => [_ctx0[0] + _ctx.bar + _ctx.baz]) + return [n1, n2, n3] + }) + } + ], true) return n5 }" `; exports[`compiler: transform slot > on component dynamically named slot 1`] = ` -"import { resolveComponent as _resolveComponent, createComponent as _createComponent, createTextNode as _createTextNode, withDestructure as _withDestructure } from 'vue/vapor'; +"import { resolveComponent as _resolveComponent, createTextNode as _createTextNode, withDestructure as _withDestructure, createComponent as _createComponent } from 'vue/vapor'; export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n1 = _createComponent(_component_Comp, null, { }, [() => ({ - name: _ctx.named, - fn: _withDestructure(({ foo }) => [foo], (_ctx0) => { - const n0 = _createTextNode(() => [_ctx0[0] + _ctx.bar]) - return n0 + const n1 = _createComponent(_component_Comp, null, [ + () => ({ + name: _ctx.named, + fn: _withDestructure(({ foo }) => [foo], (_ctx0) => { + const n0 = _createTextNode(() => [_ctx0[0] + _ctx.bar]) + return n0 + }) }) - })], true) + ], true) return n1 }" `; exports[`compiler: transform slot > on component named slot 1`] = ` -"import { resolveComponent as _resolveComponent, createComponent as _createComponent, createTextNode as _createTextNode, withDestructure as _withDestructure } from 'vue/vapor'; +"import { resolveComponent as _resolveComponent, createTextNode as _createTextNode, withDestructure as _withDestructure, createComponent as _createComponent } from 'vue/vapor'; export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n1 = _createComponent(_component_Comp, null, { named: _withDestructure(({ foo }) => [foo], (_ctx0) => { - const n0 = _createTextNode(() => [_ctx0[0] + _ctx.bar]) - return n0 - }) }, null, true) + const n1 = _createComponent(_component_Comp, null, [ + { + named: _withDestructure(({ foo }) => [foo], (_ctx0) => { + const n0 = _createTextNode(() => [_ctx0[0] + _ctx.bar]) + return n0 + }) + } + ], true) return n1 }" `; exports[`compiler: transform slot > on-component default slot 1`] = ` -"import { resolveComponent as _resolveComponent, createComponent as _createComponent, createTextNode as _createTextNode, withDestructure as _withDestructure } from 'vue/vapor'; +"import { resolveComponent as _resolveComponent, createTextNode as _createTextNode, withDestructure as _withDestructure, createComponent as _createComponent } from 'vue/vapor'; export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n1 = _createComponent(_component_Comp, null, { default: _withDestructure(({ foo }) => [foo], (_ctx0) => { - const n0 = _createTextNode(() => [_ctx0[0] + _ctx.bar]) - return n0 - }) }, null, true) + const n1 = _createComponent(_component_Comp, null, [ + { + default: _withDestructure(({ foo }) => [foo], (_ctx0) => { + const n0 = _createTextNode(() => [_ctx0[0] + _ctx.bar]) + return n0 + }) + } + ], true) return n1 }" `; diff --git a/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts b/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts index bb5b8970f..746ac44cc 100644 --- a/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts @@ -182,9 +182,7 @@ describe('compiler: element transform', () => { bindingMetadata: { Comp: BindingTypes.SETUP_CONST }, }) expect(code).toMatchSnapshot() - expect(code).contains( - '_createComponent(_ctx.Comp, null, null, null, true)', - ) + expect(code).contains('_createComponent(_ctx.Comp, null, null, true)') }) test('generate multi root component', () => { diff --git a/packages/compiler-vapor/__tests__/transforms/vSlot.spec.ts b/packages/compiler-vapor/__tests__/transforms/vSlot.spec.ts index 966ecfcbc..b5445d60e 100644 --- a/packages/compiler-vapor/__tests__/transforms/vSlot.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vSlot.spec.ts @@ -1,7 +1,7 @@ import { ErrorCodes, NodeTypes } from '@vue/compiler-core' import { - DynamicSlotType, IRNodeTypes, + IRSlotType, transformChildren, transformElement, transformSlotOutlet, @@ -42,14 +42,19 @@ describe('compiler: transform slot', () => { id: 1, tag: 'Comp', props: [[]], - slots: { - default: { - type: IRNodeTypes.BLOCK, - dynamic: { - children: [{ template: 0 }], + slots: [ + { + slotType: IRSlotType.STATIC, + slots: { + default: { + type: IRNodeTypes.BLOCK, + dynamic: { + children: [{ template: 0 }], + }, + }, }, }, - }, + ], }, ]) expect(ir.block.returns).toEqual([1]) @@ -73,19 +78,24 @@ describe('compiler: transform slot', () => { type: IRNodeTypes.CREATE_COMPONENT_NODE, tag: 'Comp', props: [[]], - slots: { - default: { - type: IRNodeTypes.BLOCK, - props: { - type: NodeTypes.SIMPLE_EXPRESSION, - content: '{ foo }', - ast: { - type: 'ArrowFunctionExpression', - params: [{ type: 'ObjectPattern' }], + slots: [ + { + slotType: IRSlotType.STATIC, + slots: { + default: { + type: IRNodeTypes.BLOCK, + props: { + type: NodeTypes.SIMPLE_EXPRESSION, + content: '{ foo }', + ast: { + type: 'ArrowFunctionExpression', + params: [{ type: 'ObjectPattern' }], + }, + }, }, }, }, - }, + ], }, ]) }) @@ -103,15 +113,20 @@ describe('compiler: transform slot', () => { { type: IRNodeTypes.CREATE_COMPONENT_NODE, tag: 'Comp', - slots: { - named: { - type: IRNodeTypes.BLOCK, - props: { - type: NodeTypes.SIMPLE_EXPRESSION, - content: '{ foo }', + slots: [ + { + slotType: IRSlotType.STATIC, + slots: { + named: { + type: IRNodeTypes.BLOCK, + props: { + type: NodeTypes.SIMPLE_EXPRESSION, + content: '{ foo }', + }, + }, }, }, - }, + ], }, ]) }) @@ -130,7 +145,7 @@ describe('compiler: transform slot', () => { { type: IRNodeTypes.CREATE_COMPONENT_NODE, tag: 'Comp', - dynamicSlots: [ + slots: [ { name: { type: NodeTypes.SIMPLE_EXPRESSION, @@ -165,20 +180,25 @@ describe('compiler: transform slot', () => { id: 4, tag: 'Comp', props: [[]], - slots: { - one: { - type: IRNodeTypes.BLOCK, - dynamic: { - children: [{ template: 0 }], + slots: [ + { + slotType: IRSlotType.STATIC, + slots: { + one: { + type: IRNodeTypes.BLOCK, + dynamic: { + children: [{ template: 0 }], + }, + }, + default: { + type: IRNodeTypes.BLOCK, + dynamic: { + children: [{}, { template: 1 }, { template: 2 }], + }, + }, }, }, - default: { - type: IRNodeTypes.BLOCK, - dynamic: { - children: [{}, { template: 1 }, { template: 2 }], - }, - }, - }, + ], }, ]) }) @@ -207,31 +227,41 @@ describe('compiler: transform slot', () => { type: IRNodeTypes.CREATE_COMPONENT_NODE, tag: 'Comp', props: [[]], - slots: { - default: { - type: IRNodeTypes.BLOCK, - props: { - type: NodeTypes.SIMPLE_EXPRESSION, - content: '{ foo }', + slots: [ + { + slotType: IRSlotType.STATIC, + slots: { + default: { + type: IRNodeTypes.BLOCK, + props: { + type: NodeTypes.SIMPLE_EXPRESSION, + content: '{ foo }', + }, + }, }, }, - }, + ], }, ]) expect( - (ir.block.operation[0] as any).slots.default.operation[0], + (ir.block.operation[0] as any).slots[0].slots.default.operation[0], ).toMatchObject({ type: IRNodeTypes.CREATE_COMPONENT_NODE, tag: 'Inner', - slots: { - default: { - type: IRNodeTypes.BLOCK, - props: { - type: NodeTypes.SIMPLE_EXPRESSION, - content: '{ bar }', + slots: [ + { + slotType: IRSlotType.STATIC, + slots: { + default: { + type: IRNodeTypes.BLOCK, + props: { + type: NodeTypes.SIMPLE_EXPRESSION, + content: '{ bar }', + }, + }, }, }, - }, + ], }) }) @@ -247,8 +277,7 @@ describe('compiler: transform slot', () => { { type: IRNodeTypes.CREATE_COMPONENT_NODE, tag: 'Comp', - slots: undefined, - dynamicSlots: [ + slots: [ { name: { type: NodeTypes.SIMPLE_EXPRESSION, @@ -278,8 +307,7 @@ describe('compiler: transform slot', () => { { type: IRNodeTypes.CREATE_COMPONENT_NODE, tag: 'Comp', - slots: undefined, - dynamicSlots: [ + slots: [ { name: { type: NodeTypes.SIMPLE_EXPRESSION, @@ -310,8 +338,7 @@ describe('compiler: transform slot', () => { { type: IRNodeTypes.CREATE_COMPONENT_NODE, tag: 'Comp', - slots: undefined, - dynamicSlots: [ + slots: [ { name: { type: NodeTypes.SIMPLE_EXPRESSION, @@ -350,21 +377,20 @@ describe('compiler: transform slot', () => { { type: IRNodeTypes.CREATE_COMPONENT_NODE, tag: 'Comp', - slots: undefined, - dynamicSlots: [ + slots: [ { - slotType: DynamicSlotType.CONDITIONAL, + slotType: IRSlotType.CONDITIONAL, condition: { content: 'condition' }, positive: { - slotType: DynamicSlotType.BASIC, + slotType: IRSlotType.DYNAMIC, }, negative: { - slotType: DynamicSlotType.CONDITIONAL, + slotType: IRSlotType.CONDITIONAL, condition: { content: 'anotherCondition' }, positive: { - slotType: DynamicSlotType.BASIC, + slotType: IRSlotType.DYNAMIC, }, - negative: { slotType: DynamicSlotType.BASIC }, + negative: { slotType: IRSlotType.DYNAMIC }, }, }, ], diff --git a/packages/compiler-vapor/src/generators/component.ts b/packages/compiler-vapor/src/generators/component.ts index b5773aa8d..e7b0bc0a8 100644 --- a/packages/compiler-vapor/src/generators/component.ts +++ b/packages/compiler-vapor/src/generators/component.ts @@ -1,18 +1,19 @@ import { camelize, extend, isArray } from '@vue/shared' import type { CodegenContext } from '../generate' import { - type ComponentBasicDynamicSlot, - type ComponentConditionalDynamicSlot, - type ComponentDynamicSlot, - type ComponentLoopDynamicSlot, - type ComponentSlotBlockIRNode, - type ComponentSlots, type CreateComponentIRNode, - DynamicSlotType, IRDynamicPropsKind, type IRProp, type IRProps, type IRPropsStatic, + type IRSlotDynamic, + type IRSlotDynamicBasic, + type IRSlotDynamicConditional, + type IRSlotDynamicLoop, + IRSlotType, + type IRSlots, + type IRSlotsStatic, + type SlotBlockIRNode, } from '../ir' import { type CodeFragment, @@ -45,8 +46,9 @@ export function genCreateComponent( const { vaporHelper } = context const tag = genTag() - const { root, slots, dynamicSlots, once } = oper - const rawProps = genRawProps(oper.props, context) + const { root, props, slots, once } = oper + const rawProps = genRawProps(props, context) + const rawSlots = genRawSlots(slots, context) return [ NEWLINE, @@ -55,8 +57,7 @@ export function genCreateComponent( vaporHelper('createComponent'), tag, rawProps, - slots && genSlots(slots, context), - dynamicSlots && genDynamicSlots(dynamicSlots, context), + rawSlots, root ? 'true' : false, once && 'true', ), @@ -152,51 +153,51 @@ function genModelModifiers( return [',', NEWLINE, ...modifiersKey, `: () => ({ ${modifiersVal} })`] } -function genSlots(slots: ComponentSlots, context: CodegenContext) { +function genRawSlots(slots: IRSlots[], context: CodegenContext) { + if (!slots.length) return + return genMulti( + DELIMITERS_ARRAY_NEWLINE, + ...slots.map(slot => + slot.slotType === IRSlotType.STATIC + ? genStaticSlots(slot, context) + : genDynamicSlot(slot, context, true), + ), + ) +} + +function genStaticSlots({ slots }: IRSlotsStatic, context: CodegenContext) { const names = Object.keys(slots) return genMulti( - names.length > 1 ? DELIMITERS_OBJECT_NEWLINE : DELIMITERS_OBJECT, + DELIMITERS_OBJECT_NEWLINE, ...names.map(name => [ - name, - ': ', + `${name}: `, ...genSlotBlockWithProps(slots[name], context), ]), ) } -function genDynamicSlots( - dynamicSlots: ComponentDynamicSlot[], - context: CodegenContext, -) { - return genMulti( - dynamicSlots.length > 1 ? DELIMITERS_ARRAY_NEWLINE : DELIMITERS_ARRAY, - ...dynamicSlots.map(slot => genDynamicSlot(slot, context, true)), - ) -} - function genDynamicSlot( - slot: ComponentDynamicSlot, + slot: IRSlotDynamic, context: CodegenContext, - top = false, + withFunction = false, ): CodeFragment[] { + let frag: CodeFragment[] switch (slot.slotType) { - case DynamicSlotType.BASIC: - return top - ? ['() => (', ...genBasicDynamicSlot(slot, context), ')'] - : genBasicDynamicSlot(slot, context) - case DynamicSlotType.LOOP: - return top - ? ['() => (', ...genLoopSlot(slot, context), ')'] - : genLoopSlot(slot, context) - case DynamicSlotType.CONDITIONAL: - return top - ? ['() => (', ...genConditionalSlot(slot, context), ')'] - : genConditionalSlot(slot, context) + case IRSlotType.DYNAMIC: + frag = genBasicDynamicSlot(slot, context) + break + case IRSlotType.LOOP: + frag = genLoopSlot(slot, context) + break + case IRSlotType.CONDITIONAL: + frag = genConditionalSlot(slot, context) + break } + return withFunction ? ['() => (', ...frag, ')'] : frag } function genBasicDynamicSlot( - slot: ComponentBasicDynamicSlot, + slot: IRSlotDynamicBasic, context: CodegenContext, ): CodeFragment[] { const { name, fn } = slot @@ -208,7 +209,7 @@ function genBasicDynamicSlot( } function genLoopSlot( - slot: ComponentLoopDynamicSlot, + slot: IRSlotDynamicLoop, context: CodegenContext, ): CodeFragment[] { const { name, fn, loop } = slot @@ -249,7 +250,7 @@ function genLoopSlot( } function genConditionalSlot( - slot: ComponentConditionalDynamicSlot, + slot: IRSlotDynamicConditional, context: CodegenContext, ): CodeFragment[] { const { condition, positive, negative } = slot @@ -266,10 +267,7 @@ function genConditionalSlot( ] } -function genSlotBlockWithProps( - oper: ComponentSlotBlockIRNode, - context: CodegenContext, -) { +function genSlotBlockWithProps(oper: SlotBlockIRNode, context: CodegenContext) { let isDestructureAssignment = false let rawProps: string | undefined let propsName: string | undefined diff --git a/packages/compiler-vapor/src/ir/component.ts b/packages/compiler-vapor/src/ir/component.ts new file mode 100644 index 000000000..c2bd99f7d --- /dev/null +++ b/packages/compiler-vapor/src/ir/component.ts @@ -0,0 +1,66 @@ +import type { SimpleExpressionNode } from '@vue/compiler-dom' +import type { DirectiveTransformResult } from '../transform' +import type { BlockIRNode, IRFor } from './index' + +// props +export interface IRProp extends Omit { + values: SimpleExpressionNode[] +} + +export enum IRDynamicPropsKind { + EXPRESSION, // v-bind="value" + ATTRIBUTE, // v-bind:[foo]="value" +} + +export type IRPropsStatic = IRProp[] +export interface IRPropsDynamicExpression { + kind: IRDynamicPropsKind.EXPRESSION + value: SimpleExpressionNode + handler?: boolean +} +export interface IRPropsDynamicAttribute extends IRProp { + kind: IRDynamicPropsKind.ATTRIBUTE +} +export type IRProps = + | IRPropsStatic + | IRPropsDynamicAttribute + | IRPropsDynamicExpression + +// slots +export interface SlotBlockIRNode extends BlockIRNode { + props?: SimpleExpressionNode +} + +export enum IRSlotType { + STATIC, + DYNAMIC, + LOOP, + CONDITIONAL, +} +export type IRSlotsStatic = { + slotType: IRSlotType.STATIC + slots: Record +} +export interface IRSlotDynamicBasic { + slotType: IRSlotType.DYNAMIC + name: SimpleExpressionNode + fn: SlotBlockIRNode +} +export interface IRSlotDynamicLoop { + slotType: IRSlotType.LOOP + name: SimpleExpressionNode + fn: SlotBlockIRNode + loop: IRFor +} +export interface IRSlotDynamicConditional { + slotType: IRSlotType.CONDITIONAL + condition: SimpleExpressionNode + positive: IRSlotDynamicBasic + negative?: IRSlotDynamicBasic | IRSlotDynamicConditional +} + +export type IRSlotDynamic = + | IRSlotDynamicBasic + | IRSlotDynamicLoop + | IRSlotDynamicConditional +export type IRSlots = IRSlotsStatic | IRSlotDynamic diff --git a/packages/compiler-vapor/src/ir.ts b/packages/compiler-vapor/src/ir/index.ts similarity index 78% rename from packages/compiler-vapor/src/ir.ts rename to packages/compiler-vapor/src/ir/index.ts index b55538b74..02318b634 100644 --- a/packages/compiler-vapor/src/ir.ts +++ b/packages/compiler-vapor/src/ir/index.ts @@ -7,11 +7,10 @@ import type { TemplateChildNode, } from '@vue/compiler-dom' import type { Prettify } from '@vue/shared' -import type { - DirectiveTransform, - DirectiveTransformResult, - NodeTransform, -} from './transform' +import type { DirectiveTransform, NodeTransform } from '../transform' +import type { IRProp, IRProps, IRSlots } from './component' + +export * from './component' export enum IRNodeTypes { ROOT, @@ -88,29 +87,6 @@ export interface ForIRNode extends BaseIRNode, IRFor { once: boolean } -export interface IRProp extends Omit { - values: SimpleExpressionNode[] -} - -export enum IRDynamicPropsKind { - EXPRESSION, // v-bind="value" - ATTRIBUTE, // v-bind:[foo]="value" -} - -export type IRPropsStatic = IRProp[] -export interface IRPropsDynamicExpression { - kind: IRDynamicPropsKind.EXPRESSION - value: SimpleExpressionNode - handler?: boolean -} -export interface IRPropsDynamicAttribute extends IRProp { - kind: IRDynamicPropsKind.ATTRIBUTE -} -export type IRProps = - | IRPropsStatic - | IRPropsDynamicAttribute - | IRPropsDynamicExpression - export interface SetPropIRNode extends BaseIRNode { type: IRNodeTypes.SET_PROP element: number @@ -207,51 +183,12 @@ export interface WithDirectiveIRNode extends BaseIRNode { asset?: boolean } -export interface ComponentSlotBlockIRNode extends BlockIRNode { - props?: SimpleExpressionNode -} -export type ComponentSlots = Record - -export enum DynamicSlotType { - BASIC, - LOOP, - CONDITIONAL, -} - -export interface ComponentBasicDynamicSlot { - slotType: DynamicSlotType.BASIC - name: SimpleExpressionNode - fn: ComponentSlotBlockIRNode -} - -export interface ComponentLoopDynamicSlot { - slotType: DynamicSlotType.LOOP - name: SimpleExpressionNode - fn: ComponentSlotBlockIRNode - loop: IRFor -} - -export interface ComponentConditionalDynamicSlot { - slotType: DynamicSlotType.CONDITIONAL - condition: SimpleExpressionNode - positive: ComponentBasicDynamicSlot - negative?: ComponentBasicDynamicSlot | ComponentConditionalDynamicSlot -} - -export type ComponentDynamicSlot = - | ComponentBasicDynamicSlot - | ComponentLoopDynamicSlot - | ComponentConditionalDynamicSlot - export interface CreateComponentIRNode extends BaseIRNode { type: IRNodeTypes.CREATE_COMPONENT_NODE id: number tag: string props: IRProps[] - - slots?: ComponentSlots - dynamicSlots?: ComponentDynamicSlot[] - + slots: IRSlots[] asset: boolean root: boolean once: boolean diff --git a/packages/compiler-vapor/src/transform.ts b/packages/compiler-vapor/src/transform.ts index 48b00ffb7..27bc690a9 100644 --- a/packages/compiler-vapor/src/transform.ts +++ b/packages/compiler-vapor/src/transform.ts @@ -16,12 +16,11 @@ import { import { EMPTY_OBJ, NOOP, extend, isArray, isString } from '@vue/shared' import { type BlockIRNode, - type ComponentDynamicSlot, - type ComponentSlots, DynamicFlag, type HackOptions, type IRDynamicInfo, IRNodeTypes, + type IRSlots, type OperationNode, type RootIRNode, type VaporDirectiveNode, @@ -81,8 +80,7 @@ export class TransformContext { component: Set = this.ir.component directive: Set = this.ir.directive - slots?: ComponentSlots - dynamicSlots?: ComponentDynamicSlot[] + slots: IRSlots[] = [] private globalId = 0 @@ -96,14 +94,12 @@ export class TransformContext { } enterBlock(ir: BlockIRNode, isVFor: boolean = false): () => void { - const { block, template, dynamic, childrenTemplate, slots, dynamicSlots } = - this + const { block, template, dynamic, childrenTemplate, slots } = this this.block = ir this.dynamic = ir.dynamic this.template = '' this.childrenTemplate = [] - this.slots = undefined - this.dynamicSlots = undefined + this.slots = [] isVFor && this.inVFor++ return () => { // exit @@ -113,7 +109,6 @@ export class TransformContext { this.dynamic = dynamic this.childrenTemplate = childrenTemplate this.slots = slots - this.dynamicSlots = dynamicSlots isVFor && this.inVFor-- } } diff --git a/packages/compiler-vapor/src/transforms/transformElement.ts b/packages/compiler-vapor/src/transforms/transformElement.ts index 173cdb58f..c5c50ad9f 100644 --- a/packages/compiler-vapor/src/transforms/transformElement.ts +++ b/packages/compiler-vapor/src/transforms/transformElement.ts @@ -105,11 +105,9 @@ function transformComponentElement( asset, root, slots: context.slots, - dynamicSlots: context.dynamicSlots, once: context.inVOnce, }) - context.slots = undefined - context.dynamicSlots = undefined + context.slots = [] } function resolveSetupReference(name: string, context: TransformContext) { diff --git a/packages/compiler-vapor/src/transforms/vSlot.ts b/packages/compiler-vapor/src/transforms/vSlot.ts index 6a8e18eb6..d1bf1c6b0 100644 --- a/packages/compiler-vapor/src/transforms/vSlot.ts +++ b/packages/compiler-vapor/src/transforms/vSlot.ts @@ -3,6 +3,7 @@ import { ElementTypes, ErrorCodes, NodeTypes, + type SimpleExpressionNode, type TemplateChildNode, createCompilerError, isTemplateNode, @@ -11,17 +12,19 @@ import { import type { NodeTransform, TransformContext } from '../transform' import { newBlock } from './utils' import { - type ComponentBasicDynamicSlot, - type ComponentConditionalDynamicSlot, - type ComponentSlotBlockIRNode, DynamicFlag, - DynamicSlotType, type IRFor, + type IRSlotDynamic, + type IRSlotDynamicBasic, + type IRSlotDynamicConditional, + IRSlotType, + type IRSlots, + type IRSlotsStatic, + type SlotBlockIRNode, type VaporDirectiveNode, } from '../ir' import { findDir, resolveExpression } from '../utils' -// TODO dynamic slots export const transformVSlot: NodeTransform = (node, context) => { if (node.type !== NodeTypes.ELEMENT) return @@ -37,163 +40,17 @@ export const transformVSlot: NodeTransform = (node, context) => { parent.node.tagType === ElementTypes.COMPONENT if (isComponent && children.length) { - const arg = dir && dir.arg - const slotName = arg ? arg.content : 'default' - - const nonSlotTemplateChildren = children.filter( - n => - isNonWhitespaceContent(node) && - !(n.type === NodeTypes.ELEMENT && n.props.some(isVSlot)), - ) - - const [block, onExit] = createSlotBlock( + return transformComponentSlot( node, dir, context as TransformContext, ) - - const slots = (context.slots ||= {}) - const dynamicSlots = (context.dynamicSlots ||= []) - - return () => { - onExit() - - let hasOtherSlots = !!Object.keys(slots).length - - if (dir && (hasOtherSlots || dynamicSlots.length)) { - // already has on-component slot - this is incorrect usage. - context.options.onError( - createCompilerError(ErrorCodes.X_V_SLOT_MIXED_SLOT_USAGE, dir.loc), - ) - // discarding other slots, referenced how compiler-core implements - Object.keys(slots).forEach(slotName => delete slots[slotName]) - dynamicSlots.length = 0 - hasOtherSlots = false - } - - if (nonSlotTemplateChildren.length) { - if (slots.default) { - context.options.onError( - createCompilerError( - ErrorCodes.X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN, - nonSlotTemplateChildren[0].loc, - ), - ) - } else if (!arg || arg.isStatic) { - slots[slotName] = block - } else { - dynamicSlots.push({ - slotType: DynamicSlotType.BASIC, - name: arg, - fn: block, - }) - } - context.slots = slots - } else if (hasOtherSlots) { - context.slots = slots - } - - if (dynamicSlots.length) context.dynamicSlots = dynamicSlots - } } else if (isSlotTemplate && dir) { - let { arg } = dir - - context.dynamic.flags |= DynamicFlag.NON_TEMPLATE - - const vFor = findDir(node, 'for') - const vIf = findDir(node, 'if') - const vElse = findDir(node, /^else(-if)?$/, true /* allowEmpty */) - const slots = context.slots! - const dynamicSlots = context.dynamicSlots! - - const [block, onExit] = createSlotBlock( + return transformTemplateSlot( node, dir, context as TransformContext, ) - - arg &&= resolveExpression(arg) - - if ((!arg || arg.isStatic) && !vFor && !vIf && !vElse) { - const slotName = arg ? arg.content : 'default' - - if (slots[slotName]) { - context.options.onError( - createCompilerError( - ErrorCodes.X_V_SLOT_DUPLICATE_SLOT_NAMES, - dir.loc, - ), - ) - } else { - slots[slotName] = block - } - } else if (vIf) { - dynamicSlots.push({ - slotType: DynamicSlotType.CONDITIONAL, - condition: vIf.exp!, - positive: { - slotType: DynamicSlotType.BASIC, - name: arg!, - fn: block, - }, - }) - } else if (vElse) { - const vIfIR = dynamicSlots[dynamicSlots.length - 1] - if (vIfIR.slotType === DynamicSlotType.CONDITIONAL) { - let ifNode = vIfIR - while ( - ifNode.negative && - ifNode.negative.slotType === DynamicSlotType.CONDITIONAL - ) - ifNode = ifNode.negative - const negative: - | ComponentBasicDynamicSlot - | ComponentConditionalDynamicSlot = vElse.exp - ? { - slotType: DynamicSlotType.CONDITIONAL, - condition: vElse.exp, - positive: { - slotType: DynamicSlotType.BASIC, - name: arg!, - fn: block, - }, - } - : { - slotType: DynamicSlotType.BASIC, - name: arg!, - fn: block, - } - ifNode.negative = negative - } else { - context.options.onError( - createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, vElse.loc), - ) - } - } else if (vFor) { - if (vFor.forParseResult) { - dynamicSlots.push({ - slotType: DynamicSlotType.LOOP, - name: arg!, - fn: block, - loop: vFor.forParseResult as IRFor, - }) - } else { - context.options.onError( - createCompilerError( - ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION, - vFor.loc, - ), - ) - } - } else { - dynamicSlots.push({ - slotType: DynamicSlotType.BASIC, - name: arg!, - fn: block, - }) - } - - return () => onExit() } else if (!isComponent && dir) { context.options.onError( createCompilerError(ErrorCodes.X_V_SLOT_MISPLACED, dir.loc), @@ -201,12 +58,183 @@ export const transformVSlot: NodeTransform = (node, context) => { } } +// +function transformComponentSlot( + node: ElementNode, + dir: VaporDirectiveNode | undefined, + context: TransformContext, +) { + const { children } = node + const arg = dir && dir.arg + const nonSlotTemplateChildren = children.filter( + n => + isNonWhitespaceContent(node) && + !(n.type === NodeTypes.ELEMENT && n.props.some(isVSlot)), + ) + + const [block, onExit] = createSlotBlock(node, dir, context) + + const { slots } = context + + return () => { + onExit() + + const hasOtherSlots = !!slots.length + if (dir && hasOtherSlots) { + // already has on-component slot - this is incorrect usage. + context.options.onError( + createCompilerError(ErrorCodes.X_V_SLOT_MIXED_SLOT_USAGE, dir.loc), + ) + return + } + + if (nonSlotTemplateChildren.length) { + if (hasStaticSlot(slots, 'default')) { + context.options.onError( + createCompilerError( + ErrorCodes.X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN, + nonSlotTemplateChildren[0].loc, + ), + ) + } else { + registerSlot(slots, arg, block) + context.slots = slots + } + } else if (hasOtherSlots) { + context.slots = slots + } + } +} + +//