From: Evan You Date: Wed, 4 Dec 2024 12:55:10 +0000 (+0800) Subject: wip(vapor): align compiler with new props runtime behavior X-Git-Tag: v3.6.0-alpha.1~16^2~239 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=23ba438be18ae38776fc0867065fe55780ab0e3f;p=thirdparty%2Fvuejs%2Fcore.git wip(vapor): align compiler with new props runtime behavior --- 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 79b8fffbb1..961a6b4138 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,7 @@ 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)) } - ], null, true) + const n0 = _createComponent(_component_Foo, { onBar: () => $event => (_ctx.handleBar($event)) }, null, true) return n0 }" `; @@ -112,12 +110,10 @@ 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") - } - ], null, true) + const n0 = _createComponent(_component_Foo, { + id: () => ("foo"), + class: () => ("bar") + }, null, true) return n0 }" `; @@ -127,9 +123,9 @@ exports[`compiler: element transform > component > v-bind="obj" 1`] = ` export function render(_ctx) { const _component_Foo = _resolveComponent("Foo") - const n0 = _createComponent(_component_Foo, [ + const n0 = _createComponent(_component_Foo, { $: [ () => (_ctx.obj) - ], null, true) + ] }, null, true) return n0 }" `; @@ -139,10 +135,12 @@ 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) - ], null, true) + const n0 = _createComponent(_component_Foo, { + id: () => ("foo"), + $: [ + () => (_ctx.obj) + ] + }, null, true) return n0 }" `; @@ -152,10 +150,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, [ + const n0 = _createComponent(_component_Foo, { $: [ () => (_ctx.obj), { id: () => ("foo") } - ], null, true) + ] }, null, true) return n0 }" `; @@ -165,11 +163,13 @@ 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") } - ], null, true) + const n0 = _createComponent(_component_Foo, { + id: () => ("foo"), + $: [ + () => (_ctx.obj), + { class: () => ("bar") } + ] + }, null, true) return n0 }" `; @@ -179,9 +179,9 @@ exports[`compiler: element transform > component > v-on="obj" 1`] = ` export function render(_ctx) { const _component_Foo = _resolveComponent("Foo") - const n0 = _createComponent(_component_Foo, [ + const n0 = _createComponent(_component_Foo, { $: [ () => (_toHandlers(_ctx.obj)) - ], null, true) + ] }, null, true) return n0 }" `; @@ -192,10 +192,10 @@ import { resolveComponent as _resolveComponent, createComponent as _createCompon export function render(_ctx) { const _component_Foo = _resolveComponent("Foo") - const n0 = _createComponent(_component_Foo, [ + const n0 = _createComponent(_component_Foo, { $: [ () => ({ [_toHandlerKey(_ctx.foo-_ctx.bar)]: () => _ctx.bar }), () => ({ [_toHandlerKey(_ctx.baz)]: () => _ctx.qux }) - ], null, true) + ] }, null, true) return n0 }" `; @@ -205,10 +205,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, [ + const n0 = _createComponent(_component_Foo, { $: [ () => ({ [_ctx.foo-_ctx.bar]: _ctx.bar }), () => ({ [_ctx.baz]: _ctx.qux }) - ], null, true) + ] }, null, true) return n0 }" `; @@ -245,9 +245,7 @@ exports[`compiler: element transform > dynamic component > normal component with export function render(_ctx) { const _component_custom_input = _resolveComponent("custom-input") - const n0 = _createComponent(_component_custom_input, [ - { is: () => ("foo") } - ], null, true) + const n0 = _createComponent(_component_custom_input, { is: () => ("foo") }, null, true) return n0 }" `; diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformSlotOutlet.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformSlotOutlet.spec.ts.snap index eab69c82bb..2b9772aa0e 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformSlotOutlet.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformSlotOutlet.spec.ts.snap @@ -27,9 +27,7 @@ exports[`compiler: transform outlets > default slot outlet with props & f const t0 = _template("
") export function render(_ctx) { - const n0 = _createSlot("default", [ - { foo: () => (_ctx.bar) } - ], () => { + const n0 = _createSlot("default", { foo: () => (_ctx.bar) }, () => { const n2 = t0() return n2 }) @@ -41,13 +39,11 @@ exports[`compiler: transform outlets > default slot outlet with props 1`] "import { createSlot as _createSlot } from 'vue/vapor'; export function render(_ctx) { - const n0 = _createSlot("default", [ - { - foo: () => ("bar"), - baz: () => (_ctx.qux), - fooBar: () => (_ctx.foo-_ctx.bar) - } - ]) + const n0 = _createSlot("default", { + foo: () => ("bar"), + baz: () => (_ctx.qux), + fooBar: () => (_ctx.foo-_ctx.bar) + }) return n0 }" `; @@ -107,9 +103,7 @@ exports[`compiler: transform outlets > named slot outlet with props & fal const t0 = _template("
") export function render(_ctx) { - const n0 = _createSlot("foo", [ - { foo: () => (_ctx.bar) } - ], () => { + const n0 = _createSlot("foo", { foo: () => (_ctx.bar) }, () => { const n2 = t0() return n2 }) @@ -130,12 +124,10 @@ exports[`compiler: transform outlets > statically named slot outlet with "import { createSlot as _createSlot } from 'vue/vapor'; export function render(_ctx) { - const n0 = _createSlot("foo", [ - { - foo: () => ("bar"), - baz: () => (_ctx.qux) - } - ]) + const n0 = _createSlot("foo", { + foo: () => ("bar"), + baz: () => (_ctx.qux) + }) return n0 }" `; @@ -144,11 +136,13 @@ exports[`compiler: transform outlets > statically named slot outlet with "import { createSlot as _createSlot } from 'vue/vapor'; export function render(_ctx) { - const n0 = _createSlot("foo", [ - { foo: () => ("bar") }, - () => (_ctx.obj), - { baz: () => (_ctx.qux) } - ]) + const n0 = _createSlot("foo", { + foo: () => ("bar"), + $: [ + () => (_ctx.obj), + { baz: () => (_ctx.qux) } + ] + }) return n0 }" `; @@ -157,11 +151,13 @@ exports[`compiler: transform outlets > statically named slot outlet with "import { createSlot as _createSlot, toHandlers as _toHandlers } from 'vue/vapor'; export function render(_ctx) { - const n0 = _createSlot("default", [ - { onClick: () => _ctx.foo }, - () => (_toHandlers(_ctx.bar)), - { baz: () => (_ctx.qux) } - ]) + const n0 = _createSlot("default", { + onClick: () => _ctx.foo, + $: [ + () => (_toHandlers(_ctx.bar)), + { baz: () => (_ctx.qux) } + ] + }) return n0 }" `; diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap index 4630eadfb5..05938f25cb 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap @@ -464,9 +464,7 @@ exports[`compiler v-bind > number value 1`] = ` export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") - const n0 = _createComponent(_component_Comp, [ - { depth: () => (0) } - ], null, true) + const n0 = _createComponent(_component_Comp, { depth: () => (0) }, 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 04ceb3c5ac..4951244841 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,9 @@ 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), - "onUpdate:modelValue": () => $event => (_ctx.foo = $event), - modelModifiers: () => ({ trim: true, "bar-baz": true }) } - ], null, true) + const n0 = _createComponent(_component_Comp, { modelValue: () => (_ctx.foo), + "onUpdate:modelValue": () => $event => (_ctx.foo = $event), + modelModifiers: () => ({ trim: true, "bar-baz": true }) }, null, true) return n0 }" `; @@ -19,10 +17,8 @@ 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) } - ], null, true) + const n0 = _createComponent(_component_Comp, { modelValue: () => (_ctx.foo), + "onUpdate:modelValue": () => $event => (_ctx.foo = $event) }, null, true) return n0 }" `; @@ -32,16 +28,14 @@ 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 }) - } - ], null, 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 }) + }, null, true) return n0 }" `; @@ -51,10 +45,8 @@ 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) } - ], null, true) + const n0 = _createComponent(_component_Comp, { bar: () => (_ctx.foo), + "onUpdate:bar": () => $event => (_ctx.foo = $event) }, null, true) return n0 }" `; @@ -64,14 +56,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, [ + 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, ["onUpdate:" + _ctx.bar]: () => $event => (_ctx.bar = $event), [_ctx.bar + "Modifiers"]: () => ({ number: true }) }) - ], null, true) + ] }, null, true) return n0 }" `; @@ -81,10 +73,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, [ + const n0 = _createComponent(_component_Comp, { $: [ () => ({ [_ctx.arg]: _ctx.foo, ["onUpdate:" + _ctx.arg]: () => $event => (_ctx.foo = $event) }) - ], 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 eacf622a77..91edd536aa 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap @@ -43,9 +43,7 @@ const t0 = _template("
") export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") const n1 = t0() - const n0 = _createComponent(_component_Comp, [ - { id: () => (_ctx.foo) } - ], null, null, true) + const n0 = _createComponent(_component_Comp, { id: () => (_ctx.foo) }, null, null, true) _insert(n0, n1) return n1 }" diff --git a/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts b/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts index 2b5f894645..8b7baee40e 100644 --- a/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts @@ -199,12 +199,10 @@ describe('compiler: element transform', () => { ) expect(code).toMatchSnapshot() - expect(code).contains(`[ - { - id: () => ("foo"), - class: () => ("bar") - } - ]`) + expect(code).contains(`{ + id: () => ("foo"), + class: () => ("bar") + }`) expect(ir.block.operation).toMatchObject([ { @@ -273,10 +271,12 @@ describe('compiler: element transform', () => { ``, ) expect(code).toMatchSnapshot() - expect(code).contains(`[ - { id: () => ("foo") }, - () => (_ctx.obj) - ]`) + expect(code).contains(`{ + id: () => ("foo"), + $: [ + () => (_ctx.obj) + ] + }`) expect(ir.block.operation).toMatchObject([ { type: IRNodeTypes.CREATE_COMPONENT_NODE, @@ -321,11 +321,13 @@ describe('compiler: element transform', () => { ``, ) expect(code).toMatchSnapshot() - expect(code).contains(`[ - { id: () => ("foo") }, - () => (_ctx.obj), - { class: () => ("bar") } - ]`) + expect(code).contains(`{ + id: () => ("foo"), + $: [ + () => (_ctx.obj), + { class: () => ("bar") } + ] + }`) expect(ir.block.operation).toMatchObject([ { type: IRNodeTypes.CREATE_COMPONENT_NODE, diff --git a/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts b/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts index 921145643a..8cbbab9dd4 100644 --- a/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts @@ -208,9 +208,9 @@ describe('compiler: vModel transform', () => { test('v-model for component should work', () => { const { code, ir } = compileWithVModel('') expect(code).toMatchSnapshot() + expect(code).contains(`modelValue: () => (_ctx.foo),`) expect(code).contains( - `modelValue: () => (_ctx.foo), - "onUpdate:modelValue": () => $event => (_ctx.foo = $event)`, + `"onUpdate:modelValue": () => $event => (_ctx.foo = $event)`, ) expect(ir.block.operation).toMatchObject([ { @@ -233,9 +233,9 @@ describe('compiler: vModel transform', () => { test('v-model with arguments for component should work', () => { const { code, ir } = compileWithVModel('') expect(code).toMatchSnapshot() + expect(code).contains(`bar: () => (_ctx.foo),`) expect(code).contains( - `bar: () => (_ctx.foo), - "onUpdate:bar": () => $event => (_ctx.foo = $event)`, + `"onUpdate:bar": () => $event => (_ctx.foo = $event)`, ) expect(ir.block.operation).toMatchObject([ { diff --git a/packages/compiler-vapor/src/generators/component.ts b/packages/compiler-vapor/src/generators/component.ts index d936a63407..00ee4df85e 100644 --- a/packages/compiler-vapor/src/generators/component.ts +++ b/packages/compiler-vapor/src/generators/component.ts @@ -40,19 +40,19 @@ import { genModelHandler } from './modelValue' import { genBlock } from './block' export function genCreateComponent( - oper: CreateComponentIRNode, + operation: CreateComponentIRNode, context: CodegenContext, ): CodeFragment[] { const { vaporHelper } = context const tag = genTag() - const { root, props, slots, once } = oper + const { root, props, slots, once } = operation const rawProps = genRawProps(props, context) const rawSlots = genRawSlots(slots, context) return [ NEWLINE, - `const n${oper.id} = `, + `const n${operation.id} = `, ...genCall( vaporHelper('createComponent'), tag, @@ -61,20 +61,20 @@ export function genCreateComponent( root ? 'true' : false, once && 'true', ), - ...genDirectivesForElement(oper.id, context), + ...genDirectivesForElement(operation.id, context), ] function genTag() { - if (oper.dynamic) { + if (operation.dynamic) { return genCall( vaporHelper('resolveDynamicComponent'), - genExpression(oper.dynamic, context), + genExpression(operation.dynamic, context), ) - } else if (oper.asset) { - return toValidAssetId(oper.tag, 'component') + } else if (operation.asset) { + return toValidAssetId(operation.tag, 'component') } else { return genExpression( - extend(createSimpleExpression(oper.tag, false), { ast: null }), + extend(createSimpleExpression(operation.tag, false), { ast: null }), context, ) } @@ -85,41 +85,65 @@ export function genRawProps( props: IRProps[], context: CodegenContext, ): CodeFragment[] | undefined { - const { vaporHelper } = context - const frag = props - .map(props => { - if (isArray(props)) { - if (!props.length) return - return genStaticProps(props, context) - } else { - let expr: CodeFragment[] - if (props.kind === IRDynamicPropsKind.ATTRIBUTE) - expr = genMulti(DELIMITERS_OBJECT, genProp(props, context)) - else { - expr = genExpression(props.value, context) - if (props.handler) expr = genCall(vaporHelper('toHandlers'), expr) - } - return ['() => (', ...expr, ')'] - } - }) - .filter( - Boolean as any as (v: CodeFragment[] | undefined) => v is CodeFragment[], + const staticProps = props[0] + if (isArray(staticProps)) { + if (!staticProps.length && props.length === 1) { + return + } + return genStaticProps( + staticProps, + context, + genDynamicProps(props.slice(1), context), ) - if (frag.length) { - return genMulti(DELIMITERS_ARRAY_NEWLINE, ...frag) + } else if (props.length) { + // all dynamic + return genStaticProps([], context, genDynamicProps(props, context)) } } function genStaticProps( props: IRPropsStatic, context: CodegenContext, + dynamicProps?: CodeFragment[], ): CodeFragment[] { + const args = props.map(prop => genProp(prop, context, true)) + if (dynamicProps) { + args.push([`$: `, ...dynamicProps]) + } return genMulti( - props.length > 1 ? DELIMITERS_OBJECT_NEWLINE : DELIMITERS_OBJECT, - ...props.map(prop => genProp(prop, context, true)), + args.length > 1 ? DELIMITERS_OBJECT_NEWLINE : DELIMITERS_OBJECT, + ...args, ) } +function genDynamicProps( + props: IRProps[], + context: CodegenContext, +): CodeFragment[] | undefined { + const { vaporHelper } = context + const frags: CodeFragment[][] = [] + for (const p of props) { + let expr: CodeFragment[] + if (isArray(p)) { + if (p.length) { + frags.push(genStaticProps(p, context)) + } + continue + } else { + if (p.kind === IRDynamicPropsKind.ATTRIBUTE) + expr = genMulti(DELIMITERS_OBJECT, genProp(p, context)) + else { + expr = genExpression(p.value, context) + if (p.handler) expr = genCall(vaporHelper('toHandlers'), expr) + } + } + frags.push(['() => (', ...expr, ')']) + } + if (frags.length) { + return genMulti(DELIMITERS_ARRAY_NEWLINE, ...frags) + } +} + function genProp(prop: IRProp, context: CodegenContext, isStatic?: boolean) { const values = genPropValue(prop.values, context) return [ diff --git a/packages/runtime-vapor/src/component.ts b/packages/runtime-vapor/src/component.ts index 3bd360cea2..d78ce73d09 100644 --- a/packages/runtime-vapor/src/component.ts +++ b/packages/runtime-vapor/src/component.ts @@ -76,10 +76,11 @@ export function createComponent( // check if we are the single root of the parent // if yes, inject parent attrs as dynamic props source if (isSingleRoot && currentInstance && currentInstance.hasFallthrough) { + const attrs = currentInstance.attrs if (rawProps) { - ;(rawProps.$ || (rawProps.$ = [])).push(currentInstance.attrs) + ;(rawProps.$ || (rawProps.$ = [])).push(() => attrs) } else { - rawProps = { $: [currentInstance.attrs] } + rawProps = { $: [() => attrs] } as RawProps } } diff --git a/packages/runtime-vapor/src/componentProps.ts b/packages/runtime-vapor/src/componentProps.ts index 17fc893fc0..3d41085325 100644 --- a/packages/runtime-vapor/src/componentProps.ts +++ b/packages/runtime-vapor/src/componentProps.ts @@ -8,14 +8,13 @@ import { } from '@vue/runtime-dom' import { normalizeEmitsOptions } from './componentEmits' -export interface RawProps { - [key: string]: PropSource +export type RawProps = Record unknown> & { $?: DynamicPropsSource[] } -type PropSource = T | (() => T) - -type DynamicPropsSource = PropSource> +type DynamicPropsSource = + | (() => Record) + | Record unknown> export function initStaticProps( comp: VaporComponent, @@ -38,40 +37,24 @@ export function initStaticProps( const needCast = needCastKeys && needCastKeys.includes(normalizedKey) const source = rawProps[key] if (propsOptions && normalizedKey in propsOptions) { - if (isFunction(source)) { - Object.defineProperty(props, normalizedKey, { - enumerable: true, - get: needCast - ? () => - resolvePropValue( - propsOptions, - normalizedKey, - source(), - instance, - resolveDefault, - ) - : source, - }) - } else { - props[normalizedKey] = needCast - ? resolvePropValue( - propsOptions, - normalizedKey, - source, - instance, - resolveDefault, - ) - : source - } + Object.defineProperty(props, normalizedKey, { + enumerable: true, + get: needCast + ? () => + resolvePropValue( + propsOptions, + normalizedKey, + source(), + instance, + resolveDefault, + ) + : source, + }) } else if (!isEmitListener(emitsOptions, key)) { - if (isFunction(source)) { - Object.defineProperty(attrs, key, { - enumerable: true, - get: source, - }) - } else { - attrs[normalizedKey] = source - } + Object.defineProperty(attrs, key, { + enumerable: true, + get: source, + }) hasAttrs = true } } @@ -98,7 +81,9 @@ function resolveDefault( } // TODO optimization: maybe convert functions into computeds -export function resolveSource(source: PropSource): Record { +export function resolveSource( + source: Record | (() => Record), +): Record { return isFunction(source) ? source() : source } @@ -138,15 +123,18 @@ export function getDynamicPropsHandlers( : passThrough if (key in target) { - return castProp(resolveSource(target[key as string])) + return castProp(target[key as string]()) } - if (target.$) { - let i = target.$.length - let source + const dynamicSources = target.$ + if (dynamicSources) { + let i = dynamicSources.length + let source, isDynamic while (i--) { - source = resolveSource(target.$[i]) + source = dynamicSources[i] + isDynamic = isFunction(source) + source = isDynamic ? (source as Function)() : source if (hasOwn(source, key)) { - return castProp(source[key]) + return castProp(isDynamic ? source[key] : source[key]()) } } } @@ -174,12 +162,14 @@ export function getDynamicPropsHandlers( : null const hasAttr = (target: RawProps, key: string) => { - if (key === '$' || isProp(key) || isEmitListener(emitsOptions, key)) + if (key === '$' || isProp(key) || isEmitListener(emitsOptions, key)) { return false - if (target.$) { - let i = target.$.length + } + const dynamicSources = target.$ + if (dynamicSources) { + let i = dynamicSources.length while (i--) { - if (hasOwn(resolveSource(target.$[i]), key)) { + if (hasOwn(resolveSource(dynamicSources[i]), key)) { return true } } @@ -201,10 +191,11 @@ export function getDynamicPropsHandlers( }, ownKeys(target) { const keys = Object.keys(target) - if (target.$) { - let i = target.$.length + const dynamicSources = target.$ + if (dynamicSources) { + let i = dynamicSources.length while (i--) { - keys.push(...Object.keys(resolveSource(target.$[i]))) + keys.push(...Object.keys(resolveSource(dynamicSources[i]))) } } return keys.filter(key => hasAttr(target, key))