From 6e0f54ab1674327beedeeec73eed1f372814ceb2 Mon Sep 17 00:00:00 2001 From: Rizumu Ayaka Date: Mon, 29 Apr 2024 23:14:03 +0800 Subject: [PATCH 1/4] feat(compiler-vapor): component with dynamic arguments --- .../transformElement.spec.ts.snap | 29 ++++ .../__snapshots__/vModel.spec.ts.snap | 17 +-- .../transforms/transformElement.spec.ts | 48 +++++++ .../__tests__/transforms/vModel.spec.ts | 42 +++--- .../src/generators/component.ts | 126 ++++++++++-------- .../compiler-vapor/src/generators/prop.ts | 4 +- packages/compiler-vapor/src/ir.ts | 11 +- .../src/transforms/transformElement.ts | 9 +- 8 files changed, 194 insertions(+), 92 deletions(-) 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 0fcf9b1e1..cdd5790b5 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap @@ -179,6 +179,35 @@ export function render(_ctx) { }" `; +exports[`compiler: element transform > component with dynamic event arguments 1`] = ` +"import { toHandlerKey as _toHandlerKey } from 'vue'; +import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor'; + +export function render(_ctx) { + const _component_Foo = _resolveComponent("Foo") + const n0 = _createComponent(_component_Foo, [() => ({ + [_toHandlerKey(_ctx.foo-_ctx.bar)]: () => _ctx.bar + }), () => ({ + [_toHandlerKey(_ctx.baz)]: () => _ctx.qux + })], true) + return n0 +}" +`; + +exports[`compiler: element transform > component with dynamic prop arguments 1`] = ` +"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor'; + +export function render(_ctx) { + const _component_Foo = _resolveComponent("Foo") + const n0 = _createComponent(_component_Foo, [() => ({ + [_ctx.foo-_ctx.bar]: _ctx.bar + }), () => ({ + [_ctx.baz]: _ctx.qux + })], true) + return n0 +}" +`; + exports[`compiler: element transform > invalid html nesting 1`] = ` "import { insert as _insert, template as _template } from 'vue/vapor'; const t0 = _template("
123
") 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 a8764d6e1..911ed1486 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap @@ -62,14 +62,15 @@ exports[`compiler: vModel transform > component > v-model with dynamic arguments export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n0 = _createComponent(_component_Comp, [{ - [_ctx.foo]: () => (_ctx.foo), + const n0 = _createComponent(_component_Comp, [() => ({ + [_ctx.foo]: _ctx.foo, ["onUpdate:" + _ctx.foo]: () => $event => (_ctx.foo = $event), - [_ctx.foo + "Modifiers"]: () => ({ trim: true }), - [_ctx.bar]: () => (_ctx.bar), + [_ctx.foo + "Modifiers"]: () => ({ trim: true }) + }), () => ({ + [_ctx.bar]: _ctx.bar, ["onUpdate:" + _ctx.bar]: () => $event => (_ctx.bar = $event), [_ctx.bar + "Modifiers"]: () => ({ number: true }) - }], true) + })], true) return n0 }" `; @@ -79,10 +80,10 @@ exports[`compiler: vModel transform > component > v-model with dynamic arguments export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n0 = _createComponent(_component_Comp, [{ - [_ctx.arg]: () => (_ctx.foo), + const n0 = _createComponent(_component_Comp, [() => ({ + [_ctx.arg]: _ctx.foo, ["onUpdate:" + _ctx.arg]: () => $event => (_ctx.foo = $event) - }], true) + })], true) return n0 }" `; diff --git a/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts b/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts index 2fa5245a9..fcadd9447 100644 --- a/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts @@ -691,6 +691,54 @@ describe('compiler: element transform', () => { expect(code).contains('_setDynamicEvents(n0, _ctx.obj)') }) + test('component with dynamic prop arguments', () => { + const { code, ir } = compileWithElementTransform( + ``, + ) + expect(code).toMatchSnapshot() + expect(ir.block.operation).toMatchObject([ + { + type: IRNodeTypes.CREATE_COMPONENT_NODE, + tag: 'Foo', + props: [ + { + key: { content: 'foo-bar' }, + values: [{ content: 'bar' }], + }, + { + key: { content: 'baz' }, + values: [{ content: 'qux' }], + }, + ], + }, + ]) + }) + + test('component with dynamic event arguments', () => { + const { code, ir } = compileWithElementTransform( + ``, + ) + expect(code).toMatchSnapshot() + expect(ir.block.operation).toMatchObject([ + { + type: IRNodeTypes.CREATE_COMPONENT_NODE, + tag: 'Foo', + props: [ + { + key: { content: 'foo-bar' }, + values: [{ content: 'bar' }], + handler: true, + }, + { + key: { content: 'baz' }, + values: [{ content: 'qux' }], + handler: true, + }, + ], + }, + ]) + }) + test('invalid html nesting', () => { const { code, ir } = compileWithElementTransform( `

123

