]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor(compiler): extract shared ast transform utils
authorEvan You <yyx990803@gmail.com>
Sun, 22 Aug 2021 17:24:16 +0000 (13:24 -0400)
committerEvan You <yyx990803@gmail.com>
Sun, 22 Aug 2021 17:24:16 +0000 (13:24 -0400)
Also improve referenced identifier check using isReferenced from  @babel/types

packages/compiler-core/src/transforms/transformExpression.ts
packages/compiler-sfc/src/compileScript.ts
packages/runtime-core/src/helpers/refSugar.ts
packages/shared/src/astUtils.ts [new file with mode: 0644]
packages/shared/src/index.ts

index 71e4b76cb18f6d64b9e16f26e902f77e91ac6b7e..4efd6d4aab90f11fce402cfcd24aacba8679b676 100644 (file)
@@ -23,14 +23,17 @@ import {
   makeMap,
   babelParserDefaultPlugins,
   hasOwn,
-  isString
+  isString,
+  isReferencedIdentifier,
+  isInDestructureAssignment,
+  isStaticProperty,
+  isStaticPropertyKey,
+  isFunctionType
 } from '@vue/shared'
 import { createCompilerError, ErrorCodes } from '../errors'
 import {
   Node,
-  Function,
   Identifier,
-  ObjectProperty,
   AssignmentExpression,
   UpdateExpression
 } from '@babel/types'
@@ -279,7 +282,7 @@ export function processExpression(
             ids.push(node)
           }
         }
