"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.DevPackager = void 0;
function _utils() {
  const data = require("@parcel/utils");
  _utils = function () {
    return data;
  };
  return data;
}
function _sourceMap() {
  const data = _interopRequireDefault(require("@parcel/source-map"));
  _sourceMap = function () {
    return data;
  };
  return data;
}
function _assert() {
  const data = _interopRequireDefault(require("assert"));
  _assert = function () {
    return data;
  };
  return data;
}
function _path() {
  const data = _interopRequireDefault(require("path"));
  _path = function () {
    return data;
  };
  return data;
}
function _fs() {
  const data = _interopRequireDefault(require("fs"));
  _fs = function () {
    return data;
  };
  return data;
}
var _utils2 = require("./utils");
var _helpers = require("./helpers");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const PRELUDE = _fs().default.readFileSync(_path().default.join(__dirname, 'dev-prelude.js'), 'utf8').trim().replace(/;$/, '');
class DevPackager {
  constructor(options, bundleGraph, bundle, parcelRequireName) {
    this.options = options;
    this.bundleGraph = bundleGraph;
    this.bundle = bundle;
    this.parcelRequireName = parcelRequireName;
  }
  async package() {
    // Load assets
    let queue = new (_utils().PromiseQueue)({
      maxConcurrent: 32
    });
    this.bundle.traverseAssets(asset => {
      queue.add(async () => {
        let [code, mapBuffer] = await Promise.all([asset.getCode(), this.bundle.env.sourceMap && asset.getMapBuffer()]);
        return {
          code,
          mapBuffer
        };
      });
    });
    let results = await queue.run();
    let assets = '';
    let i = 0;
    let first = true;
    let map = new (_sourceMap().default)(this.options.projectRoot);
    let prefix = this.getPrefix();
    let lineOffset = (0, _utils().countLines)(prefix);
    let script = null;
    let externals = new Set();
    let usedHelpers = 0;
    this.bundle.traverse(node => {
      let wrapped = first ? '' : ',';
      if (node.type === 'dependency') {
        let resolved = this.bundleGraph.getResolvedAsset(node.value, this.bundle);
        if (resolved && resolved.type !== 'js') {
          // if this is a reference to another javascript asset, we should not include
          // its output, as its contents should already be loaded.
          (0, _assert().default)(!this.bundle.hasAsset(resolved));
          wrapped += JSON.stringify(this.bundleGraph.getAssetPublicId(resolved)) + ':[function() {},{}]';
        } else {
          return;
        }
      }
      if (node.type === 'asset') {
        let asset = node.value;
        (0, _assert().default)(asset.type === 'js', 'all assets in a js bundle must be js assets');
        if (typeof asset.meta.usedHelpers === 'number') {
          usedHelpers |= asset.meta.usedHelpers;
        }

        // If this is the main entry of a script rather than a module, we need to hoist it
        // outside the bundle wrapper function so that its variables are exposed as globals.
        if (this.bundle.env.sourceType === 'script' && asset === this.bundle.getMainEntry()) {
          script = results[i++];
          return;
        }
        let deps = {};
        let dependencies = this.bundleGraph.getDependencies(asset);
        for (let dep of dependencies) {
          let resolved = this.bundleGraph.getResolvedAsset(dep, this.bundle);
          let specifier = (0, _utils2.getSpecifier)(dep);
          if (this.bundleGraph.isDependencySkipped(dep)) {
            deps[specifier] = false;
          } else if (resolved) {
            deps[specifier] = this.bundleGraph.getAssetPublicId(resolved);
          } else {
            // An external module - map placeholder to original specifier.
            deps[specifier] = dep.specifier;
            if (this.bundle.env.outputFormat === 'esmodule' && !dep.isOptional) {
              externals.add(dep.specifier);
            }
          }
        }

        // Add dependencies for parcelRequire calls added by runtimes
        // so that the HMR runtime can correctly traverse parents.
        let hmrDeps = asset.meta.hmrDeps;
        if (this.options.hmrOptions && Array.isArray(hmrDeps)) {
          for (let id of hmrDeps) {
            (0, _assert().default)(typeof id === 'string');
            deps[id] = id;
          }
        }
        let {
          code,
          mapBuffer
        } = results[i];
        let output = code || '';
        wrapped += JSON.stringify(this.bundleGraph.getAssetPublicId(asset)) + ':[function(require,module,exports,__globalThis) {\n' + output + '\n},';
        wrapped += JSON.stringify(deps);
        wrapped += ']';
        if (this.bundle.env.isNode() && asset.meta.has_node_replacements === true) {
          const relPath = (0, _utils().normalizeSeparators)(_path().default.relative(this.bundle.target.distDir, _path().default.dirname(asset.filePath)));
          wrapped = wrapped.replace('$parcel$dirnameReplace', relPath);
          wrapped = wrapped.replace('$parcel$filenameReplace', relPath);
        }
        if (this.bundle.env.sourceMap) {
          if (mapBuffer) {
            map.addBuffer(mapBuffer, lineOffset);
          } else {
            map.addEmptyMap(_path().default.relative(this.options.projectRoot, asset.filePath).replace(/\\+/g, '/'), output, lineOffset);
          }
          lineOffset += (0, _utils().countLines)(output) + 1;
        }
        i++;
      }
      assets += wrapped;
      first = false;
    });
    let entries = this.bundle.getEntryAssets();
    let mainEntry = this.bundle.getMainEntry();
    if (!this.isEntry() && this.bundle.env.outputFormat !== 'commonjs' || this.bundle.env.sourceType === 'script') {
      // In async bundles we don't want the main entry to execute until we require it
      // as there might be dependencies in a sibling bundle that hasn't loaded yet.
      entries = entries.filter(a => {
        var _mainEntry;
        return a.id !== ((_mainEntry = mainEntry) === null || _mainEntry === void 0 ? void 0 : _mainEntry.id);
      });
      mainEntry = null;
    }
    let load = '';
    if (usedHelpers & 4) {
      load += _helpers.helpers.$parcel$import(this.bundle.env, this.bundle, new Set());
      load += 'newRequire.load = $parcel$import;\n';
    }
    if (usedHelpers & 8) {
      load += _helpers.helpers.$parcel$resolve(this.bundle.env, this.bundle, new Set());
      load += 'newRequire.resolve = $parcel$resolve;\n';
    }
    if (usedHelpers & 16) {
      load += _helpers.helpers.$parcel$extendImportMap(this.bundle.env);
      load += `newRequire.extendImportMap = $parcel$extendImportMap;\n`;
    }
    if (load) {
      usedHelpers |= 1 | 2;
      // Remove newlines to avoid messing up source maps
      prefix = prefix.replace('// INSERT_LOAD_HERE', load.replace(/\n/g, ''));
    }
    let externalImports = '';
    let externalMap = '{';
    let e = 0;
    for (let external of externals) {
      let name = `__parcelExternal${e++}`;
      externalImports += `import * as ${name} from ${JSON.stringify(external)};\n`;
      externalMap += `${JSON.stringify(external)}: ${name},`;
    }
    externalMap += '}';
    let contents = externalImports + prefix + '({' + assets + '},' + JSON.stringify(entries.map(asset => this.bundleGraph.getAssetPublicId(asset))) + ', ' + JSON.stringify(mainEntry ? this.bundleGraph.getAssetPublicId(mainEntry) : null) + ', ' + JSON.stringify(this.parcelRequireName) + ', ' + externalMap;
    if (usedHelpers & 1) {
      // Generate a relative path from this bundle to the root of the dist dir.
      let distDir = (0, _utils().relativePath)(_path().default.dirname(this.bundle.name), '');
      if (!distDir.endsWith('/')) {
        distDir += '/';
      }
      contents += ', ' + JSON.stringify(distDir);
    } else if (usedHelpers & (2 | 32)) {
      contents += ', null';
    }
    if (usedHelpers & 2) {
      // Ensure the public url always ends with a slash to code can easily join paths to it.
      let publicUrl = this.bundle.target.publicUrl;
      if (!publicUrl.endsWith('/')) {
        publicUrl += '/';
      }
      contents += ', ' + JSON.stringify(publicUrl);
    } else if (usedHelpers & 32) {
      contents += ', null';
    }
    if (usedHelpers & 32) {
      let code = _helpers.helpers.$parcel$devServer(this.bundle.env, this.bundle, new Set(), this.options);
      contents += ', ' + code.slice('var $parcel$devServer = '.length, -2);
    }
    contents += ')\n';

    // Add ES module exports from the entry asset.
    if (this.bundle.env.outputFormat === 'esmodule' && mainEntry && (this.bundle.env.isLibrary || !this.bundle.env.isBrowser())) {
      let hasNamespace = mainEntry.symbols.hasExportSymbol('*');
      let importedSymbols = new Map();
      let exportedSymbols = new Map();
      for (let {
        exportAs,
        symbol,
        exportSymbol
      } of this.bundleGraph.getExportedSymbols(mainEntry)) {
        if (typeof symbol === 'string') {
          if (hasNamespace && exportAs !== '*') {
            continue;
          }
          if (exportAs === '*') {
            exportAs = 'default';
          }
          let id = (0, _utils2.makeValidIdentifier)(exportSymbol);
          if (id === 'default') {
            id = '_default';
          }
          importedSymbols.set(exportSymbol, id);
          exportedSymbols.set(exportAs, id);
        }
      }
      contents += 'let {';
      for (let [key, value] of importedSymbols) {
        contents += (0, _utils2.isValidIdentifier)(key) ? key : JSON.stringify(key);
        if (value !== key) {
          contents += ': ';
          contents += value;
        }
        contents += ', ';
      }
      contents += '} = ' + this.parcelRequireName + '(' + JSON.stringify(this.bundleGraph.getAssetPublicId(mainEntry)) + ');\n';
      contents += 'export {';
      for (let [exportAs, ident] of exportedSymbols) {
        contents += ident;
        if (exportAs !== ident) {
          contents += ' as ';
          contents += (0, _utils2.isValidIdentifier)(exportAs) ? exportAs : JSON.stringify(exportAs);
        }
        contents += ', ';
      }
      contents += '};\n';
    }

    // The entry asset of a script bundle gets hoisted outside the bundle wrapper function
    // so that its variables become globals. We need to replace any require calls for
    // runtimes with a parcelRequire call.
    if (this.bundle.env.sourceType === 'script' && script) {
      let entryMap;
      let mapBuffer = script.mapBuffer;
      if (mapBuffer) {
        entryMap = new (_sourceMap().default)(this.options.projectRoot, mapBuffer);
      }
      contents += (0, _utils2.replaceScriptDependencies)(this.bundleGraph, this.bundle, script.code, entryMap, this.parcelRequireName);
      if (this.bundle.env.sourceMap && entryMap) {
        map.addSourceMap(entryMap, lineOffset);
      }
    }
    return {
      contents,
      map
    };
  }
  getPrefix() {
    let interpreter;
    let mainEntry = this.bundle.getMainEntry();
    if (mainEntry && this.isEntry() && !this.bundle.target.env.isBrowser()) {
      let _interpreter = mainEntry.meta.interpreter;
      (0, _assert().default)(_interpreter == null || typeof _interpreter === 'string');
      interpreter = _interpreter;
    }
    let importScripts = '';
    if (this.bundle.env.isWorker()) {
      let bundles = this.bundleGraph.getReferencedBundles(this.bundle);
      for (let b of bundles) {
        importScripts += `importScripts("${(0, _utils().relativeBundlePath)(this.bundle, b)}");\n`;
      }
    } else if (this.bundle.env.isNode()) {
      let bundles = this.bundleGraph.getReferencedBundles(this.bundle, {
        includeInline: false
      });
      for (let b of bundles) {
        if (b.type !== 'js') {
          continue;
        }
        if (this.bundle.env.outputFormat === 'esmodule') {
          importScripts += `import "${(0, _utils().relativeBundlePath)(this.bundle, b)}";\n`;
        } else {
          importScripts += `require("${(0, _utils().relativeBundlePath)(this.bundle, b)}");\n`;
        }
      }
    }
    return (
      // If the entry asset included a hashbang, repeat it at the top of the bundle
      (interpreter != null ? `#!${interpreter}\n` : '') + importScripts + PRELUDE
    );
  }
  isEntry() {
    return !this.bundleGraph.hasParentBundleOfType(this.bundle, 'js') || this.bundle.env.isIsolated() || this.bundle.bundleBehavior === 'isolated';
  }
}
exports.DevPackager = DevPackager;