diff --git a/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts b/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts index 80a22c880..921145643 100644 --- a/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts @@ -259,7 +259,7 @@ describe('compiler: vModel transform', () => { const { code, ir } = compileWithVModel('') expect(code).toMatchSnapshot() expect(code).contains( - `[_ctx.arg]: () => (_ctx.foo), + `[_ctx.arg]: _ctx.foo, ["onUpdate:" + _ctx.arg]: () => $event => (_ctx.foo = $event)`, ) expect(ir.block.operation).toMatchObject([ @@ -267,14 +267,12 @@ describe('compiler: vModel transform', () => { type: IRNodeTypes.CREATE_COMPONENT_NODE, tag: 'Comp', props: [ - [ - { - key: { content: 'arg', isStatic: false }, - values: [{ content: 'foo', isStatic: false }], - model: true, - modelModifiers: [], - }, - ], + { + key: { content: 'arg', isStatic: false }, + values: [{ content: 'foo', isStatic: false }], + model: true, + modelModifiers: [], + }, ], }, ]) @@ -349,20 +347,18 @@ describe('compiler: vModel transform', () => { type: IRNodeTypes.CREATE_COMPONENT_NODE, tag: 'Comp', props: [ - [ - { - key: { content: 'foo', isStatic: false }, - values: [{ content: 'foo', isStatic: false }], - model: true, - modelModifiers: ['trim'], - }, - { - key: { content: 'bar', isStatic: false }, - values: [{ content: 'bar', isStatic: false }], - model: true, - modelModifiers: ['number'], - }, - ], + { + key: { content: 'foo', isStatic: false }, + values: [{ content: 'foo', isStatic: false }], + model: true, + modelModifiers: ['trim'], + }, + { + key: { content: 'bar', isStatic: false }, + values: [{ content: 'bar', isStatic: false }], + model: true, + modelModifiers: ['number'], + }, ], }, ]) diff --git a/packages/compiler-vapor/src/generators/component.ts b/packages/compiler-vapor/src/generators/component.ts index 5f3d060b8..63e7137da 100644 --- a/packages/compiler-vapor/src/generators/component.ts +++ b/packages/compiler-vapor/src/generators/component.ts @@ -1,6 +1,6 @@ import { camelize, extend, isArray } from '@vue/shared' import type { CodegenContext } from '../generate' -import type { CreateComponentIRNode, IRProp } from '../ir' +import type { CreateComponentIRNode, IRProp, IRProps } from '../ir' import { type CodeFragment, NEWLINE, @@ -21,11 +21,11 @@ export function genCreateComponent( oper: CreateComponentIRNode, context: CodegenContext, ): CodeFragment[] { - const { helper, vaporHelper } = context + const { vaporHelper } = context const tag = genTag() const isRoot = oper.root - const rawProps = genRawProps() + const rawProps = genRawProps(oper.props, context) return [ NEWLINE, @@ -49,63 +49,83 @@ export function genCreateComponent( ) } } +} - function genRawProps() { - const props = oper.props - .map(props => { - if (isArray(props)) { - if (!props.length) return - return genStaticProps(props) - } else { - let expr = genExpression(props.value, context) - if (props.handler) expr = genCall(helper('toHandlers'), expr) - return ['() => (', ...expr, ')'] +export function genRawProps(props: IRProps[], context: CodegenContext) { + const frag = props + .map(props => { + if (isArray(props)) { + if (!props.length) return + return genStaticProps(props, context) + } else { + let expr: CodeFragment[] + if ('key' in props) + expr = genMulti( + SEGMENTS_OBJECT_NEWLINE, + genProp(props, context, false), + ) + else { + expr = genExpression(props.value, context) + if (props.handler) expr = genCall(context.helper('toHandlers'), expr) } - }) - .filter(Boolean) - if (props.length) { - return genMulti(SEGMENTS_ARRAY, ...props) - } + return ['() => (', ...expr, ')'] + } + }) + .filter( + Boolean as any as (v: CodeFragment[] | undefined) => v is CodeFragment[], + ) + if (frag.length) { + return genMulti(SEGMENTS_ARRAY, ...frag) } +} - function genStaticProps(props: IRProp[]) { - return genMulti( - SEGMENTS_OBJECT_NEWLINE, - ...props.map(prop => { - return [ - ...genPropKey(prop, context), - ': ', - ...(prop.handler - ? genEventHandler(context, prop.values[0]) - : ['() => (', ...genExpression(prop.values[0], context), ')']), - ...(prop.model - ? [...genModelEvent(prop), ...genModelModifiers(prop)] - : []), - ] - }), - ) +function genStaticProps( + props: IRProp[], + context: CodegenContext, +): CodeFragment[] { + return genMulti( + SEGMENTS_OBJECT_NEWLINE, + ...props.map(prop => genProp(prop, context, true)), + ) +} + +function genProp(prop: IRProp, context: CodegenContext, isStaticArg: boolean) { + return [ + ...genPropKey(prop, context), + ': ', + ...(prop.handler + ? genEventHandler(context, prop.values[0]) + : isStaticArg + ? ['() => (', ...genExpression(prop.values[0], context), ')'] + : genExpression(prop.values[0], context)), + ...(prop.model + ? [...genModelEvent(prop, context), ...genModelModifiers(prop, context)] + : []), + ] +} - function genModelEvent(prop: IRProp): CodeFragment[] { - const name = prop.key.isStatic - ? [JSON.stringify(`onUpdate:${camelize(prop.key.content)}`)] - : ['["onUpdate:" + ', ...genExpression(prop.key, context), ']'] - const handler = genModelHandler(prop.values[0], context) +function genModelEvent(prop: IRProp, context: CodegenContext): CodeFragment[] { + const name = prop.key.isStatic + ? [JSON.stringify(`onUpdate:${camelize(prop.key.content)}`)] + : ['["onUpdate:" + ', ...genExpression(prop.key, context), ']'] + const handler = genModelHandler(prop.values[0], context) - return [',', NEWLINE, ...name, ': ', ...handler] - } + return [',', NEWLINE, ...name, ': ', ...handler] +} - function genModelModifiers(prop: IRProp): CodeFragment[] { - const { key, modelModifiers } = prop - if (!modelModifiers || !modelModifiers.length) return [] +function genModelModifiers( + prop: IRProp, + context: CodegenContext, +): CodeFragment[] { + const { key, modelModifiers } = prop + if (!modelModifiers || !modelModifiers.length) return [] - const modifiersKey = key.isStatic - ? key.content === 'modelValue' - ? [`modelModifiers`] - : [`${key.content}Modifiers`] - : ['[', ...genExpression(key, context), ' + "Modifiers"]'] + const modifiersKey = key.isStatic + ? key.content === 'modelValue' + ? [`modelModifiers`] + : [`${key.content}Modifiers`] + : ['[', ...genExpression(key, context), ' + "Modifiers"]'] - const modifiersVal = genDirectiveModifiers(modelModifiers) - return [',', NEWLINE, ...modifiersKey, `: () => ({ ${modifiersVal} })`] - } - } + const modifiersVal = genDirectiveModifiers(modelModifiers) + return [',', NEWLINE, ...modifiersKey, `: () => ({ ${modifiersVal} })`] } diff --git a/packages/compiler-vapor/src/generators/prop.ts b/packages/compiler-vapor/src/generators/prop.ts index 1f31e4ceb..c91510f23 100644 --- a/packages/compiler-vapor/src/generators/prop.ts +++ b/packages/compiler-vapor/src/generators/prop.ts @@ -73,7 +73,9 @@ export function genDynamicProps( props => Array.isArray(props) ? genLiteralObjectProps(props, context) // static and dynamic arg props - : genExpression(props.value, context), // v-bind="" + : 'key' in props + ? genLiteralObjectProps([props], context) // dynamic arg props + : genExpression(props.value, context), // v-bind="" ), ), ] diff --git a/packages/compiler-vapor/src/ir.ts b/packages/compiler-vapor/src/ir.ts index e5ba223d7..457b646b0 100644 --- a/packages/compiler-vapor/src/ir.ts +++ b/packages/compiler-vapor/src/ir.ts @@ -83,12 +83,11 @@ export interface ForIRNode extends BaseIRNode { export interface IRProp extends Omit { values: SimpleExpressionNode[] } -export type IRProps = - | IRProp[] - | { - value: SimpleExpressionNode - handler?: boolean - } +export interface IRDynamicProps { + value: SimpleExpressionNode + handler?: boolean +} +export type IRProps = IRProp[] | IRProp | IRDynamicProps export interface SetPropIRNode extends BaseIRNode { type: IRNodeTypes.SET_PROP diff --git a/packages/compiler-vapor/src/transforms/transformElement.ts b/packages/compiler-vapor/src/transforms/transformElement.ts index e0ce97b35..a741b6b14 100644 --- a/packages/compiler-vapor/src/transforms/transformElement.ts +++ b/packages/compiler-vapor/src/transforms/transformElement.ts @@ -241,8 +241,15 @@ function buildProps( const result = transformProp(prop, node, context) if (result) { - results.push(result) dynamicExpr.push(result.key, result.value) + if (isComponent && !result.key.isStatic) { + // v-bind:[name]="value" or v-on:[name]="value" + pushMergeArg() + dynamicArgs.push(normalizeIRProp(result)) + } else { + // other static props + results.push(result) + } } } From 94ab8ce60138f71a48ed5b299ec96cb89dae1839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E6=99=BA=E5=AD=90=20Kevin=20Deng?= Date: Wed, 1 May 2024 02:20:32 +0900 Subject: [PATCH 2/4] refactor --- packages/compiler-vapor/src/ir.ts | 18 +++++++++-- .../src/transforms/transformElement.ts | 32 ++++++++++++++----- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/packages/compiler-vapor/src/ir.ts b/packages/compiler-vapor/src/ir.ts index 457b646b0..0232a49c4 100644 --- a/packages/compiler-vapor/src/ir.ts +++ b/packages/compiler-vapor/src/ir.ts @@ -83,11 +83,25 @@ export interface ForIRNode extends BaseIRNode { export interface IRProp extends Omit { values: SimpleExpressionNode[] } -export interface IRDynamicProps { + +export enum DynamicPropsKind { + EXPRESSION, // v-bind="value" + ATTRIBUTE, // v-bind:[foo]="value" +} + +export type IRPropsStatic = IRProp[] +export interface IRPropsDynamicExpression { + kind: DynamicPropsKind.EXPRESSION value: SimpleExpressionNode handler?: boolean } -export type IRProps = IRProp[] | IRProp | IRDynamicProps +export interface IRPropsDynamicAttribute extends IRProp { + kind: DynamicPropsKind.ATTRIBUTE +} +export type IRProps = + | IRPropsStatic + | IRPropsDynamicAttribute + | IRPropsDynamicExpression export interface SetPropIRNode extends BaseIRNode { type: IRNodeTypes.SET_PROP diff --git a/packages/compiler-vapor/src/transforms/transformElement.ts b/packages/compiler-vapor/src/transforms/transformElement.ts index a741b6b14..e700146dd 100644 --- a/packages/compiler-vapor/src/transforms/transformElement.ts +++ b/packages/compiler-vapor/src/transforms/transformElement.ts @@ -24,9 +24,11 @@ import type { } from '../transform' import { DynamicFlag, + DynamicPropsKind, IRNodeTypes, type IRProp, type IRProps, + type IRPropsDynamicAttribute, type VaporDirectiveNode, } from '../ir' import { EMPTY_EXPRESSION } from './utils' @@ -205,7 +207,10 @@ function buildProps( if (prop.exp) { dynamicExpr.push(prop.exp) pushMergeArg() - dynamicArgs.push({ value: prop.exp }) + dynamicArgs.push({ + kind: DynamicPropsKind.EXPRESSION, + value: prop.exp, + }) } else { context.options.onError( createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, prop.loc), @@ -218,7 +223,11 @@ function buildProps( if (isComponent) { dynamicExpr.push(prop.exp) pushMergeArg() - dynamicArgs.push({ value: prop.exp, handler: true }) + dynamicArgs.push({ + kind: DynamicPropsKind.EXPRESSION, + value: prop.exp, + handler: true, + }) } else { context.registerEffect( [prop.exp], @@ -245,7 +254,11 @@ function buildProps( if (isComponent && !result.key.isStatic) { // v-bind:[name]="value" or v-on:[name]="value" pushMergeArg() - dynamicArgs.push(normalizeIRProp(result)) + dynamicArgs.push( + extend(resolveDirectiveResult(result), { + kind: DynamicPropsKind.ATTRIBUTE, + }) as IRPropsDynamicAttribute, + ) } else { // other static props results.push(result) @@ -304,7 +317,7 @@ function dedupeProperties(results: DirectiveTransformResult[]): IRProp[] { const deduped: IRProp[] = [] for (const result of results) { - const prop = normalizeIRProp(result) + const prop = resolveDirectiveResult(result) // dynamic keys are always allowed if (!prop.key.isStatic) { deduped.push(prop) @@ -314,7 +327,7 @@ function dedupeProperties(results: DirectiveTransformResult[]): IRProp[] { const existing = knownProps.get(name) if (existing) { if (name === 'style' || name === 'class') { - mergeAsArray(existing, prop) + mergePropValues(existing, prop) } // unexpected duplicate, should have emitted error during parse } else { @@ -325,11 +338,14 @@ function dedupeProperties(results: DirectiveTransformResult[]): IRProp[] { return deduped } -function normalizeIRProp(prop: DirectiveTransformResult): IRProp { - return extend({}, prop, { value: undefined, values: [prop.value] }) +function resolveDirectiveResult(prop: DirectiveTransformResult): IRProp { + return extend({}, prop, { + value: undefined, + values: [prop.value], + }) } -function mergeAsArray(existing: IRProp, incoming: IRProp) { +function mergePropValues(existing: IRProp, incoming: IRProp) { const newValues = incoming.values existing.values.push(...newValues) } From 4cfd4ce2db98ee90b0b210f1bcf54e027af1381d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E6=99=BA=E5=AD=90=20Kevin=20Deng?= Date: Wed, 1 May 2024 02:43:25 +0900 Subject: [PATCH 3/4] refactor: format --- .../transformElement.spec.ts.snap | 66 ++++++++++--------- .../__snapshots__/vModel.spec.ts.snap | 63 +++++++++--------- .../transforms/transformElement.spec.ts | 38 +++++++---- .../src/generators/component.ts | 28 ++++---- .../compiler-vapor/src/generators/prop.ts | 13 ++-- .../compiler-vapor/src/generators/utils.ts | 5 ++ 6 files changed, 121 insertions(+), 92 deletions(-) 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 cdd5790b5..ed6a96272 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap @@ -100,9 +100,9 @@ exports[`compiler: element transform > component > should wrap as function if v- export function render(_ctx) { const _component_Foo = _resolveComponent("Foo") - const n0 = _createComponent(_component_Foo, [{ - onBar: () => $event => (_ctx.handleBar($event)) - }], true) + const n0 = _createComponent(_component_Foo, [ + { onBar: () => $event => (_ctx.handleBar($event)) } + ], true) return n0 }" `; @@ -112,10 +112,12 @@ exports[`compiler: element transform > component > static props 1`] = ` export function render(_ctx) { const _component_Foo = _resolveComponent("Foo") - const n0 = _createComponent(_component_Foo, [{ - id: () => ("foo"), - class: () => ("bar") - }], true) + const n0 = _createComponent(_component_Foo, [ + { + id: () => ("foo"), + class: () => ("bar") + } + ], true) return n0 }" `; @@ -125,7 +127,9 @@ exports[`compiler: element transform > component > v-bind="obj" 1`] = ` export function render(_ctx) { const _component_Foo = _resolveComponent("Foo") - const n0 = _createComponent(_component_Foo, [() => (_ctx.obj)], true) + const n0 = _createComponent(_component_Foo, [ + () => (_ctx.obj) + ], true) return n0 }" `; @@ -135,9 +139,10 @@ exports[`compiler: element transform > component > v-bind="obj" after static pro export function render(_ctx) { const _component_Foo = _resolveComponent("Foo") - const n0 = _createComponent(_component_Foo, [{ - id: () => ("foo") - }, () => (_ctx.obj)], true) + const n0 = _createComponent(_component_Foo, [ + { id: () => ("foo") }, + () => (_ctx.obj) + ], true) return n0 }" `; @@ -147,9 +152,10 @@ exports[`compiler: element transform > component > v-bind="obj" before static pr export function render(_ctx) { const _component_Foo = _resolveComponent("Foo") - const n0 = _createComponent(_component_Foo, [() => (_ctx.obj), { - id: () => ("foo") - }], true) + const n0 = _createComponent(_component_Foo, [ + () => (_ctx.obj), + { id: () => ("foo") } + ], true) return n0 }" `; @@ -159,11 +165,11 @@ exports[`compiler: element transform > component > v-bind="obj" between static p export function render(_ctx) { const _component_Foo = _resolveComponent("Foo") - const n0 = _createComponent(_component_Foo, [{ - id: () => ("foo") - }, () => (_ctx.obj), { - class: () => ("bar") - }], true) + const n0 = _createComponent(_component_Foo, [ + { id: () => ("foo") }, + () => (_ctx.obj), + { class: () => ("bar") } + ], true) return n0 }" `; @@ -174,7 +180,9 @@ import { resolveComponent as _resolveComponent, createComponent as _createCompon export function render(_ctx) { const _component_Foo = _resolveComponent("Foo") - const n0 = _createComponent(_component_Foo, [() => (_toHandlers(_ctx.obj))], true) + const n0 = _createComponent(_component_Foo, [ + () => (_toHandlers(_ctx.obj)) + ], true) return n0 }" `; @@ -185,11 +193,10 @@ import { resolveComponent as _resolveComponent, createComponent as _createCompon export function render(_ctx) { const _component_Foo = _resolveComponent("Foo") - const n0 = _createComponent(_component_Foo, [() => ({ - [_toHandlerKey(_ctx.foo-_ctx.bar)]: () => _ctx.bar - }), () => ({ - [_toHandlerKey(_ctx.baz)]: () => _ctx.qux - })], true) + const n0 = _createComponent(_component_Foo, [ + () => ({ [_toHandlerKey(_ctx.foo-_ctx.bar)]: () => _ctx.bar }), + () => ({ [_toHandlerKey(_ctx.baz)]: () => _ctx.qux }) + ], true) return n0 }" `; @@ -199,11 +206,10 @@ exports[`compiler: element transform > component with dynamic prop arguments 1`] export function render(_ctx) { const _component_Foo = _resolveComponent("Foo") - const n0 = _createComponent(_component_Foo, [() => ({ - [_ctx.foo-_ctx.bar]: _ctx.bar - }), () => ({ - [_ctx.baz]: _ctx.qux - })], true) + const n0 = _createComponent(_component_Foo, [ + () => ({ [_ctx.foo-_ctx.bar]: _ctx.bar }), + () => ({ [_ctx.baz]: _ctx.qux }) + ], 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 911ed1486..5f44f54cf 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap @@ -5,11 +5,11 @@ exports[`compiler: vModel transform > component > v-model for component should g export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n0 = _createComponent(_component_Comp, [{ - modelValue: () => (_ctx.foo), + const n0 = _createComponent(_component_Comp, [ + { modelValue: () => (_ctx.foo), "onUpdate:modelValue": () => $event => (_ctx.foo = $event), - modelModifiers: () => ({ trim: true, "bar-baz": true }) - }], true) + modelModifiers: () => ({ trim: true, "bar-baz": true }) } + ], true) return n0 }" `; @@ -19,10 +19,10 @@ exports[`compiler: vModel transform > component > v-model for component should w export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n0 = _createComponent(_component_Comp, [{ - modelValue: () => (_ctx.foo), - "onUpdate:modelValue": () => $event => (_ctx.foo = $event) - }], true) + const n0 = _createComponent(_component_Comp, [ + { modelValue: () => (_ctx.foo), + "onUpdate:modelValue": () => $event => (_ctx.foo = $event) } + ], true) return n0 }" `; @@ -32,14 +32,16 @@ exports[`compiler: vModel transform > component > v-model with arguments for com export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n0 = _createComponent(_component_Comp, [{ - foo: () => (_ctx.foo), - "onUpdate:foo": () => $event => (_ctx.foo = $event), - fooModifiers: () => ({ trim: true }), - bar: () => (_ctx.bar), - "onUpdate:bar": () => $event => (_ctx.bar = $event), - barModifiers: () => ({ number: true }) - }], true) + const n0 = _createComponent(_component_Comp, [ + { + foo: () => (_ctx.foo), + "onUpdate:foo": () => $event => (_ctx.foo = $event), + fooModifiers: () => ({ trim: true }), + bar: () => (_ctx.bar), + "onUpdate:bar": () => $event => (_ctx.bar = $event), + barModifiers: () => ({ number: true }) + } + ], true) return n0 }" `; @@ -49,10 +51,10 @@ exports[`compiler: vModel transform > component > v-model with arguments for com export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n0 = _createComponent(_component_Comp, [{ - bar: () => (_ctx.foo), - "onUpdate:bar": () => $event => (_ctx.foo = $event) - }], true) + const n0 = _createComponent(_component_Comp, [ + { bar: () => (_ctx.foo), + "onUpdate:bar": () => $event => (_ctx.foo = $event) } + ], true) return n0 }" `; @@ -62,15 +64,14 @@ exports[`compiler: vModel transform > component > v-model with dynamic arguments export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n0 = _createComponent(_component_Comp, [() => ({ - [_ctx.foo]: _ctx.foo, + const n0 = _createComponent(_component_Comp, [ + () => ({ [_ctx.foo]: _ctx.foo, ["onUpdate:" + _ctx.foo]: () => $event => (_ctx.foo = $event), - [_ctx.foo + "Modifiers"]: () => ({ trim: true }) - }), () => ({ - [_ctx.bar]: _ctx.bar, + [_ctx.foo + "Modifiers"]: () => ({ trim: true }) }), + () => ({ [_ctx.bar]: _ctx.bar, ["onUpdate:" + _ctx.bar]: () => $event => (_ctx.bar = $event), - [_ctx.bar + "Modifiers"]: () => ({ number: true }) - })], true) + [_ctx.bar + "Modifiers"]: () => ({ number: true }) }) + ], true) return n0 }" `; @@ -80,10 +81,10 @@ exports[`compiler: vModel transform > component > v-model with dynamic arguments export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n0 = _createComponent(_component_Comp, [() => ({ - [_ctx.arg]: _ctx.foo, - ["onUpdate:" + _ctx.arg]: () => $event => (_ctx.foo = $event) - })], true) + const n0 = _createComponent(_component_Comp, [ + () => ({ [_ctx.arg]: _ctx.foo, + ["onUpdate:" + _ctx.arg]: () => $event => (_ctx.foo = $event) }) + ], true) return n0 }" `; diff --git a/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts b/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts index fcadd9447..2faad78dd 100644 --- a/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts @@ -198,10 +198,12 @@ describe('compiler: element transform', () => { ) expect(code).toMatchSnapshot() - expect(code).contains('_createComponent(_component_Foo, [{') - expect(code).contains(' id: () => ("foo")') - expect(code).contains(' class: () => ("bar")') - expect(code).contains('}], true)') + expect(code).contains(`[ + { + id: () => ("foo"), + class: () => ("bar") + } + ]`) expect(ir.block.operation).toMatchObject([ { @@ -248,7 +250,9 @@ describe('compiler: element transform', () => { test('v-bind="obj"', () => { const { code, ir } = compileWithElementTransform(``) expect(code).toMatchSnapshot() - expect(code).contains('[() => (_ctx.obj)]') + expect(code).contains(`[ + () => (_ctx.obj) + ]`) expect(ir.block.operation).toMatchObject([ { type: IRNodeTypes.CREATE_COMPONENT_NODE, @@ -263,8 +267,10 @@ describe('compiler: element transform', () => { ``, ) expect(code).toMatchSnapshot() - expect(code).contains('id: () => ("foo")') - expect(code).contains('}, () => (_ctx.obj)]') + expect(code).contains(`[ + { id: () => ("foo") }, + () => (_ctx.obj) + ]`) expect(ir.block.operation).toMatchObject([ { type: IRNodeTypes.CREATE_COMPONENT_NODE, @@ -282,8 +288,10 @@ describe('compiler: element transform', () => { ``, ) expect(code).toMatchSnapshot() - expect(code).contains('[() => (_ctx.obj), {') - expect(code).contains('id: () => ("foo")') + expect(code).contains(`[ + () => (_ctx.obj), + { id: () => ("foo") } + ]`) expect(ir.block.operation).toMatchObject([ { type: IRNodeTypes.CREATE_COMPONENT_NODE, @@ -301,9 +309,11 @@ describe('compiler: element transform', () => { ``, ) expect(code).toMatchSnapshot() - expect(code).contains('id: () => ("foo")') - expect(code).contains('}, () => (_ctx.obj), {') - expect(code).contains('class: () => ("bar")') + expect(code).contains(`[ + { id: () => ("foo") }, + () => (_ctx.obj), + { class: () => ("bar") } + ]`) expect(ir.block.operation).toMatchObject([ { type: IRNodeTypes.CREATE_COMPONENT_NODE, @@ -356,7 +366,9 @@ describe('compiler: element transform', () => { test('v-on="obj"', () => { const { code, ir } = compileWithElementTransform(``) expect(code).toMatchSnapshot() - expect(code).contains('[() => (_toHandlers(_ctx.obj))]') + expect(code).contains(`[ + () => (_toHandlers(_ctx.obj)) + ]`) expect(ir.block.operation).toMatchObject([ { type: IRNodeTypes.CREATE_COMPONENT_NODE, diff --git a/packages/compiler-vapor/src/generators/component.ts b/packages/compiler-vapor/src/generators/component.ts index 63e7137da..ef2ba8b7a 100644 --- a/packages/compiler-vapor/src/generators/component.ts +++ b/packages/compiler-vapor/src/generators/component.ts @@ -1,10 +1,17 @@ import { camelize, extend, isArray } from '@vue/shared' import type { CodegenContext } from '../generate' -import type { CreateComponentIRNode, IRProp, IRProps } from '../ir' +import { + type CreateComponentIRNode, + DynamicPropsKind, + type IRProp, + type IRProps, + type IRPropsStatic, +} from '../ir' import { type CodeFragment, NEWLINE, - SEGMENTS_ARRAY, + SEGMENTS_ARRAY_NEWLINE, + SEGMENTS_OBJECT, SEGMENTS_OBJECT_NEWLINE, genCall, genMulti, @@ -59,11 +66,8 @@ export function genRawProps(props: IRProps[], context: CodegenContext) { return genStaticProps(props, context) } else { let expr: CodeFragment[] - if ('key' in props) - expr = genMulti( - SEGMENTS_OBJECT_NEWLINE, - genProp(props, context, false), - ) + if (props.kind === DynamicPropsKind.ATTRIBUTE) + expr = genMulti(SEGMENTS_OBJECT, genProp(props, context)) else { expr = genExpression(props.value, context) if (props.handler) expr = genCall(context.helper('toHandlers'), expr) @@ -75,27 +79,27 @@ export function genRawProps(props: IRProps[], context: CodegenContext) { Boolean as any as (v: CodeFragment[] | undefined) => v is CodeFragment[], ) if (frag.length) { - return genMulti(SEGMENTS_ARRAY, ...frag) + return genMulti(SEGMENTS_ARRAY_NEWLINE, ...frag) } } function genStaticProps( - props: IRProp[], + props: IRPropsStatic, context: CodegenContext, ): CodeFragment[] { return genMulti( - SEGMENTS_OBJECT_NEWLINE, + props.length > 1 ? SEGMENTS_OBJECT_NEWLINE : SEGMENTS_OBJECT, ...props.map(prop => genProp(prop, context, true)), ) } -function genProp(prop: IRProp, context: CodegenContext, isStaticArg: boolean) { +function genProp(prop: IRProp, context: CodegenContext, isStatic?: boolean) { return [ ...genPropKey(prop, context), ': ', ...(prop.handler ? genEventHandler(context, prop.values[0]) - : isStaticArg + : isStatic ? ['() => (', ...genExpression(prop.values[0], context), ')'] : genExpression(prop.values[0], context)), ...(prop.model diff --git a/packages/compiler-vapor/src/generators/prop.ts b/packages/compiler-vapor/src/generators/prop.ts index c91510f23..e172ce5db 100644 --- a/packages/compiler-vapor/src/generators/prop.ts +++ b/packages/compiler-vapor/src/generators/prop.ts @@ -4,11 +4,12 @@ import { isSimpleIdentifier, } from '@vue/compiler-core' import type { CodegenContext } from '../generate' -import type { - IRProp, - SetDynamicPropsIRNode, - SetPropIRNode, - VaporHelper, +import { + DynamicPropsKind, + type IRProp, + type SetDynamicPropsIRNode, + type SetPropIRNode, + type VaporHelper, } from '../ir' import { genExpression } from './expression' import { @@ -73,7 +74,7 @@ export function genDynamicProps( props => Array.isArray(props) ? genLiteralObjectProps(props, context) // static and dynamic arg props - : 'key' in props + : props.kind === DynamicPropsKind.ATTRIBUTE ? genLiteralObjectProps([props], context) // dynamic arg props : genExpression(props.value, context), // v-bind="" ), diff --git a/packages/compiler-vapor/src/generators/utils.ts b/packages/compiler-vapor/src/generators/utils.ts index c2e71630a..9a31bc6cb 100644 --- a/packages/compiler-vapor/src/generators/utils.ts +++ b/packages/compiler-vapor/src/generators/utils.ts @@ -57,6 +57,11 @@ export function genMulti( } } export const SEGMENTS_ARRAY: Segments = ['[', ']', ', '] +export const SEGMENTS_ARRAY_NEWLINE: Segments = [ + ['[', INDENT_START, NEWLINE], + [INDENT_END, NEWLINE, ']'], + [', ', NEWLINE], +] export const SEGMENTS_OBJECT: Segments = ['{ ', ' }', ', '] export const SEGMENTS_OBJECT_NEWLINE: Segments = [ ['{', INDENT_START, NEWLINE], From 273336c61fa852e2c133466680f4c9ef3d7fdd66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E6=99=BA=E5=AD=90=20Kevin=20Deng?= Date: Wed, 1 May 2024 03:07:12 +0900 Subject: [PATCH 4/4] test: check IRDynamicPropsKind --- .../transforms/transformElement.spec.ts | 47 ++++++++++++++++--- .../src/generators/component.ts | 4 +- .../compiler-vapor/src/generators/prop.ts | 4 +- packages/compiler-vapor/src/ir.ts | 6 +-- .../src/transforms/transformElement.ts | 8 ++-- 5 files changed, 51 insertions(+), 18 deletions(-) diff --git a/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts b/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts index 2faad78dd..4bf38ba3e 100644 --- a/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts @@ -1,5 +1,6 @@ import { makeCompile } from './_utils' import { + IRDynamicPropsKind, IRNodeTypes, transformChildren, transformElement, @@ -257,7 +258,12 @@ describe('compiler: element transform', () => { { type: IRNodeTypes.CREATE_COMPONENT_NODE, tag: 'Foo', - props: [{ value: { content: 'obj', isStatic: false } }], + props: [ + { + kind: IRDynamicPropsKind.EXPRESSION, + value: { content: 'obj', isStatic: false }, + }, + ], }, ]) }) @@ -277,7 +283,10 @@ describe('compiler: element transform', () => { tag: 'Foo', props: [ [{ key: { content: 'id' }, values: [{ content: 'foo' }] }], - { value: { content: 'obj' } }, + { + kind: IRDynamicPropsKind.EXPRESSION, + value: { content: 'obj' }, + }, ], }, ]) @@ -297,7 +306,10 @@ describe('compiler: element transform', () => { type: IRNodeTypes.CREATE_COMPONENT_NODE, tag: 'Foo', props: [ - { value: { content: 'obj' } }, + { + kind: IRDynamicPropsKind.EXPRESSION, + value: { content: 'obj' }, + }, [{ key: { content: 'id' }, values: [{ content: 'foo' }] }], ], }, @@ -320,7 +332,10 @@ describe('compiler: element transform', () => { tag: 'Foo', props: [ [{ key: { content: 'id' }, values: [{ content: 'foo' }] }], - { value: { content: 'obj' } }, + { + kind: IRDynamicPropsKind.EXPRESSION, + value: { content: 'obj' }, + }, [{ key: { content: 'class' }, values: [{ content: 'bar' }] }], ], }, @@ -373,7 +388,13 @@ describe('compiler: element transform', () => { { type: IRNodeTypes.CREATE_COMPONENT_NODE, tag: 'Foo', - props: [{ value: { content: 'obj' }, handler: true }], + props: [ + { + kind: IRDynamicPropsKind.EXPRESSION, + value: { content: 'obj' }, + handler: true, + }, + ], }, ]) }) @@ -444,6 +465,7 @@ describe('compiler: element transform', () => { element: 0, props: [ { + kind: IRDynamicPropsKind.EXPRESSION, value: { type: NodeTypes.SIMPLE_EXPRESSION, content: 'obj', @@ -479,6 +501,7 @@ describe('compiler: element transform', () => { props: [ [{ key: { content: 'id' }, values: [{ content: 'foo' }] }], { + kind: IRDynamicPropsKind.EXPRESSION, value: { type: NodeTypes.SIMPLE_EXPRESSION, content: 'obj', @@ -506,7 +529,10 @@ describe('compiler: element transform', () => { type: IRNodeTypes.SET_DYNAMIC_PROPS, element: 0, props: [ - { value: { content: 'obj' } }, + { + kind: IRDynamicPropsKind.EXPRESSION, + value: { content: 'obj' }, + }, [{ key: { content: 'id' }, values: [{ content: 'foo' }] }], ], }, @@ -530,7 +556,10 @@ describe('compiler: element transform', () => { element: 0, props: [ [{ key: { content: 'id' }, values: [{ content: 'foo' }] }], - { value: { content: 'obj' } }, + { + kind: IRDynamicPropsKind.EXPRESSION, + value: { content: 'obj' }, + }, [{ key: { content: 'class' }, values: [{ content: 'bar' }] }], ], }, @@ -714,10 +743,12 @@ describe('compiler: element transform', () => { tag: 'Foo', props: [ { + kind: IRDynamicPropsKind.ATTRIBUTE, key: { content: 'foo-bar' }, values: [{ content: 'bar' }], }, { + kind: IRDynamicPropsKind.ATTRIBUTE, key: { content: 'baz' }, values: [{ content: 'qux' }], }, @@ -737,11 +768,13 @@ describe('compiler: element transform', () => { tag: 'Foo', props: [ { + kind: IRDynamicPropsKind.ATTRIBUTE, key: { content: 'foo-bar' }, values: [{ content: 'bar' }], handler: true, }, { + kind: IRDynamicPropsKind.ATTRIBUTE, key: { content: 'baz' }, values: [{ content: 'qux' }], handler: true, diff --git a/packages/compiler-vapor/src/generators/component.ts b/packages/compiler-vapor/src/generators/component.ts index ef2ba8b7a..fba45ab1e 100644 --- a/packages/compiler-vapor/src/generators/component.ts +++ b/packages/compiler-vapor/src/generators/component.ts @@ -2,7 +2,7 @@ import { camelize, extend, isArray } from '@vue/shared' import type { CodegenContext } from '../generate' import { type CreateComponentIRNode, - DynamicPropsKind, + IRDynamicPropsKind, type IRProp, type IRProps, type IRPropsStatic, @@ -66,7 +66,7 @@ export function genRawProps(props: IRProps[], context: CodegenContext) { return genStaticProps(props, context) } else { let expr: CodeFragment[] - if (props.kind === DynamicPropsKind.ATTRIBUTE) + if (props.kind === IRDynamicPropsKind.ATTRIBUTE) expr = genMulti(SEGMENTS_OBJECT, genProp(props, context)) else { expr = genExpression(props.value, context) diff --git a/packages/compiler-vapor/src/generators/prop.ts b/packages/compiler-vapor/src/generators/prop.ts index e172ce5db..861397c9a 100644 --- a/packages/compiler-vapor/src/generators/prop.ts +++ b/packages/compiler-vapor/src/generators/prop.ts @@ -5,7 +5,7 @@ import { } from '@vue/compiler-core' import type { CodegenContext } from '../generate' import { - DynamicPropsKind, + IRDynamicPropsKind, type IRProp, type SetDynamicPropsIRNode, type SetPropIRNode, @@ -74,7 +74,7 @@ export function genDynamicProps( props => Array.isArray(props) ? genLiteralObjectProps(props, context) // static and dynamic arg props - : props.kind === DynamicPropsKind.ATTRIBUTE + : props.kind === IRDynamicPropsKind.ATTRIBUTE ? genLiteralObjectProps([props], context) // dynamic arg props : genExpression(props.value, context), // v-bind="" ), diff --git a/packages/compiler-vapor/src/ir.ts b/packages/compiler-vapor/src/ir.ts index 0232a49c4..408e37557 100644 --- a/packages/compiler-vapor/src/ir.ts +++ b/packages/compiler-vapor/src/ir.ts @@ -84,19 +84,19 @@ export interface IRProp extends Omit { values: SimpleExpressionNode[] } -export enum DynamicPropsKind { +export enum IRDynamicPropsKind { EXPRESSION, // v-bind="value" ATTRIBUTE, // v-bind:[foo]="value" } export type IRPropsStatic = IRProp[] export interface IRPropsDynamicExpression { - kind: DynamicPropsKind.EXPRESSION + kind: IRDynamicPropsKind.EXPRESSION value: SimpleExpressionNode handler?: boolean } export interface IRPropsDynamicAttribute extends IRProp { - kind: DynamicPropsKind.ATTRIBUTE + kind: IRDynamicPropsKind.ATTRIBUTE } export type IRProps = | IRPropsStatic diff --git a/packages/compiler-vapor/src/transforms/transformElement.ts b/packages/compiler-vapor/src/transforms/transformElement.ts index e700146dd..b7de58506 100644 --- a/packages/compiler-vapor/src/transforms/transformElement.ts +++ b/packages/compiler-vapor/src/transforms/transformElement.ts @@ -24,7 +24,7 @@ import type { } from '../transform' import { DynamicFlag, - DynamicPropsKind, + IRDynamicPropsKind, IRNodeTypes, type IRProp, type IRProps, @@ -208,7 +208,7 @@ function buildProps( dynamicExpr.push(prop.exp) pushMergeArg() dynamicArgs.push({ - kind: DynamicPropsKind.EXPRESSION, + kind: IRDynamicPropsKind.EXPRESSION, value: prop.exp, }) } else { @@ -224,7 +224,7 @@ function buildProps( dynamicExpr.push(prop.exp) pushMergeArg() dynamicArgs.push({ - kind: DynamicPropsKind.EXPRESSION, + kind: IRDynamicPropsKind.EXPRESSION, value: prop.exp, handler: true, }) @@ -256,7 +256,7 @@ function buildProps( pushMergeArg() dynamicArgs.push( extend(resolveDirectiveResult(result), { - kind: DynamicPropsKind.ATTRIBUTE, + kind: IRDynamicPropsKind.ATTRIBUTE, }) as IRPropsDynamicAttribute, ) } else {