feat: not be hoisted if it's used by other assignments

This commit is contained in:
zqran 2023-06-17 21:44:01 +08:00
parent a5cf72ea00
commit 401ee32342
2 changed files with 37 additions and 11 deletions

View File

@ -627,5 +627,19 @@ const props = defineProps({ foo: String })
</script>`) </script>`)
}).toThrow(`cannot accept both type and non-type arguments`) }).toThrow(`cannot accept both type and non-type arguments`)
}) })
test('withDefaults (locally variable)', () => {
expect(() => {
compile(`
<script setup lang="ts">
const defaults = { bar: 1 }
withDefaults(defineProps<{
bar?: number
}>(), defaults)
defaults.bar++
</script>
`)
}).toThrow(`cannot reference locally declared variables`)
})
}) })
}) })

View File

@ -197,7 +197,7 @@ export function compileScript(
string, string,
{ {
node: Statement node: Statement
useWithDefaults: boolean needHoist?: boolean
} }
> = {} > = {}
@ -268,14 +268,13 @@ export function compileScript(
if ( if (
binding && binding &&
binding !== BindingTypes.LITERAL_CONST && binding !== BindingTypes.LITERAL_CONST &&
!withDefaultsVariables[id.name].useWithDefaults !withDefaultsVariables[id.name].needHoist
) { ) {
ctx.error( ctx.error(
`\`${method}()\` in <script setup> cannot reference locally ` + `\`${method}()\` in <script setup> cannot reference locally declared variables ` +
`declared variables because it will be hoisted outside of the ` + `because it will be hoisted outside of the setup() function. ` +
`setup() function. If your component options require initialization ` + `If your component options require initialization in the module scope, ` +
`in the module scope, use a separate normal <script> to export ` + `use a separate normal <script> to export the options instead.`,
`the options instead.`,
id id
) )
} }
@ -651,8 +650,7 @@ export function compileScript(
if (child.type === 'Identifier') { if (child.type === 'Identifier') {
if (parent.type === 'VariableDeclarator') { if (parent.type === 'VariableDeclarator') {
withDefaultsVariables[child.name] = { withDefaultsVariables[child.name] = {
node, node
useWithDefaults: false
} }
} else if ( } else if (
parent.type === 'CallExpression' && parent.type === 'CallExpression' &&
@ -661,8 +659,15 @@ export function compileScript(
withDefaultsVariables[child.name] withDefaultsVariables[child.name]
) { ) {
const variable = withDefaultsVariables[child.name] const variable = withDefaultsVariables[child.name]
variable.useWithDefaults = true if (variable.needHoist !== false) {
hoistNode(variable.node) variable.needHoist = true
}
} else if (
parent.type === 'MemberExpression' &&
withDefaultsVariables[child.name]
) {
const variable = withDefaultsVariables[child.name]
variable.needHoist = false
} }
} }
}, },
@ -700,6 +705,13 @@ export function compileScript(
} }
} }
for (const key in withDefaultsVariables) {
const variable = withDefaultsVariables[key]
if (variable.needHoist) {
hoistNode(variable.node)
}
}
// 3 props destructure transform // 3 props destructure transform
if (ctx.propsDestructureDecl) { if (ctx.propsDestructureDecl) {
transformDestructuredProps(ctx, vueImportAliases) transformDestructuredProps(ctx, vueImportAliases)