"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
function _assert() {
  const data = _interopRequireDefault(require("assert"));
  _assert = function () {
    return data;
  };
  return data;
}
function _stream() {
  const data = require("stream");
  _stream = function () {
    return data;
  };
  return data;
}
function _plugin() {
  const data = require("@parcel/plugin");
  _plugin = function () {
    return data;
  };
  return data;
}
function _utils() {
  const data = require("@parcel/utils");
  _utils = function () {
    return data;
  };
  return data;
}
function _posthtml() {
  const data = _interopRequireDefault(require("posthtml"));
  _posthtml = function () {
    return data;
  };
  return data;
}
function _nullthrows() {
  const data = _interopRequireDefault(require("nullthrows"));
  _nullthrows = function () {
    return data;
  };
  return data;
}
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// https://www.w3.org/TR/html5/dom.html#metadata-content-2
const metadataContent = new Set(['base', 'link', 'meta', 'noscript',
// 'script', // retain script order (somewhat)
'style', 'template', 'title']);
var _default = exports.default = new (_plugin().Packager)({
  async loadConfig({
    config
  }) {
    var _posthtmlConfig$conte;
    let posthtmlConfig = await config.getConfig(['.posthtmlrc', '.posthtmlrc.js', '.posthtmlrc.cjs', '.posthtmlrc.mjs', 'posthtml.config.js', 'posthtml.config.cjs', 'posthtml.config.mjs'], {
      packageKey: 'posthtml'
    });
    return {
      render: posthtmlConfig === null || posthtmlConfig === void 0 || (_posthtmlConfig$conte = posthtmlConfig.contents) === null || _posthtmlConfig$conte === void 0 ? void 0 : _posthtmlConfig$conte.render
    };
  },
  async package({
    bundle,
    bundleGraph,
    getInlineBundleContents,
    config
  }) {
    let assets = [];
    bundle.traverseAssets(asset => {
      assets.push(asset);
    });
    _assert().default.equal(assets.length, 1, 'HTML bundles must only contain one asset');
    let asset = assets[0];
    let code = await asset.getCode();

    // Add bundles in the same bundle group that are not inline. For example, if two inline
    // bundles refer to the same library that is extracted into a shared bundle.
    let referencedBundles = [...(0, _utils().setDifference)(new Set(bundleGraph.getReferencedBundles(bundle)), new Set(bundleGraph.getReferencedBundles(bundle, {
      recursive: false
    })))];
    let renderConfig = config === null || config === void 0 ? void 0 : config.render;
    let {
      html
    } = await (0, _posthtml().default)([tree => insertBundleReferences(referencedBundles, tree), tree => replaceInlineAssetContent(bundleGraph, getInlineBundleContents, tree)]).process(code, {
      ...renderConfig,
      xmlMode: bundle.type === 'xhtml',
      closingSingleTag: bundle.type === 'xhtml' ? 'slash' : undefined
    });
    let {
      contents,
      map
    } = (0, _utils().replaceURLReferences)({
      bundle,
      bundleGraph,
      contents: html,
      relative: false,
      getReplacement: contents => contents.replace(/"/g, '"')
    });
    return (0, _utils().replaceInlineReferences)({
      bundle,
      bundleGraph,
      contents,
      getInlineBundleContents,
      getInlineReplacement: (dep, inlineType, contents) => ({
        from: dep.id,
        to: contents.replace(/"/g, '"').trim()
      }),
      map
    });
  }
});
async function getAssetContent(bundleGraph, getInlineBundleContents, assetId) {
  let inlineBundle;
  bundleGraph.traverseBundles((bundle, context, {
    stop
  }) => {
    let entryAssets = bundle.getEntryAssets();
    if (entryAssets.some(a => a.uniqueKey === assetId)) {
      inlineBundle = bundle;
      stop();
    }
  });
  if (inlineBundle) {
    const bundleResult = await getInlineBundleContents(inlineBundle, bundleGraph);
    return {
      bundle: inlineBundle,
      contents: bundleResult.contents
    };
  }
  return null;
}
async function replaceInlineAssetContent(bundleGraph, getInlineBundleContents, tree) {
  const inlineNodes = [];
  tree.walk(node => {
    if (node.attrs && node.attrs['data-parcel-key']) {
      inlineNodes.push(node);
    }
    return node;
  });
  for (let node of inlineNodes) {
    let newContent = await getAssetContent(bundleGraph, getInlineBundleContents, node.attrs['data-parcel-key']);
    if (newContent != null) {
      let {
        contents,
        bundle
      } = newContent;
      node.content = (contents instanceof _stream().Readable ? await (0, _utils().bufferStream)(contents) : contents).toString();
      if (node.tag === 'script' && (0, _nullthrows().default)(bundle).env.outputFormat === 'esmodule') {
        node.attrs.type = 'module';
      }

      // Escape closing script tags and HTML comments in JS content.
      // https://www.w3.org/TR/html52/semantics-scripting.html#restrictions-for-contents-of-script-elements
      // Avoid replacing </script with <\/script as it would break the following valid JS: 0</script/ (i.e. regexp literal).
      // Instead, escape the s character.
      if (node.tag === 'script') {
        node.content = node.content.replace(/<!--/g, '<\\!--').replace(/<\/(script)/gi, '</\\$1');
      }

      // Escape closing style tags in CSS content.
      if (node.tag === 'style') {
        node.content = node.content.replace(/<\/(style)/gi, '<\\/$1');
      }

      // remove attr from output
      delete node.attrs['data-parcel-key'];
    }
  }
  return tree;
}
function insertBundleReferences(siblingBundles, tree) {
  const bundles = [];
  for (let bundle of siblingBundles) {
    if (bundle.type === 'css') {
      bundles.push({
        tag: 'link',
        attrs: {
          rel: 'stylesheet',
          href: (0, _utils().urlJoin)(bundle.target.publicUrl, bundle.name)
        }
      });
    } else if (bundle.type === 'js') {
      let nomodule = bundle.env.outputFormat !== 'esmodule' && bundle.env.sourceType === 'module' && bundle.env.shouldScopeHoist;
      bundles.push({
        tag: 'script',
        attrs: {
          type: bundle.env.outputFormat === 'esmodule' ? 'module' : undefined,
          nomodule: nomodule ? '' : undefined,
          defer: nomodule ? '' : undefined,
          src: (0, _utils().urlJoin)(bundle.target.publicUrl, bundle.name)
        }
      });
    }
  }
  addBundlesToTree(bundles, tree);
}
function addBundlesToTree(bundles, tree) {
  const main = find(tree, 'head') || find(tree, 'html');
  const content = main ? main.content || (main.content = []) : tree;
  const index = findBundleInsertIndex(content);
  content.splice(index, 0, ...bundles);
}
function find(tree, tag) {
  let res;
  tree.match({
    tag
  }, node => {
    res = node;
    return node;
  });
  return res;
}
function findBundleInsertIndex(content) {
  // HTML document order (https://html.spec.whatwg.org/multipage/syntax.html#writing)
  //   - Any number of comments and ASCII whitespace.
  //   - A DOCTYPE.
  //   - Any number of comments and ASCII whitespace.
  //   - The document element, in the form of an html element.
  //   - Any number of comments and ASCII whitespace.
  //
  // -> Insert before first non-metadata (or script) element; if none was found, after the doctype

  let doctypeIndex;
  for (let index = 0; index < content.length; index++) {
    const node = content[index];
    if (node && node.tag && !metadataContent.has(node.tag)) {
      return index;
    }
    if (typeof node === 'string' && node.toLowerCase().startsWith('<!doctype')) {
      doctypeIndex = index;
    }
  }
  return doctypeIndex ? doctypeIndex + 1 : 0;
}