]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(sfc): support $shallowRef ref sugar
authorEvan You <yyx990803@gmail.com>
Wed, 11 Aug 2021 14:19:58 +0000 (10:19 -0400)
committerEvan You <yyx990803@gmail.com>
Wed, 11 Aug 2021 14:19:58 +0000 (10:19 -0400)
packages/compiler-sfc/__tests__/__snapshots__/compileScriptRefSugar.spec.ts.snap
packages/compiler-sfc/__tests__/compileScriptRefSugar.spec.ts
packages/compiler-sfc/src/compileScript.ts
packages/runtime-core/src/helpers/refSugar.ts
packages/runtime-core/src/index.ts
packages/runtime-core/types/scriptSetupHelpers.d.ts
test-dts/refSugar.test-d.ts

index 32acabe3db30a8c0fd3bed12ef9d2efce19bf960..dbe6aa1dd1b1ac6096c3378e6c674c128584c5f7 100644 (file)
@@ -33,8 +33,8 @@ return { a, b, c }
 }"
 `;
 
-exports[`<script setup> ref sugar $ref declarations 1`] = `
-"import { ref as _ref } from 'vue'
+exports[`<script setup> ref sugar $ref & $shallowRef declarations 1`] = `
+"import { ref as _ref, shallowRef as _shallowRef } from 'vue'
 
 export default {
   setup(__props, { expose }) {
@@ -42,7 +42,7 @@ export default {
 
     let foo = _ref()
     let a = _ref(1)
-    let b = _ref({
+    let b = _shallowRef({
       count: 0
     })
     let c = () => {}
index 53172fa755a50faa0f70fc1a906e4913920be639..12baa1049ed9b9ea7890879a725a165ff75ff6d4 100644 (file)
@@ -6,24 +6,26 @@ describe('<script setup> ref sugar', () => {
     return compile(src, { refSugar: true })
   }
 
-  test('$ref declarations', () => {
+  test('$ref & $shallowRef declarations', () => {
     const { content, bindings } = compileWithRefSugar(`<script setup>
     let foo = $ref()
     let a = $ref(1)
