directive.ts 2.7 KB

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