]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-sfc): fix sfc template unref rewrite for class instantiation
authorEvan You <yyx990803@gmail.com>
Thu, 4 Jan 2024 07:57:54 +0000 (15:57 +0800)
committerEvan You <yyx990803@gmail.com>
Thu, 4 Jan 2024 07:58:13 +0000 (15:58 +0800)
close #6483
close #6491

packages/compiler-core/src/babelUtils.ts
packages/compiler-core/src/transforms/transformExpression.ts
packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap
packages/compiler-sfc/__tests__/compileScript.spec.ts

index e0e0ef2222bf81206bbe5beaed4f537c5dfa18b8..0a7f48af9027d625b901dd6fe64b37a50d347b58 100644 (file)
@@ -146,6 +146,19 @@ export function isInDestructureAssignment(
   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(
   node: Function,
   onIdent: (id: Identifier) => void,
index 093fb4447ff7f61a2cdfba415437ecae7337f6e0..c7cd1b63d56537e619fcad6e37e121687c5c605b 100644 (file)
@@ -19,6 +19,7 @@ import {
 } from '../ast'
 import {
   isInDestructureAssignment,
+  isInNewExpression,
   isStaticProperty,
   isStaticPropertyKey,
   walkIdentifiers,
@@ -131,6 +132,11 @@ export function processExpression(
       // ({ x } = y)
       const isDestructureAssignment =
         parent && isInDestructureAssignment(parent, parentStack)
+      const isNewExpression = parent && isInNewExpression(parentStack)
+      const wrapWithUnref = (raw: string) => {
+        const wrapped = `${context.helperString(UNREF)}(${raw})`
+        return isNewExpression ? `(${wrapped})` : wrapped
+      }
 
       if (
         isConst(type) ||
@@ -147,7 +153,7 @@ export function processExpression(
         // that assumes the value to be a ref for more efficiency
         return isAssignmentLVal || isUpdateArg || isDestructureAssignment
           ? `${raw}.value`
-          : `${context.helperString(UNREF)}(${raw})`
+          : wrapWithUnref(raw)
       } else if (type === BindingTypes.SETUP_LET) {
         if (isAssignmentLVal) {
           // let binding.
@@ -190,7 +196,7 @@ export function processExpression(
           // for now
           return raw
         } else {
-          return `${context.helperString(UNREF)}(${raw})`
+          return wrapWithUnref(raw)
         }
       } else if (type === BindingTypes.PROPS) {
         // use __props which is generated by compileScript so in ts mode
index d63e6ec4d40f20e7df76167d1035749df11d6df8..6efe6fb92afb73eff9e17b67216b2123e96297c2 100644 (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`] = `
 "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"
 
index b692394f51cee61bae7348118164dccf0c8a9426..7c21816eb7549104b04d2e6be66a6cf4eac820e8 100644 (file)
@@ -650,6 +650,24 @@ describe('SFC compile <script setup>', () => {
         ),
       ).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', () => {