]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(reactivity-transform): support optionally importing macros
authorEvan You <yyx990803@gmail.com>
Sat, 11 Dec 2021 10:28:03 +0000 (18:28 +0800)
committerEvan You <yyx990803@gmail.com>
Sat, 11 Dec 2021 10:28:03 +0000 (18:28 +0800)
packages/ref-transform/__tests__/__snapshots__/refTransform.spec.ts.snap
packages/ref-transform/__tests__/refTransform.spec.ts
packages/ref-transform/src/refTransform.ts

index 5253bcce1983bc61d7400816c7ad891e029b9e03..b120724ff6a18b2db8b519cdb706f97aad95cc18 100644 (file)
@@ -80,6 +80,18 @@ exports[`handle TS casting syntax 1`] = `
       "
 `;
 
+exports[`macro import alias and removal 1`] = `
+"import { ref as _ref, toRef as _toRef } from 'vue'
+
+    
+
+    let a = _ref(1)
+    const __$temp_1 = (useMouse()),
+  x = _toRef(__$temp_1, 'x'),
+  y = _toRef(__$temp_1, 'y')
+    "
+`;
+
 exports[`mixing $ref & $computed declarations 1`] = `
 "import { ref as _ref, computed as _computed } from 'vue'
 
index 712a234027a0d99d9ce018c53b84a862b49356d3..5fffcd5d6d236e3983a0719020d71299e29d2c23 100644 (file)
@@ -362,6 +362,22 @@ test('handle TS casting syntax', () => {
   assertCode(code)
 })
 
+test('macro import alias and removal', () => {
+  const { code } = transform(
+    `
+    import { $ as fromRefs, $ref } from 'vue/macros'
+
+    let a = $ref(1)
+    const { x, y } = fromRefs(useMouse())
+    `
+  )
+  // should remove imports
+  expect(code).not.toMatch(`from 'vue/macros'`)
+  expect(code).toMatch(`let a = _ref(1)`)
+  expect(code).toMatch(`const __$temp_1 = (useMouse())`)
+  assertCode(code)
+})
+
 describe('errors', () => {
   test('$ref w/ destructure', () => {
     expect(() => transform(`let { a } = $ref(1)`)).toThrow(
index 1acdca74d1ca97c2da36bb62c6444ec08ae73a0a..6a94f3b58a5f1ffd2c69a6691d5e38ac6fae4000 100644 (file)
@@ -22,7 +22,7 @@ import {
 import { parse, ParserPlugin } from '@babel/parser'
 import { hasOwn, isArray, isString } from '@vue/shared'
 
-const TO_VAR_SYMBOL = '$'
+const CONVERT_SYMBOL = '$'
 const ESCAPE_SYMBOL = '$$'
 const shorthands = ['ref', 'computed', 'shallowRef', 'toRef', 'customRef']
 const transformCheckRE = /[^\w]\$(?:\$|ref|computed|shallowRef)?\s*(\(|\<)/
@@ -114,10 +114,44 @@ export function transformAST(
   // TODO remove when out of experimental
   warnExperimental()
 
+  let convertSymbol = CONVERT_SYMBOL
+  let escapeSymbol = ESCAPE_SYMBOL
+
+  // macro import handling
+  for (const node of ast.body) {
+    if (
+      node.type === 'ImportDeclaration' &&
+      node.source.value === 'vue/macros'
+    ) {
+      // remove macro imports
+      s.remove(node.start! + offset, node.end! + offset)
+      // check aliasing
+      for (const specifier of node.specifiers) {
+        if (specifier.type === 'ImportSpecifier') {
+          const imported = (specifier.imported as Identifier).name
+          const local = specifier.local.name
+          if (local !== imported) {
+            if (imported === ESCAPE_SYMBOL) {
+              escapeSymbol = local
+            } else if (imported === CONVERT_SYMBOL) {
+              convertSymbol = local
+            } else {
+              error(
+                `macro imports for ref-creating methods do not support aliasing.`,
+                specifier
+              )
+            }
+          }
+        }
+      }
+    }
+  }
+
   const importedHelpers = new Set<string>()
   const rootScope: Scope = {}
   const scopeStack: Scope[] = [rootScope]
   let currentScope: Scope = rootScope
+  let escapeScope: CallExpression | undefined // inside $$()
   const excludedIds = new WeakSet<Identifier>()
   const parentStack: Node[] = []
   const propsLocalToPublicMap = Object.create(null)
@@ -135,6 +169,16 @@ export function transformAST(
     }
   }
 
+  function isRefCreationCall(callee: string): string | false {
+    if (callee === convertSymbol) {
+      return convertSymbol
+    }
+    if (callee[0] === '$' && shorthands.includes(callee.slice(1))) {
+      return callee
+    }
+    return false
+  }
+
   function error(msg: string, node: Node) {
     const e = new Error(msg)
     ;(e as any).node = node
@@ -174,20 +218,16 @@ export function transformAST(
       if (stmt.type === 'VariableDeclaration') {
         if (stmt.declare) continue
         for (const decl of stmt.declarations) {
-          let toVarCall
+          let refCall
           const isCall =
             decl.init &&
             decl.init.type === 'CallExpression' &&
             decl.init.callee.type === 'Identifier'
           if (
             isCall &&
-            (toVarCall = isToVarCall((decl as any).init.callee.name))
+            (refCall = isRefCreationCall((decl as any).init.callee.name))
           ) {
-            processRefDeclaration(
-              toVarCall,
-              decl.id,
-              decl.init as CallExpression
-            )
+            processRefDeclaration(refCall, decl.id, decl.init as CallExpression)
           } else {
             const isProps =
               isRoot &&
@@ -220,7 +260,7 @@ export function transformAST(
     call: CallExpression
   ) {
     excludedIds.add(call.callee as Identifier)
-    if (method === TO_VAR_SYMBOL) {
+    if (method === convertSymbol) {
       // $
       // remove macro
       s.remove(call.callee.start! + offset, call.callee.end! + offset)
@@ -491,9 +531,6 @@ export function transformAST(
 
   // check root scope first
   walkScope(ast, true)
-
-  // inside $$()
-  let escapeScope: CallExpression | undefined
   ;(walk as any)(ast, {
     enter(node: Node, parent?: Node) {
       parent && parentStack.push(parent)
@@ -544,16 +581,16 @@ export function transformAST(
       if (node.type === 'CallExpression' && node.callee.type === 'Identifier') {
         const callee = node.callee.name
 
-        const toVarCall = isToVarCall(callee)
-        if (toVarCall && (!parent || parent.type !== 'VariableDeclarator')) {
+        const refCall = isRefCreationCall(callee)
+        if (refCall && (!parent || parent.type !== 'VariableDeclarator')) {
           return error(
-            `${toVarCall} can only be used as the initializer of ` +
+            `${refCall} can only be used as the initializer of ` +
               `a variable declaration.`,
             node
           )
         }
 
-        if (callee === ESCAPE_SYMBOL) {
+        if (callee === escapeSymbol) {
           s.remove(node.callee.start! + offset, node.callee.end! + offset)
           escapeScope = node
         }
@@ -596,16 +633,6 @@ export function transformAST(
   }
 }
 
-function isToVarCall(callee: string): string | false {
-  if (callee === TO_VAR_SYMBOL) {
-    return TO_VAR_SYMBOL
-  }
-  if (callee[0] === TO_VAR_SYMBOL && shorthands.includes(callee.slice(1))) {
-    return callee
-  }
-  return false
-}
-
 const RFC_LINK = `https://github.com/vuejs/rfcs/discussions/369`
 const hasWarned: Record<string, boolean> = {}