"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.TargetResolver = void 0;
exports.default = createTargetRequest;
exports.skipTarget = skipTarget;
function _diagnostic() {
  const data = _interopRequireWildcard(require("@parcel/diagnostic"));
  _diagnostic = function () {
    return data;
  };
  return data;
}
function _path() {
  const data = _interopRequireDefault(require("path"));
  _path = function () {
    return data;
  };
  return data;
}
function _utils() {
  const data = require("@parcel/utils");
  _utils = function () {
    return data;
  };
  return data;
}
function _logger() {
  const data = _interopRequireDefault(require("@parcel/logger"));
  _logger = function () {
    return data;
  };
  return data;
}
var _Environment = require("../Environment");
var _ParcelConfigRequest = _interopRequireWildcard(require("./ParcelConfigRequest"));
function _browserslist() {
  const data = _interopRequireDefault(require("browserslist"));
  _browserslist = function () {
    return data;
  };
  return data;
}
function _jsonSourcemap() {
  const data = require("@mischnic/json-sourcemap");
  _jsonSourcemap = function () {
    return data;
  };
  return data;
}
function _assert() {
  const data = _interopRequireDefault(require("assert"));
  _assert = function () {
    return data;
  };
  return data;
}
function _nullthrows() {
  const data = _interopRequireDefault(require("nullthrows"));
  _nullthrows = function () {
    return data;
  };
  return data;
}
var _TargetDescriptor = require("../TargetDescriptor.schema");
var _utils2 = require("../utils");
var _projectPath = require("../projectPath");
var _RequestTracker = require("../RequestTracker");
var _Environment2 = require("../public/Environment");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
// $FlowFixMe
const DEFAULT_DIST_DIRNAME = 'dist';
const JS_RE = /\.[mc]?js$/;
const JS_EXTENSIONS = ['.js', '.mjs', '.cjs'];
const COMMON_TARGETS = {
  main: {
    match: JS_RE,
    extensions: JS_EXTENSIONS
  },
  module: {
    // module field is always ESM. Don't allow .cjs extension here.
    match: /\.m?js$/,
    extensions: ['.js', '.mjs']
  },
  browser: {
    match: JS_RE,
    extensions: JS_EXTENSIONS
  },
  types: {
    match: /\.d\.ts$/,
    extensions: ['.d.ts']
  }
};
const DEFAULT_ENGINES = {
  node: process.versions.node,
  browsers: ['last 1 Chrome version', 'last 1 Safari version', 'last 1 Firefox version', 'last 1 Edge version']
};
const type = 'target_request';
function createTargetRequest(input) {
  return {
    id: `${type}:${(0, _utils().hashObject)(input)}`,
    type: _RequestTracker.requestTypes.target_request,
    run,
    input
  };
}
function skipTarget(targetName, exclusiveTarget, descriptorSource) {
  //  We skip targets if they have a descriptor.source and don't match the current exclusiveTarget
  //  They will be handled by a separate resolvePackageTargets call from their Entry point
  //  but with exclusiveTarget set.

  return exclusiveTarget == null ? descriptorSource != null : targetName !== exclusiveTarget;
}
async function run({
  input,
  api,
  options
}) {
  let targetResolver = new TargetResolver(api, (0, _utils2.optionsProxy)(options, api.invalidateOnOptionChange));
  let targets = await targetResolver.resolve((0, _projectPath.fromProjectPath)(options.projectRoot, input.packagePath), input.target);
  assertTargetsAreNotEntries(targets, input, options);
  let configResult = (0, _nullthrows().default)(await api.runRequest((0, _ParcelConfigRequest.default)()));
  let parcelConfig = (0, _ParcelConfigRequest.getCachedParcelConfig)(configResult, options);

  // Find named pipelines for each target.
  let pipelineNames = new Set(parcelConfig.getNamedPipelines());
  for (let target of targets) {
    if (pipelineNames.has(target.name)) {
      target.pipeline = target.name;
    }
  }
  if (options.logLevel === 'verbose') {
    await debugResolvedTargets(input, targets, targetResolver.targetInfo, options);
  }
  return targets;
}
class TargetResolver {
  constructor(api, options) {
    this.api = api;
    this.fs = options.inputFS;
    this.options = options;
    this.targetInfo = new Map();
  }
  async resolve(rootDir, exclusiveTarget) {
    let optionTargets = this.options.targets;
    if (exclusiveTarget != null && optionTargets == null) {
      optionTargets = [exclusiveTarget];
    }
    let packageTargets = await this.resolvePackageTargets(rootDir, exclusiveTarget);
    let targets;
    if (optionTargets) {
      if (Array.isArray(optionTargets)) {
        if (optionTargets.length === 0) {
          throw new (_diagnostic().default)({
            diagnostic: {
              message: `Targets option is an empty array`,
              origin: '@parcel/core'
            }
          });
        }

        // Only build the intersection of the exclusive target and option targets.
        if (exclusiveTarget != null) {
          optionTargets = optionTargets.filter(target => target === exclusiveTarget);
        }

        // If an array of strings is passed, it's a filter on the resolved package
        // targets. Load them, and find the matching targets.
        targets = optionTargets.map(target => {
          // null means skipped.
          if (!packageTargets.has(target)) {
            throw new (_diagnostic().default)({
              diagnostic: {
                message: (0, _diagnostic().md)`Could not find target with name "${target}"`,
                origin: '@parcel/core'
              }
            });
          }
          return packageTargets.get(target);
        }).filter(Boolean);
      } else {
        // Otherwise, it's an object map of target descriptors (similar to those
        // in package.json). Adapt them to native targets.
        targets = Object.entries(optionTargets).map(([name, _descriptor]) => {
          let {
            distDir,
            ...descriptor
          } = parseDescriptor(name, _descriptor, null, JSON.stringify({
            targets: optionTargets
          }, null, '\t'));
          if (distDir == null) {
            let optionTargetsString = JSON.stringify(optionTargets, null, '\t');
            throw new (_diagnostic().default)({
              diagnostic: {
                message: (0, _diagnostic().md)`Missing distDir for target "${name}"`,
                origin: '@parcel/core',
                codeFrames: [{
                  code: optionTargetsString,
                  codeHighlights: (0, _diagnostic().generateJSONCodeHighlights)(optionTargetsString || '', [{
                    key: `/${name}`,
                    type: 'value'
                  }])
                }]
              }
            });
          }
          let target = {
            name,
            distDir: (0, _projectPath.toProjectPath)(this.options.projectRoot, _path().default.resolve(this.fs.cwd(), distDir)),
            publicUrl: descriptor.publicUrl ?? this.options.defaultTargetOptions.publicUrl,
            env: (0, _Environment.createEnvironment)({
              engines: descriptor.engines,
              context: descriptor.context,
              isLibrary: descriptor.isLibrary ?? this.options.defaultTargetOptions.isLibrary,
              includeNodeModules: descriptor.includeNodeModules,
              outputFormat: descriptor.outputFormat ?? this.options.defaultTargetOptions.outputFormat,
              shouldOptimize: this.options.defaultTargetOptions.shouldOptimize && descriptor.optimize !== false,
              shouldScopeHoist: this.options.defaultTargetOptions.shouldScopeHoist && descriptor.scopeHoist !== false,
              sourceMap: normalizeSourceMap(this.options, descriptor.sourceMap)
            })
          };
          if (descriptor.distEntry != null) {
            target.distEntry = descriptor.distEntry;
          }
          if (descriptor.source != null) {
            target.source = descriptor.source;
          }
          return target;
        }).filter(target => !skipTarget(target.name, exclusiveTarget, target.source));
      }
      let serve = this.options.serveOptions;
      if (serve && targets.length > 0 && targets.every(t => _Environment2.BROWSER_ENVS.has(t.env.context))) {
        // In serve mode, we only support a single browser target. If the user
        // provided more than one, or the matching target is not a browser, throw.
        if (targets.length > 1) {
          throw new (_diagnostic().default)({
            diagnostic: {
              message: `More than one target is not supported in serve mode`,
              origin: '@parcel/core'
            }
          });
        }
        targets[0].distDir = (0, _projectPath.toProjectPath)(this.options.projectRoot, serve.distDir);
      }
    } else {
      targets = Array.from(packageTargets.values()).filter(Boolean).filter(descriptor => {
        return descriptor && !skipTarget(descriptor.name, exclusiveTarget, descriptor.source);
      });

      // Explicit targets were not provided. Either use a modern target for server
      // mode, or simply use the package.json targets.
      if (this.options.serveOptions && targets.every(t => _Environment2.BROWSER_ENVS.has(t.env.context))) {
        // In serve mode, we only support a single browser target. Since the user
        // hasn't specified a target, use one targeting modern browsers for development
        let distDir = (0, _projectPath.toProjectPath)(this.options.projectRoot, this.options.serveOptions.distDir);
        let mainTarget = targets.length === 1 ? targets[0] : null;
        if (mainTarget !== null && mainTarget !== void 0 && mainTarget.env.isLibrary) {
          let loc = mainTarget.loc;
          throw new (_diagnostic().default)({
            diagnostic: {
              origin: '@parcel/core',
              message: (0, _diagnostic().md)`
Library targets are not supported in serve mode.
              `,
              codeFrames: loc ? [{
                filePath: (0, _projectPath.fromProjectPath)(this.options.projectRoot, loc.filePath),
                codeHighlights: [(0, _diagnostic().convertSourceLocationToHighlight)(loc, 'Target declared here')]
              }] : [],
              hints: [`The "${mainTarget.name}" field is meant for libraries, not applications. Either remove the "${mainTarget.name}" field or choose a different target name.`],
              documentationURL: 'https://parceljs.org/features/targets/#library-targets'
            }
          });
        }
        let context = (mainTarget === null || mainTarget === void 0 ? void 0 : mainTarget.env.context) ?? 'browser';
        let engines = _Environment2.BROWSER_ENVS.has(context) ? {
          browsers: DEFAULT_ENGINES.browsers
        } : {
          node: DEFAULT_ENGINES.node
        };
        targets = [{
          name: 'default',
          distDir,
          publicUrl: this.options.defaultTargetOptions.publicUrl ?? '/',
          env: (0, _Environment.createEnvironment)({
            context,
            engines,
            includeNodeModules: mainTarget === null || mainTarget === void 0 ? void 0 : mainTarget.env.includeNodeModules,
            shouldOptimize: this.options.defaultTargetOptions.shouldOptimize,
            outputFormat: (mainTarget === null || mainTarget === void 0 ? void 0 : mainTarget.env.outputFormat) ?? this.options.defaultTargetOptions.outputFormat,
            shouldScopeHoist: this.options.defaultTargetOptions.shouldScopeHoist,
            sourceMap: this.options.defaultTargetOptions.sourceMaps ? {} : undefined
          })
        }];
      }
    }
    return targets;
  }
  async resolvePackageTargets(rootDir, exclusiveTarget) {
    let rootFile = _path().default.join(rootDir, 'index');
    let conf = await (0, _utils().loadConfig)(this.fs, rootFile, ['package.json'], this.options.projectRoot);
    let rootFileProject = (0, _projectPath.toProjectPath)(this.options.projectRoot, rootFile);

    // Invalidate whenever a package.json file is added.
    this.api.invalidateOnFileCreate({
      fileName: 'package.json',
      aboveFilePath: rootFileProject
    });
    let pkg;
    let pkgContents;
    let pkgFilePath;
    let pkgDir;
    let pkgMap;
    if (conf) {
      pkg = conf.config;
      let pkgFile = conf.files[0];
      if (pkgFile == null) {
        throw new (_diagnostic().default)({
          diagnostic: {
            message: (0, _diagnostic().md)`Expected package.json file in ${rootDir}`,
            origin: '@parcel/core'
          }
        });
      }
      let _pkgFilePath = pkgFilePath = pkgFile.filePath; // For Flow
      pkgDir = _path().default.dirname(_pkgFilePath);
      pkgContents = await this.fs.readFile(_pkgFilePath, 'utf8');
      pkgMap = (0, _jsonSourcemap().parse)(pkgContents, undefined, {
        tabWidth: 1
      });
      let pp = (0, _projectPath.toProjectPath)(this.options.projectRoot, _pkgFilePath);
      this.api.invalidateOnFileUpdate(pp);
      this.api.invalidateOnFileDelete(pp);
    } else {
      pkg = {};
      pkgDir = this.fs.cwd();
    }
    let pkgTargets = pkg.targets || {};
    let pkgEngines = parseEngines(pkg.engines, pkgFilePath, pkgContents, '/engines', 'Invalid engines in package.json') || {};
    let browsersLoc = {
      path: '/engines/browsers'
    };
    let nodeLoc = {
      path: '/engines/node'
    };
    if (pkgEngines.browsers == null) {
      let env = this.options.env.BROWSERSLIST_ENV ?? this.options.env.NODE_ENV ?? this.options.mode;
      if (pkg.browserslist != null) {
        let pkgBrowserslist = pkg.browserslist;
        let browserslist = typeof pkgBrowserslist === 'object' && !Array.isArray(pkgBrowserslist) ? pkgBrowserslist[env] : pkgBrowserslist;
        pkgEngines = {
          ...pkgEngines,
          browsers: browserslist
        };
        browsersLoc = {
          path: '/browserslist'
        };
      } else {
        let browserslistConfig = await (0, _utils().resolveConfig)(this.fs, _path().default.join(rootDir, 'index'), ['browserslist', '.browserslistrc'], this.options.projectRoot);
        this.api.invalidateOnFileCreate({
          fileName: 'browserslist',
          aboveFilePath: rootFileProject
        });
        this.api.invalidateOnFileCreate({
          fileName: '.browserslistrc',
          aboveFilePath: rootFileProject
        });
        if (browserslistConfig != null) {
          let contents = await this.fs.readFile(browserslistConfig, 'utf8');
          let config = _browserslist().default.parseConfig(contents);
          let browserslistBrowsers = config[env] || config.defaults;
          let pp = (0, _projectPath.toProjectPath)(this.options.projectRoot, browserslistConfig);
          if ((browserslistBrowsers === null || browserslistBrowsers === void 0 ? void 0 : browserslistBrowsers.length) > 0) {
            pkgEngines = {
              ...pkgEngines,
              browsers: browserslistBrowsers
            };
            browsersLoc = {
              message: `(defined in ${_path().default.relative(process.cwd(), browserslistConfig)})`
            };
          }

          // Invalidate whenever browserslist config file or relevant environment variables change
          this.api.invalidateOnFileUpdate(pp);
          this.api.invalidateOnFileDelete(pp);
          this.api.invalidateOnEnvChange('BROWSERSLIST_ENV');
          this.api.invalidateOnEnvChange('NODE_ENV');
        }
      }
    }
    let targets = new Map();
    let node = pkgEngines.node;
    let browsers = pkgEngines.browsers;
    let defaultEngines = this.options.defaultTargetOptions.engines;
    let context = browsers ?? node == null ? 'browser' : 'node';
    if (context === 'browser' && pkgEngines.browsers == null) {
      pkgEngines = {
        ...pkgEngines,
        browsers: (defaultEngines === null || defaultEngines === void 0 ? void 0 : defaultEngines.browsers) ?? DEFAULT_ENGINES.browsers
      };
      browsersLoc = {
        message: '(default)'
      };
    } else if (context === 'node' && pkgEngines.node == null) {
      pkgEngines = {
        ...pkgEngines,
        node: (defaultEngines === null || defaultEngines === void 0 ? void 0 : defaultEngines.node) ?? DEFAULT_ENGINES.node
      };
      nodeLoc = {
        message: '(default)'
      };
    }

    // If there is a separate `browser` target, or an `engines.node` field but no browser targets, then
    // the `main` and `module` targets refer to node, otherwise browser.
    let mainContext = pkg.browser ?? pkgTargets.browser ?? (node != null && browsers == null) ? 'node' : 'browser';
    let mainContextLoc = pkg.browser != null ? {
      inferred: '/browser',
      message: '(because a browser field also exists)',
      type: 'key'
    } : pkgTargets.browser ? {
      inferred: '/targets/browser',
      message: '(because a browser target also exists)',
      type: 'key'
    } : node != null && browsers == null ? nodeLoc.path ? {
      inferred: nodeLoc.path,
      message: '(because node engines were defined)',
      type: 'key'
    } : nodeLoc : {
      message: '(default)'
    };
    let moduleContext = pkg.browser ?? pkgTargets.browser ? 'browser' : mainContext;
    let moduleContextLoc = pkg.browser != null ? {
      inferred: '/browser',
      message: '(because a browser field also exists)',
      type: 'key'
    } : pkgTargets.browser ? {
      inferred: '/targets/browser',
      message: '(becausea browser target also exists)',
      type: 'key'
    } : mainContextLoc;
    let getEnginesLoc = (targetName, descriptor) => {
      let enginesLoc = `/targets/${targetName}/engines`;
      switch (context) {
        case 'browser':
        case 'web-worker':
        case 'service-worker':
        case 'worklet':
          {
            if (descriptor.engines) {
              return {
                path: enginesLoc + '/browsers'
              };
            } else {
              return browsersLoc;
            }
          }
        case 'node':
          {
            if (descriptor.engines) {
              return {
                path: enginesLoc + '/node'
              };
            } else {
              return nodeLoc;
            }
          }
        case 'electron-main':
        case 'electron-renderer':
          {
            var _descriptor$engines, _pkgEngines;
            if (((_descriptor$engines = descriptor.engines) === null || _descriptor$engines === void 0 ? void 0 : _descriptor$engines.electron) != null) {
              return {
                path: enginesLoc + '/electron'
              };
            } else if (((_pkgEngines = pkgEngines) === null || _pkgEngines === void 0 ? void 0 : _pkgEngines.electron) != null) {
              return {
                path: '/engines/electron'
              };
            }
          }
      }
      return {
        message: '(default)'
      };
    };
    for (let targetName in COMMON_TARGETS) {
      let _targetDist;
      let pointer;
      if (targetName === 'browser' && pkg[targetName] != null && typeof pkg[targetName] === 'object' && pkg.name) {
        // The `browser` field can be a file path or an alias map.
        _targetDist = pkg[targetName][pkg.name];
        pointer = `/${targetName}/${(0, _diagnostic().encodeJSONKeyComponent)(pkg.name)}`;
      } else {
        _targetDist = pkg[targetName];
        pointer = `/${targetName}`;
      }

      // For Flow
      let targetDist = _targetDist;
      if (typeof targetDist === 'string' || pkgTargets[targetName]) {
        let distDir;
        let distEntry;
        let loc;
        (0, _assert().default)(pkgMap != null);
        let _descriptor = pkgTargets[targetName] ?? {};
        if (typeof targetDist === 'string') {
          distDir = (0, _projectPath.toProjectPath)(this.options.projectRoot, _path().default.resolve(pkgDir, _path().default.dirname(targetDist)));
          distEntry = _path().default.basename(targetDist);
          loc = {
            filePath: (0, _nullthrows().default)(pkgFilePath),
            ...(0, _diagnostic().getJSONSourceLocation)(pkgMap.pointers[pointer], 'value')
          };
        } else {
          distDir = this.options.defaultTargetOptions.distDir ?? (0, _projectPath.toProjectPath)(this.options.projectRoot, _path().default.join(pkgDir, DEFAULT_DIST_DIRNAME, targetName));
        }
        if (_descriptor == false) {
          continue;
        }
        let descriptor = parseCommonTargetDescriptor(targetName, _descriptor, pkgFilePath, pkgContents);
        if (skipTarget(targetName, exclusiveTarget, descriptor.source)) {
          targets.set(targetName, null);
          continue;
        }
        if (distEntry != null && !COMMON_TARGETS[targetName].match.test(distEntry)) {
          let contents = typeof pkgContents === 'string' ? pkgContents :
          // $FlowFixMe
          JSON.stringify(pkgContents, null, '\t');
          // $FlowFixMe
          let listFormat = new Intl.ListFormat('en-US', {
            type: 'disjunction'
          });
          let extensions = listFormat.format(COMMON_TARGETS[targetName].extensions);
          let ext = _path().default.extname(distEntry);
          throw new (_diagnostic().default)({
            diagnostic: {
              message: (0, _diagnostic().md)`Unexpected output file type ${ext} in target "${targetName}"`,
              origin: '@parcel/core',
              codeFrames: [{
                language: 'json',
                filePath: pkgFilePath ?? undefined,
                code: contents,
                codeHighlights: (0, _diagnostic().generateJSONCodeHighlights)(contents, [{
                  key: pointer,
                  type: 'value',
                  message: `File extension must be ${extensions}`
                }])
              }],
              hints: [`The "${targetName}" field is meant for libraries. If you meant to output a ${ext} file, either remove the "${targetName}" field or choose a different target name.`],
              documentationURL: 'https://parceljs.org/features/targets/#library-targets'
            }
          });
        }
        if (descriptor.outputFormat === 'global') {
          let contents = typeof pkgContents === 'string' ? pkgContents :
          // $FlowFixMe
          JSON.stringify(pkgContents, null, '\t');
          throw new (_diagnostic().default)({
            diagnostic: {
              message: (0, _diagnostic().md)`The "global" output format is not supported in the "${targetName}" target.`,
              origin: '@parcel/core',
              codeFrames: [{
                language: 'json',
                filePath: pkgFilePath ?? undefined,
                code: contents,
                codeHighlights: (0, _diagnostic().generateJSONCodeHighlights)(contents, [{
                  key: `/targets/${targetName}/outputFormat`,
                  type: 'value'
                }])
              }],
              hints: [`The "${targetName}" field is meant for libraries. The outputFormat must be either "commonjs" or "esmodule". Either change or remove the declared outputFormat.`],
              documentationURL: 'https://parceljs.org/features/targets/#library-targets'
            }
          });
        }
        let [inferredOutputFormat, inferredOutputFormatField] = this.inferOutputFormat(distEntry, descriptor, targetName, pkg, pkgFilePath, pkgContents);
        let outputFormat = descriptor.outputFormat ?? this.options.defaultTargetOptions.outputFormat ?? inferredOutputFormat ?? (targetName === 'module' ? 'esmodule' : 'commonjs');
        let isModule = outputFormat === 'esmodule';
        if (targetName === 'main' && outputFormat === 'esmodule' && inferredOutputFormat !== 'esmodule') {
          let contents = typeof pkgContents === 'string' ? pkgContents :
          // $FlowFixMe
          JSON.stringify(pkgContents, null, '\t');
          throw new (_diagnostic().default)({
            diagnostic: {
              // prettier-ignore
              message: (0, _diagnostic().md)`Output format "esmodule" cannot be used in the "main" target without a .mjs extension or "type": "module" field.`,
              origin: '@parcel/core',
              codeFrames: [{
                language: 'json',
                filePath: pkgFilePath ?? undefined,
                code: contents,
                codeHighlights: (0, _diagnostic().generateJSONCodeHighlights)(contents, [{
                  key: `/targets/${targetName}/outputFormat`,
                  type: 'value',
                  message: 'Declared output format defined here'
                }, {
                  key: '/main',
                  type: 'value',
                  message: 'Inferred output format defined here'
                }])
              }],
              hints: [`Either change the output file extension to .mjs, add "type": "module" to package.json, or remove the declared outputFormat.`],
              documentationURL: 'https://parceljs.org/features/targets/#library-targets'
            }
          });
        }
        if (descriptor.scopeHoist === false) {
          let contents = typeof pkgContents === 'string' ? pkgContents :
          // $FlowFixMe
          JSON.stringify(pkgContents, null, '\t');
          throw new (_diagnostic().default)({
            diagnostic: {
              message: 'Scope hoisting cannot be disabled for library targets.',
              origin: '@parcel/core',
              codeFrames: [{
                language: 'json',
                filePath: pkgFilePath ?? undefined,
                code: contents,
                codeHighlights: (0, _diagnostic().generateJSONCodeHighlights)(contents, [{
                  key: `/targets/${targetName}/scopeHoist`,
                  type: 'value'
                }])
              }],
              hints: [`The "${targetName}" target is meant for libraries. Either remove the "scopeHoist" option, or use a different target name.`],
              documentationURL: 'https://parceljs.org/features/targets/#library-targets'
            }
          });
        }
        let context = descriptor.context ?? (targetName === 'browser' ? 'browser' : isModule ? moduleContext : mainContext);
        let engines = descriptor.engines ?? pkgEngines;
        if (context === 'browser' && engines.browsers == null) {
          engines = {
            ...engines,
            browsers: (defaultEngines === null || defaultEngines === void 0 ? void 0 : defaultEngines.browsers) ?? DEFAULT_ENGINES.browsers
          };
        } else if (context === 'node' && engines.node == null) {
          engines = {
            ...engines,
            node: (defaultEngines === null || defaultEngines === void 0 ? void 0 : defaultEngines.node) ?? DEFAULT_ENGINES.node
          };
        }
        targets.set(targetName, {
          name: targetName,
          distDir,
          distEntry,
          publicUrl: descriptor.publicUrl ?? this.options.defaultTargetOptions.publicUrl,
          env: (0, _Environment.createEnvironment)({
            engines,
            context,
            includeNodeModules: descriptor.includeNodeModules ?? false,
            outputFormat,
            isLibrary: true,
            shouldOptimize: this.options.defaultTargetOptions.shouldOptimize && descriptor.optimize === true,
            shouldScopeHoist: true,
            sourceMap: normalizeSourceMap(this.options, descriptor.sourceMap)
          }),
          loc: (0, _utils2.toInternalSourceLocation)(this.options.projectRoot, loc)
        });
        this.targetInfo.set(targetName, {
          output: {
            path: pointer
          },
          engines: getEnginesLoc(targetName, descriptor),
          context: descriptor.context ? {
            path: `/targets/${targetName}/context`
          } : targetName === 'browser' ? {
            message: '(inferred from target name)',
            inferred: pointer,
            type: 'key'
          } : isModule ? moduleContextLoc : mainContextLoc,
          includeNodeModules: descriptor.includeNodeModules ? {
            path: `/targets/${targetName}/includeNodeModules`,
            type: 'key'
          } : {
            message: '(default)'
          },
          outputFormat: descriptor.outputFormat ? {
            path: `/targets/${targetName}/outputFormat`
          } : inferredOutputFormatField === '/type' ? {
            message: `(inferred from package.json#type)`,
            inferred: inferredOutputFormatField
          } : inferredOutputFormatField != null ? {
            message: `(inferred from file extension)`,
            inferred: inferredOutputFormatField
          } : {
            message: '(default)'
          },
          isLibrary: {
            message: '(default)'
          },
          shouldOptimize: descriptor.optimize ? {
            path: `/targets/${targetName}/optimize`
          } : {
            message: '(default)'
          },
          shouldScopeHoist: {
            message: '(default)'
          }
        });
      }
    }
    let customTargets = Object.keys(pkgTargets).filter(targetName => !COMMON_TARGETS[targetName]);

    // Custom targets
    for (let targetName of customTargets) {
      let distPath = pkg[targetName];
      let distDir;
      let distEntry;
      let loc;
      let pointer;
      if (distPath == null) {
        distDir = (0, _projectPath.fromProjectPath)(this.options.projectRoot, this.options.defaultTargetOptions.distDir) ?? _path().default.join(pkgDir, DEFAULT_DIST_DIRNAME);
        if (customTargets.length >= 2) {
          distDir = _path().default.join(distDir, targetName);
        }
        (0, _assert().default)(pkgMap != null);
        (0, _assert().default)(typeof pkgFilePath === 'string');
        loc = {
          filePath: pkgFilePath,
          ...(0, _diagnostic().getJSONSourceLocation)(pkgMap.pointers[`/targets/${targetName}`], 'key')
        };
      } else {
        if (typeof distPath !== 'string') {
          let contents = typeof pkgContents === 'string' ? pkgContents :
          // $FlowFixMe
          JSON.stringify(pkgContents, null, '\t');
          throw new (_diagnostic().default)({
            diagnostic: {
              message: (0, _diagnostic().md)`Invalid distPath for target "${targetName}"`,
              origin: '@parcel/core',
              codeFrames: [{
                language: 'json',
                filePath: pkgFilePath ?? undefined,
                code: contents,
                codeHighlights: (0, _diagnostic().generateJSONCodeHighlights)(contents, [{
                  key: `/${targetName}`,
                  type: 'value',
                  message: 'Expected type string'
                }])
              }]
            }
          });
        }
        distDir = _path().default.resolve(pkgDir, _path().default.dirname(distPath));
        distEntry = _path().default.basename(distPath);
        (0, _assert().default)(typeof pkgFilePath === 'string');
        (0, _assert().default)(pkgMap != null);
        loc = {
          filePath: pkgFilePath,
          ...(0, _diagnostic().getJSONSourceLocation)(pkgMap.pointers[`/${targetName}`], 'value')
        };
        pointer = `/${targetName}`;
      }
      if (targetName in pkgTargets) {
        let descriptor = parsePackageDescriptor(targetName, pkgTargets[targetName], pkgFilePath, pkgContents);
        let pkgDir = _path().default.dirname((0, _nullthrows().default)(pkgFilePath));
        if (skipTarget(targetName, exclusiveTarget, descriptor.source)) {
          targets.set(targetName, null);
          continue;
        }
        let [inferredOutputFormat, inferredOutputFormatField] = this.inferOutputFormat(distEntry, descriptor, targetName, pkg, pkgFilePath, pkgContents);
        if (descriptor.scopeHoist === false && descriptor.isLibrary) {
          let contents = typeof pkgContents === 'string' ? pkgContents :
          // $FlowFixMe
          JSON.stringify(pkgContents, null, '\t');
          throw new (_diagnostic().default)({
            diagnostic: {
              message: 'Scope hoisting cannot be disabled for library targets.',
              origin: '@parcel/core',
              codeFrames: [{
                language: 'json',
                filePath: pkgFilePath ?? undefined,
                code: contents,
                codeHighlights: (0, _diagnostic().generateJSONCodeHighlights)(contents, [{
                  key: `/targets/${targetName}/scopeHoist`,
                  type: 'value'
                }, {
                  key: `/targets/${targetName}/isLibrary`,
                  type: 'value'
                }])
              }],
              hints: [`Either remove the "scopeHoist" or "isLibrary" option.`],
              documentationURL: 'https://parceljs.org/features/targets/#library-targets'
            }
          });
        }
        let isLibrary = descriptor.isLibrary ?? this.options.defaultTargetOptions.isLibrary ?? false;
        let shouldScopeHoist = isLibrary ? true : this.options.defaultTargetOptions.shouldScopeHoist;
        let engines = descriptor.engines ?? pkgEngines;
        if (descriptor.context === 'browser' && engines.browsers == null) {
          engines = {
            ...engines,
            browsers: (defaultEngines === null || defaultEngines === void 0 ? void 0 : defaultEngines.browsers) ?? DEFAULT_ENGINES.browsers
          };
        } else if (descriptor.context === 'node' && engines.node == null) {
          engines = {
            ...engines,
            node: (defaultEngines === null || defaultEngines === void 0 ? void 0 : defaultEngines.node) ?? DEFAULT_ENGINES.node
          };
        }
        targets.set(targetName, {
          name: targetName,
          distDir: (0, _projectPath.toProjectPath)(this.options.projectRoot, descriptor.distDir != null ? _path().default.resolve(pkgDir, descriptor.distDir) : distDir),
          distEntry,
          publicUrl: descriptor.publicUrl ?? this.options.defaultTargetOptions.publicUrl,
          env: (0, _Environment.createEnvironment)({
            engines,
            context: descriptor.context,
            includeNodeModules: descriptor.includeNodeModules,
            outputFormat: descriptor.outputFormat ?? this.options.defaultTargetOptions.outputFormat ?? inferredOutputFormat ?? undefined,
            isLibrary,
            shouldOptimize: this.options.defaultTargetOptions.shouldOptimize && (
            // Libraries are not optimized by default, users must explicitly configure this.
            isLibrary ? descriptor.optimize === true : descriptor.optimize !== false),
            shouldScopeHoist: shouldScopeHoist && descriptor.scopeHoist !== false,
            sourceMap: normalizeSourceMap(this.options, descriptor.sourceMap)
          }),
          loc: (0, _utils2.toInternalSourceLocation)(this.options.projectRoot, loc)
        });
        this.targetInfo.set(targetName, {
          output: pointer != null ? {
            path: pointer
          } : {
            message: '(default)'
          },
          engines: getEnginesLoc(targetName, descriptor),
          context: descriptor.context ? {
            path: `/targets/${targetName}/context`
          } : {
            message: '(default)'
          },
          includeNodeModules: descriptor.includeNodeModules ? {
            path: `/targets/${targetName}/includeNodeModules`,
            type: 'key'
          } : {
            message: '(default)'
          },
          outputFormat: descriptor.outputFormat ? {
            path: `/targets/${targetName}/outputFormat`
          } : inferredOutputFormatField === '/type' ? {
            message: `(inferred from package.json#type)`,
            inferred: inferredOutputFormatField
          } : inferredOutputFormatField != null ? {
            message: `(inferred from file extension)`,
            inferred: inferredOutputFormatField
          } : {
            message: '(default)'
          },
          isLibrary: descriptor.isLibrary != null ? {
            path: `/targets/${targetName}/isLibrary`
          } : {
            message: '(default)'
          },
          shouldOptimize: descriptor.optimize != null ? {
            path: `/targets/${targetName}/optimize`
          } : {
            message: '(default)'
          },
          shouldScopeHoist: descriptor.scopeHoist != null ? {
            path: `/targets/${targetName}/scopeHoist`
          } : {
            message: '(default)'
          }
        });
      }
    }

    // If no explicit targets were defined, add a default.
    if (targets.size === 0) {
      targets.set('default', {
        name: 'default',
        distDir: this.options.defaultTargetOptions.distDir ?? (0, _projectPath.toProjectPath)(this.options.projectRoot, _path().default.join(pkgDir, DEFAULT_DIST_DIRNAME)),
        publicUrl: this.options.defaultTargetOptions.publicUrl,
        env: (0, _Environment.createEnvironment)({
          engines: pkgEngines,
          context,
          outputFormat: this.options.defaultTargetOptions.outputFormat,
          isLibrary: this.options.defaultTargetOptions.isLibrary,
          shouldOptimize: this.options.defaultTargetOptions.shouldOptimize,
          shouldScopeHoist: this.options.defaultTargetOptions.shouldScopeHoist ?? (this.options.mode === 'production' && !this.options.defaultTargetOptions.isLibrary),
          sourceMap: this.options.defaultTargetOptions.sourceMaps ? {} : undefined
        })
      });
    }
    assertNoDuplicateTargets(this.options, targets, pkgFilePath, pkgContents);
    return targets;
  }
  inferOutputFormat(distEntry, descriptor, targetName, pkg, pkgFilePath, pkgContents) {
    // Infer the outputFormat based on package.json properties.
    // If the extension is .mjs it's always a module.
    // If the extension is .cjs, it's always commonjs.
    // If the "type" field is set to "module" and the extension is .js, it's a module.
    let ext = distEntry != null ? _path().default.extname(distEntry) : null;
    let inferredOutputFormat, inferredOutputFormatField;
    switch (ext) {
      case '.mjs':
        inferredOutputFormat = 'esmodule';
        inferredOutputFormatField = `/${targetName}`;
        break;
      case '.cjs':
        inferredOutputFormat = 'commonjs';
        inferredOutputFormatField = `/${targetName}`;
        break;
      case '.js':
        if (pkg.type === 'module') {
          inferredOutputFormat = 'esmodule';
          inferredOutputFormatField = '/type';
        }
        break;
    }
    if (descriptor.outputFormat && inferredOutputFormat && descriptor.outputFormat !== inferredOutputFormat) {
      let contents = typeof pkgContents === 'string' ? pkgContents :
      // $FlowFixMe
      JSON.stringify(pkgContents, null, '\t');
      let expectedExtensions;
      switch (descriptor.outputFormat) {
        case 'esmodule':
          expectedExtensions = ['.mjs', '.js'];
          break;
        case 'commonjs':
          expectedExtensions = ['.cjs', '.js'];
          break;
        case 'global':
          expectedExtensions = ['.js'];
          break;
      }
      // $FlowFixMe
      let listFormat = new Intl.ListFormat('en-US', {
        type: 'disjunction'
      });
      throw new (_diagnostic().default)({
        diagnostic: {
          message: (0, _diagnostic().md)`Declared output format "${descriptor.outputFormat}" does not match expected output format "${inferredOutputFormat}".`,
          origin: '@parcel/core',
          codeFrames: [{
            language: 'json',
            filePath: pkgFilePath ?? undefined,
            code: contents,
            codeHighlights: (0, _diagnostic().generateJSONCodeHighlights)(contents, [{
              key: `/targets/${targetName}/outputFormat`,
              type: 'value',
              message: 'Declared output format defined here'
            }, {
              key: (0, _nullthrows().default)(inferredOutputFormatField),
              type: 'value',
              message: 'Inferred output format defined here'
            }])
          }],
          hints: [inferredOutputFormatField === '/type' ? 'Either remove the target\'s declared "outputFormat" or remove the "type" field.' : `Either remove the target's declared "outputFormat" or change the extension to ${listFormat.format(expectedExtensions)}.`],
          documentationURL: 'https://parceljs.org/features/targets/#library-targets'
        }
      });
    }
    return [inferredOutputFormat, inferredOutputFormatField];
  }
}
exports.TargetResolver = TargetResolver;
function parseEngines(engines, pkgPath, pkgContents, prependKey, message) {
  if (engines === undefined) {
    return engines;
  } else {
    _utils().validateSchema.diagnostic(_TargetDescriptor.ENGINES_SCHEMA, {
      data: engines,
      source: pkgContents,
      filePath: pkgPath,
      prependKey
    }, '@parcel/core', message);
    // $FlowFixMe we just verified this
    return engines;
  }
}
function parseDescriptor(targetName, descriptor, pkgPath, pkgContents) {
  _utils().validateSchema.diagnostic(_TargetDescriptor.DESCRIPTOR_SCHEMA, {
    data: descriptor,
    source: pkgContents,
    filePath: pkgPath,
    prependKey: `/targets/${targetName}`
  }, '@parcel/core', `Invalid target descriptor for target "${targetName}"`);

  // $FlowFixMe we just verified this
  return descriptor;
}
function parsePackageDescriptor(targetName, descriptor, pkgPath, pkgContents) {
  _utils().validateSchema.diagnostic(_TargetDescriptor.PACKAGE_DESCRIPTOR_SCHEMA, {
    data: descriptor,
    source: pkgContents,
    filePath: pkgPath,
    prependKey: `/targets/${targetName}`
  }, '@parcel/core', `Invalid target descriptor for target "${targetName}"`);
  // $FlowFixMe we just verified this
  return descriptor;
}
function parseCommonTargetDescriptor(targetName, descriptor, pkgPath, pkgContents) {
  _utils().validateSchema.diagnostic(_TargetDescriptor.COMMON_TARGET_DESCRIPTOR_SCHEMA, {
    data: descriptor,
    source: pkgContents,
    filePath: pkgPath,
    prependKey: `/targets/${targetName}`
  }, '@parcel/core', `Invalid target descriptor for target "${targetName}"`);

  // $FlowFixMe we just verified this
  return descriptor;
}
function assertNoDuplicateTargets(options, targets, pkgFilePath, pkgContents) {
  // Detect duplicate targets by destination path and provide a nice error.
  // Without this, an assertion is thrown much later after naming the bundles and finding duplicates.
  let targetsByPath = new Map();
  for (let target of targets.values()) {
    if (!target) {
      continue;
    }
    let {
      distEntry
    } = target;
    if (distEntry != null) {
      var _targetsByPath$get;
      let distPath = _path().default.join((0, _projectPath.fromProjectPath)(options.projectRoot, target.distDir), distEntry);
      if (!targetsByPath.has(distPath)) {
        targetsByPath.set(distPath, []);
      }
      (_targetsByPath$get = targetsByPath.get(distPath)) === null || _targetsByPath$get === void 0 || _targetsByPath$get.push(target.name);
    }
  }
  let diagnostics = [];
  for (let [targetPath, targetNames] of targetsByPath) {
    if (targetNames.length > 1 && pkgContents != null && pkgFilePath != null) {
      diagnostics.push({
        message: (0, _diagnostic().md)`Multiple targets have the same destination path "${_path().default.relative(_path().default.dirname(pkgFilePath), targetPath)}"`,
        origin: '@parcel/core',
        codeFrames: [{
          language: 'json',
          filePath: pkgFilePath || undefined,
          code: pkgContents,
          codeHighlights: (0, _diagnostic().generateJSONCodeHighlights)(pkgContents, targetNames.map(t => ({
            key: `/${t}`,
            type: 'value'
          })))
        }]
      });
    }
  }
  if (diagnostics.length > 0) {
    // Only add hints to the last diagnostic so it isn't duplicated on each one
    diagnostics[diagnostics.length - 1].hints = ['Try removing the duplicate targets, or changing the destination paths.'];
    throw new (_diagnostic().default)({
      diagnostic: diagnostics
    });
  }
}
function normalizeSourceMap(options, sourceMap) {
  if (options.defaultTargetOptions.sourceMaps) {
    if (typeof sourceMap === 'boolean') {
      return sourceMap ? {} : undefined;
    } else {
      return sourceMap ?? {};
    }
  } else {
    return undefined;
  }
}
function assertTargetsAreNotEntries(targets, input, options) {
  for (const target of targets) {
    if (target.distEntry != null && (0, _projectPath.joinProjectPath)(target.distDir, target.distEntry) === input.filePath) {
      let loc = target.loc;
      let relativeEntry = _path().default.relative(process.cwd(), (0, _projectPath.fromProjectPath)(options.projectRoot, input.filePath));
      let codeFrames = [];
      if (loc) {
        codeFrames.push({
          filePath: (0, _projectPath.fromProjectPath)(options.projectRoot, loc.filePath),
          codeHighlights: [(0, _diagnostic().convertSourceLocationToHighlight)(loc, 'Target defined here')]
        });
        let inputLoc = input.loc;
        if (inputLoc) {
          let highlight = (0, _diagnostic().convertSourceLocationToHighlight)(inputLoc, 'Entry defined here');
          if (inputLoc.filePath === loc.filePath) {
            codeFrames[0].codeHighlights.push(highlight);
          } else {
            codeFrames.push({
              filePath: (0, _projectPath.fromProjectPath)(options.projectRoot, inputLoc.filePath),
              codeHighlights: [highlight]
            });
          }
        }
      }
      throw new (_diagnostic().default)({
        diagnostic: {
          origin: '@parcel/core',
          message: `Target "${target.name}" is configured to overwrite entry "${relativeEntry}".`,
          codeFrames,
          hints: [(COMMON_TARGETS[target.name] ? `The "${target.name}" field is an _output_ file path so that your build can be consumed by other tools. ` : '') + `Change the "${target.name}" field to point to an output file rather than your source code.`],
          documentationURL: 'https://parceljs.org/features/targets/'
        }
      });
    }
  }
}
async function debugResolvedTargets(input, targets, targetInfo, options) {
  for (let target of targets) {
    let info = targetInfo.get(target.name);
    let loc = target.loc;
    if (!loc || !info) {
      continue;
    }
    let output = (0, _projectPath.fromProjectPath)(options.projectRoot, target.distDir);
    if (target.distEntry != null) {
      output = _path().default.join(output, target.distEntry);
    }

    // Resolve relevant engines for context.
    let engines;
    switch (target.env.context) {
      case 'browser':
      case 'web-worker':
      case 'service-worker':
      case 'worklet':
        {
          let browsers = target.env.engines.browsers;
          engines = Array.isArray(browsers) ? browsers.join(', ') : browsers;
          break;
        }
      case 'node':
        engines = target.env.engines.node;
        break;
      case 'electron-main':
      case 'electron-renderer':
        engines = target.env.engines.electron;
        break;
    }
    let highlights = [];
    if (input.loc) {
      highlights.push((0, _diagnostic().convertSourceLocationToHighlight)(input.loc, 'entry defined here'));
    }

    // Read package.json where target is defined.
    let targetFilePath = (0, _projectPath.fromProjectPath)(options.projectRoot, loc.filePath);
    let contents = await options.inputFS.readFile(targetFilePath, 'utf8');

    // Builds up map of code highlights for each defined/inferred path in the package.json.
    let jsonHighlights = new Map();
    for (let key in info) {
      let keyInfo = info[key];
      let path = keyInfo.path || keyInfo.inferred;
      if (!path) {
        continue;
      }
      let type = keyInfo.type || 'value';
      let highlight = jsonHighlights.get(path);
      if (!highlight) {
        highlight = {
          type: type,
          defined: '',
          inferred: []
        };
        jsonHighlights.set(path, highlight);
      } else if (highlight.type !== type) {
        highlight.type = null;
      }
      if (keyInfo.path) {
        highlight.defined = (0, _diagnostic().md)`${key} defined here`;
      }
      if (keyInfo.inferred) {
        highlight.inferred.push((0, _diagnostic().md)`${key} to be ${JSON.stringify(target.env[key])}`);
      }
    }

    // $FlowFixMe
    let listFormat = new Intl.ListFormat('en-US');

    // Generate human friendly messages for each field.
    let highlightsWithMessages = [...jsonHighlights].map(([k, v]) => {
      let message = v.defined;
      if (v.inferred.length > 0) {
        message += (message ? ', ' : '') + 'caused ';
        message += listFormat.format(v.inferred);
      }
      return {
        key: k,
        type: v.type,
        message
      };
    });

    // Get code highlights from JSON paths.
    highlights.push(...(0, _diagnostic().generateJSONCodeHighlights)(contents, highlightsWithMessages));

    // Format includeNodeModules to be human readable.
    let includeNodeModules;
    if (typeof target.env.includeNodeModules === 'boolean') {
      includeNodeModules = String(target.env.includeNodeModules);
    } else if (Array.isArray(target.env.includeNodeModules)) {
      includeNodeModules = 'only ' + listFormat.format(target.env.includeNodeModules.map(m => JSON.stringify(m)));
    } else if (target.env.includeNodeModules && typeof target.env.includeNodeModules === 'object') {
      includeNodeModules = 'all except ' + listFormat.format(Object.entries(target.env.includeNodeModules).filter(([, v]) => v === false).map(([k]) => JSON.stringify(k)));
    }
    let format = v => v.message != null ? _diagnostic().md.italic(v.message) : '';
    _logger().default.verbose({
      origin: '@parcel/core',
      message: (0, _diagnostic().md)`**Target** "${target.name}"

               **Entry**: ${_path().default.relative(process.cwd(), (0, _projectPath.fromProjectPath)(options.projectRoot, input.filePath))}
              **Output**: ${_path().default.relative(process.cwd(), output)}
              **Format**: ${target.env.outputFormat} ${format(info.outputFormat)}
             **Context**: ${target.env.context} ${format(info.context)}
             **Engines**: ${engines || ''} ${format(info.engines)}
        **Library Mode**: ${String(target.env.isLibrary)} ${format(info.isLibrary)}
**Include Node Modules**: ${includeNodeModules} ${format(info.includeNodeModules)}
            **Optimize**: ${String(target.env.shouldOptimize)} ${format(info.shouldOptimize)}`,
      codeFrames: target.loc ? [{
        filePath: targetFilePath,
        codeHighlights: highlights
      }] : []
    });
  }
}