fix(compiler-sfc): fix sfc template unref rewrite for class instantiation

close #6483
close #6491
This commit is contained in:
Evan You 2024-01-04 15:57:54 +08:00
parent fda51925f4
commit ae60a91cc2
4 changed files with 59 additions and 2 deletions

View File

@ -146,6 +146,19 @@ export function isInDestructureAssignment(
return false return false
} }
export function isInNewExpression(parentStack: Node[]): boolean {
let i = parentStack.length
while (i--) {
const p = parentStack[i]
if (p.type === 'NewExpression') {
return true
} else if (p.type !== 'MemberExpression') {
break
}
}
return false
}
export function walkFunctionParams( export function walkFunctionParams(
node: Function, node: Function,
onIdent: (id: Identifier) => void, onIdent: (id: Identifier) => void,

View File

@ -19,6 +19,7 @@ import {
} from '../ast' } from '../ast'
import { import {
isInDestructureAssignment, isInDestructureAssignment,
isInNewExpression,
isStaticProperty, isStaticProperty,
isStaticPropertyKey, isStaticPropertyKey,
walkIdentifiers, walkIdentifiers,
@ -131,6 +132,11 @@ export function processExpression(
// ({ x } = y) // ({ x } = y)
const isDestructureAssignment = const isDestructureAssignment =
parent && isInDestructureAssignment(parent, parentStack) parent && isInDestructureAssignment(parent, parentStack)
const isNewExpression = parent && isInNewExpression(parentStack)
const wrapWithUnref = (raw: string) => {
const wrapped = `${context.helperString(UNREF)}(${raw})`
return isNewExpression ? `(${wrapped})` : wrapped
}
if ( if (
isConst(type) || isConst(type) ||
@ -147,7 +153,7 @@ export function processExpression(
// that assumes the value to be a ref for more efficiency // that assumes the value to be a ref for more efficiency
return isAssignmentLVal || isUpdateArg || isDestructureAssignment return isAssignmentLVal || isUpdateArg || isDestructureAssignment
? `${raw}.value` ? `${raw}.value`
: `${context.helperString(UNREF)}(${raw})` : wrapWithUnref(raw)
} else if (type === BindingTypes.SETUP_LET) { } else if (type === BindingTypes.SETUP_LET) {
if (isAssignmentLVal) { if (isAssignmentLVal) {
// let binding. // let binding.
@ -190,7 +196,7 @@ export function processExpression(
// for now // for now
return raw return raw
} else { } else {
return `${context.helperString(UNREF)}(${raw})` return wrapWithUnref(raw)
} }
} else if (type === BindingTypes.PROPS) { } else if (type === BindingTypes.PROPS) {
// use __props which is generated by compileScript so in ts mode // use __props which is generated by compileScript so in ts mode

View File

@ -1028,6 +1028,26 @@ return (_ctx, _cache) => {
}" }"
`; `;
exports[`SFC compile <script setup> > inlineTemplate mode > unref + new expression 1`] = `
"import { unref as _unref, toDisplayString as _toDisplayString, createElementVNode as _createElementVNode, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
import Foo from './foo'
export default {
setup(__props) {
return (_ctx, _cache) => {
return (_openBlock(), _createElementBlock(_Fragment, null, [
_createElementVNode("div", null, _toDisplayString(new (_unref(Foo))()), 1 /* TEXT */),
_createElementVNode("div", null, _toDisplayString(new (_unref(Foo)).Bar()), 1 /* TEXT */)
], 64 /* STABLE_FRAGMENT */))
}
}
}"
`;
exports[`SFC compile <script setup> > inlineTemplate mode > v-model codegen 1`] = ` exports[`SFC compile <script setup> > inlineTemplate mode > v-model codegen 1`] = `
"import { vModelText as _vModelText, createElementVNode as _createElementVNode, withDirectives as _withDirectives, unref as _unref, isRef as _isRef, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue" "import { vModelText as _vModelText, createElementVNode as _createElementVNode, withDirectives as _withDirectives, unref as _unref, isRef as _isRef, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"

View File

@ -650,6 +650,24 @@ describe('SFC compile <script setup>', () => {
), ),
).not.toThrowError() ).not.toThrowError()
}) })
test('unref + new expression', () => {
const { content } = compile(
`
<script setup>
import Foo from './foo'
</script>
<template>
<div>{{ new Foo() }}</div>
<div>{{ new Foo.Bar() }}</div>
</template>
`,
{ inlineTemplate: true },
)
expect(content).toMatch(`new (_unref(Foo))()`)
expect(content).toMatch(`new (_unref(Foo)).Bar()`)
assertCode(content)
})
}) })
describe('with TypeScript', () => { describe('with TypeScript', () => {