vBind.ts 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import type { DirectiveTransform } from '../transform'
  2. import {
  3. type ExpressionNode,
  4. NodeTypes,
  5. createObjectProperty,
  6. createSimpleExpression,
  7. } from '../ast'
  8. import { ErrorCodes, createCompilerError } from '../errors'
  9. import { camelize } from '@vue/shared'
  10. import { CAMELIZE } from '../runtimeHelpers'
  11. // v-bind without arg is handled directly in ./transformElement.ts due to its affecting
  12. // codegen for the entire props object. This transform here is only for v-bind
  13. // *with* args.
  14. export const transformBind: DirectiveTransform = (dir, _node, context) => {
  15. const { modifiers, loc } = dir
  16. const arg = dir.arg!
  17. let { exp } = dir
  18. // handle empty expression
  19. if (exp && exp.type === NodeTypes.SIMPLE_EXPRESSION && !exp.content.trim()) {
  20. if (!__BROWSER__) {
  21. // #10280 only error against empty expression in non-browser build
  22. // because :foo in in-DOM templates will be parsed into :foo="" by the
  23. // browser
  24. context.onError(
  25. createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc),
  26. )
  27. return {
  28. props: [
  29. createObjectProperty(arg, createSimpleExpression('', true, loc)),
  30. ],
  31. }
  32. } else {
  33. exp = undefined
  34. }
  35. }
  36. if (arg.type !== NodeTypes.SIMPLE_EXPRESSION) {
  37. arg.children.unshift(`(`)
  38. arg.children.push(`) || ""`)
  39. } else if (!arg.isStatic) {
  40. arg.content = arg.content ? `${arg.content} || ""` : `""`
  41. }
  42. // .sync is replaced by v-model:arg
  43. if (modifiers.some(mod => mod.content === 'camel')) {
  44. if (arg.type === NodeTypes.SIMPLE_EXPRESSION) {
  45. if (arg.isStatic) {
  46. arg.content = camelize(arg.content)
  47. } else {
  48. arg.content = `${context.helperString(CAMELIZE)}(${arg.content})`
  49. }
  50. } else {
  51. arg.children.unshift(`${context.helperString(CAMELIZE)}(`)
  52. arg.children.push(`)`)
  53. }
  54. }
  55. if (!context.inSSR) {
  56. if (modifiers.some(mod => mod.content === 'prop')) {
  57. injectPrefix(arg, '.')
  58. }
  59. if (modifiers.some(mod => mod.content === 'attr')) {
  60. injectPrefix(arg, '^')
  61. }
  62. }
  63. return {
  64. props: [createObjectProperty(arg, exp!)],
  65. }
  66. }
  67. const injectPrefix = (arg: ExpressionNode, prefix: string) => {
  68. if (arg.type === NodeTypes.SIMPLE_EXPRESSION) {
  69. if (arg.isStatic) {
  70. arg.content = prefix + arg.content
  71. } else {
  72. arg.content = `\`${prefix}\${${arg.content}}\``
  73. }
  74. } else {
  75. arg.children.unshift(`'${prefix}' + (`)
  76. arg.children.push(`)`)
  77. }
  78. }