text: 'use strict';
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.filterEscapeSync = exports.filterEscape = exports.filterSync = exports.filter = exports.escapeSync = exports.escape = undefined;
  
  var _keys = require('babel-runtime/core-js/object/keys');
  
  var _keys2 = _interopRequireDefault(_keys);
  
  var _promise = require('babel-runtime/core-js/promise');
  
  var _promise2 = _interopRequireDefault(_promise);
  
  var _reduce2 = require('lodash/reduce');
  
  var _reduce3 = _interopRequireDefault(_reduce2);
  
  var _includes2 = require('lodash/includes');
  
  var _includes3 = _interopRequireDefault(_includes2);
  
  var _forEach2 = require('lodash/forEach');
  
  var _forEach3 = _interopRequireDefault(_forEach2);
  
  var _curry2 = require('lodash/curry');
  
  var _curry3 = _interopRequireDefault(_curry2);
  
  var _htmlBase = require('./html-base');
  
  Object.defineProperty(exports, 'escape', {
    enumerable: true,
    get: function get() {
      return _htmlBase.escape;
    }
  });
  Object.defineProperty(exports, 'escapeSync', {
    enumerable: true,
    get: function get() {
      return _htmlBase.escapeSync;
    }
  });
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  /**
   * Some browsers don't implement {@link Element#remove()} or
   * {@link NodeList#remove()} or {@link HTMLCollection#remove()}. This wrapper
   * calls the appropriate `#remove()` method if available, or falls back to a
   * non-global-polluting polyfill.
   * @param {Element|NodeList|HTMLCollection} node
   * @returns {undefined}
   */
  function removeNode(node) {
    if (node.remove) {
      node.remove();
  
      return;
    }
  
    if (node.parentElement) {
      node.parentElement.removeChild(node);
  
      return;
    }
  
    if ('length' in node) {
      for (var i = node.length - 1; i >= 0; i -= 1) {
        removeNode(node[i]);
      }
  
      return;
    }
  
    throw new Error('Could not find a way to remove node');
  }
  
  /**
   * @param {Object} allowedTags
   * @param {Array<string>} allowedStyles
   * @param {string} html
   * @private
   * @returns {string}
   */
  function _filter() {
    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }
  
    return new _promise2.default(function (resolve) {
      resolve(_filterSync.apply(undefined, args));
    });
  }
  
  /**
   * Curried async HTML filter.
   * @param {Object} allowedTags Map of tagName -> array of allowed attributes
   * @param {Array<string>} allowedStyles Array of allowed styles
   * @param {string} html html to filter
   * @returns {string}
   */
  var filter = exports.filter = (0, _curry3.default)(_filter, 4);
  
  /**
   * @param {function} processCallback callback function to do additional
   * processing on node. of the form process(node)
   * @param {Object} allowedTags
   * @param {Array<string>} allowedStyles
   * @param {string} html
   * @private
   * @returns {string}
   */
  function _filterSync(processCallback, allowedTags, allowedStyles, html) {
    if (!html || !allowedStyles || !allowedTags) {
      if (html.length === 0) {
        return html;
      }
  
      throw new Error('`allowedTags`, `allowedStyles`, and `html` must be provided');
    }
  
    var doc = new DOMParser().parseFromString(html, 'text/html');
  
    depthFirstForEach(doc.body.childNodes, filterNode);
    processCallback(doc.body);
  
    if (html.indexOf('body') === 1) {
      return '<body>' + doc.body.innerHTML + '</body>';
    }
  
    return doc.body.innerHTML;
  
    /**
     * @param {Node} node
     * @private
     * @returns {undefined}
     */
    function filterNode(node) {
      if (!isElement(node)) {
        return;
      }
  
      var nodeName = node.nodeName.toLowerCase();
      var allowedTagNames = (0, _keys2.default)(allowedTags);
  
      depthFirstForEach(node.childNodes, filterNode);
  
      if ((0, _includes3.default)(allowedTagNames, nodeName)) {
        var allowedAttributes = allowedTags[nodeName];
  
        (0, _forEach3.default)(listAttributeNames(node.attributes), function (attrName) {
          if (!(0, _includes3.default)(allowedAttributes, attrName)) {
            node.removeAttribute(attrName);
          } else if (attrName === 'href' || attrName === 'src') {
            var attrValue = node.attributes.getNamedItem(attrName).value.trim().toLowerCase();
  
            // We're doing at runtime what the no-script-url rule does at compile
            // time
            // eslint-disable-next-line no-script-url
            if (attrValue.indexOf('javascript:') === 0 || attrValue.indexOf('vbscript:') === 0) {
              reparent(node);
            }
          } else if (attrName === 'style') {
            var styles = node.attributes.getNamedItem('style').value.split(';').map(function (style) {
              var styleName = trim(style.split(':')[0]);
  
              if ((0, _includes3.default)(allowedStyles, styleName)) {
                return style;
              }
  
              return null;
            }).filter(function (style) {
              return Boolean(style);
            }).join(';');
  
            node.setAttribute('style', styles);
          }
        });
      } else {
        reparent(node);
      }
    }
  }
  
  /**
   * Same as _filter, but escapes rather than removes disallowed values
   * @param {Function} processCallback
   * @param {Object} allowedTags
   * @param {Array<string>} allowedStyles
   * @param {string} html
   * @returns {Promise<string>}
   */
  function _filterEscape() {
    for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
      args[_key2] = arguments[_key2];
    }
  
    return new _promise2.default(function (resolve) {
      resolve(_filterEscapeSync.apply(undefined, args));
    });
  }
  
  /**
   * Same as _filterSync, but escapes rather than removes disallowed values
   * @param {Function} processCallback
   * @param {Object} allowedTags
   * @param {Array<string>} allowedStyles
   * @param {string} html
   * @returns {string}
   */
  function _filterEscapeSync(processCallback, allowedTags, allowedStyles, html) {
    if (!html || !allowedStyles || !allowedTags) {
      if (html.length === 0) {
        return html;
      }
  
      throw new Error('`allowedTags`, `allowedStyles`, and `html` must be provided');
    }
  
    var doc = new DOMParser().parseFromString(html, 'text/html');
  
    depthFirstForEach(doc.body.childNodes, filterNode);
    processCallback(doc.body);
  
    if (html.indexOf('body') === 1) {
      return '<body>' + doc.body.innerHTML + '</body>';
    }
  
    return doc.body.innerHTML;
  
    /**
     * @param {Node} node
     * @private
     * @returns {undefined}
     */
    function filterNode(node) {
      if (!isElement(node)) {
        return;
      }
  
      depthFirstForEach(node.childNodes, filterNode);
  
      var nodeName = node.nodeName.toLowerCase();
      var allowedTagNames = (0, _keys2.default)(allowedTags);
  
      if ((0, _includes3.default)(allowedTagNames, nodeName)) {
        var allowedAttributes = allowedTags[nodeName];
  
        (0, _forEach3.default)(listAttributeNames(node.attributes), function (attrName) {
          if (!(0, _includes3.default)(allowedAttributes, attrName)) {
            node.removeAttribute(attrName);
          } else if (attrName === 'href' || attrName === 'src') {
            var attrValue = node.attributes.getNamedItem(attrName).value.toLowerCase();
  
            // We're doing at runtime what the no-script-url rule does at compile
            // time
            // eslint-disable-next-line no-script-url
            if (attrValue.indexOf('javascript:') === 0 || attrValue.indexOf('vbscript:') === 0) {
              reparent(node);
            }
          } else if (attrName === 'style') {
            var styles = node.attributes.getNamedItem('style').value.split(';').map(function (style) {
              var styleName = trim(style.split(':')[0]);
  
              if ((0, _includes3.default)(allowedStyles, styleName)) {
                return style;
              }
  
              return null;
            }).filter(function (style) {
              return Boolean(style);
            }).join(';');
  
            node.setAttribute('style', styles);
          }
        });
      } else {
        escapeNode(node);
      }
    }
  }
  
  /**
   * Escapes a given html node
   * @param {Node} node
   * @returns {undefined}
   */
  function escapeNode(node) {
    var before = document.createTextNode('<' + node.nodeName.toLowerCase() + '>');
    var after = document.createTextNode('</' + node.nodeName.toLowerCase() + '>');
  
    node.parentNode.insertBefore(before, node);
    while (node.childNodes.length > 0) {
      node.parentNode.insertBefore(node.childNodes[0], node);
    }
    node.parentNode.insertBefore(after, node);
  
    removeNode(node);
  }
  
  var trimPattern = /^\s|\s$/g;
  
  /**
   * @param {string} str
   * @returns {string}
   */
  function trim(str) {
    return str.replace(trimPattern, '');
  }
  
  /**
   * @param {Node} node
   * @private
   * @returns {undefined}
   */
  function reparent(node) {
    while (node.childNodes.length > 0) {
      node.parentNode.insertBefore(node.childNodes[0], node);
    }
    removeNode(node);
  }
  
  /**
   * @param {NamedNodeMap} attributes
   * @private
   * @returns {Array<string>}
   */
  function listAttributeNames(attributes) {
    return (0, _reduce3.default)(attributes, function (attrNames, attr) {
      attrNames.push(attr.name);
  
      return attrNames;
    }, []);
  }
  
  /**
   * @param {Array} list
   * @param {Function} fn
   * @private
   * @returns {undefined}
   */
  function depthFirstForEach(list, fn) {
    for (var i = list.length; i >= 0; i -= 1) {
      fn(list[i]);
    }
  }
  
  /**
   * @param {Node} o
   * @private
   * @returns {Boolean}
   */
  function isElement(o) {
    if (!o) {
      return false;
    }
  
    if (o.ownerDocument === undefined) {
      return false;
    }
  
    if (o.nodeType !== 1) {
      return false;
    }
  
    if (typeof o.nodeName !== 'string') {
      return false;
    }
  
    return true;
  }
  
  /**
   * Curried HTML filter.
   * @param {Object} allowedTags Map of tagName -> array of allowed attributes
   * @param {Array<string>} allowedStyles Array of allowed styles
   * @param {string} html html to filter
   * @returns {string}
   */
  var filterSync = exports.filterSync = (0, _curry3.default)(_filterSync, 4);
  
  /**
   * Curried HTML filter that escapes rather than removes disallowed tags
   * @param {Object} allowedTags Map of tagName -> array of allowed attributes
   * @param {Array<string>} allowedStyles Array of allowed styles
   * @param {string} html html to filter
   * @returns {Promise<string>}
   */
  var filterEscape = exports.filterEscape = (0, _curry3.default)(_filterEscape, 4);
  
  /**
   * Curried HTML filter that escapes rather than removes disallowed tags
   * @param {Object} allowedTags Map of tagName -> array of allowed attributes
   * @param {Array<string>} allowedStyles Array of allowed styles
   * @param {string} html html to filter
   * @returns {string}
   */
  var filterEscapeSync = exports.filterEscapeSync = (0, _curry3.default)(_filterEscapeSync, 4);
  //# sourceMappingURL=html.shim.js.map
  