From d1d9f00b1bd660842addf5e6b1d1b64c852a9eea Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Sun, 5 Nov 2023 17:16:09 +0800 Subject: added hover prefixer --- node_modules/webpack/lib/ConstPlugin.js | 545 ++++++++++++++++++++++++++++++++ 1 file changed, 545 insertions(+) create mode 100644 node_modules/webpack/lib/ConstPlugin.js (limited to 'node_modules/webpack/lib/ConstPlugin.js') diff --git a/node_modules/webpack/lib/ConstPlugin.js b/node_modules/webpack/lib/ConstPlugin.js new file mode 100644 index 00000000..74806b12 --- /dev/null +++ b/node_modules/webpack/lib/ConstPlugin.js @@ -0,0 +1,545 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +"use strict"; + +const { + JAVASCRIPT_MODULE_TYPE_AUTO, + JAVASCRIPT_MODULE_TYPE_DYNAMIC, + JAVASCRIPT_MODULE_TYPE_ESM +} = require("./ModuleTypeConstants"); +const CachedConstDependency = require("./dependencies/CachedConstDependency"); +const ConstDependency = require("./dependencies/ConstDependency"); +const { evaluateToString } = require("./javascript/JavascriptParserHelpers"); +const { parseResource } = require("./util/identifier"); + +/** @typedef {import("estree").AssignmentProperty} AssignmentProperty */ +/** @typedef {import("estree").Expression} Expression */ +/** @typedef {import("estree").Identifier} Identifier */ +/** @typedef {import("estree").Pattern} Pattern */ +/** @typedef {import("estree").SourceLocation} SourceLocation */ +/** @typedef {import("estree").Statement} Statement */ +/** @typedef {import("estree").Super} Super */ +/** @typedef {import("./Compiler")} Compiler */ +/** @typedef {import("./javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */ +/** @typedef {import("./javascript/JavascriptParser")} JavascriptParser */ +/** @typedef {import("./javascript/JavascriptParser").Range} Range */ + +/** + * @param {Set} declarations set of declarations + * @param {Identifier | Pattern} pattern pattern to collect declarations from + */ +const collectDeclaration = (declarations, pattern) => { + const stack = [pattern]; + while (stack.length > 0) { + const node = /** @type {Pattern} */ (stack.pop()); + switch (node.type) { + case "Identifier": + declarations.add(node.name); + break; + case "ArrayPattern": + for (const element of node.elements) { + if (element) { + stack.push(element); + } + } + break; + case "AssignmentPattern": + stack.push(node.left); + break; + case "ObjectPattern": + for (const property of node.properties) { + stack.push(/** @type {AssignmentProperty} */ (property).value); + } + break; + case "RestElement": + stack.push(node.argument); + break; + } + } +}; + +/** + * @param {Statement} branch branch to get hoisted declarations from + * @param {boolean} includeFunctionDeclarations whether to include function declarations + * @returns {Array} hoisted declarations + */ +const getHoistedDeclarations = (branch, includeFunctionDeclarations) => { + const declarations = new Set(); + /** @type {Array} */ + const stack = [branch]; + while (stack.length > 0) { + const node = stack.pop(); + // Some node could be `null` or `undefined`. + if (!node) continue; + switch (node.type) { + // Walk through control statements to look for hoisted declarations. + // Some branches are skipped since they do not allow declarations. + case "BlockStatement": + for (const stmt of node.body) { + stack.push(stmt); + } + break; + case "IfStatement": + stack.push(node.consequent); + stack.push(node.alternate); + break; + case "ForStatement": + stack.push(node.init); + stack.push(node.body); + break; + case "ForInStatement": + case "ForOfStatement": + stack.push(node.left); + stack.push(node.body); + break; + case "DoWhileStatement": + case "WhileStatement": + case "LabeledStatement": + stack.push(node.body); + break; + case "SwitchStatement": + for (const cs of node.cases) { + for (const consequent of cs.consequent) { + stack.push(consequent); + } + } + break; + case "TryStatement": + stack.push(node.block); + if (node.handler) { + stack.push(node.handler.body); + } + stack.push(node.finalizer); + break; + case "FunctionDeclaration": + if (includeFunctionDeclarations) { + collectDeclaration(declarations, /** @type {Identifier} */ (node.id)); + } + break; + case "VariableDeclaration": + if (node.kind === "var") { + for (const decl of node.declarations) { + collectDeclaration(declarations, decl.id); + } + } + break; + } + } + return Array.from(declarations); +}; + +const PLUGIN_NAME = "ConstPlugin"; + +class ConstPlugin { + /** + * Apply the plugin + * @param {Compiler} compiler the compiler instance + * @returns {void} + */ + apply(compiler) { + const cachedParseResource = parseResource.bindCache(compiler.root); + compiler.hooks.compilation.tap( + PLUGIN_NAME, + (compilation, { normalModuleFactory }) => { + compilation.dependencyTemplates.set( + ConstDependency, + new ConstDependency.Template() + ); + + compilation.dependencyTemplates.set( + CachedConstDependency, + new CachedConstDependency.Template() + ); + + /** + * @param {JavascriptParser} parser the parser + */ + const handler = parser => { + parser.hooks.statementIf.tap(PLUGIN_NAME, statement => { + if (parser.scope.isAsmJs) return; + const param = parser.evaluateExpression(statement.test); + const bool = param.asBool(); + if (typeof bool === "boolean") { + if (!param.couldHaveSideEffects()) { + const dep = new ConstDependency( + `${bool}`, + /** @type {Range} */ (param.range) + ); + dep.loc = /** @type {SourceLocation} */ (statement.loc); + parser.state.module.addPresentationalDependency(dep); + } else { + parser.walkExpression(statement.test); + } + const branchToRemove = bool + ? statement.alternate + : statement.consequent; + if (branchToRemove) { + // Before removing the dead branch, the hoisted declarations + // must be collected. + // + // Given the following code: + // + // if (true) f() else g() + // if (false) { + // function f() {} + // const g = function g() {} + // if (someTest) { + // let a = 1 + // var x, {y, z} = obj + // } + // } else { + // … + // } + // + // the generated code is: + // + // if (true) f() else {} + // if (false) { + // var f, x, y, z; (in loose mode) + // var x, y, z; (in strict mode) + // } else { + // … + // } + // + // NOTE: When code runs in strict mode, `var` declarations + // are hoisted but `function` declarations don't. + // + let declarations; + if (parser.scope.isStrict) { + // If the code runs in strict mode, variable declarations + // using `var` must be hoisted. + declarations = getHoistedDeclarations(branchToRemove, false); + } else { + // Otherwise, collect all hoisted declaration. + declarations = getHoistedDeclarations(branchToRemove, true); + } + let replacement; + if (declarations.length > 0) { + replacement = `{ var ${declarations.join(", ")}; }`; + } else { + replacement = "{}"; + } + const dep = new ConstDependency( + replacement, + /** @type {Range} */ (branchToRemove.range) + ); + dep.loc = /** @type {SourceLocation} */ (branchToRemove.loc); + parser.state.module.addPresentationalDependency(dep); + } + return bool; + } + }); + parser.hooks.expressionConditionalOperator.tap( + PLUGIN_NAME, + expression => { + if (parser.scope.isAsmJs) return; + const param = parser.evaluateExpression(expression.test); + const bool = param.asBool(); + if (typeof bool === "boolean") { + if (!param.couldHaveSideEffects()) { + const dep = new ConstDependency( + ` ${bool}`, + /** @type {Range} */ (param.range) + ); + dep.loc = /** @type {SourceLocation} */ (expression.loc); + parser.state.module.addPresentationalDependency(dep); + } else { + parser.walkExpression(expression.test); + } + // Expressions do not hoist. + // It is safe to remove the dead branch. + // + // Given the following code: + // + // false ? someExpression() : otherExpression(); + // + // the generated code is: + // + // false ? 0 : otherExpression(); + // + const branchToRemove = bool + ? expression.alternate + : expression.consequent; + const dep = new ConstDependency( + "0", + /** @type {Range} */ (branchToRemove.range) + ); + dep.loc = /** @type {SourceLocation} */ (branchToRemove.loc); + parser.state.module.addPresentationalDependency(dep); + return bool; + } + } + ); + parser.hooks.expressionLogicalOperator.tap( + PLUGIN_NAME, + expression => { + if (parser.scope.isAsmJs) return; + if ( + expression.operator === "&&" || + expression.operator === "||" + ) { + const param = parser.evaluateExpression(expression.left); + const bool = param.asBool(); + if (typeof bool === "boolean") { + // Expressions do not hoist. + // It is safe to remove the dead branch. + // + // ------------------------------------------ + // + // Given the following code: + // + // falsyExpression() && someExpression(); + // + // the generated code is: + // + // falsyExpression() && false; + // + // ------------------------------------------ + // + // Given the following code: + // + // truthyExpression() && someExpression(); + // + // the generated code is: + // + // true && someExpression(); + // + // ------------------------------------------ + // + // Given the following code: + // + // truthyExpression() || someExpression(); + // + // the generated code is: + // + // truthyExpression() || false; + // + // ------------------------------------------ + // + // Given the following code: + // + // falsyExpression() || someExpression(); + // + // the generated code is: + // + // false && someExpression(); + // + const keepRight = + (expression.operator === "&&" && bool) || + (expression.operator === "||" && !bool); + + if ( + !param.couldHaveSideEffects() && + (param.isBoolean() || keepRight) + ) { + // for case like + // + // return'development'===process.env.NODE_ENV&&'foo' + // + // we need a space before the bool to prevent result like + // + // returnfalse&&'foo' + // + const dep = new ConstDependency( + ` ${bool}`, + /** @type {Range} */ (param.range) + ); + dep.loc = /** @type {SourceLocation} */ (expression.loc); + parser.state.module.addPresentationalDependency(dep); + } else { + parser.walkExpression(expression.left); + } + if (!keepRight) { + const dep = new ConstDependency( + "0", + /** @type {Range} */ (expression.right.range) + ); + dep.loc = /** @type {SourceLocation} */ (expression.loc); + parser.state.module.addPresentationalDependency(dep); + } + return keepRight; + } + } else if (expression.operator === "??") { + const param = parser.evaluateExpression(expression.left); + const keepRight = param.asNullish(); + if (typeof keepRight === "boolean") { + // ------------------------------------------ + // + // Given the following code: + // + // nonNullish ?? someExpression(); + // + // the generated code is: + // + // nonNullish ?? 0; + // + // ------------------------------------------ + // + // Given the following code: + // + // nullish ?? someExpression(); + // + // the generated code is: + // + // null ?? someExpression(); + // + if (!param.couldHaveSideEffects() && keepRight) { + // cspell:word returnnull + // for case like + // + // return('development'===process.env.NODE_ENV&&null)??'foo' + // + // we need a space before the bool to prevent result like + // + // returnnull??'foo' + // + const dep = new ConstDependency( + " null", + /** @type {Range} */ (param.range) + ); + dep.loc = /** @type {SourceLocation} */ (expression.loc); + parser.state.module.addPresentationalDependency(dep); + } else { + const dep = new ConstDependency( + "0", + /** @type {Range} */ (expression.right.range) + ); + dep.loc = /** @type {SourceLocation} */ (expression.loc); + parser.state.module.addPresentationalDependency(dep); + parser.walkExpression(expression.left); + } + + return keepRight; + } + } + } + ); + parser.hooks.optionalChaining.tap(PLUGIN_NAME, expr => { + /** @type {Expression[]} */ + const optionalExpressionsStack = []; + /** @type {Expression | Super} */ + let next = expr.expression; + + while ( + next.type === "MemberExpression" || + next.type === "CallExpression" + ) { + if (next.type === "MemberExpression") { + if (next.optional) { + // SuperNode can not be optional + optionalExpressionsStack.push( + /** @type {Expression} */ (next.object) + ); + } + next = next.object; + } else { + if (next.optional) { + // SuperNode can not be optional + optionalExpressionsStack.push( + /** @type {Expression} */ (next.callee) + ); + } + next = next.callee; + } + } + + while (optionalExpressionsStack.length) { + const expression = optionalExpressionsStack.pop(); + const evaluated = parser.evaluateExpression( + /** @type {Expression} */ (expression) + ); + + if (evaluated.asNullish()) { + // ------------------------------------------ + // + // Given the following code: + // + // nullishMemberChain?.a.b(); + // + // the generated code is: + // + // undefined; + // + // ------------------------------------------ + // + const dep = new ConstDependency( + " undefined", + /** @type {Range} */ (expr.range) + ); + dep.loc = /** @type {SourceLocation} */ (expr.loc); + parser.state.module.addPresentationalDependency(dep); + return true; + } + } + }); + parser.hooks.evaluateIdentifier + .for("__resourceQuery") + .tap(PLUGIN_NAME, expr => { + if (parser.scope.isAsmJs) return; + if (!parser.state.module) return; + return evaluateToString( + cachedParseResource(parser.state.module.resource).query + )(expr); + }); + parser.hooks.expression + .for("__resourceQuery") + .tap(PLUGIN_NAME, expr => { + if (parser.scope.isAsmJs) return; + if (!parser.state.module) return; + const dep = new CachedConstDependency( + JSON.stringify( + cachedParseResource(parser.state.module.resource).query + ), + /** @type {Range} */ (expr.range), + "__resourceQuery" + ); + dep.loc = /** @type {SourceLocation} */ (expr.loc); + parser.state.module.addPresentationalDependency(dep); + return true; + }); + + parser.hooks.evaluateIdentifier + .for("__resourceFragment") + .tap(PLUGIN_NAME, expr => { + if (parser.scope.isAsmJs) return; + if (!parser.state.module) return; + return evaluateToString( + cachedParseResource(parser.state.module.resource).fragment + )(expr); + }); + parser.hooks.expression + .for("__resourceFragment") + .tap(PLUGIN_NAME, expr => { + if (parser.scope.isAsmJs) return; + if (!parser.state.module) return; + const dep = new CachedConstDependency( + JSON.stringify( + cachedParseResource(parser.state.module.resource).fragment + ), + /** @type {Range} */ (expr.range), + "__resourceFragment" + ); + dep.loc = /** @type {SourceLocation} */ (expr.loc); + parser.state.module.addPresentationalDependency(dep); + return true; + }); + }; + + normalModuleFactory.hooks.parser + .for(JAVASCRIPT_MODULE_TYPE_AUTO) + .tap(PLUGIN_NAME, handler); + normalModuleFactory.hooks.parser + .for(JAVASCRIPT_MODULE_TYPE_DYNAMIC) + .tap(PLUGIN_NAME, handler); + normalModuleFactory.hooks.parser + .for(JAVASCRIPT_MODULE_TYPE_ESM) + .tap(PLUGIN_NAME, handler); + } + ); + } +} + +module.exports = ConstPlugin; -- cgit v1.2.3