block.ts 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import { isArray } from '@vue/shared'
  2. import { type VaporComponentInstance, isVaporComponent } from './component'
  3. import { createComment } from './dom/element'
  4. export type Block = Node | Fragment | VaporComponentInstance | Block[]
  5. export class Fragment {
  6. nodes: Block
  7. anchor?: Node
  8. constructor(nodes: Block, anchorLabel?: string) {
  9. this.nodes = nodes
  10. if (anchorLabel) {
  11. this.anchor = __DEV__
  12. ? createComment(anchorLabel)
  13. : // eslint-disable-next-line no-restricted-globals
  14. document.createTextNode('')
  15. }
  16. }
  17. }
  18. export function isFragment(val: NonNullable<unknown>): val is Fragment {
  19. return val instanceof Fragment
  20. }
  21. export function isBlock(val: NonNullable<unknown>): val is Block {
  22. return (
  23. val instanceof Node ||
  24. isArray(val) ||
  25. isVaporComponent(val) ||
  26. isFragment(val)
  27. )
  28. }
  29. /*! #__NO_SIDE_EFFECTS__ */
  30. // TODO this should be optimized away
  31. export function normalizeBlock(block: Block): Node[] {
  32. const nodes: Node[] = []
  33. if (block instanceof Node) {
  34. nodes.push(block)
  35. } else if (isArray(block)) {
  36. block.forEach(child => nodes.push(...normalizeBlock(child)))
  37. } else if (isVaporComponent(block)) {
  38. nodes.push(...normalizeBlock(block.block!))
  39. } else if (block) {
  40. nodes.push(...normalizeBlock(block.nodes))
  41. block.anchor && nodes.push(block.anchor)
  42. }
  43. return nodes
  44. }
  45. export function findFirstRootElement(
  46. instance: VaporComponentInstance,
  47. ): Element | undefined {
  48. const element = getFirstNode(instance.block)
  49. return element instanceof Element ? element : undefined
  50. }
  51. export function getFirstNode(block: Block | null): Node | undefined {
  52. if (!block || isVaporComponent(block)) return
  53. if (block instanceof Node) return block
  54. if (isArray(block)) {
  55. if (block.length === 1) {
  56. return getFirstNode(block[0])
  57. }
  58. } else {
  59. return getFirstNode(block.nodes)
  60. }
  61. }
  62. // TODO optimize
  63. export function isValidBlock(block: Block): boolean {
  64. return (
  65. normalizeBlock(block).filter(node => !(node instanceof Comment)).length > 0
  66. )
  67. }