fix(compiler-sfc): resolve computed object key (#6963)

This commit is contained in:
三咲智子 Kevin Deng 2022-11-09 10:57:40 +08:00 committed by GitHub
parent 7663a79a29
commit 910fa7677f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 79 additions and 28 deletions

View File

@ -1743,12 +1743,13 @@ export default /*#__PURE__*/_defineComponent({
foo: { type: String, required: false, default: 'hi' }, foo: { type: String, required: false, default: 'hi' },
bar: { type: Number, required: false }, bar: { type: Number, required: false },
baz: { type: Boolean, required: true }, 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 }) { setup(__props: any, { expose }) {
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 };

View File

@ -44,6 +44,25 @@ exports[`sfc props transform basic usage 1`] = `
"import { toDisplayString as _toDisplayString } from \\"vue\\" "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 computed static key 1`] = `
"import { toDisplayString as _toDisplayString } from \\"vue\\"
export default { export default {
props: ['foo'], props: ['foo'],
setup(__props) { setup(__props) {

View File

@ -1039,10 +1039,12 @@ const emit = defineEmits(['a', 'b'])
foo?: string foo?: string
bar?: number; bar?: number;
baz: boolean; baz: boolean;
qux?(): number qux?(): number;
quux?(): void
}>(), { }>(), {
foo: 'hi', foo: 'hi',
qux() { return 1 } qux() { return 1 },
['quux']() { }
}) })
</script> </script>
`) `)
@ -1056,7 +1058,10 @@ const emit = defineEmits(['a', 'b'])
`qux: { type: Function, required: false, default() { return 1 } }` `qux: { type: Function, required: false, default() { return 1 } }`
) )
expect(content).toMatch( 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(content).toMatch(`const props = __props`)
expect(bindings).toStrictEqual({ expect(bindings).toStrictEqual({
@ -1064,6 +1069,7 @@ const emit = defineEmits(['a', 'b'])
bar: BindingTypes.PROPS, bar: BindingTypes.PROPS,
baz: BindingTypes.PROPS, baz: BindingTypes.PROPS,
qux: BindingTypes.PROPS, qux: BindingTypes.PROPS,
quux: BindingTypes.PROPS,
props: BindingTypes.SETUP_CONST props: BindingTypes.SETUP_CONST
}) })
}) })

View File

@ -184,6 +184,24 @@ describe('sfc props transform', () => {
assertCode(content) assertCode(content)
}) })
// #6960
test('computed static key', () => {
const { content, bindings } = compile(`
<script setup>
const { ['foo']: foo } = defineProps(['foo'])
console.log(foo)
</script>
<template>{{ foo }}</template>
`)
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', () => { describe('errors', () => {
test('should error on deep destructure', () => { test('should error on deep destructure', () => {
expect(() => expect(() =>

View File

@ -447,18 +447,15 @@ export function compileScript(
// props destructure - handle compilation sugar // props destructure - handle compilation sugar
for (const prop of declId.properties) { for (const prop of declId.properties) {
if (prop.type === 'ObjectProperty') { if (prop.type === 'ObjectProperty') {
if (prop.computed) { const propKey = resolveObjectKey(prop.key, prop.computed)
if (!propKey) {
error( error(
`${DEFINE_PROPS}() destructure cannot use computed key.`, `${DEFINE_PROPS}() destructure cannot use computed key.`,
prop.key prop.key
) )
} }
const propKey =
prop.key.type === 'StringLiteral'
? prop.key.value
: (prop.key as Identifier).name
if (prop.value.type === 'AssignmentPattern') { if (prop.value.type === 'AssignmentPattern') {
// default value { foo = 123 } // default value { foo = 123 }
const { left, right } = prop.value const { left, right } = prop.value
@ -774,7 +771,8 @@ export function compileScript(
propsRuntimeDefaults.type === 'ObjectExpression' && propsRuntimeDefaults.type === 'ObjectExpression' &&
propsRuntimeDefaults.properties.every( propsRuntimeDefaults.properties.every(
node => node =>
(node.type === 'ObjectProperty' && !node.computed) || (node.type === 'ObjectProperty' &&
(!node.computed || node.key.type.endsWith('Literal'))) ||
node.type === 'ObjectMethod' node.type === 'ObjectMethod'
) )
) )
@ -795,9 +793,10 @@ export function compileScript(
if (destructured) { if (destructured) {
defaultString = `default: ${destructured}` defaultString = `default: ${destructured}`
} else if (hasStaticDefaults) { } else if (hasStaticDefaults) {
const prop = propsRuntimeDefaults!.properties.find( const prop = propsRuntimeDefaults!.properties.find(node => {
(node: any) => node.key.name === key if (node.type === 'SpreadElement') return false
) as ObjectProperty | ObjectMethod return resolveObjectKey(node.key, node.computed) === key
}) as ObjectProperty | ObjectMethod
if (prop) { if (prop) {
if (prop.type === 'ObjectProperty') { if (prop.type === 'ObjectProperty') {
// prop has corresponding static default value // prop has corresponding static default value
@ -874,9 +873,13 @@ export function compileScript(
m.key.type === 'Identifier' m.key.type === 'Identifier'
) { ) {
if ( if (
propsRuntimeDefaults!.properties.some( propsRuntimeDefaults!.properties.some(p => {
(p: any) => p.key.name === (m.key as Identifier).name if (p.type === 'SpreadElement') return false
return (
resolveObjectKey(p.key, p.computed) ===
(m.key as Identifier).name
) )
})
) { ) {
res += res +=
m.key.name + m.key.name +
@ -2139,16 +2142,9 @@ function analyzeBindingsFromOptions(node: ObjectExpression): BindingMetadata {
function getObjectExpressionKeys(node: ObjectExpression): string[] { function getObjectExpressionKeys(node: ObjectExpression): string[] {
const keys = [] const keys = []
for (const prop of node.properties) { for (const prop of node.properties) {
if ( if (prop.type === 'SpreadElement') continue
(prop.type === 'ObjectProperty' || prop.type === 'ObjectMethod') && const key = resolveObjectKey(prop.key, prop.computed)
!prop.computed if (key) keys.push(String(key))
) {
if (prop.key.type === 'Identifier') {
keys.push(prop.key.name)
} else if (prop.key.type === 'StringLiteral') {
keys.push(prop.key.value)
}
}
} }
return keys return keys
} }
@ -2297,3 +2293,14 @@ export function hmrShouldReload(
return false 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
}