utils.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import { isGloballyAllowed } from '@vue/shared'
  2. import {
  3. type AttributeNode,
  4. type BindingMetadata,
  5. BindingTypes,
  6. type ElementNode,
  7. NodeTypes,
  8. type SimpleExpressionNode,
  9. findDir as _findDir,
  10. findProp as _findProp,
  11. createSimpleExpression,
  12. isConstantNode,
  13. isLiteralWhitelisted,
  14. } from '@vue/compiler-dom'
  15. import type { VaporDirectiveNode } from './ir'
  16. import { EMPTY_EXPRESSION } from './transforms/utils'
  17. import type { TransformContext } from './transform'
  18. export const findProp = _findProp as (
  19. node: ElementNode,
  20. name: string,
  21. dynamicOnly?: boolean,
  22. allowEmpty?: boolean,
  23. ) => AttributeNode | VaporDirectiveNode | undefined
  24. /** find directive */
  25. export const findDir = _findDir as (
  26. node: ElementNode,
  27. name: string | RegExp,
  28. allowEmpty?: boolean,
  29. ) => VaporDirectiveNode | undefined
  30. export function propToExpression(
  31. prop: AttributeNode | VaporDirectiveNode,
  32. ): SimpleExpressionNode | undefined {
  33. return prop.type === NodeTypes.ATTRIBUTE
  34. ? prop.value
  35. ? createSimpleExpression(prop.value.content, true, prop.value.loc)
  36. : EMPTY_EXPRESSION
  37. : prop.exp
  38. }
  39. export function isConstantExpression(exp: SimpleExpressionNode): boolean {
  40. return (
  41. isLiteralWhitelisted(exp.content) ||
  42. isGloballyAllowed(exp.content) ||
  43. getLiteralExpressionValue(exp) !== null
  44. )
  45. }
  46. export function isStaticExpression(
  47. node: SimpleExpressionNode,
  48. bindings: BindingMetadata,
  49. ): boolean {
  50. if (node.ast) {
  51. return isConstantNode(node.ast, bindings)
  52. } else if (node.ast === null) {
  53. if (
  54. !node.isStatic &&
  55. (node.content === 'true' || node.content === 'false')
  56. ) {
  57. return true
  58. }
  59. const type = bindings[node.content]
  60. return type === BindingTypes.LITERAL_CONST
  61. }
  62. return false
  63. }
  64. export function resolveExpression(
  65. exp: SimpleExpressionNode,
  66. isComponent?: boolean,
  67. ): SimpleExpressionNode {
  68. if (!exp.isStatic) {
  69. const value = getLiteralExpressionValue(exp, isComponent)
  70. if (value !== null) {
  71. return createSimpleExpression(value, true, exp.loc)
  72. }
  73. }
  74. return exp
  75. }
  76. export function getLiteralExpressionValue(
  77. exp: SimpleExpressionNode,
  78. excludeNumber?: boolean,
  79. ): string | null {
  80. if (exp.ast) {
  81. if (exp.ast.type === 'StringLiteral') {
  82. return exp.ast.value
  83. } else if (
  84. !excludeNumber &&
  85. (exp.ast.type === 'NumericLiteral' || exp.ast.type === 'BigIntLiteral')
  86. ) {
  87. return String(exp.ast.value)
  88. } else if (exp.ast.type === 'TemplateLiteral') {
  89. let result = ''
  90. for (const [index, quasi] of exp.ast.quasis.entries()) {
  91. result += quasi.value.cooked!
  92. if (exp.ast.expressions[index]) {
  93. let expressionValue = getLiteralExpressionValue({
  94. ast: exp.ast.expressions[index],
  95. } as SimpleExpressionNode)
  96. if (expressionValue == null) {
  97. return null
  98. } else {
  99. result += expressionValue
  100. }
  101. }
  102. }
  103. return result
  104. }
  105. }
  106. return exp.isStatic ? exp.content : null
  107. }
  108. export function isInTransition(
  109. context: TransformContext<ElementNode>,
  110. ): boolean {
  111. const parentNode = context.parent && context.parent.node
  112. return !!(parentNode && isTransitionNode(parentNode as ElementNode))
  113. }
  114. export function isTransitionNode(node: ElementNode): boolean {
  115. return node.type === NodeTypes.ELEMENT && isTransitionTag(node.tag)
  116. }
  117. export function isTransitionGroupNode(node: ElementNode): boolean {
  118. return node.type === NodeTypes.ELEMENT && isTransitionGroupTag(node.tag)
  119. }
  120. export function isTransitionTag(tag: string): boolean {
  121. tag = tag.toLowerCase()
  122. return tag === 'transition' || tag === 'vaportransition'
  123. }
  124. export function isTransitionGroupTag(tag: string): boolean {
  125. tag = tag.toLowerCase().replace(/-/g, '')
  126. return tag === 'transitiongroup' || tag === 'vaportransitiongroup'
  127. }
  128. export function isKeepAliveTag(tag: string): boolean {
  129. tag = tag.toLowerCase()
  130. return tag === 'keepalive' || tag === 'vaporkeepalive'
  131. }
  132. export function isTeleportTag(tag: string): boolean {
  133. tag = tag.toLowerCase()
  134. return tag === 'teleport' || tag === 'vaporteleport'
  135. }
  136. export function isBuiltInComponent(tag: string): string | undefined {
  137. if (isTeleportTag(tag)) {
  138. return 'VaporTeleport'
  139. } else if (isKeepAliveTag(tag)) {
  140. return 'VaporKeepAlive'
  141. } else if (isTransitionTag(tag)) {
  142. return 'VaporTransition'
  143. } else if (isTransitionGroupTag(tag)) {
  144. return 'VaporTransitionGroup'
  145. }
  146. }