utils.ts 4.6 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1
import {
fxy060608's avatar
fxy060608 已提交
2
  conditionalExpression,
fxy060608's avatar
fxy060608 已提交
3 4 5 6
  Expression,
  Identifier,
  identifier,
  isIdentifier,
fxy060608's avatar
fxy060608 已提交
7
  isLiteral,
fxy060608's avatar
fxy060608 已提交
8
  isReferenced,
fxy060608's avatar
fxy060608 已提交
9
  isTemplateLiteral,
fxy060608's avatar
fxy060608 已提交
10
  MemberExpression,
fxy060608's avatar
fxy060608 已提交
11
  numericLiteral,
fxy060608's avatar
fxy060608 已提交
12 13
  objectProperty,
  SpreadElement,
fxy060608's avatar
fxy060608 已提交
14
  stringLiteral,
fxy060608's avatar
fxy060608 已提交
15 16 17 18 19
} from '@babel/types'
import {
  createSimpleExpression,
  ExpressionNode,
  NodeTypes,
fxy060608's avatar
fxy060608 已提交
20
  SimpleExpressionNode,
fxy060608's avatar
fxy060608 已提交
21 22 23 24 25
  SourceLocation,
} from '@vue/compiler-core'
import { walk, BaseNode } from 'estree-walker'
import { isUndefined, parseExpr } from '../ast'
import { genBabelExpr, genExpr } from '../codegen'
fxy060608's avatar
fxy060608 已提交
26
import { CodegenScope } from '../options'
fxy060608's avatar
fxy060608 已提交
27
import { isVForScope, isVIfScope, TransformContext } from '../transform'
fxy060608's avatar
fxy060608 已提交
28

fxy060608's avatar
fxy060608 已提交
29 30 31 32
export const ATTR_VUE_ID = 'v-i'
export const ATTR_VUE_SLOTS = 'v-s'
export const SCOPED_SLOT_IDENTIFIER = '__SCOPED_SLOT__'

fxy060608's avatar
fxy060608 已提交
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
export function rewriteSpreadElement(
  name: symbol,
  expr: SpreadElement,
  loc: SourceLocation,
  context: TransformContext
) {
  return rewirteWithHelper(name, expr.argument, loc, context)
}

export function rewirteWithHelper(
  name: symbol,
  expr: Expression,
  loc: SourceLocation,
  context: TransformContext
) {
  return parseExprWithRewrite(
    context.helperString(name) + '(' + genBabelExpr(expr) + ')',
    loc,
    context
  )
}

export function parseExprWithRewrite(
  code: string,
  loc: SourceLocation,
  context: TransformContext,
  node?: Expression
) {
  return parseExpr(
    rewriteExpression(createSimpleExpression(code, false, loc), context, node),
    context
  ) as Identifier | MemberExpression | undefined
}

fxy060608's avatar
fxy060608 已提交
67 68 69 70 71 72 73 74 75 76 77 78
export function parseExprWithRewriteClass(
  code: string,
  loc: SourceLocation,
  context: TransformContext,
  node: Expression
) {
  // a?1:0
  return parseExpr(
    rewriteExpression(
      createSimpleExpression(code, false, loc),
      context,
      !isUndefined(node)
fxy060608's avatar
fxy060608 已提交
79
        ? conditionalExpression(node, numericLiteral(1), stringLiteral(''))
fxy060608's avatar
fxy060608 已提交
80 81 82 83 84 85
        : node
    ),
    context
  ) as Identifier | MemberExpression | undefined
}

