Categories
interview

HTMLElement to Virtual DOM and back

/**
 * @param {HTMLElement} 
 * @return {object} object literal presentation
 */
function virtualize(element) {
  if (element.nodeType === 3)
    return element.textContent;
  const ret = {
    type: element.tagName.toLowerCase(),
    props: {
      children: []
    }
  };
  element.childNodes.forEach(child => ret.props.children.push(virtualize(child)));
  if (ret.props.children.length === 1)
    ret.props.children = ret.props.children[0];
  for (const {
      name,
      value
    } of element.attributes)
    ret.props[name === 'class' ? 'className' : name] = value;
  return ret;
}

/**
 * @param {object} valid object literal presentation
 * @return {HTMLElement} 
 */
function render(obj) {
  if (typeof obj === 'string') return document.createTextNode(obj);
  const {
    type,
    props: {
      children,
      ...attributes
    }
  } = obj;
  const ret = document.createElement(type);
  const childNodes = typeof children === 'string' ? [children] : children;
  childNodes.forEach(childNode => ret.append(render(childNode)));
  for (const [key, val] of Object.entries(attributes)) {
    ret.setAttribute(key === 'className' ? 'class' : key, val)
  }
  return ret;
}

Demo