123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- /*
- MIT License http://www.opensource.org/licenses/mit-license.php
- Author Ivan Kopeykin @vankop
- */
- "use strict";
- const WebpackError = require("../WebpackError");
- const {
- evaluateToIdentifier
- } = require("../javascript/JavascriptParserHelpers");
- const ImportMetaContextDependency = require("./ImportMetaContextDependency");
- /** @typedef {import("estree").Expression} ExpressionNode */
- /** @typedef {import("estree").ObjectExpression} ObjectExpressionNode */
- /** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
- /** @typedef {import("../ContextModule").ContextModuleOptions} ContextModuleOptions */
- /** @typedef {import("../ChunkGroup").RawChunkGroupOptions} RawChunkGroupOptions */
- /** @typedef {Pick<ContextModuleOptions, 'mode'|'recursive'|'regExp'|'include'|'exclude'|'chunkName'>&{groupOptions: RawChunkGroupOptions, exports?: ContextModuleOptions["referencedExports"]}} ImportMetaContextOptions */
- function createPropertyParseError(prop, expect) {
- return createError(
- `Parsing import.meta.webpackContext options failed. Unknown value for property ${JSON.stringify(
- prop.key.name
- )}, expected type ${expect}.`,
- prop.value.loc
- );
- }
- function createError(msg, loc) {
- const error = new WebpackError(msg);
- error.name = "ImportMetaContextError";
- error.loc = loc;
- return error;
- }
- module.exports = class ImportMetaContextDependencyParserPlugin {
- apply(parser) {
- parser.hooks.evaluateIdentifier
- .for("import.meta.webpackContext")
- .tap("ImportMetaContextDependencyParserPlugin", expr => {
- return evaluateToIdentifier(
- "import.meta.webpackContext",
- "import.meta",
- () => ["webpackContext"],
- true
- )(expr);
- });
- parser.hooks.call
- .for("import.meta.webpackContext")
- .tap("ImportMetaContextDependencyParserPlugin", expr => {
- if (expr.arguments.length < 1 || expr.arguments.length > 2) return;
- const [directoryNode, optionsNode] = expr.arguments;
- if (optionsNode && optionsNode.type !== "ObjectExpression") return;
- const requestExpr = parser.evaluateExpression(directoryNode);
- if (!requestExpr.isString()) return;
- const request = requestExpr.string;
- const errors = [];
- let regExp = /^\.\/.*$/;
- let recursive = true;
- /** @type {ContextModuleOptions["mode"]} */
- let mode = "sync";
- /** @type {ContextModuleOptions["include"]} */
- let include;
- /** @type {ContextModuleOptions["exclude"]} */
- let exclude;
- /** @type {RawChunkGroupOptions} */
- const groupOptions = {};
- /** @type {ContextModuleOptions["chunkName"]} */
- let chunkName;
- /** @type {ContextModuleOptions["referencedExports"]} */
- let exports;
- if (optionsNode) {
- for (const prop of optionsNode.properties) {
- if (prop.type !== "Property" || prop.key.type !== "Identifier") {
- errors.push(
- createError(
- "Parsing import.meta.webpackContext options failed.",
- optionsNode.loc
- )
- );
- break;
- }
- switch (prop.key.name) {
- case "regExp": {
- const regExpExpr = parser.evaluateExpression(
- /** @type {ExpressionNode} */ (prop.value)
- );
- if (!regExpExpr.isRegExp()) {
- errors.push(createPropertyParseError(prop, "RegExp"));
- } else {
- regExp = regExpExpr.regExp;
- }
- break;
- }
- case "include": {
- const regExpExpr = parser.evaluateExpression(
- /** @type {ExpressionNode} */ (prop.value)
- );
- if (!regExpExpr.isRegExp()) {
- errors.push(createPropertyParseError(prop, "RegExp"));
- } else {
- include = regExpExpr.regExp;
- }
- break;
- }
- case "exclude": {
- const regExpExpr = parser.evaluateExpression(
- /** @type {ExpressionNode} */ (prop.value)
- );
- if (!regExpExpr.isRegExp()) {
- errors.push(createPropertyParseError(prop, "RegExp"));
- } else {
- exclude = regExpExpr.regExp;
- }
- break;
- }
- case "mode": {
- const modeExpr = parser.evaluateExpression(
- /** @type {ExpressionNode} */ (prop.value)
- );
- if (!modeExpr.isString()) {
- errors.push(createPropertyParseError(prop, "string"));
- } else {
- mode = /** @type {ContextModuleOptions["mode"]} */ (
- modeExpr.string
- );
- }
- break;
- }
- case "chunkName": {
- const expr = parser.evaluateExpression(
- /** @type {ExpressionNode} */ (prop.value)
- );
- if (!expr.isString()) {
- errors.push(createPropertyParseError(prop, "string"));
- } else {
- chunkName = expr.string;
- }
- break;
- }
- case "exports": {
- const expr = parser.evaluateExpression(
- /** @type {ExpressionNode} */ (prop.value)
- );
- if (expr.isString()) {
- exports = [[expr.string]];
- } else if (expr.isArray()) {
- const items = expr.items;
- if (
- items.every(i => {
- if (!i.isArray()) return false;
- const innerItems = i.items;
- return innerItems.every(i => i.isString());
- })
- ) {
- exports = [];
- for (const i1 of items) {
- const export_ = [];
- for (const i2 of i1.items) {
- export_.push(i2.string);
- }
- exports.push(export_);
- }
- } else {
- errors.push(
- createPropertyParseError(prop, "string|string[][]")
- );
- }
- } else {
- errors.push(
- createPropertyParseError(prop, "string|string[][]")
- );
- }
- break;
- }
- case "prefetch": {
- const expr = parser.evaluateExpression(
- /** @type {ExpressionNode} */ (prop.value)
- );
- if (expr.isBoolean()) {
- groupOptions.prefetchOrder = 0;
- } else if (expr.isNumber()) {
- groupOptions.prefetchOrder = expr.number;
- } else {
- errors.push(createPropertyParseError(prop, "boolean|number"));
- }
- break;
- }
- case "preload": {
- const expr = parser.evaluateExpression(
- /** @type {ExpressionNode} */ (prop.value)
- );
- if (expr.isBoolean()) {
- groupOptions.preloadOrder = 0;
- } else if (expr.isNumber()) {
- groupOptions.preloadOrder = expr.number;
- } else {
- errors.push(createPropertyParseError(prop, "boolean|number"));
- }
- break;
- }
- case "recursive": {
- const recursiveExpr = parser.evaluateExpression(
- /** @type {ExpressionNode} */ (prop.value)
- );
- if (!recursiveExpr.isBoolean()) {
- errors.push(createPropertyParseError(prop, "boolean"));
- } else {
- recursive = recursiveExpr.bool;
- }
- break;
- }
- default:
- errors.push(
- createError(
- `Parsing import.meta.webpackContext options failed. Unknown property ${JSON.stringify(
- prop.key.name
- )}.`,
- optionsNode.loc
- )
- );
- }
- }
- }
- if (errors.length) {
- for (const error of errors) parser.state.current.addError(error);
- return;
- }
- const dep = new ImportMetaContextDependency(
- {
- request,
- include,
- exclude,
- recursive,
- regExp,
- groupOptions,
- chunkName,
- referencedExports: exports,
- mode,
- category: "esm"
- },
- expr.range
- );
- dep.loc = expr.loc;
- dep.optional = !!parser.scope.inTry;
- parser.state.current.addDependency(dep);
- return true;
- });
- }
- };
|