"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
var _slugid = _interopRequireDefault(require("slugid"));
var _typeOf = _interopRequireDefault(require("type-of"));
var _constants = require("./constants");
var _rules = _interopRequireDefault(require("./rules"));
var _helper = require("./helper");
const cruftNewline = element => {
  return !(element.nodeName === '#text' && element.nodeValue === '\n');
};
const deserializeElement = element => {
  let node;
  const next = elements => {
    if (Object.prototype.toString.call(elements) === '[object NodeList]') {
      elements = Array.from(elements);
    }
    switch ((0, _typeOf.default)(elements)) {
      case 'array':
        return deserializeElements(elements);
      case 'object':
        return deserializeElement(elements);
      case 'null':
      case 'undefined':
        return;
      default:
        throw new Error(`The \`next\` argument was called with invalid children: "${elements}".`);
    }
  };
  for (let i = 0; i < _rules.default.length; i++) {
    const rule = _rules.default[i];
    if (!rule) continue;
    const ret = rule(element, next);
    const type = (0, _typeOf.default)(ret);
    if (type !== 'array' && type !== 'object' && type !== 'null' && type !== 'undefined') {
      throw new Error(`A rule returned an invalid deserialized representation: "${node}".`);
    }

    // Not eligible for current component processing
    if (ret === undefined) {
      continue;
    }

    // Empty tags will be discarded and not converted accordingly
    if (ret === null) {
      return null;
    }

    // Assign the final processing result to node
    node = ret;
    break;
  }

  // If node is undefined, it means that the label is not processed, and continue to process the child nodes of the element
  return node || next(element.childNodes);
};
const deserializeElements = function () {
  let elements = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  let isTopLevel = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
  let nodes = [];
  elements.filter(cruftNewline).forEach(element => {
    const node = deserializeElement(element);
    switch ((0, _typeOf.default)(node)) {
      case 'array':
        const formatNode = isTopLevel ? formatElementNodes(node) : node;
        nodes = nodes.concat(formatNode);
        break;
      case 'object':
        nodes.push(node);
        break;
      default:
      // nothing todo
    }
  });
  return (0, _helper.formatInlineNodes)(nodes);
};
const formatElementNodes = nodes => {
  if (nodes.length === 0) {
    return [{
      id: _slugid.default.nice(),
      type: _constants.PARAGRAPH,
      children: [{
        text: '',
        id: _slugid.default.nice()
      }]
    }];
  }
  nodes = nodes.reduce((memo, node) => {
    if (_constants.TOP_LEVEL_TYPES.includes(node.type)) {
      memo.push(node);
    }
    if (node.type === _constants.LIST_ITEM) {
      const newNode = {
        id: _slugid.default.nice(),
        type: _constants.UNORDERED_LIST,
        children: [node]
      };
      memo.push(newNode);
      return memo;
    }

    // The following types will not appear individually during the pasting process
    // code_line
    // table_row | table_cell

    // text | image | link
    if (!node.type || _constants.INLINE_LEVEL_TYPES.includes(node.type)) {
      let prevNode = memo[memo.length - 1];
      if (prevNode && prevNode.type === _constants.PARAGRAPH) {
        prevNode.children.push(node);
        return memo;
      }
      const newNode = {
        id: _slugid.default.nice(),
        type: _constants.PARAGRAPH,
        children: [node]
      };
      memo.push(newNode);
      return memo;
    }
    return memo;
  }, []);
  return nodes;
};
const deserializeHtml = html => {
  const parsed = new DOMParser().parseFromString(html, 'text/html');
  const fragment = parsed.body;
  const children = Array.from(fragment.childNodes);
  let nodes = [];
  nodes = deserializeElements(children, true);
  nodes = formatElementNodes(nodes);
  return nodes;
};
var _default = exports.default = deserializeHtml;