All files / compiler-sfc/src/script utils.ts

93% Statements 93/100
91.07% Branches 51/56
87.5% Functions 14/16
93% Lines 93/100

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147                        1x   1x   1x 124x 124x 124x 124x 124x 124x 10x 124x 114x 124x 1x 1x   1x 125x 125x 125x 125x   1x 77x 77x   1x 3462x 3462x 3462x 3462x 3462x 3462x 3247x 1327x 1246x 1076x 170x   3462x   1x 136x 136x   1x 151x       151x 151x 151x 132x 2x 17x 15x 15x       1x 85x 83x 2x 2x   85x   1x 305x 305x 305x 2x 1x 1x 303x 268x 35x 34x 1x 1x   305x   1x 1x 1x                         1x 6x 6x 6x 6x       1x 1x 1x 124x 124x   1x 1x           1x 1x   1x 156x 156x   1x 610x 1x 609x  
import type {
  CallExpression,
  Expression,
  Identifier,
  ImportDefaultSpecifier,
  ImportNamespaceSpecifier,
  ImportSpecifier,
  Node,
  StringLiteral,
  TSMethodSignature,
  TSPropertySignature,
} from '@babel/types'
import path from 'path'
 
export const UNKNOWN_TYPE = 'Unknown'
 
export function resolveObjectKey(
  node: Node,
  computed: boolean,
): string | undefined {
  switch (node.type) {
    case 'StringLiteral':
    case 'NumericLiteral':
      return String(node.value)
    case 'Identifier':
      if (!computed) return node.name
  }
  return undefined
}
 
export function concatStrings(
  strs: Array<string | null | undefined | false>,
): string {
  return strs.filter((s): s is string => !!s).join(', ')
}
 
export function isLiteralNode(node: Node): boolean {
  return node.type.endsWith('Literal')
}
 
export function isCallOf(
  node: Node | null | undefined,
  test: string | ((id: string) => boolean) | null | undefined,
): node is CallExpression {
  return !!(
    node &&
    test &&
    node.type === 'CallExpression' &&
    node.callee.type === 'Identifier' &&
    (typeof test === 'string'
      ? node.callee.name === test
      : test(node.callee.name))
  )
}
 
export function toRuntimeTypeString(types: string[]): string {
  return types.length > 1 ? `[${types.join(', ')}]` : types[0]
}
 
export function getImportedName(
  specifier:
    | ImportSpecifier
    | ImportDefaultSpecifier
    | ImportNamespaceSpecifier,
): string {
  if (specifier.type === 'ImportSpecifier')
    return specifier.imported.type === 'Identifier'
      ? specifier.imported.name
      : specifier.imported.value
  else if (specifier.type === 'ImportNamespaceSpecifier') return '*'
  return 'default'
}
 
export function getId(node: Identifier | StringLiteral): string
export function getId(node: Expression): string | null
export function getId(node: Expression) {
  return node.type === 'Identifier'
    ? node.name
    : node.type === 'StringLiteral'
      ? node.value
      : null
}
 
export function getStringLiteralKey(
  node: TSPropertySignature | TSMethodSignature,
): string | null {
  return node.computed
    ? node.key.type === 'TemplateLiteral' && !node.key.expressions.length
      ? node.key.quasis.map(q => q.value.cooked).join('')
      : null
    : node.key.type === 'Identifier'
      ? node.key.name
      : node.key.type === 'StringLiteral'
        ? node.key.value
        : node.key.type === 'NumericLiteral'
          ? String(node.key.value)
          : null
}
 
const identity = (str: string) => str
const fileNameLowerCaseRegExp = /[^\u0130\u0131\u00DFa-z0-9\\/:\-_\. ]+/g
const toLowerCase = (str: string) => str.toLowerCase()
 
function toFileNameLowerCase(x: string) {
  return fileNameLowerCaseRegExp.test(x)
    ? x.replace(fileNameLowerCaseRegExp, toLowerCase)
    : x
}
 
/**
 * We need `getCanonicalFileName` when creating ts module resolution cache,
 * but TS does not expose it directly. This implementation is replicated from
 * the TS source code.
 */
export function createGetCanonicalFileName(
  useCaseSensitiveFileNames: boolean,
): (str: string) => string {
  return useCaseSensitiveFileNames ? identity : toFileNameLowerCase
}
 
// in the browser build, the polyfill doesn't expose posix, but defaults to
// posix behavior.
const normalize = (path.posix || path).normalize
const windowsSlashRE = /\\/g
export function normalizePath(p: string): string {
  return normalize(p.replace(windowsSlashRE, '/'))
}
 
export const joinPaths: (...paths: string[]) => string = (path.posix || path)
  .join
 
/**
 * key may contain symbols
 * e.g. onUpdate:modelValue -> "onUpdate:modelValue"
 */
export const propNameEscapeSymbolsRE: RegExp =
  /[ !"#$%&'()*+,./:;<=>?@[\\\]^`{|}~\-]/
 
export function getEscapedPropName(key: string): string {
  return propNameEscapeSymbolsRE.test(key) ? JSON.stringify(key) : key
}
 
export const isJS = (...langs: (string | null | undefined)[]): boolean =>
  langs.some(lang => lang === 'js' || lang === 'jsx')
export const isTS = (...langs: (string | null | undefined)[]): boolean =>
  langs.some(lang => lang === 'ts' || lang === 'tsx')