| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 | 
							- /*
 
- 	MIT License http://www.opensource.org/licenses/mit-license.php
 
- 	Author Tobias Koppers @sokra
 
- */
 
- "use strict";
 
- const asyncLib = require("neo-async");
 
- const path = require("path");
 
- const {
 
- 	Tapable,
 
- 	AsyncSeriesWaterfallHook,
 
- 	SyncWaterfallHook
 
- } = require("tapable");
 
- const ContextModule = require("./ContextModule");
 
- const ContextElementDependency = require("./dependencies/ContextElementDependency");
 
- /** @typedef {import("./Module")} Module */
 
- const EMPTY_RESOLVE_OPTIONS = {};
 
- module.exports = class ContextModuleFactory extends Tapable {
 
- 	constructor(resolverFactory) {
 
- 		super();
 
- 		this.hooks = {
 
- 			/** @type {AsyncSeriesWaterfallHook<TODO>} */
 
- 			beforeResolve: new AsyncSeriesWaterfallHook(["data"]),
 
- 			/** @type {AsyncSeriesWaterfallHook<TODO>} */
 
- 			afterResolve: new AsyncSeriesWaterfallHook(["data"]),
 
- 			/** @type {SyncWaterfallHook<string[]>} */
 
- 			contextModuleFiles: new SyncWaterfallHook(["files"]),
 
- 			/** @type {SyncWaterfallHook<TODO[]>} */
 
- 			alternatives: new AsyncSeriesWaterfallHook(["modules"])
 
- 		};
 
- 		this._pluginCompat.tap("ContextModuleFactory", options => {
 
- 			switch (options.name) {
 
- 				case "before-resolve":
 
- 				case "after-resolve":
 
- 				case "alternatives":
 
- 					options.async = true;
 
- 					break;
 
- 			}
 
- 		});
 
- 		this.resolverFactory = resolverFactory;
 
- 	}
 
- 	create(data, callback) {
 
- 		const context = data.context;
 
- 		const dependencies = data.dependencies;
 
- 		const resolveOptions = data.resolveOptions;
 
- 		const dependency = dependencies[0];
 
- 		this.hooks.beforeResolve.callAsync(
 
- 			Object.assign(
 
- 				{
 
- 					context: context,
 
- 					dependencies: dependencies,
 
- 					resolveOptions
 
- 				},
 
- 				dependency.options
 
- 			),
 
- 			(err, beforeResolveResult) => {
 
- 				if (err) return callback(err);
 
- 				// Ignored
 
- 				if (!beforeResolveResult) return callback();
 
- 				const context = beforeResolveResult.context;
 
- 				const request = beforeResolveResult.request;
 
- 				const resolveOptions = beforeResolveResult.resolveOptions;
 
- 				let loaders,
 
- 					resource,
 
- 					loadersPrefix = "";
 
- 				const idx = request.lastIndexOf("!");
 
- 				if (idx >= 0) {
 
- 					let loadersRequest = request.substr(0, idx + 1);
 
- 					let i;
 
- 					for (
 
- 						i = 0;
 
- 						i < loadersRequest.length && loadersRequest[i] === "!";
 
- 						i++
 
- 					) {
 
- 						loadersPrefix += "!";
 
- 					}
 
- 					loadersRequest = loadersRequest
 
- 						.substr(i)
 
- 						.replace(/!+$/, "")
 
- 						.replace(/!!+/g, "!");
 
- 					if (loadersRequest === "") {
 
- 						loaders = [];
 
- 					} else {
 
- 						loaders = loadersRequest.split("!");
 
- 					}
 
- 					resource = request.substr(idx + 1);
 
- 				} else {
 
- 					loaders = [];
 
- 					resource = request;
 
- 				}
 
- 				const contextResolver = this.resolverFactory.get(
 
- 					"context",
 
- 					resolveOptions || EMPTY_RESOLVE_OPTIONS
 
- 				);
 
- 				const loaderResolver = this.resolverFactory.get(
 
- 					"loader",
 
- 					EMPTY_RESOLVE_OPTIONS
 
- 				);
 
- 				asyncLib.parallel(
 
- 					[
 
- 						callback => {
 
- 							contextResolver.resolve(
 
- 								{},
 
- 								context,
 
- 								resource,
 
- 								{},
 
- 								(err, result) => {
 
- 									if (err) return callback(err);
 
- 									callback(null, result);
 
- 								}
 
- 							);
 
- 						},
 
- 						callback => {
 
- 							asyncLib.map(
 
- 								loaders,
 
- 								(loader, callback) => {
 
- 									loaderResolver.resolve(
 
- 										{},
 
- 										context,
 
- 										loader,
 
- 										{},
 
- 										(err, result) => {
 
- 											if (err) return callback(err);
 
- 											callback(null, result);
 
- 										}
 
- 									);
 
- 								},
 
- 								callback
 
- 							);
 
- 						}
 
- 					],
 
- 					(err, result) => {
 
- 						if (err) return callback(err);
 
- 						this.hooks.afterResolve.callAsync(
 
- 							Object.assign(
 
- 								{
 
- 									addon:
 
- 										loadersPrefix +
 
- 										result[1].join("!") +
 
- 										(result[1].length > 0 ? "!" : ""),
 
- 									resource: result[0],
 
- 									resolveDependencies: this.resolveDependencies.bind(this)
 
- 								},
 
- 								beforeResolveResult
 
- 							),
 
- 							(err, result) => {
 
- 								if (err) return callback(err);
 
- 								// Ignored
 
- 								if (!result) return callback();
 
- 								return callback(
 
- 									null,
 
- 									new ContextModule(result.resolveDependencies, result)
 
- 								);
 
- 							}
 
- 						);
 
- 					}
 
- 				);
 
- 			}
 
- 		);
 
- 	}
 
- 	resolveDependencies(fs, options, callback) {
 
- 		const cmf = this;
 
- 		let resource = options.resource;
 
- 		let resourceQuery = options.resourceQuery;
 
- 		let recursive = options.recursive;
 
- 		let regExp = options.regExp;
 
- 		let include = options.include;
 
- 		let exclude = options.exclude;
 
- 		if (!regExp || !resource) return callback(null, []);
 
- 		const addDirectory = (directory, callback) => {
 
- 			fs.readdir(directory, (err, files) => {
 
- 				if (err) return callback(err);
 
- 				files = cmf.hooks.contextModuleFiles.call(files);
 
- 				if (!files || files.length === 0) return callback(null, []);
 
- 				asyncLib.map(
 
- 					files.filter(p => p.indexOf(".") !== 0),
 
- 					(segment, callback) => {
 
- 						const subResource = path.join(directory, segment);
 
- 						if (!exclude || !subResource.match(exclude)) {
 
- 							fs.stat(subResource, (err, stat) => {
 
- 								if (err) {
 
- 									if (err.code === "ENOENT") {
 
- 										// ENOENT is ok here because the file may have been deleted between
 
- 										// the readdir and stat calls.
 
- 										return callback();
 
- 									} else {
 
- 										return callback(err);
 
- 									}
 
- 								}
 
- 								if (stat.isDirectory()) {
 
- 									if (!recursive) return callback();
 
- 									addDirectory.call(this, subResource, callback);
 
- 								} else if (
 
- 									stat.isFile() &&
 
- 									(!include || subResource.match(include))
 
- 								) {
 
- 									const obj = {
 
- 										context: resource,
 
- 										request:
 
- 											"." +
 
- 											subResource.substr(resource.length).replace(/\\/g, "/")
 
- 									};
 
- 									this.hooks.alternatives.callAsync(
 
- 										[obj],
 
- 										(err, alternatives) => {
 
- 											if (err) return callback(err);
 
- 											alternatives = alternatives
 
- 												.filter(obj => regExp.test(obj.request))
 
- 												.map(obj => {
 
- 													const dep = new ContextElementDependency(
 
- 														obj.request + resourceQuery,
 
- 														obj.request
 
- 													);
 
- 													dep.optional = true;
 
- 													return dep;
 
- 												});
 
- 											callback(null, alternatives);
 
- 										}
 
- 									);
 
- 								} else {
 
- 									callback();
 
- 								}
 
- 							});
 
- 						} else {
 
- 							callback();
 
- 						}
 
- 					},
 
- 					(err, result) => {
 
- 						if (err) return callback(err);
 
- 						if (!result) return callback(null, []);
 
- 						callback(
 
- 							null,
 
- 							result.filter(Boolean).reduce((a, i) => a.concat(i), [])
 
- 						);
 
- 					}
 
- 				);
 
- 			});
 
- 		};
 
- 		addDirectory(resource, callback);
 
- 	}
 
- };
 
 
  |