-      } else if (isFunction(node)) {
+      } else if (isFunctionType(node)) {
         // walk function expressions and add its arguments to known identifiers
         // so that we don't prefix them
         node.params.forEach(p =>
@@ -372,97 +375,16 @@ export function processExpression(
   return ret
 }
 
-const isFunction = (node: Node): node is Function => {
-  return /Function(?:Expression|Declaration)$|Method$/.test(node.type)
-}
-
-const isStaticProperty = (node: Node): node is ObjectProperty =>
-  node &&
-  (node.type === 'ObjectProperty' || node.type === 'ObjectMethod') &&
-  !node.computed
-
-const isStaticPropertyKey = (node: Node, parent: Node) =>
-  isStaticProperty(parent) && parent.key === node
-
 function shouldPrefix(id: Identifier, parent: Node, parentStack: Node[]) {
-  // declaration id
-  if (
-    (parent.type === 'VariableDeclarator' ||
-      parent.type === 'ClassDeclaration') &&
-    parent.id === id
-  ) {
-    return false
-  }
-
-  if (isFunction(parent)) {
-    // function decalration/expression id
-    if ((parent as any).id === id) {
-      return false
-    }
-    // params list
-    if (parent.params.includes(id)) {
-      return false
-    }
-  }
-
-  // property key
-  // this also covers object destructure pattern
-  if (isStaticPropertyKey(id, parent)) {
-    return false
-  }
-
-  // non-assignment array destructure pattern
-  if (
-    parent.type === 'ArrayPattern' &&
-    !isInDestructureAssignment(parent, parentStack)
-  ) {
-    return false
-  }
-
-  // member expression property
-  if (
-    (parent.type === 'MemberExpression' ||
-      parent.type === 'OptionalMemberExpression') &&
-    parent.property === id &&
-    !parent.computed
-  ) {
-    return false
-  }
-
-  // is a special keyword but parsed as identifier
-  if (id.name === 'arguments') {
-    return false
-  }
-
   // skip whitelisted globals
   if (isGloballyWhitelisted(id.name)) {
     return false
   }
-
   // special case for webpack compilation
   if (id.name === 'require') {
     return false
   }
-
-  return true
-}
-
-function isInDestructureAssignment(parent: Node, parentStack: Node[]): boolean {
-  if (
-    parent &&
-    (parent.type === 'ObjectProperty' || parent.type === 'ArrayPattern')
-  ) {
-    let i = parentStack.length
-    while (i--) {
-      const p = parentStack[i]
-      if (p.type === 'AssignmentExpression') {
-        return true
-      } else if (p.type !== 'ObjectProperty' && !p.type.endsWith('Pattern')) {
-        break
-      }
-    }
-  }
-  return false
+  return isReferencedIdentifier(id, parent, parentStack)
 }
 
 function stringifyExpression(exp: ExpressionNode | string): string {
index 5aa8a9f5533b0079a9a22c04c79a8c8034023aea..1e560fe8dacf95431e125c3a705b3dc8f8ad8066 100644 (file)
@@ -22,6 +22,10 @@ import {
   camelize,
   capitalize,
   generateCodeFrame,
+  isFunctionType,
+  isReferencedIdentifier,
+  isStaticProperty,
+  isStaticPropertyKey,
   makeMap
 } from '@vue/shared'
 import {
@@ -32,7 +36,6 @@ import {
   ArrayPattern,
   Identifier,
   ExportSpecifier,
-  Function as FunctionNode,
   TSType,
   TSTypeLiteral,
   TSFunctionType,
@@ -1028,7 +1031,7 @@ export function compileScript(
     ) {
       ;(walk as any)(node, {
         enter(child: Node, parent: Node) {
-          if (isFunction(child)) {
+          if (isFunctionType(child)) {
             this.skip()
           }
           if (child.type === 'AwaitExpression') {
@@ -1819,11 +1822,11 @@ export function walkIdentifiers(
       if (node.type === 'Identifier') {
         if (
           !knownIds[node.name] &&
-          isRefIdentifier(node, parent!, parentStack)
+          isReferencedIdentifier(node, parent!, parentStack)
         ) {
           onIdentifier(node, parent!, parentStack)
         }
-      } else if (isFunction(node)) {
+      } else if (isFunctionType(node)) {
         // #3445
         // should not rewrite local variables sharing a name with a top-level ref
         if (node.body.type === 'BlockStatement') {
@@ -1881,79 +1884,6 @@ export function walkIdentifiers(
   })
 }
 
-function isRefIdentifier(
-  id: Identifier,
-  parent: Node | null,
-  parentStack: Node[]
-) {
-  if (!parent) {
-    return true
-  }
-
-  // declaration id
-  if (
-    (parent.type === 'VariableDeclarator' ||
-      parent.type === 'ClassDeclaration') &&
-    parent.id === id
-  ) {
-    return false
-  }
-
-  if (isFunction(parent)) {
-    // function decalration/expression id
-    if ((parent as any).id === id) {
-      return false
-    }
-    // params list
-    if (parent.params.includes(id)) {
-      return false
-    }
-  }
-
-  // property key
-  // this also covers object destructure pattern
-  if (isStaticPropertyKey(id, parent)) {
-    return false
-  }
-
-  // non-assignment array destructure pattern
-  if (
-    parent.type === 'ArrayPattern' &&
-    !isInDestructureAssignment(parent, parentStack)
-  ) {
-    return false
-  }
-
-  // member expression property
-  if (
-    (parent.type === 'MemberExpression' ||
-      parent.type === 'OptionalMemberExpression') &&
-    parent.property === id &&
-    !parent.computed
-  ) {
-    return false
-  }
-
-  // is a special keyword but parsed as identifier
-  if (id.name === 'arguments') {
-    return false
-  }
-
-  return true
-}
-
-const isStaticProperty = (node: Node): node is ObjectProperty =>
-  node &&
-  (node.type === 'ObjectProperty' || node.type === 'ObjectMethod') &&
-  !node.computed
-
-const isStaticPropertyKey = (node: Node, parent: Node) =>
-  isStaticProperty(parent) && parent.key === node
-
-function isFunction(node: Node): node is FunctionNode {
-  return /Function(?:Expression|Declaration)$|Method$/.test(node.type)
-}
-
 function isCallOf(
   node: Node | null | undefined,
   test: string | ((id: string) => boolean)
index b9d8d7c9b6722123714101161e4eee6130f354a9..45d0c399e2cf67f4cf585d01efcd5a3e5fc1f0e3 100644 (file)
@@ -8,27 +8,29 @@ import {
   WritableComputedRef
 } from '@vue/reactivity'
 
-export function $ref<T>(arg: T | Ref<T>): UnwrapRef<T>
+declare const RefMarker: unique symbol
+type RefValue<T> = T & { [RefMarker]?: any }
+
+export function $ref<T>(arg?: T | Ref<T>): RefValue<UnwrapRef<T>>
 export function $ref() {}
 
-export function $shallowRef<T>(arg: T): T {
-  return arg
-}
+export function $shallowRef<T>(arg?: T): RefValue<T>
+export function $shallowRef() {}
 
 declare const ComputedRefMarker: unique symbol
-type ComputedValue<T> = T & { [ComputedRefMarker]?: any }
+type ComputedRefValue<T> = T & { [ComputedRefMarker]?: any }
 
 declare const WritableComputedRefMarker: unique symbol
-type WritableComputedValue<T> = T & { [WritableComputedRefMarker]?: any }
+type WritableComputedRefValue<T> = T & { [WritableComputedRefMarker]?: any }
 
 export function $computed<T>(
   getter: () => T,
   debuggerOptions?: DebuggerOptions
-): ComputedValue<T>
+): ComputedRefValue<T>
 export function $computed<T>(
   options: WritableComputedOptions<T>,
   debuggerOptions?: DebuggerOptions
-): WritableComputedValue<T>
+): WritableComputedRefValue<T>
 export function $computed() {}
 
 export function $fromRefs<T>(source: T): ShallowUnwrapRef<T>
@@ -36,9 +38,13 @@ export function $fromRefs() {
   return null as any
 }
 
-export function $raw<T>(value: ComputedValue<T>): ComputedRef<T>
-export function $raw<T>(value: WritableComputedValue<T>): WritableComputedRef<T>
-export function $raw<T>(value: T): Ref<T>
+export function $raw<T extends ComputedRefValue<any>>(
+  value: T
+): T extends ComputedRefValue<infer V> ? ComputedRef<V> : never
+export function $raw<T>(
+  value: WritableComputedRefValue<T>
+): WritableComputedRef<T>
+export function $raw<T>(value: RefValue<T>): Ref<T>
 export function $raw() {
   return null as any
 }
diff --git a/packages/shared/src/astUtils.ts b/packages/shared/src/astUtils.ts
new file mode 100644 (file)
index 0000000..cb01c8e
--- /dev/null
@@ -0,0 +1,72 @@
+import {
+  Identifier,
+  Node,
+  isReferenced,
+  Function,
+  ObjectProperty
+} from '@babel/types'
+
+export function isReferencedIdentifier(
+  id: Identifier,
+  parent: Node | null,
+  parentStack: Node[]
+) {
+  if (!parent) {
+    return true
+  }
+
+  // is a special keyword but parsed as identifier
+  if (id.name === 'arguments') {
+    return false
+  }
+
+  if (isReferenced(id, parent)) {
+    return true
+  }
+
+  // babel's isReferenced check returns false for ids being assigned to, so we
+  // need to cover those cases here
+  switch (parent.type) {
+    case 'AssignmentExpression':
+    case 'AssignmentPattern':
+      return true
+    case 'ObjectPattern':
+    case 'ArrayPattern':
+      return isInDestructureAssignment(parent, parentStack)
+  }
+
+  return false
+}
+
+export function isInDestructureAssignment(
+  parent: Node,
+  parentStack: Node[]
+): boolean {
+  if (
+    parent &&
+    (parent.type === 'ObjectProperty' || parent.type === 'ArrayPattern')
+  ) {
+    let i = parentStack.length
+    while (i--) {
+      const p = parentStack[i]
+      if (p.type === 'AssignmentExpression') {
+        return true
+      } else if (p.type !== 'ObjectProperty' && !p.type.endsWith('Pattern')) {
+        break
+      }
+    }
+  }
+  return false
+}
+
+export const isFunctionType = (node: Node): node is Function => {
+  return /Function(?:Expression|Declaration)$|Method$/.test(node.type)
+}
+
+export const isStaticProperty = (node: Node): node is ObjectProperty =>
+  node &&
+  (node.type === 'ObjectProperty' || node.type === 'ObjectMethod') &&
+  !node.computed
+
+export const isStaticPropertyKey = (node: Node, parent: Node) =>
+  isStaticProperty(parent) && parent.key === node
index 8c98b3b6cc4f255ef451b2098640b01a5c69c80b..0bd2df43802daa3fb0f27c0f4bdad81a675ffbff 100644 (file)
@@ -12,6 +12,7 @@ export * from './domAttrConfig'
 export * from './escapeHtml'
 export * from './looseEqual'
 export * from './toDisplayString'
+export * from './astUtils'
 
 /**
  * List of @babel/parser plugins that are used for template expression