package.lib.dependencies.AMDRequireDependenciesBlockParserPlugin.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of webpack Show documentation
Show all versions of webpack Show documentation
Packs ECMAScript/CommonJs/AMD modules for the browser. Allows you to split your codebase into multiple bundles, which can be loaded on demand. Supports loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.
The newest version!
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning");
const AMDRequireArrayDependency = require("./AMDRequireArrayDependency");
const AMDRequireContextDependency = require("./AMDRequireContextDependency");
const AMDRequireDependenciesBlock = require("./AMDRequireDependenciesBlock");
const AMDRequireDependency = require("./AMDRequireDependency");
const AMDRequireItemDependency = require("./AMDRequireItemDependency");
const ConstDependency = require("./ConstDependency");
const ContextDependencyHelpers = require("./ContextDependencyHelpers");
const LocalModuleDependency = require("./LocalModuleDependency");
const { getLocalModule } = require("./LocalModulesHelpers");
const UnsupportedDependency = require("./UnsupportedDependency");
const getFunctionExpression = require("./getFunctionExpression");
/** @typedef {import("estree").CallExpression} CallExpression */
/** @typedef {import("estree").Expression} Expression */
/** @typedef {import("estree").Identifier} Identifier */
/** @typedef {import("estree").SourceLocation} SourceLocation */
/** @typedef {import("estree").SpreadElement} SpreadElement */
/** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
/** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
/** @typedef {import("../Module").BuildInfo} BuildInfo */
/** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */
/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
/** @typedef {import("../javascript/JavascriptParser").Range} Range */
class AMDRequireDependenciesBlockParserPlugin {
/**
* @param {JavascriptParserOptions} options parserOptions
*/
constructor(options) {
this.options = options;
}
/**
* @param {JavascriptParser} parser the parser
* @param {Expression | SpreadElement} expression expression
* @returns {boolean} need bind this
*/
processFunctionArgument(parser, expression) {
let bindThis = true;
const fnData = getFunctionExpression(expression);
if (fnData) {
parser.inScope(
fnData.fn.params.filter(i => {
return !["require", "module", "exports"].includes(
/** @type {Identifier} */ (i).name
);
}),
() => {
if (fnData.fn.body.type === "BlockStatement") {
parser.walkStatement(fnData.fn.body);
} else {
parser.walkExpression(fnData.fn.body);
}
}
);
parser.walkExpressions(fnData.expressions);
if (fnData.needThis === false) {
bindThis = false;
}
} else {
parser.walkExpression(expression);
}
return bindThis;
}
/**
* @param {JavascriptParser} parser the parser
* @returns {void}
*/
apply(parser) {
parser.hooks.call
.for("require")
.tap(
"AMDRequireDependenciesBlockParserPlugin",
this.processCallRequire.bind(this, parser)
);
}
/**
* @param {JavascriptParser} parser the parser
* @param {CallExpression} expr call expression
* @param {BasicEvaluatedExpression} param param
* @returns {boolean | undefined} result
*/
processArray(parser, expr, param) {
if (param.isArray()) {
for (const p of /** @type {BasicEvaluatedExpression[]} */ (param.items)) {
const result = this.processItem(parser, expr, p);
if (result === undefined) {
this.processContext(parser, expr, p);
}
}
return true;
} else if (param.isConstArray()) {
/** @type {(string | LocalModuleDependency | AMDRequireItemDependency)[]} */
const deps = [];
for (const request of /** @type {any[]} */ (param.array)) {
let dep, localModule;
if (request === "require") {
dep = RuntimeGlobals.require;
} else if (["exports", "module"].includes(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 = !!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 = !!parser.scope.inTry;
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
*/
processItem(parser, expr, param) {
if (param.isConditional()) {
for (const p of /** @type {BasicEvaluatedExpression[]} */ (
param.options
)) {
const result = this.processItem(parser, expr, p);
if (result === undefined) {
this.processContext(parser, expr, p);
}
}
return true;
} else if (param.isString()) {
let dep, localModule;
if (param.string === "require") {
dep = new ConstDependency(
RuntimeGlobals.require,
/** @type {TODO} */ (param.string),
[RuntimeGlobals.require]
);
} else if (param.string === "module") {
dep = new ConstDependency(
/** @type {BuildInfo} */
(parser.state.module.buildInfo).moduleArgument,
/** @type {Range} */ (param.range),
[RuntimeGlobals.module]
);
} else if (param.string === "exports") {
dep = new ConstDependency(
/** @type {BuildInfo} */
(parser.state.module.buildInfo).exportsArgument,
/** @type {Range} */ (param.range),
[RuntimeGlobals.exports]
);
} else if (
(localModule = getLocalModule(
parser.state,
/** @type {string} */ (param.string)
))
) {
localModule.flagUsed();
dep = new LocalModuleDependency(localModule, param.range, false);
} else {
dep = this.newRequireItemDependency(
/** @type {string} */ (param.string),
param.range
);
dep.loc = /** @type {DependencyLocation} */ (expr.loc);
dep.optional = !!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 = !!parser.scope.inTry;
parser.state.current.addDependency(dep);
return true;
}
/**
* @param {BasicEvaluatedExpression} param param
* @returns {string | undefined} result
*/
processArrayForRequestString(param) {
if (param.isArray()) {
const result =
/** @type {BasicEvaluatedExpression[]} */
(param.items).map(item => this.processItemForRequestString(item));
if (result.every(Boolean)) return result.join(" ");
} else if (param.isConstArray()) {
return /** @type {string[]} */ (param.array).join(" ");
}
}
/**
* @param {BasicEvaluatedExpression} param param
* @returns {string | undefined} result
*/
processItemForRequestString(param) {
if (param.isConditional()) {
const result =
/** @type {BasicEvaluatedExpression[]} */
(param.options).map(item => this.processItemForRequestString(item));
if (result.every(Boolean)) return result.join("|");
} else if (param.isString()) {
return param.string;
}
}
/**
* @param {JavascriptParser} parser the parser
* @param {CallExpression} expr call expression
* @returns {boolean | undefined} result
*/
processCallRequire(parser, expr) {
/** @type {BasicEvaluatedExpression | undefined} */
let param;
/** @type {AMDRequireDependenciesBlock | undefined | null} */
let depBlock;
/** @type {AMDRequireDependency | undefined} */
let dep;
/** @type {boolean | undefined} */
let result;
const old = parser.state.current;
if (expr.arguments.length >= 1) {
param = parser.evaluateExpression(expr.arguments[0]);
depBlock = this.newRequireDependenciesBlock(
/** @type {DependencyLocation} */ (expr.loc),
/** @type {string} */ (this.processArrayForRequestString(param))
);
dep = this.newRequireDependency(
/** @type {Range} */ (expr.range),
/** @type {Range} */ (param.range),
expr.arguments.length > 1
? /** @type {Range} */ (expr.arguments[1].range)
: null,
expr.arguments.length > 2
? /** @type {Range} */ (expr.arguments[2].range)
: null
);
dep.loc = /** @type {DependencyLocation} */ (expr.loc);
depBlock.addDependency(dep);
parser.state.current = /** @type {TODO} */ (depBlock);
}
if (expr.arguments.length === 1) {
parser.inScope([], () => {
result = this.processArray(
parser,
expr,
/** @type {BasicEvaluatedExpression} */ (param)
);
});
parser.state.current = old;
if (!result) return;
parser.state.current.addBlock(
/** @type {AMDRequireDependenciesBlock} */ (depBlock)
);
return true;
}
if (expr.arguments.length === 2 || expr.arguments.length === 3) {
try {
parser.inScope([], () => {
result = this.processArray(
parser,
expr,
/** @type {BasicEvaluatedExpression} */ (param)
);
});
if (!result) {
const dep = new UnsupportedDependency(
"unsupported",
/** @type {Range} */ (expr.range)
);
old.addPresentationalDependency(dep);
if (parser.state.module) {
parser.state.module.addError(
new UnsupportedFeatureWarning(
"Cannot statically analyse 'require(…, …)' in line " +
/** @type {SourceLocation} */ (expr.loc).start.line,
/** @type {DependencyLocation} */ (expr.loc)
)
);
}
depBlock = null;
return true;
}
/** @type {AMDRequireDependency} */
(dep).functionBindThis = this.processFunctionArgument(
parser,
expr.arguments[1]
);
if (expr.arguments.length === 3) {
/** @type {AMDRequireDependency} */
(dep).errorCallbackBindThis = this.processFunctionArgument(
parser,
expr.arguments[2]
);
}
} finally {
parser.state.current = old;
if (depBlock) parser.state.current.addBlock(depBlock);
}
return true;
}
}
/**
* @param {DependencyLocation} loc location
* @param {string} request request
* @returns {AMDRequireDependenciesBlock} AMDRequireDependenciesBlock
*/
newRequireDependenciesBlock(loc, request) {
return new AMDRequireDependenciesBlock(loc, request);
}
/**
* @param {Range} outerRange outer range
* @param {Range} arrayRange array range
* @param {Range | null} functionRange function range
* @param {Range | null} errorCallbackRange error callback range
* @returns {AMDRequireDependency} dependency
*/
newRequireDependency(
outerRange,
arrayRange,
functionRange,
errorCallbackRange
) {
return new AMDRequireDependency(
outerRange,
arrayRange,
functionRange,
errorCallbackRange
);
}
/**
* @param {string} request request
* @param {Range=} range range
* @returns {AMDRequireItemDependency} AMDRequireItemDependency
*/
newRequireItemDependency(request, range) {
return new AMDRequireItemDependency(request, range);
}
/**
* @param {(string | LocalModuleDependency | AMDRequireItemDependency)[]} depsArray deps array
* @param {Range} range range
* @returns {AMDRequireArrayDependency} AMDRequireArrayDependency
*/
newRequireArrayDependency(depsArray, range) {
return new AMDRequireArrayDependency(depsArray, range);
}
}
module.exports = AMDRequireDependenciesBlockParserPlugin;