directive.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import { createSimpleExpression, isSimpleIdentifier } from '@vue/compiler-dom'
  2. import { camelize } from '@vue/shared'
  3. import { genExpression } from './expression'
  4. import type { CodegenContext } from '../generate'
  5. import { type CodeFragment, NEWLINE, genCall, genMulti } from './utils'
  6. import {
  7. IRNodeTypes,
  8. type OperationNode,
  9. type WithDirectiveIRNode,
  10. } from '../ir'
  11. export function genDirectivesForElement(id: number, context: CodegenContext) {
  12. const dirs = filterDirectives(id, context.block.operation)
  13. return dirs.length ? genWithDirective(dirs, context) : []
  14. }
  15. export function genWithDirective(
  16. opers: WithDirectiveIRNode[],
  17. context: CodegenContext,
  18. ): CodeFragment[] {
  19. const { vaporHelper } = context
  20. const element = `n${opers[0].element}`
  21. const directiveItems = opers.map(genDirective)
  22. const directives = genMulti(['[', ']', ', '], ...directiveItems)
  23. return [
  24. NEWLINE,
  25. ...genCall(vaporHelper('withDirectives'), element, directives),
  26. ]
  27. function genDirective({ dir, builtin }: WithDirectiveIRNode): CodeFragment[] {
  28. const NULL = 'void 0'
  29. const directive = genDirective()
  30. const value = dir.exp
  31. ? ['() => ', ...genExpression(dir.exp, context)]
  32. : dir.arg || dir.modifiers.length
  33. ? NULL
  34. : false
  35. const argument = dir.arg
  36. ? genExpression(dir.arg, context)
  37. : dir.modifiers.length
  38. ? NULL
  39. : false
  40. const modifiers = dir.modifiers.length
  41. ? ['{ ', genDirectiveModifiers(dir.modifiers), ' }']
  42. : false
  43. return genMulti(['[', ']', ', '], directive, value, argument, modifiers)
  44. function genDirective() {
  45. const {
  46. vaporHelper,
  47. options: { bindingMetadata },
  48. } = context
  49. if (dir.name === 'show') {
  50. return [vaporHelper('vShow')]
  51. } else if (builtin) {
  52. return [vaporHelper(builtin)]
  53. } else {
  54. const directiveReference = camelize(`v-${dir.name}`)
  55. // TODO resolve directive
  56. if (bindingMetadata[directiveReference]) {
  57. const directiveExpression = createSimpleExpression(directiveReference)
  58. directiveExpression.ast = null
  59. return genExpression(directiveExpression, context)
  60. } else {
  61. return `${vaporHelper('resolveDirective')}("${directiveReference}")`
  62. }
  63. }
  64. }
  65. }
  66. }
  67. export function genDirectiveModifiers(modifiers: string[]) {
  68. return modifiers
  69. .map(
  70. value =>
  71. `${isSimpleIdentifier(value) ? value : JSON.stringify(value)}: true`,
  72. )
  73. .join(', ')
  74. }
  75. function filterDirectives(
  76. id: number,
  77. operations: OperationNode[],
  78. ): WithDirectiveIRNode[] {
  79. return operations.filter(
  80. (oper): oper is WithDirectiveIRNode =>
  81. oper.type === IRNodeTypes.WITH_DIRECTIVE && oper.element === id,
  82. )
  83. }