-    let b = $ref({
+    let b = $shallowRef({
       count: 0
     })
     let c = () => {}
     let d
     </script>`)
-    expect(content).toMatch(`import { ref as _ref } from 'vue'`)
+    expect(content).toMatch(
+      `import { ref as _ref, shallowRef as _shallowRef } from 'vue'`
+    )
     expect(content).not.toMatch(`$ref()`)
     expect(content).not.toMatch(`$ref(1)`)
-    expect(content).not.toMatch(`$ref({`)
+    expect(content).not.toMatch(`$shallowRef({`)
     expect(content).toMatch(`let foo = _ref()`)
     expect(content).toMatch(`let a = _ref(1)`)
     expect(content).toMatch(`
-    let b = _ref({
+    let b = _shallowRef({
       count: 0
     })
     `)
index 000dff41230b0b827a03dc979ddbfec5260b31bb..9e4a2ceb85a49a890ca60b924518a0dff407dcec 100644 (file)
@@ -65,6 +65,7 @@ const DEFINE_EXPOSE = 'defineExpose'
 const WITH_DEFAULTS = 'withDefaults'
 
 const $REF = `$ref`
+const $SHALLOW_REF = '$shallowRef'
 const $COMPUTED = `$computed`
 const $FROM_REFS = `$fromRefs`
 const $RAW = `$raw`
@@ -531,7 +532,12 @@ export function compileScript(
   }
 
   function isRefSugarCall(callee: string) {
-    return callee === $REF || callee === $COMPUTED || callee === $FROM_REFS
+    return (
+      callee === $REF ||
+      callee === $COMPUTED ||
+      callee === $FROM_REFS ||
+      callee === $SHALLOW_REF
+    )
   }
 
   function processRefSugar(
@@ -558,24 +564,28 @@ export function compileScript(
 
     const callee = (decl.init.callee as Identifier).name
     const start = decl.init.start! + startOffset
-    if (callee === $REF) {
+    if (callee === $REF || callee === $SHALLOW_REF) {
       if (statement.kind !== 'let') {
-        error(`${$REF}() bindings can only be declared with let.`, decl)
+        error(`${callee}() bindings can only be declared with let.`, decl)
       }
       if (decl.id.type !== 'Identifier') {
         error(
-          `${$REF}() bindings cannot be used with destructuring. ` +
+          `${callee}() bindings cannot be used with destructuring. ` +
             `If you are trying to destructure from an object of refs, ` +
             `use \`let { x } = $fromRefs(obj)\`.`,
           decl.id
         )
       }
       registerRefBinding(decl.id)
-      s.overwrite(start, start + $REF.length, helper('ref'))
+      s.overwrite(
+        start,
+        start + callee.length,
+        helper(callee === $REF ? 'ref' : 'shallowRef')
+      )
     } else if (callee === $COMPUTED) {
       if (decl.id.type !== 'Identifier') {
         error(
-          `${$COMPUTED}() bindings cannot be used with destructuring.`,
+          `${callee}() bindings cannot be used with destructuring.`,
           decl.id
         )
       }
@@ -584,7 +594,7 @@ export function compileScript(
     } else if (callee === $FROM_REFS) {
       if (!decl.id.type.endsWith('Pattern')) {
         error(
-          `${$FROM_REFS}() declaration must be used with destructure patterns.`,
+          `${callee}() declaration must be used with destructure patterns.`,
           decl
         )
       }
@@ -1124,10 +1134,7 @@ export function compileScript(
         return false // skip walk
       } else if (
         parent &&
-        isCallOf(
-          node,
-          id => id === $REF || id === $FROM_REFS || id === $COMPUTED
-        ) &&
+        isCallOf(node, isRefSugarCall) &&
         (parent.type !== 'VariableDeclarator' || node !== parent.init)
       ) {
         error(
index 4c62441d2d978fd8113d1b32c60dc7e20ca9dfb0..91480dfa94f1a88b3d629e07e67f9f8799d77e05 100644 (file)
@@ -3,6 +3,10 @@ import { Ref, UnwrapRef, ShallowUnwrapRef, ComputedRef } from '@vue/reactivity'
 export function $ref<T>(arg: T | Ref<T>): UnwrapRef<T>
 export function $ref() {}
 
+export function $shallowRef<T>(arg: T): T {
+  return arg
+}
+
 declare const ComputedRefMarker: unique symbol
 type ComputedRefValue<T> = T & { [ComputedRefMarker]?: any }
 
index a784bd73f4739fc2503f6a0e47b5c4c2ffad524a..c46b6df22764e07c1089f11c5b67d01bb9609869 100644 (file)
@@ -354,4 +354,10 @@ export const compatUtils = (
 
 // Ref sugar macros ------------------------------------------------------------
 // for dts generation only
-export { $ref, $computed, $raw, $fromRefs } from './helpers/refSugar'
+export {
+  $ref,
+  $shallowRef,
+  $computed,
+  $raw,
+  $fromRefs
+} from './helpers/refSugar'
index fc56cb19cf446fcba1ac34742ac47a941ccb6aed..69cab07ada3d9bd93e6c49b20f44c470b2889116 100644 (file)
@@ -6,6 +6,7 @@ type _defineExpose = typeof defineExpose
 type _withDefaults = typeof withDefaults
 
 type _ref = typeof $ref
+type _shallowRef = typeof $shallowRef
 type _computed = typeof $computed
 type _fromRefs = typeof $fromRefs
 type _raw = typeof $raw
@@ -17,6 +18,7 @@ declare global {
   const withDefaults: _withDefaults
 
   const $ref: _ref
+  const $shallowRef: _shallowRef
   const $computed: _computed
   const $fromRefs: _fromRefs
   const $raw: _raw
index 29d837091c0932fb9b271b00865ee2e837dc2f95..4ea579b91cb96fbe38ce448a6e3e68e5e759906b 100644 (file)
@@ -1,6 +1,7 @@
 import {
   expectType,
   $ref,
+  $shallowRef,
   $computed,
   $fromRefs,
   $raw,
@@ -14,6 +15,10 @@ expectType<number>($ref(1))
 expectType<number>($ref(ref(1)))
 expectType<{ foo: number }>($ref({ foo: ref(1) }))
 
+// $shallowRef
+expectType<number>($shallowRef(1))
+expectType<{ foo: Ref<number> }>($shallowRef({ foo: ref(1) }))
+
 // $computed
 expectType<number>($computed(() => 1))
 let b = $ref(1)