"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _parse = require("parse5");

var _utils = require("../utils");

var _default = options => function process(html) {
  const sources = [];
  const document = (0, _parse.parse)(html, {
    sourceCodeLocationInfo: true,
    scriptingEnabled: options.sources.scriptingEnabled
  });
  let needIgnore = false;
  (0, _utils.traverse)(document, node => {
    const {
      tagName,
      attrs: attributes,
      sourceCodeLocation
    } = node;

    if (node.nodeName === "#comment") {
      const match = node.data.match(_utils.webpackIgnoreCommentRegexp);

      if (match) {
        needIgnore = match[2] === "true";
      }

      return;
    }

    if (!tagName) {
      return;
    }

    if (needIgnore) {
      needIgnore = false;
      return;
    }

    attributes.forEach(attribute => {
      let {
        name
      } = attribute;
      name = attribute.prefix ? `${attribute.prefix}:${name}` : name;
      const handlers = new Map([...(options.sources.list.get("*") || new Map()), ...(options.sources.list.get(tagName.toLowerCase()) || new Map())]);

      if (handlers.size === 0) {
        return;
      }

      const handler = handlers.get(name.toLowerCase());

      if (!handler) {
        return;
      }

      if (handler.filter && !handler.filter(tagName, name, attributes, options.resourcePath)) {
        return;
      }

      const attributeAndValue = html.slice(sourceCodeLocation.attrs[name].startOffset, sourceCodeLocation.attrs[name].endOffset);
      const isValueQuoted = attributeAndValue[attributeAndValue.length - 1] === '"' || attributeAndValue[attributeAndValue.length - 1] === "'";
      const valueStartOffset = sourceCodeLocation.attrs[name].startOffset + attributeAndValue.indexOf(attribute.value);
      const valueEndOffset = sourceCodeLocation.attrs[name].endOffset - (isValueQuoted ? 1 : 0);
      const optionsForTypeFn = {
        tag: tagName,
        startTag: {
          startOffset: sourceCodeLocation.startTag.startOffset,
          endOffset: sourceCodeLocation.startTag.endOffset
        },
        endTag: sourceCodeLocation.endTag ? {
          startOffset: sourceCodeLocation.endTag.startOffset,
          endOffset: sourceCodeLocation.endTag.endOffset
        } : // eslint-disable-next-line no-undefined
        undefined,
        attributes,
        attribute: name,
        attributePrefix: attribute.prefix,
        attributeNamespace: attribute.namespace,
        attributeStartOffset: sourceCodeLocation.attrs[name].startOffset,
        attributeEndOffset: sourceCodeLocation.attrs[name].endOffset,
        value: attribute.value,
        isValueQuoted,
        valueEndOffset,
        valueStartOffset,
        html
      };
      let result;

      try {
        result = handler.type(optionsForTypeFn);
      } catch (error) {
        options.errors.push(error);
      }

      result = Array.isArray(result) ? result : [result];

      for (const source of result) {
        if (!source) {
          // eslint-disable-next-line no-continue
          continue;
        }

        sources.push({ ...source,
          name,
          isValueQuoted
        });
      }
    });
  });
  const urlFilter = (0, _utils.getFilter)(options.sources.urlFilter);
  const imports = new Map();
  const replacements = new Map();
  let offset = 0;

  for (const source of sources) {
    const {
      name,
      value,
      isValueQuoted,
      format,
      runtime,
      startOffset,
      endOffset
    } = source;
    let request = value;

    if (!urlFilter(name, value, options.resourcePath)) {
      // eslint-disable-next-line no-continue
      continue;
    }

    let hash;
    const indexHash = request.lastIndexOf("#");

    if (indexHash >= 0) {
      hash = request.substring(indexHash);
      request = request.substring(0, indexHash);
    }

    request = (0, _utils.requestify)(options.context, request);
    let importName = imports.get(request);

    if (!importName) {
      importName = `___HTML_LOADER_IMPORT_${imports.size}___`;
      imports.set(request, importName);
      options.imports.push({
        format,
        importName,
        request
      });
    }

    const replacementKey = JSON.stringify({
      request,
      isValueQuoted,
      hash
    });
    let replacementName = replacements.get(replacementKey);

    if (!replacementName) {
      replacementName = `___HTML_LOADER_REPLACEMENT_${replacements.size}___`;
      replacements.set(replacementKey, replacementName);
      options.replacements.push({
        replacementName,
        importName,
        hash,
        isValueQuoted,
        runtime
      });
    } // eslint-disable-next-line no-param-reassign


    html = html.slice(0, startOffset + offset) + replacementName + html.slice(endOffset + offset);
    offset += startOffset + replacementName.length - endOffset;
  }

  return html;
};

exports.default = _default;