text: /*
  	MIT License http://www.opensource.org/licenses/mit-license.php
  	Author Tobias Koppers @sokra
  */
  "use strict";
  
  const DependencyReference = require("./DependencyReference");
  const HarmonyImportDependency = require("./HarmonyImportDependency");
  const Template = require("../Template");
  const HarmonyLinkingError = require("../HarmonyLinkingError");
  
  /** @typedef {import("../Module")} Module */
  
  /** @typedef {"missing"|"unused"|"empty-star"|"reexport-non-harmony-default"|"reexport-named-default"|"reexport-namespace-object"|"reexport-non-harmony-default-strict"|"reexport-fake-namespace-object"|"rexport-non-harmony-undefined"|"safe-reexport"|"checked-reexport"|"dynamic-reexport"} ExportModeType */
  
  /** @type {Map<string, string>} */
  const EMPTY_MAP = new Map();
  
  class ExportMode {
  	/**
  	 * @param {ExportModeType} type type of the mode
  	 */
  	constructor(type) {
  		/** @type {ExportModeType} */
  		this.type = type;
  		/** @type {string|null} */
  		this.name = null;
  		/** @type {Map<string, string>} */
  		this.map = EMPTY_MAP;
  		/** @type {Module|null} */
  		this.module = null;
  		/** @type {string|null} */
  		this.userRequest = null;
  	}
  }
  
  const EMPTY_STAR_MODE = new ExportMode("empty-star");
  
  class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
  	constructor(
  		request,
  		originModule,
  		sourceOrder,
  		parserScope,
  		id,
  		name,
  		activeExports,
  		otherStarExports,
  		strictExportPresence
  	) {
  		super(request, originModule, sourceOrder, parserScope);
  		this.id = id;
  		this.redirectedId = undefined;
  		this.name = name;
  		this.activeExports = activeExports;
  		this.otherStarExports = otherStarExports;
  		this.strictExportPresence = strictExportPresence;
  	}
  
  	get type() {
  		return "harmony export imported specifier";
  	}
  
  	get _id() {
  		return this.redirectedId || this.id;
  	}
  
  	getMode(ignoreUnused) {
  		const name = this.name;
  		const id = this._id;
  		const used = this.originModule.isUsed(name);
  		const importedModule = this._module;
  
  		if (!importedModule) {
  			const mode = new ExportMode("missing");
  			mode.userRequest = this.userRequest;
  			return mode;
  		}
  
  		if (
  			!ignoreUnused &&
  			(name ? !used : this.originModule.usedExports === false)
  		) {
  			const mode = new ExportMode("unused");
  			mode.name = name || "*";
  			return mode;
  		}
  
  		const strictHarmonyModule = this.originModule.buildMeta.strictHarmonyModule;
  		if (name && id === "default" && importedModule.buildMeta) {
  			if (!importedModule.buildMeta.exportsType) {
  				const mode = new ExportMode(
  					strictHarmonyModule
  						? "reexport-non-harmony-default-strict"
  						: "reexport-non-harmony-default"
  				);
  				mode.name = name;
  				mode.module = importedModule;
  				return mode;
  			} else if (importedModule.buildMeta.exportsType === "named") {
  				const mode = new ExportMode("reexport-named-default");
  				mode.name = name;
  				mode.module = importedModule;
  				return mode;
  			}
  		}
  
  		const isNotAHarmonyModule =
  			importedModule.buildMeta && !importedModule.buildMeta.exportsType;
  		if (name) {
  			let mode;
  			if (id) {
  				// export { name as name }
  				if (isNotAHarmonyModule && strictHarmonyModule) {
  					mode = new ExportMode("rexport-non-harmony-undefined");
  					mode.name = name;
  				} else {
  					mode = new ExportMode("safe-reexport");
  					mode.map = new Map([[name, id]]);
  				}
  			} else {
  				// export { * as name }
  				if (isNotAHarmonyModule && strictHarmonyModule) {
  					mode = new ExportMode("reexport-fake-namespace-object");
  					mode.name = name;
  				} else {
  					mode = new ExportMode("reexport-namespace-object");
  					mode.name = name;
  				}
  			}
  			mode.module = importedModule;
  			return mode;
  		}
  
  		const hasUsedExports = Array.isArray(this.originModule.usedExports);
  		const hasProvidedExports = Array.isArray(
  			importedModule.buildMeta.providedExports
  		);
  		const activeFromOtherStarExports = this._discoverActiveExportsFromOtherStartExports();
  
  		// export *
  		if (hasUsedExports) {
  			// reexport * with known used exports
  			if (hasProvidedExports) {
  				const map = new Map(
  					this.originModule.usedExports
  						.filter(id => {
  							if (id === "default") return false;
  							if (this.activeExports.has(id)) return false;
  							if (activeFromOtherStarExports.has(id)) return false;
  							if (!importedModule.buildMeta.providedExports.includes(id))
  								return false;
  							return true;
  						})
  						.map(item => [item, item])
  				);
  
  				if (map.size === 0) {
  					return EMPTY_STAR_MODE;
  				}
  
  				const mode = new ExportMode("safe-reexport");
  				mode.module = importedModule;
  				mode.map = map;
  				return mode;
  			}
  
  			const map = new Map(
  				this.originModule.usedExports
  					.filter(id => {
  						if (id === "default") return false;
  						if (this.activeExports.has(id)) return false;
  						if (activeFromOtherStarExports.has(id)) return false;
  
  						return true;
  					})
  					.map(item => [item, item])
  			);
  
  			if (map.size === 0) {
  				return EMPTY_STAR_MODE;
  			}
  
  			const mode = new ExportMode("checked-reexport");
  			mode.module = importedModule;
  			mode.map = map;
  			return mode;
  		}
  
  		if (hasProvidedExports) {
  			const map = new Map(
  				importedModule.buildMeta.providedExports
  					.filter(id => {
  						if (id === "default") return false;
  						if (this.activeExports.has(id)) return false;
  						if (activeFromOtherStarExports.has(id)) return false;
  
  						return true;
  					})
  					.map(item => [item, item])
  			);
  
  			if (map.size === 0) {
  				return EMPTY_STAR_MODE;
  			}
  
  			const mode = new ExportMode("safe-reexport");
  			mode.module = importedModule;
  			mode.map = map;
  			return mode;
  		}
  
  		const mode = new ExportMode("dynamic-reexport");
  		mode.module = importedModule;
  		return mode;
  	}
  
  	getReference() {
  		const mode = this.getMode(false);
  
  		switch (mode.type) {
  			case "missing":
  			case "unused":
  			case "empty-star":
  				return null;
  
  			case "reexport-non-harmony-default":
  			case "reexport-named-default":
  				return new DependencyReference(
  					mode.module,
  					["default"],
  					false,
  					this.sourceOrder
  				);
  
  			case "reexport-namespace-object":
  			case "reexport-non-harmony-default-strict":
  			case "reexport-fake-namespace-object":
  			case "rexport-non-harmony-undefined":
  				return new DependencyReference(
  					mode.module,
  					true,
  					false,
  					this.sourceOrder
  				);
  
  			case "safe-reexport":
  			case "checked-reexport":
  				return new DependencyReference(
  					mode.module,
  					Array.from(mode.map.values()),
  					false,
  					this.sourceOrder
  				);
  
  			case "dynamic-reexport":
  				return new DependencyReference(
  					mode.module,
  					true,
  					false,
  					this.sourceOrder
  				);
  
  			default:
  				throw new Error(`Unknown mode ${mode.type}`);
  		}
  	}
  
  	_discoverActiveExportsFromOtherStartExports() {
  		if (!this.otherStarExports) return new Set();
  		const result = new Set();
  		// try to learn impossible exports from other star exports with provided exports
  		for (const otherStarExport of this.otherStarExports) {
  			const otherImportedModule = otherStarExport._module;
  			if (
  				otherImportedModule &&
  				Array.isArray(otherImportedModule.buildMeta.providedExports)
  			) {
  				for (const exportName of otherImportedModule.buildMeta
  					.providedExports) {
  					result.add(exportName);
  				}
  			}
  		}
  		return result;
  	}
  
  	getExports() {
  		if (this.name) {
  			return {
  				exports: [this.name],
  				dependencies: undefined
  			};
  		}
  
  		const importedModule = this._module;
  
  		if (!importedModule) {
  			// no imported module available
  			return {
  				exports: null,
  				dependencies: undefined
  			};
  		}
  
  		if (Array.isArray(importedModule.buildMeta.providedExports)) {
  			const activeFromOtherStarExports = this._discoverActiveExportsFromOtherStartExports();
  			return {
  				exports: importedModule.buildMeta.providedExports.filter(
  					id =>
  						id !== "default" &&
  						!activeFromOtherStarExports.has(id) &&
  						!this.activeExports.has(id)
  				),
  				dependencies: [importedModule]
  			};
  		}
  
  		if (importedModule.buildMeta.providedExports) {
  			return {
  				exports: true,
  				dependencies: undefined
  			};
  		}
  
  		return {
  			exports: null,
  			dependencies: [importedModule]
  		};
  	}
  
  	getWarnings() {
  		if (
  			this.strictExportPresence ||
  			this.originModule.buildMeta.strictHarmonyModule
  		) {
  			return [];
  		}
  		return this._getErrors();
  	}
  
  	getErrors() {
  		if (
  			this.strictExportPresence ||
  			this.originModule.buildMeta.strictHarmonyModule
  		) {
  			return this._getErrors();
  		}
  		return [];
  	}
  
  	_getErrors() {
  		const importedModule = this._module;
  		if (!importedModule) {
  			return;
  		}
  
  		if (!importedModule.buildMeta || !importedModule.buildMeta.exportsType) {
  			// It's not an harmony module
  			if (
  				this.originModule.buildMeta.strictHarmonyModule &&
  				this._id &&
  				this._id !== "default"
  			) {
  				// In strict harmony modules we only support the default export
  				return [
  					new HarmonyLinkingError(
  						`Can't reexport the named export '${this._id}' from non EcmaScript module (only default export is available)`
  					)
  				];
  			}
  			return;
  		}
  
  		if (!this._id) {
  			return;
  		}
  
  		if (importedModule.isProvided(this._id) !== false) {
  			// It's provided or we are not sure
  			return;
  		}
  
  		// We are sure that it's not provided
  		const idIsNotNameMessage =
  			this._id !== this.name ? ` (reexported as '${this.name}')` : "";
  		const errorMessage = `"export '${this._id}'${idIsNotNameMessage} was not found in '${this.userRequest}'`;
  		return [new HarmonyLinkingError(errorMessage)];
  	}
  
  	updateHash(hash) {
  		super.updateHash(hash);
  		const hashValue = this.getHashValue(this._module);
  		hash.update(hashValue);
  	}
  
  	getHashValue(importedModule) {
  		if (!importedModule) {
  			return "";
  		}
  
  		const stringifiedUsedExport = JSON.stringify(importedModule.usedExports);
  		const stringifiedProvidedExport = JSON.stringify(
  			importedModule.buildMeta.providedExports
  		);
  		return (
  			importedModule.used + stringifiedUsedExport + stringifiedProvidedExport
  		);
  	}
  
  	disconnect() {
  		super.disconnect();
  		this.redirectedId = undefined;
  	}
  }
  
  module.exports = HarmonyExportImportedSpecifierDependency;
  
  HarmonyExportImportedSpecifierDependency.Template = class HarmonyExportImportedSpecifierDependencyTemplate extends HarmonyImportDependency.Template {
  	harmonyInit(dep, source, runtime, dependencyTemplates) {
  		super.harmonyInit(dep, source, runtime, dependencyTemplates);
  		const content = this.getContent(dep);
  		source.insert(-1, content);
  	}
  
  	getHarmonyInitOrder(dep) {
  		if (dep.name) {
  			const used = dep.originModule.isUsed(dep.name);
  			if (!used) return NaN;
  		} else {
  			const importedModule = dep._module;
  
  			const activeFromOtherStarExports = dep._discoverActiveExportsFromOtherStartExports();
  
  			if (Array.isArray(dep.originModule.usedExports)) {
  				// we know which exports are used
  
  				const unused = dep.originModule.usedExports.every(id => {
  					if (id === "default") return true;
  					if (dep.activeExports.has(id)) return true;
  					if (importedModule.isProvided(id) === false) return true;
  					if (activeFromOtherStarExports.has(id)) return true;
  					return false;
  				});
  				if (unused) return NaN;
  			} else if (
  				dep.originModule.usedExports &&
  				importedModule &&
  				Array.isArray(importedModule.buildMeta.providedExports)
  			) {
  				// not sure which exports are used, but we know which are provided
  
  				const unused = importedModule.buildMeta.providedExports.every(id => {
  					if (id === "default") return true;
  					if (dep.activeExports.has(id)) return true;
  					if (activeFromOtherStarExports.has(id)) return true;
  					return false;
  				});
  				if (unused) return NaN;
  			}
  		}
  		return super.getHarmonyInitOrder(dep);
  	}
  
  	getContent(dep) {
  		const mode = dep.getMode(false);
  		const module = dep.originModule;
  		const importedModule = dep._module;
  		const importVar = dep.getImportVar();
  
  		switch (mode.type) {
  			case "missing":
  				return `throw new Error(${JSON.stringify(
  					`Cannot find module '${mode.userRequest}'`
  				)});\n`;
  
  			case "unused":
  				return `${Template.toNormalComment(
  					`unused harmony reexport ${mode.name}`
  				)}\n`;
  
  			case "reexport-non-harmony-default":
  				return (
  					"/* harmony reexport (default from non-harmony) */ " +
  					this.getReexportStatement(
  						module,
  						module.isUsed(mode.name),
  						importVar,
  						null
  					)
  				);
  
  			case "reexport-named-default":
  				return (
  					"/* harmony reexport (default from named exports) */ " +
  					this.getReexportStatement(
  						module,
  						module.isUsed(mode.name),
  						importVar,
  						""
  					)
  				);
  
  			case "reexport-fake-namespace-object":
  				return (
  					"/* harmony reexport (fake namespace object from non-harmony) */ " +
  					this.getReexportFakeNamespaceObjectStatement(
  						module,
  						module.isUsed(mode.name),
  						importVar
  					)
  				);
  
  			case "rexport-non-harmony-undefined":
  				return (
  					"/* harmony reexport (non default export from non-harmony) */ " +
  					this.getReexportStatement(
  						module,
  						module.isUsed(mode.name),
  						"undefined",
  						""
  					)
  				);
  
  			case "reexport-non-harmony-default-strict":
  				return (
  					"/* harmony reexport (default from non-harmony) */ " +
  					this.getReexportStatement(
  						module,
  						module.isUsed(mode.name),
  						importVar,
  						""
  					)
  				);
  
  			case "reexport-namespace-object":
  				return (
  					"/* harmony reexport (module object) */ " +
  					this.getReexportStatement(
  						module,
  						module.isUsed(mode.name),
  						importVar,
  						""
  					)
  				);
  
  			case "empty-star":
  				return "/* empty/unused harmony star reexport */";
  
  			case "safe-reexport":
  				return Array.from(mode.map.entries())
  					.map(item => {
  						return (
  							"/* harmony reexport (safe) */ " +
  							this.getReexportStatement(
  								module,
  								module.isUsed(item[0]),
  								importVar,
  								importedModule.isUsed(item[1])
  							) +
  							"\n"
  						);
  					})
  					.join("");
  
  			case "checked-reexport":
  				return Array.from(mode.map.entries())
  					.map(item => {
  						return (
  							"/* harmony reexport (checked) */ " +
  							this.getConditionalReexportStatement(
  								module,
  								item[0],
  								importVar,
  								item[1]
  							) +
  							"\n"
  						);
  					})
  					.join("");
  
  			case "dynamic-reexport": {
  				const activeExports = new Set([
  					...dep.activeExports,
  					...dep._discoverActiveExportsFromOtherStartExports()
  				]);
  				let content =
  					"/* harmony reexport (unknown) */ for(var __WEBPACK_IMPORT_KEY__ in " +
  					importVar +
  					") ";
  
  				// Filter out exports which are defined by other exports
  				// and filter out default export because it cannot be reexported with *
  				if (activeExports.size > 0) {
  					content +=
  						"if(" +
  						JSON.stringify(Array.from(activeExports).concat("default")) +
  						".indexOf(__WEBPACK_IMPORT_KEY__) < 0) ";
  				} else {
  					content += "if(__WEBPACK_IMPORT_KEY__ !== 'default') ";
  				}
  				const exportsName = dep.originModule.exportsArgument;
  				return (
  					content +
  					`(function(key) { __webpack_require__.d(${exportsName}, key, function() { return ${importVar}[key]; }) }(__WEBPACK_IMPORT_KEY__));\n`
  				);
  			}
  
  			default:
  				throw new Error(`Unknown mode ${mode.type}`);
  		}
  	}
  
  	getReexportStatement(module, key, name, valueKey) {
  		const exportsName = module.exportsArgument;
  		const returnValue = this.getReturnValue(name, valueKey);
  		return `__webpack_require__.d(${exportsName}, ${JSON.stringify(
  			key
  		)}, function() { return ${returnValue}; });\n`;
  	}
  
  	getReexportFakeNamespaceObjectStatement(module, key, name) {
  		const exportsName = module.exportsArgument;
  		return `__webpack_require__.d(${exportsName}, ${JSON.stringify(
  			key
  		)}, function() { return __webpack_require__.t(${name}); });\n`;
  	}
  
  	getConditionalReexportStatement(module, key, name, valueKey) {
  		if (valueKey === false) {
  			return "/* unused export */\n";
  		}
  		const exportsName = module.exportsArgument;
  		const returnValue = this.getReturnValue(name, valueKey);
  		return `if(__webpack_require__.o(${name}, ${JSON.stringify(
  			valueKey
  		)})) __webpack_require__.d(${exportsName}, ${JSON.stringify(
  			key
  		)}, function() { return ${returnValue}; });\n`;
  	}
  
  	getReturnValue(name, valueKey) {
  		if (valueKey === null) {
  			return `${name}_default.a`;
  		}
  		if (valueKey === "") {
  			return name;
  		}
  		if (valueKey === false) {
  			return "/* unused export */ undefined";
  		}
  
  		return `${name}[${JSON.stringify(valueKey)}]`;
  	}
  };
  