prefixIdentifiers.ts 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import MagicString from 'magic-string'
  2. import { parseExpression, ParserOptions, ParserPlugin } from '@babel/parser'
  3. import { makeMap } from 'shared/util'
  4. import { isStaticProperty, walkIdentifiers } from './babelUtils'
  5. import { BindingMetadata } from './types'
  6. const doNotPrefix = makeMap(
  7. 'Infinity,undefined,NaN,isFinite,isNaN,' +
  8. 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +
  9. 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' +
  10. 'require,' + // for webpack
  11. 'arguments,' + // parsed as identifier but is a special keyword...
  12. '_c' // cached to save property access
  13. )
  14. /**
  15. * The input is expected to be a valid expression.
  16. */
  17. export function prefixIdentifiers(
  18. source: string,
  19. isFunctional = false,
  20. isTS = false,
  21. babelOptions: ParserOptions = {},
  22. bindings?: BindingMetadata
  23. ) {
  24. const s = new MagicString(source)
  25. const plugins: ParserPlugin[] = [
  26. ...(isTS ? (['typescript'] as const) : []),
  27. ...(babelOptions?.plugins || [])
  28. ]
  29. const ast = parseExpression(source, {
  30. ...babelOptions,
  31. plugins
  32. })
  33. const isScriptSetup = bindings && bindings.__isScriptSetup !== false
  34. walkIdentifiers(
  35. ast,
  36. (ident, parent) => {
  37. const { name } = ident
  38. if (doNotPrefix(name)) {
  39. return
  40. }
  41. let prefix = `_vm.`
  42. if (isScriptSetup) {
  43. const type = bindings[name]
  44. if (type && type.startsWith('setup')) {
  45. prefix = `_setup.`
  46. }
  47. }
  48. if (isStaticProperty(parent) && parent.shorthand) {
  49. // property shorthand like { foo }, we need to add the key since
  50. // we rewrite the value
  51. // { foo } -> { foo: _vm.foo }
  52. s.appendLeft(ident.end!, `: ${prefix}${name}`)
  53. } else {
  54. s.prependRight(ident.start!, prefix)
  55. }
  56. },
  57. node => {
  58. if (node.type === 'WithStatement') {
  59. s.remove(node.start!, node.body.start! + 1)
  60. s.remove(node.end! - 1, node.end!)
  61. if (!isFunctional) {
  62. s.prependRight(
  63. node.start!,
  64. `var _vm=this,_c=_vm._self._c${
  65. isScriptSetup ? `,_setup=_vm._self._setupProxy;` : `;`
  66. }`
  67. )
  68. }
  69. }
  70. }
  71. )
  72. return s.toString()
  73. }