# src/Bindings/DomBinding/typeObserver.js

    import YXmlText from '../../Types/YXml/YXmlText.js'
    import YXmlHook from '../../Types/YXml/YXmlHook.js'
    import { removeDomChildrenUntilElementFound } from './util.js'

    /**
     * @private
     */
    export default function typeObserver (events) {
      this._mutualExclude(() => {
        events.forEach(event => {
          const yxml = event.target
          const dom = this.typeToDom.get(yxml)
          if (dom !== undefined && dom !== false) {
            if (yxml.constructor === YXmlText) {
              dom.nodeValue = yxml.toString()
              // TODO: use hasOwnProperty instead of === undefined check
            } else if (event.attributesChanged !== undefined) {
              // update attributes
              event.attributesChanged.forEach(attributeName => {
                const value = yxml.getAttribute(attributeName)
                if (value === undefined) {
                  dom.removeAttribute(attributeName)
                } else {
                  dom.setAttribute(attributeName, value)
                }
              })
              /*
               * TODO: instead of hard-checking the types, it would be best to
               *       specify the type's features. E.g.
               *         - _yxmlHasAttributes
               *         - _yxmlHasChildren
               *       Furthermore, the features shouldn't be encoded in the types,
               *       only in the attributes (above)
               */
              if (event.childListChanged && yxml.constructor !== YXmlHook) {
                let currentChild = dom.firstChild
                yxml.forEach(childType => {
                  const childNode = this.typeToDom.get(childType)
                  switch (childNode) {
                    case undefined:
                      // Does not exist. Create it.
                      const node = childType.toDom(this.opts.document, this.opts.hooks, this)
                      dom.insertBefore(node, currentChild)
                      break
                    case false:
                      // nop
                      break
                    default:
                      // Is already attached to the dom.
                      // Find it and remove all dom nodes in-between.
                      removeDomChildrenUntilElementFound(dom, currentChild, childNode)
                      currentChild = childNode.nextSibling
                      break
                  }
                })
                removeDomChildrenUntilElementFound(dom, currentChild, null)
              }
            }
          }
        })
      })
    }