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' },
|
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 };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -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(() =>
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue