mirror of https://github.com/vuejs/core.git
fix(compiler-sfc): resolve computed object key (#6963)
This commit is contained in:
parent
7663a79a29
commit
910fa7677f
|
@ -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 };
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
|
@ -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']() { }
|
||||
})
|
||||
</script>
|
||||
`)
|
||||
|
@ -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
|
||||
})
|
||||
})
|
||||
|
|
|
@ -184,6 +184,24 @@ describe('sfc props transform', () => {
|
|||
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', () => {
|
||||
test('should error on deep destructure', () => {
|
||||
expect(() =>
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue