| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555 | 
							- /*
 
- 	MIT License http://www.opensource.org/licenses/mit-license.php
 
- 	Author Tobias Koppers @sokra
 
- */
 
- "use strict";
 
- const path = require("path");
 
- const NativeModule = require("module");
 
- const crypto = require("crypto");
 
- const SourceMapSource = require("webpack-sources").SourceMapSource;
 
- const OriginalSource = require("webpack-sources").OriginalSource;
 
- const RawSource = require("webpack-sources").RawSource;
 
- const ReplaceSource = require("webpack-sources").ReplaceSource;
 
- const CachedSource = require("webpack-sources").CachedSource;
 
- const LineToLineMappedSource = require("webpack-sources").LineToLineMappedSource;
 
- const WebpackError = require("./WebpackError");
 
- const Module = require("./Module");
 
- const ModuleParseError = require("./ModuleParseError");
 
- const ModuleBuildError = require("./ModuleBuildError");
 
- const ModuleError = require("./ModuleError");
 
- const ModuleWarning = require("./ModuleWarning");
 
- const runLoaders = require("loader-runner").runLoaders;
 
- const getContext = require("loader-runner").getContext;
 
- function asString(buf) {
 
- 	if(Buffer.isBuffer(buf)) {
 
- 		return buf.toString("utf-8");
 
- 	}
 
- 	return buf;
 
- }
 
- function contextify(context, request) {
 
- 	return request.split("!").map(function(r) {
 
- 		let rp = path.relative(context, r);
 
- 		if(path.sep === "\\")
 
- 			rp = rp.replace(/\\/g, "/");
 
- 		if(rp.indexOf("../") !== 0)
 
- 			rp = "./" + rp;
 
- 		return rp;
 
- 	}).join("!");
 
- }
 
- class NonErrorEmittedError extends WebpackError {
 
- 	constructor(error) {
 
- 		super();
 
- 		this.name = "NonErrorEmittedError";
 
- 		this.message = "(Emitted value instead of an instance of Error) " + error;
 
- 		Error.captureStackTrace(this, this.constructor);
 
- 	}
 
- }
 
- const dependencyTemplatesHashMap = new WeakMap();
 
- class NormalModule extends Module {
 
- 	constructor(request, userRequest, rawRequest, loaders, resource, parser) {
 
- 		super();
 
- 		this.request = request;
 
- 		this.userRequest = userRequest;
 
- 		this.rawRequest = rawRequest;
 
- 		this.parser = parser;
 
- 		this.resource = resource;
 
- 		this.context = getContext(resource);
 
- 		this.loaders = loaders;
 
- 		this.fileDependencies = [];
 
- 		this.contextDependencies = [];
 
- 		this.warnings = [];
 
- 		this.errors = [];
 
- 		this.error = null;
 
- 		this._source = null;
 
- 		this.assets = {};
 
- 		this.built = false;
 
- 		this._cachedSource = null;
 
- 	}
 
- 	identifier() {
 
- 		return this.request;
 
- 	}
 
- 	readableIdentifier(requestShortener) {
 
- 		return requestShortener.shorten(this.userRequest);
 
- 	}
 
- 	libIdent(options) {
 
- 		return contextify(options.context, this.userRequest);
 
- 	}
 
- 	nameForCondition() {
 
- 		const idx = this.resource.indexOf("?");
 
- 		if(idx >= 0) return this.resource.substr(0, idx);
 
- 		return this.resource;
 
- 	}
 
- 	createSourceForAsset(name, content, sourceMap) {
 
- 		if(!sourceMap) {
 
- 			return new RawSource(content);
 
- 		}
 
- 		if(typeof sourceMap === "string") {
 
- 			return new OriginalSource(content, sourceMap);
 
- 		}
 
- 		return new SourceMapSource(content, name, sourceMap);
 
- 	}
 
- 	createLoaderContext(resolver, options, compilation, fs) {
 
- 		const loaderContext = {
 
- 			version: 2,
 
- 			emitWarning: (warning) => {
 
- 				if(!(warning instanceof Error))
 
- 					warning = new NonErrorEmittedError(warning);
 
- 				this.warnings.push(new ModuleWarning(this, warning));
 
- 			},
 
- 			emitError: (error) => {
 
- 				if(!(error instanceof Error))
 
- 					error = new NonErrorEmittedError(error);
 
- 				this.errors.push(new ModuleError(this, error));
 
- 			},
 
- 			exec: (code, filename) => {
 
- 				const module = new NativeModule(filename, this);
 
- 				module.paths = NativeModule._nodeModulePaths(this.context);
 
- 				module.filename = filename;
 
- 				module._compile(code, filename);
 
- 				return module.exports;
 
- 			},
 
- 			resolve(context, request, callback) {
 
- 				resolver.resolve({}, context, request, callback);
 
- 			},
 
- 			resolveSync(context, request) {
 
- 				return resolver.resolveSync({}, context, request);
 
- 			},
 
- 			emitFile: (name, content, sourceMap) => {
 
- 				this.assets[name] = this.createSourceForAsset(name, content, sourceMap);
 
- 			},
 
- 			options: options,
 
- 			webpack: true,
 
- 			sourceMap: !!this.useSourceMap,
 
- 			_module: this,
 
- 			_compilation: compilation,
 
- 			_compiler: compilation.compiler,
 
- 			fs: fs,
 
- 		};
 
- 		compilation.applyPlugins("normal-module-loader", loaderContext, this);
 
- 		if(options.loader)
 
- 			Object.assign(loaderContext, options.loader);
 
- 		return loaderContext;
 
- 	}
 
- 	createSource(source, resourceBuffer, sourceMap) {
 
- 		// if there is no identifier return raw source
 
- 		if(!this.identifier) {
 
- 			return new RawSource(source);
 
- 		}
 
- 		// from here on we assume we have an identifier
 
- 		const identifier = this.identifier();
 
- 		if(this.lineToLine && resourceBuffer) {
 
- 			return new LineToLineMappedSource(
 
- 				source, identifier, asString(resourceBuffer));
 
- 		}
 
- 		if(this.useSourceMap && sourceMap) {
 
- 			return new SourceMapSource(source, identifier, sourceMap);
 
- 		}
 
- 		return new OriginalSource(source, identifier);
 
- 	}
 
- 	doBuild(options, compilation, resolver, fs, callback) {
 
- 		this.cacheable = false;
 
- 		const loaderContext = this.createLoaderContext(resolver, options, compilation, fs);
 
- 		runLoaders({
 
- 			resource: this.resource,
 
- 			loaders: this.loaders,
 
- 			context: loaderContext,
 
- 			readResource: fs.readFile.bind(fs)
 
- 		}, (err, result) => {
 
- 			if(result) {
 
- 				this.cacheable = result.cacheable;
 
- 				this.fileDependencies = result.fileDependencies;
 
- 				this.contextDependencies = result.contextDependencies;
 
- 			}
 
- 			if(err) {
 
- 				const error = new ModuleBuildError(this, err);
 
- 				return callback(error);
 
- 			}
 
- 			const resourceBuffer = result.resourceBuffer;
 
- 			const source = result.result[0];
 
- 			const sourceMap = result.result[1];
 
- 			if(!Buffer.isBuffer(source) && typeof source !== "string") {
 
- 				const error = new ModuleBuildError(this, new Error("Final loader didn't return a Buffer or String"));
 
- 				return callback(error);
 
- 			}
 
- 			this._source = this.createSource(asString(source), resourceBuffer, sourceMap);
 
- 			return callback();
 
- 		});
 
- 	}
 
- 	disconnect() {
 
- 		this.built = false;
 
- 		super.disconnect();
 
- 	}
 
- 	markModuleAsErrored(error) {
 
- 		this.meta = null;
 
- 		this.error = error;
 
- 		this.errors.push(this.error);
 
- 		this._source = new RawSource("throw new Error(" + JSON.stringify(this.error.message) + ");");
 
- 	}
 
- 	applyNoParseRule(rule, content) {
 
- 		// must start with "rule" if rule is a string
 
- 		if(typeof rule === "string") {
 
- 			return content.indexOf(rule) === 0;
 
- 		}
 
- 		if(typeof rule === "function") {
 
- 			return rule(content);
 
- 		}
 
- 		// we assume rule is a regexp
 
- 		return rule.test(content);
 
- 	}
 
- 	// check if module should not be parsed
 
- 	// returns "true" if the module should !not! be parsed
 
- 	// returns "false" if the module !must! be parsed
 
- 	shouldPreventParsing(noParseRule, request) {
 
- 		// if no noParseRule exists, return false
 
- 		// the module !must! be parsed.
 
- 		if(!noParseRule) {
 
- 			return false;
 
- 		}
 
- 		// we only have one rule to check
 
- 		if(!Array.isArray(noParseRule)) {
 
- 			// returns "true" if the module is !not! to be parsed
 
- 			return this.applyNoParseRule(noParseRule, request);
 
- 		}
 
- 		for(let i = 0; i < noParseRule.length; i++) {
 
- 			const rule = noParseRule[i];
 
- 			// early exit on first truthy match
 
- 			// this module is !not! to be parsed
 
- 			if(this.applyNoParseRule(rule, request)) {
 
- 				return true;
 
- 			}
 
- 		}
 
- 		// no match found, so this module !should! be parsed
 
- 		return false;
 
- 	}
 
- 	build(options, compilation, resolver, fs, callback) {
 
- 		this.buildTimestamp = Date.now();
 
- 		this.built = true;
 
- 		this._source = null;
 
- 		this.error = null;
 
- 		this.errors.length = 0;
 
- 		this.warnings.length = 0;
 
- 		this.meta = {};
 
- 		return this.doBuild(options, compilation, resolver, fs, (err) => {
 
- 			this.dependencies.length = 0;
 
- 			this.variables.length = 0;
 
- 			this.blocks.length = 0;
 
- 			this._cachedSource = null;
 
- 			// if we have an error mark module as failed and exit
 
- 			if(err) {
 
- 				this.markModuleAsErrored(err);
 
- 				return callback();
 
- 			}
 
- 			// check if this module should !not! be parsed.
 
- 			// if so, exit here;
 
- 			const noParseRule = options.module && options.module.noParse;
 
- 			if(this.shouldPreventParsing(noParseRule, this.request)) {
 
- 				return callback();
 
- 			}
 
- 			try {
 
- 				this.parser.parse(this._source.source(), {
 
- 					current: this,
 
- 					module: this,
 
- 					compilation: compilation,
 
- 					options: options
 
- 				});
 
- 			} catch(e) {
 
- 				const source = this._source.source();
 
- 				const error = new ModuleParseError(this, source, e);
 
- 				this.markModuleAsErrored(error);
 
- 				return callback();
 
- 			}
 
- 			return callback();
 
- 		});
 
- 	}
 
- 	getHashDigest(dependencyTemplates) {
 
- 		let dtHash = dependencyTemplatesHashMap.get("hash");
 
- 		const hash = crypto.createHash("md5");
 
- 		this.updateHash(hash);
 
- 		hash.update(`${dtHash}`);
 
- 		return hash.digest("hex");
 
- 	}
 
- 	sourceDependency(dependency, dependencyTemplates, source, outputOptions, requestShortener) {
 
- 		const template = dependencyTemplates.get(dependency.constructor);
 
- 		if(!template) throw new Error("No template for dependency: " + dependency.constructor.name);
 
- 		template.apply(dependency, source, outputOptions, requestShortener, dependencyTemplates);
 
- 	}
 
- 	sourceVariables(variable, availableVars, dependencyTemplates, outputOptions, requestShortener) {
 
- 		const name = variable.name;
 
- 		const expr = variable.expressionSource(dependencyTemplates, outputOptions, requestShortener);
 
- 		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(block) {
 
- 		if(this === block) {
 
- 			return this.exportsArgument || "exports";
 
- 		}
 
- 		return "this";
 
- 	}
 
- 	/*
 
- 	 * creates the end part of a IIFE around the module to inject a variable name
 
- 	 * (function(...){
 
- 	 * }.call(...))   <- this part
 
- 	 */
 
- 	variableInjectionFunctionWrapperEndCode(varExpressions, block) {
 
- 		const firstParam = this.contextArgument(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);
 
- 	}
 
- 	sourceBlock(block, availableVars, dependencyTemplates, source, outputOptions, requestShortener) {
 
- 		block.dependencies.forEach((dependency) => this.sourceDependency(
 
- 			dependency, dependencyTemplates, source, outputOptions, requestShortener));
 
- 		/**
 
- 		 * 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 paramter in a IIFE the expression as its value.
 
- 		 */
 
- 		const vars = block.variables.reduce((result, value) => {
 
- 			const variable = this.sourceVariables(
 
- 				value, availableVars, dependencyTemplates, outputOptions, requestShortener);
 
- 			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(
 
- 					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] : (this._source.size() + 1);
 
- 				source.insert(start + 0.5, varStartCode);
 
- 				source.insert(end + 0.5, "\n/* WEBPACK VAR INJECTION */" + varEndCode);
 
- 			}
 
- 		}
 
- 		block.blocks.forEach((block) =>
 
- 			this.sourceBlock(
 
- 				block,
 
- 				availableVars.concat(vars),
 
- 				dependencyTemplates,
 
- 				source,
 
- 				outputOptions,
 
- 				requestShortener
 
- 			)
 
- 		);
 
- 	}
 
- 	source(dependencyTemplates, outputOptions, requestShortener) {
 
- 		const hashDigest = this.getHashDigest(dependencyTemplates);
 
- 		if(this._cachedSource && this._cachedSource.hash === hashDigest) {
 
- 			return this._cachedSource.source;
 
- 		}
 
- 		if(!this._source) {
 
- 			return new RawSource("throw new Error('No source available');");
 
- 		}
 
- 		const source = new ReplaceSource(this._source);
 
- 		this._cachedSource = {
 
- 			source: source,
 
- 			hash: hashDigest
 
- 		};
 
- 		this.sourceBlock(this, [], dependencyTemplates, source, outputOptions, requestShortener);
 
- 		return new CachedSource(source);
 
- 	}
 
- 	originalSource() {
 
- 		return this._source;
 
- 	}
 
- 	getHighestTimestamp(keys, timestampsByKey) {
 
- 		let highestTimestamp = 0;
 
- 		for(let i = 0; i < keys.length; i++) {
 
- 			const key = keys[i];
 
- 			const timestamp = timestampsByKey[key];
 
- 			// if there is no timestamp yet, early return with Infinity
 
- 			if(!timestamp) return Infinity;
 
- 			highestTimestamp = Math.max(highestTimestamp, timestamp);
 
- 		}
 
- 		return highestTimestamp;
 
- 	}
 
- 	needRebuild(fileTimestamps, contextTimestamps) {
 
- 		const highestFileDepTimestamp = this.getHighestTimestamp(
 
- 			this.fileDependencies, fileTimestamps);
 
- 		// if the hightest is Infinity, we need a rebuild
 
- 		// exit early here.
 
- 		if(highestFileDepTimestamp === Infinity) {
 
- 			return true;
 
- 		}
 
- 		const highestContextDepTimestamp = this.getHighestTimestamp(
 
- 			this.contextDependencies, contextTimestamps);
 
- 		// Again if the hightest is Infinity, we need a rebuild
 
- 		// exit early here.
 
- 		if(highestContextDepTimestamp === Infinity) {
 
- 			return true;
 
- 		}
 
- 		// else take the highest of file and context timestamps and compare
 
- 		// to last build timestamp
 
- 		return Math.max(highestContextDepTimestamp, highestFileDepTimestamp) >= this.buildTimestamp;
 
- 	}
 
- 	size() {
 
- 		return this._source ? this._source.size() : -1;
 
- 	}
 
- 	updateHashWithSource(hash) {
 
- 		if(!this._source) {
 
- 			hash.update("null");
 
- 			return;
 
- 		}
 
- 		hash.update("source");
 
- 		this._source.updateHash(hash);
 
- 	}
 
- 	updateHashWithMeta(hash) {
 
- 		hash.update("meta");
 
- 		hash.update(JSON.stringify(this.meta));
 
- 	}
 
- 	updateHash(hash) {
 
- 		this.updateHashWithSource(hash);
 
- 		this.updateHashWithMeta(hash);
 
- 		super.updateHash(hash);
 
- 	}
 
- }
 
- module.exports = NormalModule;
 
 
  |