fxy060608's avatar
fxy060608 已提交
86
export function rewriteExpressionWithoutProperty(
fxy060608's avatar
fxy060608 已提交
87 88 89 90
  node: ExpressionNode,
  context: TransformContext,
  babelNode?: Expression,
  scope: CodegenScope = context.currentScope
fxy060608's avatar
fxy060608 已提交
91
) {
fxy060608's avatar
fxy060608 已提交
92 93 94 95
  return rewriteExpression(node, context, babelNode, scope, {
    property: false,
    ignoreLiteral: false,
  })
fxy060608's avatar
fxy060608 已提交
96 97 98 99 100 101
}
export function rewriteExpression(
  node: ExpressionNode,
  context: TransformContext,
  babelNode?: Expression,
  scope: CodegenScope = context.currentScope,
fxy060608's avatar
fxy060608 已提交
102
  { property, ignoreLiteral } = { property: true, ignoreLiteral: false }
fxy060608's avatar
fxy060608 已提交
103 104 105 106 107 108 109 110 111 112 113
) {
  if (node.type === NodeTypes.SIMPLE_EXPRESSION && node.isStatic) {
    return node
  }
  if (!babelNode) {
    const code = genExpr(node)
    babelNode = parseExpr(code, context, node)
    if (!babelNode) {
      return createSimpleExpression(code)
    }
  }
fxy060608's avatar
fxy060608 已提交
114 115 116
  if (!ignoreLiteral && isStaticLiteral(babelNode)) {
    return node as SimpleExpressionNode
  }
fxy060608's avatar
fxy060608 已提交
117 118 119 120
  if (isUndefined(babelNode)) {
    return createSimpleExpression('undefined', false, node.loc)
  }

fxy060608's avatar
fxy060608 已提交
121 122 123 124 125 126 127
  // wxs 等表达式
  if (context.filters?.length) {
    if (isReferencedByIds(babelNode, context.filters)) {
      return createSimpleExpression(genExpr(node), false, node.loc)
    }
  }

fxy060608's avatar
fxy060608 已提交
128
  scope = findReferencedScope(babelNode, scope)
fxy060608's avatar
fxy060608 已提交
129
  const id = scope.id.next()
fxy060608's avatar
fxy060608 已提交
130 131 132
  if (property) {
    scope.properties.push(objectProperty(identifier(id), babelNode!))
  }
fxy060608's avatar
fxy060608 已提交
133 134 135 136
  // 在v-for中包含的v-if块,所有变量需要补充当前v-for value前缀
  if (isVIfScope(scope)) {
    if (isVForScope(scope.parentScope)) {
      return createSimpleExpression(scope.parentScope.valueAlias + '.' + id)
fxy060608's avatar
fxy060608 已提交
137
    }
fxy060608's avatar
fxy060608 已提交
138 139 140
    return createSimpleExpression(id)
  } else if (isVForScope(scope)) {
    return createSimpleExpression(scope.valueAlias + '.' + id)
fxy060608's avatar
fxy060608 已提交
141 142 143 144
  }
  return createSimpleExpression(id)
}

fxy060608's avatar
fxy060608 已提交
145
function findReferencedScope(
fxy060608's avatar
fxy060608 已提交
146 147
  node: Expression,
  scope: CodegenScope
fxy060608's avatar
fxy060608 已提交
148 149 150 151
): CodegenScope {
  if (isVIfScope(scope)) {
    return scope
  } else if (isVForScope(scope)) {
fxy060608's avatar
fxy060608 已提交
152
    if (isReferencedByIds(node, scope.locals)) {
fxy060608's avatar
fxy060608 已提交
153 154
      return scope
    }
fxy060608's avatar
fxy060608 已提交
155
    return findReferencedScope(node, scope.parent!)
fxy060608's avatar
fxy060608 已提交
156
  }
fxy060608's avatar
fxy060608 已提交
157
  return scope
fxy060608's avatar
fxy060608 已提交
158 159
}

fxy060608's avatar
fxy060608 已提交
160
function isReferencedByIds(node: Expression, knownIds: string[]) {
fxy060608's avatar
fxy060608 已提交
161 162 163 164 165 166 167 168 169 170 171
  let referenced = false
  walk(node as unknown as BaseNode, {
    enter(node: BaseNode, parent: BaseNode) {
      if (referenced) {
        return this.skip()
      }
      if (!isIdentifier(node)) {
        return
      }
      if (
        knownIds.includes(node.name) &&
fxy060608's avatar
fxy060608 已提交
172
        (!parent || isReferenced(node, parent as any))
fxy060608's avatar
fxy060608 已提交
173 174 175 176 177 178 179 180
      ) {
        referenced = true
        return this.skip()
      }
    },
  })
  return referenced
}
fxy060608's avatar
fxy060608 已提交
181 182 183 184

export function isStaticLiteral(value: object | null | undefined) {
  return isLiteral(value) && !isTemplateLiteral(value)
}