summaryrefslogtreecommitdiff
path: root/node_modules/webpack/lib/dependencies/AMDDefineDependencyParserPlugin.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/webpack/lib/dependencies/AMDDefineDependencyParserPlugin.js')
-rw-r--r--node_modules/webpack/lib/dependencies/AMDDefineDependencyParserPlugin.js497
1 files changed, 497 insertions, 0 deletions
diff --git a/node_modules/webpack/lib/dependencies/AMDDefineDependencyParserPlugin.js b/node_modules/webpack/lib/dependencies/AMDDefineDependencyParserPlugin.js
new file mode 100644
index 00000000..14fbe4af
--- /dev/null
+++ b/node_modules/webpack/lib/dependencies/AMDDefineDependencyParserPlugin.js
@@ -0,0 +1,497 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const RuntimeGlobals = require("../RuntimeGlobals");
+const AMDDefineDependency = require("./AMDDefineDependency");
+const AMDRequireArrayDependency = require("./AMDRequireArrayDependency");
+const AMDRequireContextDependency = require("./AMDRequireContextDependency");
+const AMDRequireItemDependency = require("./AMDRequireItemDependency");
+const ConstDependency = require("./ConstDependency");
+const ContextDependencyHelpers = require("./ContextDependencyHelpers");
+const DynamicExports = require("./DynamicExports");
+const LocalModuleDependency = require("./LocalModuleDependency");
+const { addLocalModule, getLocalModule } = require("./LocalModulesHelpers");
+
+/** @typedef {import("estree").ArrowFunctionExpression} ArrowFunctionExpression */
+/** @typedef {import("estree").CallExpression} CallExpression */
+/** @typedef {import("estree").Expression} Expression */
+/** @typedef {import("estree").FunctionExpression} FunctionExpression */
+/** @typedef {import("estree").Identifier} Identifier */
+/** @typedef {import("estree").Literal} Literal */
+/** @typedef {import("estree").MemberExpression} MemberExpression */
+/** @typedef {import("estree").ObjectExpression} ObjectExpression */
+/** @typedef {import("estree").SimpleCallExpression} SimpleCallExpression */
+/** @typedef {import("estree").SpreadElement} SpreadElement */
+/** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
+/** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
+/** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */
+/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
+/** @typedef {import("../javascript/JavascriptParser").Range} Range */
+
+/**
+ * @param {Expression | SpreadElement} expr expression
+ * @returns {expr is CallExpression} true if it's a bound function expression
+ */
+const isBoundFunctionExpression = expr => {
+ if (expr.type !== "CallExpression") return false;
+ if (expr.callee.type !== "MemberExpression") return false;
+ if (expr.callee.computed) return false;
+ if (expr.callee.object.type !== "FunctionExpression") return false;
+ if (expr.callee.property.type !== "Identifier") return false;
+ if (expr.callee.property.name !== "bind") return false;
+ return true;
+};
+
+/** @typedef {FunctionExpression | ArrowFunctionExpression} UnboundFunctionExpression */
+
+/**
+ * @param {Expression | SpreadElement} expr expression
+ * @returns {expr is FunctionExpression | ArrowFunctionExpression} true when unbound function expression
+ */
+const isUnboundFunctionExpression = expr => {
+ if (expr.type === "FunctionExpression") return true;
+ if (expr.type === "ArrowFunctionExpression") return true;
+ return false;
+};
+
+/**
+ * @param {Expression | SpreadElement} expr expression
+ * @returns {expr is FunctionExpression | ArrowFunctionExpression | CallExpression} true when callable
+ */
+const isCallable = expr => {
+ if (isUnboundFunctionExpression(expr)) return true;
+ if (isBoundFunctionExpression(expr)) return true;
+ return false;
+};
+
+class AMDDefineDependencyParserPlugin {
+ /**
+ * @param {JavascriptParserOptions} options parserOptions
+ */
+ constructor(options) {
+ this.options = options;
+ }
+
+ /**
+ * @param {JavascriptParser} parser the parser
+ * @returns {void}
+ */
+ apply(parser) {
+ parser.hooks.call
+ .for("define")
+ .tap(
+ "AMDDefineDependencyParserPlugin",
+ this.processCallDefine.bind(this, parser)
+ );
+ }
+
+ /**
+ * @param {JavascriptParser} parser the parser
+ * @param {CallExpression} expr call expression
+ * @param {BasicEvaluatedExpression} param param
+ * @param {Record<number, string>} identifiers identifiers
+ * @param {string=} namedModule named module
+ * @returns {boolean | undefined} result
+ */
+ processArray(parser, expr, param, identifiers, namedModule) {
+ if (param.isArray()) {
+ const items = /** @type {BasicEvaluatedExpression[]} */ (param.items);
+ for (const [idx, item] of items.entries()) {
+ if (
+ item.isString() &&
+ ["require", "module", "exports"].includes(
+ /** @type {string} */ (item.string)
+ )
+ )
+ identifiers[/** @type {number} */ (idx)] = /** @type {string} */ (
+ item.string
+ );
+ const result = this.processItem(parser, expr, item, namedModule);
+ if (result === undefined) {
+ this.processContext(parser, expr, item);
+ }
+ }
+ return true;
+ } else if (param.isConstArray()) {
+ /** @type {(string | LocalModuleDependency | AMDRequireItemDependency)[]} */
+ const deps = [];
+ const array = /** @type {string[]} */ (param.array);
+ for (const [idx, request] of array.entries()) {
+ let dep;
+ let localModule;
+ if (request === "require") {
+ identifiers[idx] = request;
+ dep = RuntimeGlobals.require;
+ } else if (["exports", "module"].includes(request)) {
+ identifiers[idx] = request;
+ dep = request;
+ } else if ((localModule = getLocalModule(parser.state, request))) {
+ localModule.flagUsed();
+ dep = new LocalModuleDependency(localModule, undefined, false);
+ dep.loc = /** @type {DependencyLocation} */ (expr.loc);
+ parser.state.module.addPresentationalDependency(dep);
+ } else {
+ dep = this.newRequireItemDependency(request);
+ dep.loc = /** @type {DependencyLocation} */ (expr.loc);
+ dep.optional = Boolean(parser.scope.inTry);
+ parser.state.current.addDependency(dep);
+ }
+ deps.push(dep);
+ }
+ const dep = this.newRequireArrayDependency(
+ deps,
+ /** @type {Range} */ (param.range)
+ );
+ dep.loc = /** @type {DependencyLocation} */ (expr.loc);
+ dep.optional = Boolean(parser.scope.inTry);
+ parser.state.module.addPresentationalDependency(dep);
+ return true;
+ }
+ }
+
+ /**
+ * @param {JavascriptParser} parser the parser
+ * @param {CallExpression} expr call expression
+ * @param {BasicEvaluatedExpression} param param
+ * @param {string=} namedModule named module
+ * @returns {boolean | undefined} result
+ */
+ processItem(parser, expr, param, namedModule) {
+ if (param.isConditional()) {
+ const options = /** @type {BasicEvaluatedExpression[]} */ (param.options);
+ for (const item of options) {
+ const result = this.processItem(parser, expr, item);
+ if (result === undefined) {
+ this.processContext(parser, expr, item);
+ }
+ }
+
+ return true;
+ } else if (param.isString()) {
+ let dep;
+ let localModule;
+
+ if (param.string === "require") {
+ dep = new ConstDependency(
+ RuntimeGlobals.require,
+ /** @type {Range} */ (param.range),
+ [RuntimeGlobals.require]
+ );
+ } else if (param.string === "exports") {
+ dep = new ConstDependency(
+ "exports",
+ /** @type {Range} */ (param.range),
+ [RuntimeGlobals.exports]
+ );
+ } else if (param.string === "module") {
+ dep = new ConstDependency(
+ "module",
+ /** @type {Range} */ (param.range),
+ [RuntimeGlobals.module]
+ );
+ } else if (
+ (localModule = getLocalModule(
+ parser.state,
+ /** @type {string} */ (param.string),
+ namedModule
+ ))
+ ) {
+ localModule.flagUsed();
+ dep = new LocalModuleDependency(localModule, param.range, false);
+ } else {
+ dep = this.newRequireItemDependency(
+ /** @type {string} */ (param.string),
+ param.range
+ );
+ dep.optional = Boolean(parser.scope.inTry);
+ parser.state.current.addDependency(dep);
+ return true;
+ }
+ dep.loc = /** @type {DependencyLocation} */ (expr.loc);
+ parser.state.module.addPresentationalDependency(dep);
+ return true;
+ }
+ }
+
+ /**
+ * @param {JavascriptParser} parser the parser
+ * @param {CallExpression} expr call expression
+ * @param {BasicEvaluatedExpression} param param
+ * @returns {boolean | undefined} result
+ */
+ processContext(parser, expr, param) {
+ const dep = ContextDependencyHelpers.create(
+ AMDRequireContextDependency,
+ /** @type {Range} */ (param.range),
+ param,
+ expr,
+ this.options,
+ {
+ category: "amd"
+ },
+ parser
+ );
+ if (!dep) return;
+ dep.loc = /** @type {DependencyLocation} */ (expr.loc);
+ dep.optional = Boolean(parser.scope.inTry);
+ parser.state.current.addDependency(dep);
+ return true;
+ }
+
+ /**
+ * @param {JavascriptParser} parser the parser
+ * @param {CallExpression} expr call expression
+ * @returns {boolean | undefined} result
+ */
+ processCallDefine(parser, expr) {
+ /** @type {TODO} */
+ let array;
+ /** @type {FunctionExpression | ArrowFunctionExpression | CallExpression | Identifier | undefined} */
+ let fn;
+ /** @type {ObjectExpression | Identifier | undefined} */
+ let obj;
+ /** @type {string | undefined} */
+ let namedModule;
+ switch (expr.arguments.length) {
+ case 1:
+ if (isCallable(expr.arguments[0])) {
+ // define(f() {…})
+ fn = expr.arguments[0];
+ } else if (expr.arguments[0].type === "ObjectExpression") {
+ // define({…})
+ obj = expr.arguments[0];
+ } else {
+ // define(expr)
+ // unclear if function or object
+ obj = fn = /** @type {Identifier} */ (expr.arguments[0]);
+ }
+ break;
+ case 2:
+ if (expr.arguments[0].type === "Literal") {
+ namedModule = /** @type {string} */ (expr.arguments[0].value);
+ // define("…", …)
+ if (isCallable(expr.arguments[1])) {
+ // define("…", f() {…})
+ fn = expr.arguments[1];
+ } else if (expr.arguments[1].type === "ObjectExpression") {
+ // define("…", {…})
+ obj = expr.arguments[1];
+ } else {
+ // define("…", expr)
+ // unclear if function or object
+ obj = fn = /** @type {Identifier} */ (expr.arguments[1]);
+ }
+ } else {
+ array = expr.arguments[0];
+ if (isCallable(expr.arguments[1])) {
+ // define([…], f() {})
+ fn = expr.arguments[1];
+ } else if (expr.arguments[1].type === "ObjectExpression") {
+ // define([…], {…})
+ obj = expr.arguments[1];
+ } else {
+ // define([…], expr)
+ // unclear if function or object
+ obj = fn = /** @type {Identifier} */ (expr.arguments[1]);
+ }
+ }
+ break;
+ case 3:
+ // define("…", […], f() {…})
+ namedModule =
+ /** @type {string} */
+ (
+ /** @type {Literal} */
+ (expr.arguments[0]).value
+ );
+ array = expr.arguments[1];
+ if (isCallable(expr.arguments[2])) {
+ // define("…", […], f() {})
+ fn = expr.arguments[2];
+ } else if (expr.arguments[2].type === "ObjectExpression") {
+ // define("…", […], {…})
+ obj = expr.arguments[2];
+ } else {
+ // define("…", […], expr)
+ // unclear if function or object
+ obj = fn = /** @type {Identifier} */ (expr.arguments[2]);
+ }
+ break;
+ default:
+ return;
+ }
+ DynamicExports.bailout(parser.state);
+ /** @type {Identifier[] | null} */
+ let fnParams = null;
+ let fnParamsOffset = 0;
+ if (fn) {
+ if (isUnboundFunctionExpression(fn)) {
+ fnParams =
+ /** @type {Identifier[]} */
+ (fn.params);
+ } else if (isBoundFunctionExpression(fn)) {
+ const object =
+ /** @type {FunctionExpression} */
+ (/** @type {MemberExpression} */ (fn.callee).object);
+
+ fnParams =
+ /** @type {Identifier[]} */
+ (object.params);
+ fnParamsOffset = fn.arguments.length - 1;
+ if (fnParamsOffset < 0) {
+ fnParamsOffset = 0;
+ }
+ }
+ }
+ const fnRenames = new Map();
+ if (array) {
+ /** @type {Record<number, string>} */
+ const identifiers = {};
+ const param = parser.evaluateExpression(array);
+ const result = this.processArray(
+ parser,
+ expr,
+ param,
+ identifiers,
+ namedModule
+ );
+ if (!result) return;
+ if (fnParams) {
+ fnParams = fnParams.slice(fnParamsOffset).filter((param, idx) => {
+ if (identifiers[idx]) {
+ fnRenames.set(param.name, parser.getVariableInfo(identifiers[idx]));
+ return false;
+ }
+ return true;
+ });
+ }
+ } else {
+ const identifiers = ["require", "exports", "module"];
+ if (fnParams) {
+ fnParams = fnParams.slice(fnParamsOffset).filter((param, idx) => {
+ if (identifiers[idx]) {
+ fnRenames.set(param.name, parser.getVariableInfo(identifiers[idx]));
+ return false;
+ }
+ return true;
+ });
+ }
+ }
+ /** @type {boolean | undefined} */
+ let inTry;
+ if (fn && isUnboundFunctionExpression(fn)) {
+ inTry = parser.scope.inTry;
+ parser.inScope(fnParams, () => {
+ for (const [name, varInfo] of fnRenames) {
+ parser.setVariable(name, varInfo);
+ }
+ parser.scope.inTry = /** @type {boolean} */ (inTry);
+ if (fn.body.type === "BlockStatement") {
+ parser.detectMode(fn.body.body);
+ const prev = parser.prevStatement;
+ parser.preWalkStatement(fn.body);
+ parser.prevStatement = prev;
+ parser.walkStatement(fn.body);
+ } else {
+ parser.walkExpression(fn.body);
+ }
+ });
+ } else if (fn && isBoundFunctionExpression(fn)) {
+ inTry = parser.scope.inTry;
+
+ const object =
+ /** @type {FunctionExpression} */
+ (/** @type {MemberExpression} */ (fn.callee).object);
+
+ parser.inScope(
+ /** @type {Identifier[]} */
+ (object.params).filter(
+ i => !["require", "module", "exports"].includes(i.name)
+ ),
+ () => {
+ for (const [name, varInfo] of fnRenames) {
+ parser.setVariable(name, varInfo);
+ }
+ parser.scope.inTry = /** @type {boolean} */ (inTry);
+
+ if (object.body.type === "BlockStatement") {
+ parser.detectMode(object.body.body);
+ const prev = parser.prevStatement;
+ parser.preWalkStatement(object.body);
+ parser.prevStatement = prev;
+ parser.walkStatement(object.body);
+ } else {
+ parser.walkExpression(object.body);
+ }
+ }
+ );
+ if (fn.arguments) {
+ parser.walkExpressions(fn.arguments);
+ }
+ } else if (fn || obj) {
+ parser.walkExpression(fn || obj);
+ }
+
+ const dep = this.newDefineDependency(
+ /** @type {Range} */ (expr.range),
+ array ? /** @type {Range} */ (array.range) : null,
+ fn ? /** @type {Range} */ (fn.range) : null,
+ obj ? /** @type {Range} */ (obj.range) : null,
+ namedModule || null
+ );
+ dep.loc = /** @type {DependencyLocation} */ (expr.loc);
+ if (namedModule) {
+ dep.localModule = addLocalModule(parser.state, namedModule);
+ }
+ parser.state.module.addPresentationalDependency(dep);
+ return true;
+ }
+
+ /**
+ * @param {Range} range range
+ * @param {Range | null} arrayRange array range
+ * @param {Range | null} functionRange function range
+ * @param {Range | null} objectRange object range
+ * @param {string | null} namedModule true, when define is called with a name
+ * @returns {AMDDefineDependency} AMDDefineDependency
+ */
+ newDefineDependency(
+ range,
+ arrayRange,
+ functionRange,
+ objectRange,
+ namedModule
+ ) {
+ return new AMDDefineDependency(
+ range,
+ arrayRange,
+ functionRange,
+ objectRange,
+ namedModule
+ );
+ }
+
+ /**
+ * @param {(string | LocalModuleDependency | AMDRequireItemDependency)[]} depsArray deps array
+ * @param {Range} range range
+ * @returns {AMDRequireArrayDependency} AMDRequireArrayDependency
+ */
+ newRequireArrayDependency(depsArray, range) {
+ return new AMDRequireArrayDependency(depsArray, range);
+ }
+
+ /**
+ * @param {string} request request
+ * @param {Range=} range range
+ * @returns {AMDRequireItemDependency} AMDRequireItemDependency
+ */
+ newRequireItemDependency(request, range) {
+ return new AMDRequireItemDependency(request, range);
+ }
+}
+
+module.exports = AMDDefineDependencyParserPlugin;