Skip to content
Permalink
Browse files
fix(compiler-sfc): resolve computed object key (#6963)
  • Loading branch information
sxzz committed Nov 9, 2022
1 parent 7663a79 commit 910fa7677f4ef690b612fae4a069b2293672c439
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 28 deletions.
@@ -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,14 +1058,18 @@ 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({
foo: BindingTypes.PROPS,
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
}

0 comments on commit 910fa76

Please sign in to comment.