text: /*
  	MIT License http://www.opensource.org/licenses/mit-license.php
  	Author Tobias Koppers @sokra
  */
  "use strict";
  
  const { ConcatSource, OriginalSource } = require("webpack-sources");
  const Template = require("./Template");
  
  /** @typedef {import("./Compilation")} Compilation */
  
  /**
   * @param {string[]} accessor the accessor to convert to path
   * @returns {string} the path
   */
  const accessorToObjectAccess = accessor => {
  	return accessor.map(a => `[${JSON.stringify(a)}]`).join("");
  };
  
  /**
   * @param {string=} base the path prefix
   * @param {string|string[]} accessor the accessor
   * @param {string=} joinWith the element separator
   * @returns {string} the path
   */
  const accessorAccess = (base, accessor, joinWith = ", ") => {
  	const accessors = Array.isArray(accessor) ? accessor : [accessor];
  	return accessors
  		.map((_, idx) => {
  			const a = base
  				? base + accessorToObjectAccess(accessors.slice(0, idx + 1))
  				: accessors[0] + accessorToObjectAccess(accessors.slice(1, idx + 1));
  			if (idx === accessors.length - 1) return a;
  			if (idx === 0 && typeof base === "undefined")
  				return `${a} = typeof ${a} === "object" ? ${a} : {}`;
  			return `${a} = ${a} || {}`;
  		})
  		.join(joinWith);
  };
  
  /** @typedef {string | string[] | Record<string, string | string[]>} UmdMainTemplatePluginName */
  
  /**
   * @typedef {Object} AuxiliaryCommentObject
   * @property {string} root
   * @property {string} commonjs
   * @property {string} commonjs2
   * @property {string} amd
   */
  
  /**
   * @typedef {Object} UmdMainTemplatePluginOption
   * @property {boolean=} optionalAmdExternalAsGlobal
   * @property {boolean} namedDefine
   * @property {string | AuxiliaryCommentObject} auxiliaryComment
   */
  
  class UmdMainTemplatePlugin {
  	/**
  	 * @param {UmdMainTemplatePluginName} name the name of the UMD library
  	 * @param {UmdMainTemplatePluginOption} options the plugin option
  	 */
  	constructor(name, options) {
  		if (typeof name === "object" && !Array.isArray(name)) {
  			this.name = name.root || name.amd || name.commonjs;
  			this.names = name;
  		} else {
  			this.name = name;
  			this.names = {
  				commonjs: name,
  				root: name,
  				amd: name
  			};
  		}
  		this.optionalAmdExternalAsGlobal = options.optionalAmdExternalAsGlobal;
  		this.namedDefine = options.namedDefine;
  		this.auxiliaryComment = options.auxiliaryComment;
  	}
  
  	/**
  	 * @param {Compilation} compilation the compilation instance
  	 * @returns {void}
  	 */
  	apply(compilation) {
  		const { mainTemplate, chunkTemplate, runtimeTemplate } = compilation;
  
  		const onRenderWithEntry = (source, chunk, hash) => {
  			let externals = chunk
  				.getModules()
  				.filter(
  					m =>
  						m.external &&
  						(m.externalType === "umd" || m.externalType === "umd2")
  				);
  			const optionalExternals = [];
  			let requiredExternals = [];
  			if (this.optionalAmdExternalAsGlobal) {
  				for (const m of externals) {
  					if (m.optional) {
  						optionalExternals.push(m);
  					} else {
  						requiredExternals.push(m);
  					}
  				}
  				externals = requiredExternals.concat(optionalExternals);
  			} else {
  				requiredExternals = externals;
  			}
  
  			function replaceKeys(str) {
  				return mainTemplate.getAssetPath(str, {
  					hash,
  					chunk
  				});
  			}
  
  			function externalsDepsArray(modules) {
  				return `[${replaceKeys(
  					modules
  						.map(m =>
  							JSON.stringify(
  								typeof m.request === "object" ? m.request.amd : m.request
  							)
  						)
  						.join(", ")
  				)}]`;
  			}
  
  			function externalsRootArray(modules) {
  				return replaceKeys(
  					modules
  						.map(m => {
  							let request = m.request;
  							if (typeof request === "object") request = request.root;
  							return `root${accessorToObjectAccess([].concat(request))}`;
  						})
  						.join(", ")
  				);
  			}
  
  			function externalsRequireArray(type) {
  				return replaceKeys(
  					externals
  						.map(m => {
  							let expr;
  							let request = m.request;
  							if (typeof request === "object") request = request[type];
  							if (typeof request === "undefined")
  								throw new Error(
  									"Missing external configuration for type:" + type
  								);
  							if (Array.isArray(request)) {
  								expr = `require(${JSON.stringify(
  									request[0]
  								)})${accessorToObjectAccess(request.slice(1))}`;
  							} else expr = `require(${JSON.stringify(request)})`;
  							if (m.optional) {
  								expr = `(function webpackLoadOptionalExternalModule() { try { return ${expr}; } catch(e) {} }())`;
  							}
  							return expr;
  						})
  						.join(", ")
  				);
  			}
  
  			function externalsArguments(modules) {
  				return modules
  					.map(
  						m =>
  							`__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(`${m.id}`)}__`
  					)
  					.join(", ");
  			}
  
  			function libraryName(library) {
  				return JSON.stringify(replaceKeys([].concat(library).pop()));
  			}
  
  			let amdFactory;
  			if (optionalExternals.length > 0) {
  				const wrapperArguments = externalsArguments(requiredExternals);
  				const factoryArguments =
  					requiredExternals.length > 0
  						? externalsArguments(requiredExternals) +
  						  ", " +
  						  externalsRootArray(optionalExternals)
  						: externalsRootArray(optionalExternals);
  				amdFactory =
  					`function webpackLoadOptionalExternalModuleAmd(${wrapperArguments}) {\n` +
  					`			return factory(${factoryArguments});\n` +
  					"		}";
  			} else {
  				amdFactory = "factory";
  			}
  
  			const auxiliaryComment = this.auxiliaryComment;
  
  			const getAuxilaryComment = type => {
  				if (auxiliaryComment) {
  					if (typeof auxiliaryComment === "string")
  						return "\t//" + auxiliaryComment + "\n";
  					if (auxiliaryComment[type])
  						return "\t//" + auxiliaryComment[type] + "\n";
  				}
  				return "";
  			};
  
  			return new ConcatSource(
  				new OriginalSource(
  					"(function webpackUniversalModuleDefinition(root, factory) {\n" +
  						getAuxilaryComment("commonjs2") +
  						"	if(typeof exports === 'object' && typeof module === 'object')\n" +
  						"		module.exports = factory(" +
  						externalsRequireArray("commonjs2") +
  						");\n" +
  						getAuxilaryComment("amd") +
  						"	else if(typeof define === 'function' && define.amd)\n" +
  						(requiredExternals.length > 0
  							? this.names.amd && this.namedDefine === true
  								? "		define(" +
  								  libraryName(this.names.amd) +
  								  ", " +
  								  externalsDepsArray(requiredExternals) +
  								  ", " +
  								  amdFactory +
  								  ");\n"
  								: "		define(" +
  								  externalsDepsArray(requiredExternals) +
  								  ", " +
  								  amdFactory +
  								  ");\n"
  							: this.names.amd && this.namedDefine === true
  								? "		define(" +
  								  libraryName(this.names.amd) +
  								  ", [], " +
  								  amdFactory +
  								  ");\n"
  								: "		define([], " + amdFactory + ");\n") +
  						(this.names.root || this.names.commonjs
  							? getAuxilaryComment("commonjs") +
  							  "	else if(typeof exports === 'object')\n" +
  							  "		exports[" +
  							  libraryName(this.names.commonjs || this.names.root) +
  							  "] = factory(" +
  							  externalsRequireArray("commonjs") +
  							  ");\n" +
  							  getAuxilaryComment("root") +
  							  "	else\n" +
  							  "		" +
  							  replaceKeys(
  									accessorAccess("root", this.names.root || this.names.commonjs)
  							  ) +
  							  " = factory(" +
  							  externalsRootArray(externals) +
  							  ");\n"
  							: "	else {\n" +
  							  (externals.length > 0
  									? "		var a = typeof exports === 'object' ? factory(" +
  									  externalsRequireArray("commonjs") +
  									  ") : factory(" +
  									  externalsRootArray(externals) +
  									  ");\n"
  									: "		var a = factory();\n") +
  							  "		for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n" +
  							  "	}\n") +
  						`})(${
  							runtimeTemplate.outputOptions.globalObject
  						}, function(${externalsArguments(externals)}) {\nreturn `,
  					"webpack/universalModuleDefinition"
  				),
  				source,
  				";\n})"
  			);
  		};
  
  		for (const template of [mainTemplate, chunkTemplate]) {
  			template.hooks.renderWithEntry.tap(
  				"UmdMainTemplatePlugin",
  				onRenderWithEntry
  			);
  		}
  
  		mainTemplate.hooks.globalHashPaths.tap("UmdMainTemplatePlugin", paths => {
  			if (this.names.root) paths = paths.concat(this.names.root);
  			if (this.names.amd) paths = paths.concat(this.names.amd);
  			if (this.names.commonjs) paths = paths.concat(this.names.commonjs);
  			return paths;
  		});
  
  		mainTemplate.hooks.hash.tap("UmdMainTemplatePlugin", hash => {
  			hash.update("umd");
  			hash.update(`${this.names.root}`);
  			hash.update(`${this.names.amd}`);
  			hash.update(`${this.names.commonjs}`);
  		});
  	}
  }
  
  module.exports = UmdMainTemplatePlugin;
  