utils.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import {
  2. CallExpression,
  3. Expression,
  4. Identifier,
  5. ImportDefaultSpecifier,
  6. ImportNamespaceSpecifier,
  7. ImportSpecifier,
  8. Node,
  9. StringLiteral
  10. } from '@babel/types'
  11. import path from 'path'
  12. import { TS_NODE_TYPES } from '@vue/compiler-dom'
  13. export const UNKNOWN_TYPE = 'Unknown'
  14. export function resolveObjectKey(node: Node, computed: boolean) {
  15. switch (node.type) {
  16. case 'StringLiteral':
  17. case 'NumericLiteral':
  18. return String(node.value)
  19. case 'Identifier':
  20. if (!computed) return node.name
  21. }
  22. return undefined
  23. }
  24. export function concatStrings(strs: Array<string | null | undefined | false>) {
  25. return strs.filter((s): s is string => !!s).join(', ')
  26. }
  27. export function isLiteralNode(node: Node) {
  28. return node.type.endsWith('Literal')
  29. }
  30. export function unwrapTSNode(node: Node): Node {
  31. if (TS_NODE_TYPES.includes(node.type)) {
  32. return unwrapTSNode((node as any).expression)
  33. } else {
  34. return node
  35. }
  36. }
  37. export function isCallOf(
  38. node: Node | null | undefined,
  39. test: string | ((id: string) => boolean) | null | undefined
  40. ): node is CallExpression {
  41. return !!(
  42. node &&
  43. test &&
  44. node.type === 'CallExpression' &&
  45. node.callee.type === 'Identifier' &&
  46. (typeof test === 'string'
  47. ? node.callee.name === test
  48. : test(node.callee.name))
  49. )
  50. }
  51. export function toRuntimeTypeString(types: string[]) {
  52. return types.length > 1 ? `[${types.join(', ')}]` : types[0]
  53. }
  54. export function getImportedName(
  55. specifier: ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier
  56. ) {
  57. if (specifier.type === 'ImportSpecifier')
  58. return specifier.imported.type === 'Identifier'
  59. ? specifier.imported.name
  60. : specifier.imported.value
  61. else if (specifier.type === 'ImportNamespaceSpecifier') return '*'
  62. return 'default'
  63. }
  64. export function getId(node: Identifier | StringLiteral): string
  65. export function getId(node: Expression): string | null
  66. export function getId(node: Expression) {
  67. return node.type === 'Identifier'
  68. ? node.name
  69. : node.type === 'StringLiteral'
  70. ? node.value
  71. : null
  72. }
  73. const identity = (str: string) => str
  74. const fileNameLowerCaseRegExp = /[^\u0130\u0131\u00DFa-z0-9\\/:\-_\. ]+/g
  75. const toLowerCase = (str: string) => str.toLowerCase()
  76. function toFileNameLowerCase(x: string) {
  77. return fileNameLowerCaseRegExp.test(x)
  78. ? x.replace(fileNameLowerCaseRegExp, toLowerCase)
  79. : x
  80. }
  81. /**
  82. * We need `getCanonicalFileName` when creating ts module resolution cache,
  83. * but TS does not expose it directly. This implementation is repllicated from
  84. * the TS source code.
  85. */
  86. export function createGetCanonicalFileName(useCaseSensitiveFileNames: boolean) {
  87. return useCaseSensitiveFileNames ? identity : toFileNameLowerCase
  88. }
  89. // in the browser build, the polyfill doesn't expose posix, but defaults to
  90. // posix behavior.
  91. const normalize = (path.posix || path).normalize
  92. const windowsSlashRE = /\\/g
  93. export function normalizePath(p: string) {
  94. return normalize(p.replace(windowsSlashRE, '/'))
  95. }
  96. export const joinPaths = (path.posix || path).join