Files
rspade_system/node_modules/webpack/lib/dependencies/CreateRequireParserPlugin.js
root 3ed8517b2a Framework updates
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-04 23:20:19 +00:00

357 lines
10 KiB
JavaScript
Executable File

/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const { fileURLToPath } = require("url");
const WebpackError = require("../WebpackError");
const BasicEvaluatedExpression = require("../javascript/BasicEvaluatedExpression");
const { VariableInfo } = require("../javascript/JavascriptParser");
const {
evaluateToString,
expressionIsUnsupported,
toConstantDependency
} = require("../javascript/JavascriptParserHelpers");
const CommonJsImportsParserPlugin = require("./CommonJsImportsParserPlugin");
const ConstDependency = require("./ConstDependency");
/** @typedef {import("estree").CallExpression} CallExpression */
/** @typedef {import("estree").Expression} Expression */
/** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
/** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
/** @typedef {import("../javascript/JavascriptParser").ImportSource} ImportSource */
/** @typedef {import("../javascript/JavascriptParser").Range} Range */
/**
* @typedef {object} CommonJsImportSettings
* @property {string=} name
* @property {string} context
*/
const createRequireSpecifierTag = Symbol("createRequire");
const createdRequireIdentifierTag = Symbol("createRequire()");
const PLUGIN_NAME = "CreateRequireParserPlugin";
const {
createProcessResolveHandler,
createRequireAsExpressionHandler,
createRequireCacheDependency,
createRequireHandler
} = CommonJsImportsParserPlugin;
class CreateRequireParserPlugin {
/**
* @param {JavascriptParserOptions} options parser options
*/
constructor(options) {
this.options = options;
}
/**
* @param {JavascriptParser} parser the parser
* @returns {void}
*/
apply(parser) {
const options = this.options;
if (!options.createRequire) return;
const getContext = () => {
if (parser.currentTagData) {
const { context } =
/** @type {CommonJsImportSettings} */
(parser.currentTagData);
return context;
}
};
/**
* @param {string | symbol} tag tag
*/
const tapRequireExpressionTag = (tag) => {
parser.hooks.typeof
.for(tag)
.tap(
PLUGIN_NAME,
toConstantDependency(parser, JSON.stringify("function"))
);
parser.hooks.evaluateTypeof
.for(tag)
.tap(PLUGIN_NAME, evaluateToString("function"));
};
/**
* @param {Expression} expr expression
* @returns {boolean} true when set undefined
*/
const defineUndefined = (expr) => {
const dep = new ConstDependency(
"undefined",
/** @type {Range} */ (expr.range)
);
dep.loc = /** @type {DependencyLocation} */ (expr.loc);
parser.state.module.addPresentationalDependency(dep);
return false;
};
const requireCache = createRequireCacheDependency(parser);
const requireAsExpressionHandler = createRequireAsExpressionHandler(
parser,
options,
getContext
);
const createRequireCallHandler = createRequireHandler(
parser,
options,
getContext
);
const processResolve = createProcessResolveHandler(
parser,
options,
getContext
);
/** @type {ImportSource[]} */
let moduleNames = [];
/** @type {string | undefined} */
let specifierName;
if (options.createRequire === true) {
moduleNames = ["module", "node:module"];
specifierName = "createRequire";
} else if (typeof options.createRequire === "string") {
/** @type {undefined | string} */
let parsedModuleName;
const match = /^(.*) from (.*)$/.exec(options.createRequire);
if (match) {
[, specifierName, parsedModuleName] = match;
}
if (!specifierName || !parsedModuleName) {
const err = new WebpackError(
`Parsing javascript parser option "createRequire" failed, got ${JSON.stringify(
options.createRequire
)}`
);
err.details =
'Expected string in format "createRequire from module", where "createRequire" is specifier name and "module" name of the module';
throw err;
}
moduleNames = [parsedModuleName];
} else {
return;
}
/**
* @param {CallExpression} expr call expression
* @returns {string | void} context
*/
const parseCreateRequireArguments = (expr) => {
const args = expr.arguments;
if (args.length !== 1) {
const err = new WebpackError(
"module.createRequire supports only one argument."
);
err.loc = /** @type {DependencyLocation} */ (expr.loc);
parser.state.module.addWarning(err);
return;
}
const arg = args[0];
const evaluated = parser.evaluateExpression(arg);
if (!evaluated.isString()) {
const err = new WebpackError(
"module.createRequire failed parsing argument."
);
err.loc = /** @type {DependencyLocation} */ (arg.loc);
parser.state.module.addWarning(err);
return;
}
const ctx = /** @type {string} */ (evaluated.string).startsWith("file://")
? fileURLToPath(/** @type {string} */ (evaluated.string))
: /** @type {string} */ (evaluated.string);
// argument always should be a filename
return ctx.slice(0, ctx.lastIndexOf(ctx.startsWith("/") ? "/" : "\\"));
};
tapRequireExpressionTag(createdRequireIdentifierTag);
tapRequireExpressionTag(createRequireSpecifierTag);
parser.hooks.evaluateCallExpression
.for(createRequireSpecifierTag)
.tap(PLUGIN_NAME, (expr) => {
const context = parseCreateRequireArguments(expr);
if (context === undefined) return;
const ident = parser.evaluatedVariable({
tag: createdRequireIdentifierTag,
data: { context },
next: undefined
});
return new BasicEvaluatedExpression()
.setIdentifier(ident, ident, () => [])
.setSideEffects(false)
.setRange(/** @type {Range} */ (expr.range));
});
parser.hooks.unhandledExpressionMemberChain
.for(createdRequireIdentifierTag)
.tap(PLUGIN_NAME, (expr, members) =>
expressionIsUnsupported(
parser,
`createRequire().${members.join(".")} is not supported by webpack.`
)(expr)
);
parser.hooks.canRename
.for(createdRequireIdentifierTag)
.tap(PLUGIN_NAME, () => true);
parser.hooks.canRename
.for(createRequireSpecifierTag)
.tap(PLUGIN_NAME, () => true);
parser.hooks.rename
.for(createRequireSpecifierTag)
.tap(PLUGIN_NAME, defineUndefined);
parser.hooks.expression
.for(createdRequireIdentifierTag)
.tap(PLUGIN_NAME, requireAsExpressionHandler);
parser.hooks.call
.for(createdRequireIdentifierTag)
.tap(PLUGIN_NAME, createRequireCallHandler(false));
parser.hooks.import.tap(
{
name: PLUGIN_NAME,
stage: -10
},
(statement, source) => {
if (
!moduleNames.includes(source) ||
statement.specifiers.length !== 1 ||
statement.specifiers[0].type !== "ImportSpecifier" ||
statement.specifiers[0].imported.type !== "Identifier" ||
statement.specifiers[0].imported.name !== specifierName
) {
return;
}
// clear for 'import { createRequire as x } from "module"'
// if any other specifier was used import module
const clearDep = new ConstDependency(
parser.isAsiPosition(/** @type {Range} */ (statement.range)[0])
? ";"
: "",
/** @type {Range} */ (statement.range)
);
clearDep.loc = /** @type {DependencyLocation} */ (statement.loc);
parser.state.module.addPresentationalDependency(clearDep);
parser.unsetAsiPosition(/** @type {Range} */ (statement.range)[1]);
return true;
}
);
parser.hooks.importSpecifier.tap(
{
name: PLUGIN_NAME,
stage: -10
},
(statement, source, id, name) => {
if (!moduleNames.includes(source) || id !== specifierName) return;
parser.tagVariable(name, createRequireSpecifierTag);
return true;
}
);
parser.hooks.preDeclarator.tap(PLUGIN_NAME, (declarator) => {
if (
declarator.id.type !== "Identifier" ||
!declarator.init ||
declarator.init.type !== "CallExpression" ||
declarator.init.callee.type !== "Identifier"
) {
return;
}
const variableInfo = parser.getVariableInfo(declarator.init.callee.name);
if (
variableInfo instanceof VariableInfo &&
variableInfo.tagInfo &&
variableInfo.tagInfo.tag === createRequireSpecifierTag
) {
const context = parseCreateRequireArguments(declarator.init);
if (context === undefined) return;
parser.tagVariable(declarator.id.name, createdRequireIdentifierTag, {
name: declarator.id.name,
context
});
return true;
}
});
parser.hooks.memberChainOfCallMemberChain
.for(createRequireSpecifierTag)
.tap(PLUGIN_NAME, (expr, calleeMembers, callExpr, members) => {
if (
calleeMembers.length !== 0 ||
members.length !== 1 ||
members[0] !== "cache"
) {
return;
}
// createRequire().cache
const context = parseCreateRequireArguments(callExpr);
if (context === undefined) return;
return requireCache(expr);
});
parser.hooks.callMemberChainOfCallMemberChain
.for(createRequireSpecifierTag)
.tap(PLUGIN_NAME, (expr, calleeMembers, innerCallExpression, members) => {
if (
calleeMembers.length !== 0 ||
members.length !== 1 ||
members[0] !== "resolve"
) {
return;
}
// createRequire().resolve()
return processResolve(expr, false);
});
parser.hooks.expressionMemberChain
.for(createdRequireIdentifierTag)
.tap(PLUGIN_NAME, (expr, members) => {
// require.cache
if (members.length === 1 && members[0] === "cache") {
return requireCache(expr);
}
});
parser.hooks.callMemberChain
.for(createdRequireIdentifierTag)
.tap(PLUGIN_NAME, (expr, members) => {
// require.resolve()
if (members.length === 1 && members[0] === "resolve") {
return processResolve(expr, false);
}
});
parser.hooks.expression
.for(createRequireSpecifierTag)
.tap(PLUGIN_NAME, (expr) => {
const clearDep = new ConstDependency(
"/* createRequire */ undefined",
/** @type {Range} */ (expr.range)
);
clearDep.loc = /** @type {DependencyLocation} */ (expr.loc);
parser.state.module.addPresentationalDependency(clearDep);
return true;
});
parser.hooks.call
.for(createRequireSpecifierTag)
.tap(PLUGIN_NAME, (expr) => {
const clearDep = new ConstDependency(
"/* createRequire() */ undefined",
/** @type {Range} */ (expr.range)
);
clearDep.loc = /** @type {DependencyLocation} */ (expr.loc);
parser.state.module.addPresentationalDependency(clearDep);
return true;
});
}
}
module.exports = CreateRequireParserPlugin;