| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 | /*	MIT License http://www.opensource.org/licenses/mit-license.php	Author Tobias Koppers @sokra*/"use strict";const RequireEnsureDependenciesBlock = require("./RequireEnsureDependenciesBlock");const RequireEnsureDependency = require("./RequireEnsureDependency");const RequireEnsureItemDependency = require("./RequireEnsureItemDependency");const getFunctionExpression = require("./getFunctionExpression");/** @typedef {import("../AsyncDependenciesBlock").GroupOptions} GroupOptions *//** @typedef {import("../ChunkGroup").ChunkGroupOptions} ChunkGroupOptions *//** @typedef {import("../Dependency").DependencyLocation} DependencyLocation *//** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression *//** @typedef {import("../javascript/JavascriptParser")} JavascriptParser *//** @typedef {import("../javascript/JavascriptParser").Range} Range */const PLUGIN_NAME = "RequireEnsureDependenciesBlockParserPlugin";module.exports = class RequireEnsureDependenciesBlockParserPlugin {	/**	 * @param {JavascriptParser} parser the parser	 * @returns {void}	 */	apply(parser) {		parser.hooks.call.for("require.ensure").tap(PLUGIN_NAME, expr => {			/** @type {string | GroupOptions | null} */			let chunkName = null;			let errorExpressionArg = null;			let errorExpression = null;			switch (expr.arguments.length) {				case 4: {					const chunkNameExpr = parser.evaluateExpression(expr.arguments[3]);					if (!chunkNameExpr.isString()) return;					chunkName =						/** @type {string} */						(chunkNameExpr.string);				}				// falls through				case 3: {					errorExpressionArg = expr.arguments[2];					errorExpression = getFunctionExpression(errorExpressionArg);					if (!errorExpression && !chunkName) {						const chunkNameExpr = parser.evaluateExpression(expr.arguments[2]);						if (!chunkNameExpr.isString()) return;						chunkName =							/** @type {string} */							(chunkNameExpr.string);					}				}				// falls through				case 2: {					const dependenciesExpr = parser.evaluateExpression(expr.arguments[0]);					const dependenciesItems = /** @type {BasicEvaluatedExpression[]} */ (						dependenciesExpr.isArray()							? dependenciesExpr.items							: [dependenciesExpr]					);					const successExpressionArg = expr.arguments[1];					const successExpression = getFunctionExpression(successExpressionArg);					if (successExpression) {						parser.walkExpressions(successExpression.expressions);					}					if (errorExpression) {						parser.walkExpressions(errorExpression.expressions);					}					const depBlock = new RequireEnsureDependenciesBlock(						chunkName,						/** @type {DependencyLocation} */						(expr.loc)					);					const errorCallbackExists =						expr.arguments.length === 4 ||						(!chunkName && expr.arguments.length === 3);					const dep = new RequireEnsureDependency(						/** @type {Range} */ (expr.range),						/** @type {Range} */ (expr.arguments[1].range),						errorCallbackExists &&							/** @type {Range} */ (expr.arguments[2].range)					);					dep.loc = /** @type {DependencyLocation} */ (expr.loc);					depBlock.addDependency(dep);					const old = parser.state.current;					parser.state.current = /** @type {TODO} */ (depBlock);					try {						let failed = false;						parser.inScope([], () => {							for (const ee of dependenciesItems) {								if (ee.isString()) {									const ensureDependency = new RequireEnsureItemDependency(										/** @type {string} */ (ee.string)									);									ensureDependency.loc =										/** @type {DependencyLocation} */										(expr.loc);									depBlock.addDependency(ensureDependency);								} else {									failed = true;								}							}						});						if (failed) {							return;						}						if (successExpression) {							if (successExpression.fn.body.type === "BlockStatement") {								// Opt-out of Dead Control Flow detection for this block								const oldTerminated = parser.scope.terminated;								parser.walkStatement(successExpression.fn.body);								parser.scope.terminated = oldTerminated;							} else {								parser.walkExpression(successExpression.fn.body);							}						}						old.addBlock(depBlock);					} finally {						parser.state.current = old;					}					if (!successExpression) {						parser.walkExpression(successExpressionArg);					}					if (errorExpression) {						if (errorExpression.fn.body.type === "BlockStatement") {							parser.walkStatement(errorExpression.fn.body);						} else {							parser.walkExpression(errorExpression.fn.body);						}					} else if (errorExpressionArg) {						parser.walkExpression(errorExpressionArg);					}					return true;				}			}		});	}};
 |