| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 | /*	MIT License http://www.opensource.org/licenses/mit-license.php	Author Tobias Koppers @sokra*/"use strict";const { RawSource, ReplaceSource } = require("webpack-sources");// TODO: clean up this file// replace with newer constructs// TODO: remove DependencyVariables and replace them with something betterclass JavascriptGenerator {	generate(module, dependencyTemplates, runtimeTemplate) {		const originalSource = module.originalSource();		if (!originalSource) {			return new RawSource("throw new Error('No source available');");		}		const source = new ReplaceSource(originalSource);		this.sourceBlock(			module,			module,			[],			dependencyTemplates,			source,			runtimeTemplate		);		return source;	}	sourceBlock(		module,		block,		availableVars,		dependencyTemplates,		source,		runtimeTemplate	) {		for (const dependency of block.dependencies) {			this.sourceDependency(				dependency,				dependencyTemplates,				source,				runtimeTemplate			);		}		/**		 * Get the variables of all blocks that we need to inject.		 * These will contain the variable name and its expression.		 * The name will be added as a parameter in a IIFE the expression as its value.		 */		const vars = block.variables.reduce((result, value) => {			const variable = this.sourceVariables(				value,				availableVars,				dependencyTemplates,				runtimeTemplate			);			if (variable) {				result.push(variable);			}			return result;		}, []);		/**		 * if we actually have variables		 * this is important as how #splitVariablesInUniqueNamedChunks works		 * it will always return an array in an array which would lead to a IIFE wrapper around		 * a module if we do this with an empty vars array.		 */		if (vars.length > 0) {			/**			 * Split all variables up into chunks of unique names.			 * e.g. imagine you have the following variable names that need to be injected:			 * [foo, bar, baz, foo, some, more]			 * we can not inject "foo" twice, therefore we just make two IIFEs like so:			 * (function(foo, bar, baz){			 *   (function(foo, some, more){			 *     …			 *   }(…));			 * }(…));			 *			 * "splitVariablesInUniqueNamedChunks" splits the variables shown above up to this:			 * [[foo, bar, baz], [foo, some, more]]			 */			const injectionVariableChunks = this.splitVariablesInUniqueNamedChunks(				vars			);			// create all the beginnings of IIFEs			const functionWrapperStarts = injectionVariableChunks.map(				variableChunk => {					return this.variableInjectionFunctionWrapperStartCode(						variableChunk.map(variable => variable.name)					);				}			);			// and all the ends			const functionWrapperEnds = injectionVariableChunks.map(variableChunk => {				return this.variableInjectionFunctionWrapperEndCode(					module,					variableChunk.map(variable => variable.expression),					block				);			});			// join them to one big string			const varStartCode = functionWrapperStarts.join("");			// reverse the ends first before joining them, as the last added must be the inner most			const varEndCode = functionWrapperEnds.reverse().join("");			// if we have anything, add it to the source			if (varStartCode && varEndCode) {				const start = block.range ? block.range[0] : -10;				const end = block.range					? block.range[1]					: module.originalSource().size() + 1;				source.insert(start + 0.5, varStartCode);				source.insert(end + 0.5, "\n/* WEBPACK VAR INJECTION */" + varEndCode);			}		}		for (const childBlock of block.blocks) {			this.sourceBlock(				module,				childBlock,				availableVars.concat(vars),				dependencyTemplates,				source,				runtimeTemplate			);		}	}	sourceDependency(dependency, dependencyTemplates, source, runtimeTemplate) {		const template = dependencyTemplates.get(dependency.constructor);		if (!template) {			throw new Error(				"No template for dependency: " + dependency.constructor.name			);		}		template.apply(dependency, source, runtimeTemplate, dependencyTemplates);	}	sourceVariables(		variable,		availableVars,		dependencyTemplates,		runtimeTemplate	) {		const name = variable.name;		const expr = variable.expressionSource(			dependencyTemplates,			runtimeTemplate		);		if (			availableVars.some(				v => v.name === name && v.expression.source() === expr.source()			)		) {			return;		}		return {			name: name,			expression: expr		};	}	/*	 * creates the start part of a IIFE around the module to inject a variable name	 * (function(…){   <- this part	 * }.call(…))	 */	variableInjectionFunctionWrapperStartCode(varNames) {		const args = varNames.join(", ");		return `/* WEBPACK VAR INJECTION */(function(${args}) {`;	}	contextArgument(module, block) {		if (this === block) {			return module.exportsArgument;		}		return "this";	}	/*	 * creates the end part of a IIFE around the module to inject a variable name	 * (function(…){	 * }.call(…))   <- this part	 */	variableInjectionFunctionWrapperEndCode(module, varExpressions, block) {		const firstParam = this.contextArgument(module, block);		const furtherParams = varExpressions.map(e => e.source()).join(", ");		return `}.call(${firstParam}, ${furtherParams}))`;	}	splitVariablesInUniqueNamedChunks(vars) {		const startState = [[]];		return vars.reduce((chunks, variable) => {			const current = chunks[chunks.length - 1];			// check if variable with same name exists already			// if so create a new chunk of variables.			const variableNameAlreadyExists = current.some(				v => v.name === variable.name			);			if (variableNameAlreadyExists) {				// start new chunk with current variable				chunks.push([variable]);			} else {				// else add it to current chunk				current.push(variable);			}			return chunks;		}, startState);	}}module.exports = JavascriptGenerator;
 |