diff --git a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap index ec94872c560..55659cb93d3 100644 --- a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap @@ -1743,12 +1743,13 @@ export default /*#__PURE__*/_defineComponent({ foo: { type: String, required: false, default: 'hi' }, bar: { type: Number, required: false }, baz: { type: Boolean, required: true }, - qux: { type: Function, required: false, default() { return 1 } } + qux: { type: Function, required: false, default() { return 1 } }, + quux: { type: Function, required: false, default() { } } }, setup(__props: any, { expose }) { expose(); -const props = __props as { foo: string, bar?: number, baz: boolean, qux(): number }; +const props = __props as { foo: string, bar?: number, baz: boolean, qux(): number, quux(): void }; diff --git a/packages/compiler-sfc/__tests__/__snapshots__/compileScriptPropsTransform.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/compileScriptPropsTransform.spec.ts.snap index 093d2b9ddf7..cbbdaabd9b5 100644 --- a/packages/compiler-sfc/__tests__/__snapshots__/compileScriptPropsTransform.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/__snapshots__/compileScriptPropsTransform.spec.ts.snap @@ -59,6 +59,25 @@ return (_ctx, _cache) => { }" `; +exports[`sfc props transform computed static key 1`] = ` +"import { toDisplayString as _toDisplayString } from \\"vue\\" + + +export default { + props: ['foo'], + setup(__props) { + + + console.log(__props.foo) + +return (_ctx, _cache) => { + return _toDisplayString(__props.foo) +} +} + +}" +`; + exports[`sfc props transform default values w/ runtime declaration 1`] = ` "import { mergeDefaults as _mergeDefaults } from 'vue' diff --git a/packages/compiler-sfc/__tests__/compileScript.spec.ts b/packages/compiler-sfc/__tests__/compileScript.spec.ts index 4e3e36f7431..c3ba6067648 100644 --- a/packages/compiler-sfc/__tests__/compileScript.spec.ts +++ b/packages/compiler-sfc/__tests__/compileScript.spec.ts @@ -1039,10 +1039,12 @@ const emit = defineEmits(['a', 'b']) foo?: string bar?: number; baz: boolean; - qux?(): number + qux?(): number; + quux?(): void }>(), { foo: 'hi', - qux() { return 1 } + qux() { return 1 }, + ['quux']() { } }) `) @@ -1056,7 +1058,10 @@ const emit = defineEmits(['a', 'b']) `qux: { type: Function, required: false, default() { return 1 } }` ) expect(content).toMatch( - `{ foo: string, bar?: number, baz: boolean, qux(): number }` + `quux: { type: Function, required: false, default() { } }` + ) + expect(content).toMatch( + `{ foo: string, bar?: number, baz: boolean, qux(): number, quux(): void }` ) expect(content).toMatch(`const props = __props`) expect(bindings).toStrictEqual({ @@ -1064,6 +1069,7 @@ const emit = defineEmits(['a', 'b']) bar: BindingTypes.PROPS, baz: BindingTypes.PROPS, qux: BindingTypes.PROPS, + quux: BindingTypes.PROPS, props: BindingTypes.SETUP_CONST }) }) diff --git a/packages/compiler-sfc/__tests__/compileScriptPropsTransform.spec.ts b/packages/compiler-sfc/__tests__/compileScriptPropsTransform.spec.ts index 25fb4bed280..7d35f91abf2 100644 --- a/packages/compiler-sfc/__tests__/compileScriptPropsTransform.spec.ts +++ b/packages/compiler-sfc/__tests__/compileScriptPropsTransform.spec.ts @@ -184,6 +184,24 @@ describe('sfc props transform', () => { assertCode(content) }) + // #6960 + test('computed static key', () => { + const { content, bindings } = compile(` + + + `) + expect(content).not.toMatch(`const { foo } =`) + expect(content).toMatch(`console.log(__props.foo)`) + expect(content).toMatch(`_toDisplayString(__props.foo)`) + assertCode(content) + expect(bindings).toStrictEqual({ + foo: BindingTypes.PROPS + }) + }) + describe('errors', () => { test('should error on deep destructure', () => { expect(() => diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts index aba5a22ec8d..d55cb795c77 100644 --- a/packages/compiler-sfc/src/compileScript.ts +++ b/packages/compiler-sfc/src/compileScript.ts @@ -447,18 +447,15 @@ export function compileScript( // props destructure - handle compilation sugar for (const prop of declId.properties) { if (prop.type === 'ObjectProperty') { - if (prop.computed) { + const propKey = resolveObjectKey(prop.key, prop.computed) + + if (!propKey) { error( `${DEFINE_PROPS}() destructure cannot use computed key.`, prop.key ) } - const propKey = - prop.key.type === 'StringLiteral' - ? prop.key.value - : (prop.key as Identifier).name - if (prop.value.type === 'AssignmentPattern') { // default value { foo = 123 } const { left, right } = prop.value @@ -774,7 +771,8 @@ export function compileScript( propsRuntimeDefaults.type === 'ObjectExpression' && propsRuntimeDefaults.properties.every( node => - (node.type === 'ObjectProperty' && !node.computed) || + (node.type === 'ObjectProperty' && + (!node.computed || node.key.type.endsWith('Literal'))) || node.type === 'ObjectMethod' ) ) @@ -795,9 +793,10 @@ export function compileScript( if (destructured) { defaultString = `default: ${destructured}` } else if (hasStaticDefaults) { - const prop = propsRuntimeDefaults!.properties.find( - (node: any) => node.key.name === key - ) as ObjectProperty | ObjectMethod + const prop = propsRuntimeDefaults!.properties.find(node => { + if (node.type === 'SpreadElement') return false + return resolveObjectKey(node.key, node.computed) === key + }) as ObjectProperty | ObjectMethod if (prop) { if (prop.type === 'ObjectProperty') { // prop has corresponding static default value @@ -874,9 +873,13 @@ export function compileScript( m.key.type === 'Identifier' ) { if ( - propsRuntimeDefaults!.properties.some( - (p: any) => p.key.name === (m.key as Identifier).name - ) + propsRuntimeDefaults!.properties.some(p => { + if (p.type === 'SpreadElement') return false + return ( + resolveObjectKey(p.key, p.computed) === + (m.key as Identifier).name + ) + }) ) { res += m.key.name + @@ -2139,16 +2142,9 @@ function analyzeBindingsFromOptions(node: ObjectExpression): BindingMetadata { function getObjectExpressionKeys(node: ObjectExpression): string[] { const keys = [] for (const prop of node.properties) { - if ( - (prop.type === 'ObjectProperty' || prop.type === 'ObjectMethod') && - !prop.computed - ) { - if (prop.key.type === 'Identifier') { - keys.push(prop.key.name) - } else if (prop.key.type === 'StringLiteral') { - keys.push(prop.key.value) - } - } + if (prop.type === 'SpreadElement') continue + const key = resolveObjectKey(prop.key, prop.computed) + if (key) keys.push(String(key)) } return keys } @@ -2297,3 +2293,14 @@ export function hmrShouldReload( return false } + +export function resolveObjectKey(node: Node, computed: boolean) { + switch (node.type) { + case 'StringLiteral': + case 'NumericLiteral': + return node.value + case 'Identifier': + if (!computed) return node.name + } + return undefined +}