Просмотр исходного кода

feat(compiler-vapor): resolve dynamic expression

三咲智子 Kevin Deng 2 лет назад
Родитель
Сommit
697102f796

+ 2 - 4
packages/compiler-vapor/src/generators/expression.ts

@@ -5,11 +5,9 @@ import {
   type SourceLocation,
   advancePositionWithClone,
   isInDestructureAssignment,
-  isLiteralWhitelisted,
   isStaticProperty,
   walkIdentifiers,
 } from '@vue/compiler-dom'
-import { isGloballyAllowed } from '@vue/shared'
 import type { Identifier } from '@babel/types'
 import {
   type CodeFragment,
@@ -17,6 +15,7 @@ import {
   buildCodeFragment,
 } from '../generate'
 import type { Node } from '@babel/types'
+import { isConstantExpression } from '../utils'
 
 export function genExpression(
   node: SimpleExpressionNode,
@@ -37,8 +36,7 @@ export function genExpression(
     !node.content.trim() ||
     // there was a parsing error
     ast === false ||
-    isGloballyAllowed(rawExpr) ||
-    isLiteralWhitelisted(rawExpr)
+    isConstantExpression(node)
   ) {
     return [[rawExpr, NewlineType.None, loc]]
   }

+ 2 - 11
packages/compiler-vapor/src/transform.ts

@@ -14,7 +14,6 @@ import {
   createSimpleExpression,
   defaultOnError,
   defaultOnWarn,
-  isLiteralWhitelisted,
   isVSlot,
 } from '@vue/compiler-dom'
 import { EMPTY_OBJ, NOOP, extend, isArray, isString } from '@vue/shared'
@@ -28,6 +27,7 @@ import {
   type RootIRNode,
   type VaporDirectiveNode,
 } from './ir'
+import { isConstantExpression } from './utils'
 
 export type NodeTransform = (
   node: RootNode | TemplateChildNode,
@@ -154,16 +154,7 @@ function createRootContext(
       return (this.dynamic.id = this.increaseId())
     },
     registerEffect(expressions, operations) {
-      expressions = expressions.filter(exp => {
-        // filter static expressions
-        if (!__BROWSER__) {
-          if (isLiteralWhitelisted(exp.content)) return false
-          if (exp.ast)
-            // also filter out string and number literals
-            return !['StringLiteral', 'NumericLiteral'].includes(exp.ast.type)
-        }
-        return !exp.isStatic
-      })
+      expressions = expressions.filter(exp => !isConstantExpression(exp))
       if (this.inVOnce || expressions.length === 0) {
         return this.registerOperation(...operations)
       }

+ 4 - 13
packages/compiler-vapor/src/transforms/transformElement.ts

@@ -72,14 +72,6 @@ function buildProps(
   const dynamicExpr: SimpleExpressionNode[] = []
   let results: DirectiveTransformResult[] = []
 
-  function pushDynamicExpressions(
-    ...exprs: (SimpleExpressionNode | undefined)[]
-  ) {
-    for (const expr of exprs) {
-      if (expr && !expr.isStatic) dynamicExpr.push(expr)
-    }
-  }
-
   function pushMergeArg() {
     if (results.length) {
       dynamicArgs.push(dedupeProperties(results))
@@ -94,7 +86,7 @@ function buildProps(
       !prop.arg
     ) {
       if (prop.exp) {
-        pushDynamicExpressions(prop.exp)
+        dynamicExpr.push(prop.exp)
         pushMergeArg()
         dynamicArgs.push(prop.exp)
       } else {
@@ -108,7 +100,7 @@ function buildProps(
     const result = transformProp(prop, node, context)
     if (result) {
       results.push(result)
-      pushDynamicExpressions(result.key, result.value)
+      dynamicExpr.push(result.key, result.value)
     }
   }
 
@@ -131,12 +123,11 @@ function buildProps(
         context.template += ` ${key.content}`
         if (values[0].content) context.template += `="${values[0].content}"`
       } else {
-        const expressions = values.filter(v => !v.isStatic)
-        context.registerEffect(expressions, [
+        context.registerEffect(values, [
           {
             type: IRNodeTypes.SET_PROP,
             element: context.reference(),
-            prop: prop,
+            prop,
           },
         ])
       }

+ 5 - 2
packages/compiler-vapor/src/transforms/vBind.ts

@@ -7,6 +7,7 @@ import {
 } from '@vue/compiler-dom'
 import { camelize, isReservedProp } from '@vue/shared'
 import type { DirectiveTransform, TransformContext } from '../transform'
+import { resolveExpression } from '../utils'
 
 // same-name shorthand - :arg is expanded to :arg="arg"
 export function normalizeBindShorthand(
@@ -33,10 +34,9 @@ export function normalizeBindShorthand(
 export const transformVBind: DirectiveTransform = (dir, node, context) => {
   const { loc, modifiers } = dir
   let { exp } = dir
-  const arg = dir.arg!
+  let arg = dir.arg!
 
   if (!exp) exp = normalizeBindShorthand(arg, context)
-
   if (!exp.content.trim()) {
     if (!__BROWSER__) {
       // #10280 only error against empty expression in non-browser build
@@ -49,6 +49,9 @@ export const transformVBind: DirectiveTransform = (dir, node, context) => {
     exp = createSimpleExpression('', true, loc)
   }
 
+  exp = resolveExpression(exp)
+  arg = resolveExpression(arg)
+
   if (arg.isStatic && isReservedProp(arg.content)) return
   let camel = false
   if (modifiers.includes('camel')) {

+ 3 - 5
packages/compiler-vapor/src/transforms/vOn.ts

@@ -7,6 +7,7 @@ import type { DirectiveTransform } from '../transform'
 import { IRNodeTypes, type KeyOverride, type SetEventIRNode } from '../ir'
 import { resolveModifiers } from '@vue/compiler-dom'
 import { camelize, extend } from '@vue/shared'
+import { resolveExpression } from '../utils'
 
 export const transformVOn: DirectiveTransform = (dir, node, context) => {
   let { arg, exp, loc, modifiers } = dir
@@ -21,6 +22,7 @@ export const transformVOn: DirectiveTransform = (dir, node, context) => {
     return
   }
 
+  arg = resolveExpression(arg)
   if (arg.isStatic) {
     if (node.tagType !== ElementTypes.ELEMENT || !/[A-Z]/.test(arg.content)) {
       arg.content = camelize(arg.content)
@@ -70,9 +72,5 @@ export const transformVOn: DirectiveTransform = (dir, node, context) => {
     keyOverride,
   }
 
-  if (arg.isStatic) {
-    context.registerOperation(operation)
-  } else {
-    context.registerEffect([arg], [operation])
-  }
+  context.registerEffect([arg], [operation])
 }

+ 35 - 0
packages/compiler-vapor/src/utils.ts

@@ -1,12 +1,16 @@
+import { isGloballyAllowed } from '@vue/shared'
 import {
   type AttributeNode,
   type ElementNode,
   NodeTypes,
+  type SimpleExpressionNode,
   findProp as _findProp,
   createSimpleExpression,
+  isLiteralWhitelisted,
 } from '@vue/compiler-dom'
 import type { VaporDirectiveNode } from './ir'
 import { EMPTY_EXPRESSION } from './transform'
+import type { NumericLiteral, StringLiteral } from '@babel/types'
 
 export const findProp = _findProp as (
   node: ElementNode,
@@ -22,3 +26,34 @@ export function propToExpression(prop: AttributeNode | VaporDirectiveNode) {
       : EMPTY_EXPRESSION
     : prop.exp
 }
+
+export function isConstantExpression(exp: SimpleExpressionNode) {
+  return (
+    isLiteralWhitelisted(exp.content) ||
+    isGloballyAllowed(exp.content) ||
+    getLiteralExpressionValue(exp) !== null
+  )
+}
+
+export function resolveExpression(exp: SimpleExpressionNode) {
+  if (!exp.isStatic) {
+    const value = getLiteralExpressionValue(exp)
+    if (value !== null) {
+      return createSimpleExpression('' + value, true, exp.loc)
+    }
+  }
+  return exp
+}
+
+export function getLiteralExpressionValue(
+  exp: SimpleExpressionNode,
+): number | string | null {
+  if (
+    !__BROWSER__ &&
+    exp.ast &&
+    ['StringLiteral', 'NumericLiteral'].includes(exp.ast.type)
+  ) {
+    return (exp.ast as StringLiteral | NumericLiteral).value
+  }
+  return exp.isStatic ? exp.content : null
+}