diff options
author | 2020-11-18 23:26:45 +0100 | |
---|---|---|
committer | 2020-11-18 23:26:45 +0100 | |
commit | 81ddf9b700bc48a1f8e472209f080f9c1d9a9b09 (patch) | |
tree | 8b959d50c5a614cbf9fcb346ed556140374d4b6d /node_modules/webpack/lib/Parser.js | |
parent | 1870f3fdf43707a15fda0f609a021f516f45eb63 (diff) | |
download | website_creator-81ddf9b700bc48a1f8e472209f080f9c1d9a9b09.tar.gz website_creator-81ddf9b700bc48a1f8e472209f080f9c1d9a9b09.tar.bz2 website_creator-81ddf9b700bc48a1f8e472209f080f9c1d9a9b09.zip |
rm node_modules
Diffstat (limited to 'node_modules/webpack/lib/Parser.js')
-rw-r--r-- | node_modules/webpack/lib/Parser.js | 2454 |
1 files changed, 0 insertions, 2454 deletions
diff --git a/node_modules/webpack/lib/Parser.js b/node_modules/webpack/lib/Parser.js deleted file mode 100644 index b496845..0000000 --- a/node_modules/webpack/lib/Parser.js +++ /dev/null @@ -1,2454 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra -*/ -"use strict"; - -// Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API - -const acorn = require("acorn"); -const { Tapable, SyncBailHook, HookMap } = require("tapable"); -const util = require("util"); -const vm = require("vm"); -const BasicEvaluatedExpression = require("./BasicEvaluatedExpression"); -const StackedSetMap = require("./util/StackedSetMap"); - -const acornParser = acorn.Parser; - -const joinRanges = (startRange, endRange) => { - if (!endRange) return startRange; - if (!startRange) return endRange; - return [startRange[0], endRange[1]]; -}; - -const defaultParserOptions = { - ranges: true, - locations: true, - ecmaVersion: 11, - sourceType: "module", - onComment: null -}; - -// regexp to match at least one "magic comment" -const webpackCommentRegExp = new RegExp(/(^|\W)webpack[A-Z]{1,}[A-Za-z]{1,}:/); - -const EMPTY_COMMENT_OPTIONS = { - options: null, - errors: null -}; - -class Parser extends Tapable { - constructor(options, sourceType = "auto") { - super(); - this.hooks = { - evaluateTypeof: new HookMap(() => new SyncBailHook(["expression"])), - evaluate: new HookMap(() => new SyncBailHook(["expression"])), - evaluateIdentifier: new HookMap(() => new SyncBailHook(["expression"])), - evaluateDefinedIdentifier: new HookMap( - () => new SyncBailHook(["expression"]) - ), - evaluateCallExpressionMember: new HookMap( - () => new SyncBailHook(["expression", "param"]) - ), - statement: new SyncBailHook(["statement"]), - statementIf: new SyncBailHook(["statement"]), - label: new HookMap(() => new SyncBailHook(["statement"])), - import: new SyncBailHook(["statement", "source"]), - importSpecifier: new SyncBailHook([ - "statement", - "source", - "exportName", - "identifierName" - ]), - export: new SyncBailHook(["statement"]), - exportImport: new SyncBailHook(["statement", "source"]), - exportDeclaration: new SyncBailHook(["statement", "declaration"]), - exportExpression: new SyncBailHook(["statement", "declaration"]), - exportSpecifier: new SyncBailHook([ - "statement", - "identifierName", - "exportName", - "index" - ]), - exportImportSpecifier: new SyncBailHook([ - "statement", - "source", - "identifierName", - "exportName", - "index" - ]), - varDeclaration: new HookMap(() => new SyncBailHook(["declaration"])), - varDeclarationLet: new HookMap(() => new SyncBailHook(["declaration"])), - varDeclarationConst: new HookMap(() => new SyncBailHook(["declaration"])), - varDeclarationVar: new HookMap(() => new SyncBailHook(["declaration"])), - canRename: new HookMap(() => new SyncBailHook(["initExpression"])), - rename: new HookMap(() => new SyncBailHook(["initExpression"])), - assigned: new HookMap(() => new SyncBailHook(["expression"])), - assign: new HookMap(() => new SyncBailHook(["expression"])), - typeof: new HookMap(() => new SyncBailHook(["expression"])), - importCall: new SyncBailHook(["expression"]), - call: new HookMap(() => new SyncBailHook(["expression"])), - callAnyMember: new HookMap(() => new SyncBailHook(["expression"])), - new: new HookMap(() => new SyncBailHook(["expression"])), - expression: new HookMap(() => new SyncBailHook(["expression"])), - expressionAnyMember: new HookMap(() => new SyncBailHook(["expression"])), - expressionConditionalOperator: new SyncBailHook(["expression"]), - expressionLogicalOperator: new SyncBailHook(["expression"]), - program: new SyncBailHook(["ast", "comments"]) - }; - const HOOK_MAP_COMPAT_CONFIG = { - evaluateTypeof: /^evaluate typeof (.+)$/, - evaluateIdentifier: /^evaluate Identifier (.+)$/, - evaluateDefinedIdentifier: /^evaluate defined Identifier (.+)$/, - evaluateCallExpressionMember: /^evaluate CallExpression .(.+)$/, - evaluate: /^evaluate (.+)$/, - label: /^label (.+)$/, - varDeclarationLet: /^var-let (.+)$/, - varDeclarationConst: /^var-const (.+)$/, - varDeclarationVar: /^var-var (.+)$/, - varDeclaration: /^var (.+)$/, - canRename: /^can-rename (.+)$/, - rename: /^rename (.+)$/, - typeof: /^typeof (.+)$/, - assigned: /^assigned (.+)$/, - assign: /^assign (.+)$/, - callAnyMember: /^call (.+)\.\*$/, - call: /^call (.+)$/, - new: /^new (.+)$/, - expressionConditionalOperator: /^expression \?:$/, - expressionAnyMember: /^expression (.+)\.\*$/, - expression: /^expression (.+)$/ - }; - this._pluginCompat.tap("Parser", options => { - for (const name of Object.keys(HOOK_MAP_COMPAT_CONFIG)) { - const regexp = HOOK_MAP_COMPAT_CONFIG[name]; - const match = regexp.exec(options.name); - if (match) { - if (match[1]) { - this.hooks[name].tap( - match[1], - options.fn.name || "unnamed compat plugin", - options.fn.bind(this) - ); - } else { - this.hooks[name].tap( - options.fn.name || "unnamed compat plugin", - options.fn.bind(this) - ); - } - return true; - } - } - }); - this.options = options; - this.sourceType = sourceType; - this.scope = undefined; - this.state = undefined; - this.comments = undefined; - this.initializeEvaluating(); - } - - initializeEvaluating() { - this.hooks.evaluate.for("Literal").tap("Parser", expr => { - switch (typeof expr.value) { - case "number": - return new BasicEvaluatedExpression() - .setNumber(expr.value) - .setRange(expr.range); - case "string": - return new BasicEvaluatedExpression() - .setString(expr.value) - .setRange(expr.range); - case "boolean": - return new BasicEvaluatedExpression() - .setBoolean(expr.value) - .setRange(expr.range); - } - if (expr.value === null) { - return new BasicEvaluatedExpression().setNull().setRange(expr.range); - } - if (expr.value instanceof RegExp) { - return new BasicEvaluatedExpression() - .setRegExp(expr.value) - .setRange(expr.range); - } - }); - this.hooks.evaluate.for("LogicalExpression").tap("Parser", expr => { - let left; - let leftAsBool; - let right; - if (expr.operator === "&&") { - left = this.evaluateExpression(expr.left); - leftAsBool = left && left.asBool(); - if (leftAsBool === false) return left.setRange(expr.range); - if (leftAsBool !== true) return; - right = this.evaluateExpression(expr.right); - return right.setRange(expr.range); - } else if (expr.operator === "||") { - left = this.evaluateExpression(expr.left); - leftAsBool = left && left.asBool(); - if (leftAsBool === true) return left.setRange(expr.range); - if (leftAsBool !== false) return; - right = this.evaluateExpression(expr.right); - return right.setRange(expr.range); - } - }); - this.hooks.evaluate.for("BinaryExpression").tap("Parser", expr => { - let left; - let right; - let res; - if (expr.operator === "+") { - left = this.evaluateExpression(expr.left); - right = this.evaluateExpression(expr.right); - if (!left || !right) return; - res = new BasicEvaluatedExpression(); - if (left.isString()) { - if (right.isString()) { - res.setString(left.string + right.string); - } else if (right.isNumber()) { - res.setString(left.string + right.number); - } else if ( - right.isWrapped() && - right.prefix && - right.prefix.isString() - ) { - // "left" + ("prefix" + inner + "postfix") - // => ("leftprefix" + inner + "postfix") - res.setWrapped( - new BasicEvaluatedExpression() - .setString(left.string + right.prefix.string) - .setRange(joinRanges(left.range, right.prefix.range)), - right.postfix, - right.wrappedInnerExpressions - ); - } else if (right.isWrapped()) { - // "left" + ([null] + inner + "postfix") - // => ("left" + inner + "postfix") - res.setWrapped(left, right.postfix, right.wrappedInnerExpressions); - } else { - // "left" + expr - // => ("left" + expr + "") - res.setWrapped(left, null, [right]); - } - } else if (left.isNumber()) { - if (right.isString()) { - res.setString(left.number + right.string); - } else if (right.isNumber()) { - res.setNumber(left.number + right.number); - } else { - return; - } - } else if (left.isWrapped()) { - if (left.postfix && left.postfix.isString() && right.isString()) { - // ("prefix" + inner + "postfix") + "right" - // => ("prefix" + inner + "postfixright") - res.setWrapped( - left.prefix, - new BasicEvaluatedExpression() - .setString(left.postfix.string + right.string) - .setRange(joinRanges(left.postfix.range, right.range)), - left.wrappedInnerExpressions - ); - } else if ( - left.postfix && - left.postfix.isString() && - right.isNumber() - ) { - // ("prefix" + inner + "postfix") + 123 - // => ("prefix" + inner + "postfix123") - res.setWrapped( - left.prefix, - new BasicEvaluatedExpression() - .setString(left.postfix.string + right.number) - .setRange(joinRanges(left.postfix.range, right.range)), - left.wrappedInnerExpressions - ); - } else if (right.isString()) { - // ("prefix" + inner + [null]) + "right" - // => ("prefix" + inner + "right") - res.setWrapped(left.prefix, right, left.wrappedInnerExpressions); - } else if (right.isNumber()) { - // ("prefix" + inner + [null]) + 123 - // => ("prefix" + inner + "123") - res.setWrapped( - left.prefix, - new BasicEvaluatedExpression() - .setString(right.number + "") - .setRange(right.range), - left.wrappedInnerExpressions - ); - } else if (right.isWrapped()) { - // ("prefix1" + inner1 + "postfix1") + ("prefix2" + inner2 + "postfix2") - // ("prefix1" + inner1 + "postfix1" + "prefix2" + inner2 + "postfix2") - res.setWrapped( - left.prefix, - right.postfix, - left.wrappedInnerExpressions && - right.wrappedInnerExpressions && - left.wrappedInnerExpressions - .concat(left.postfix ? [left.postfix] : []) - .concat(right.prefix ? [right.prefix] : []) - .concat(right.wrappedInnerExpressions) - ); - } else { - // ("prefix" + inner + postfix) + expr - // => ("prefix" + inner + postfix + expr + [null]) - res.setWrapped( - left.prefix, - null, - left.wrappedInnerExpressions && - left.wrappedInnerExpressions.concat( - left.postfix ? [left.postfix, right] : [right] - ) - ); - } - } else { - if (right.isString()) { - // left + "right" - // => ([null] + left + "right") - res.setWrapped(null, right, [left]); - } else if (right.isWrapped()) { - // left + (prefix + inner + "postfix") - // => ([null] + left + prefix + inner + "postfix") - res.setWrapped( - null, - right.postfix, - right.wrappedInnerExpressions && - (right.prefix ? [left, right.prefix] : [left]).concat( - right.wrappedInnerExpressions - ) - ); - } else { - return; - } - } - res.setRange(expr.range); - return res; - } else if (expr.operator === "-") { - left = this.evaluateExpression(expr.left); - right = this.evaluateExpression(expr.right); - if (!left || !right) return; - if (!left.isNumber() || !right.isNumber()) return; - res = new BasicEvaluatedExpression(); - res.setNumber(left.number - right.number); - res.setRange(expr.range); - return res; - } else if (expr.operator === "*") { - left = this.evaluateExpression(expr.left); - right = this.evaluateExpression(expr.right); - if (!left || !right) return; - if (!left.isNumber() || !right.isNumber()) return; - res = new BasicEvaluatedExpression(); - res.setNumber(left.number * right.number); - res.setRange(expr.range); - return res; - } else if (expr.operator === "/") { - left = this.evaluateExpression(expr.left); - right = this.evaluateExpression(expr.right); - if (!left || !right) return; - if (!left.isNumber() || !right.isNumber()) return; - res = new BasicEvaluatedExpression(); - res.setNumber(left.number / right.number); - res.setRange(expr.range); - return res; - } else if (expr.operator === "**") { - left = this.evaluateExpression(expr.left); - right = this.evaluateExpression(expr.right); - if (!left || !right) return; - if (!left.isNumber() || !right.isNumber()) return; - res = new BasicEvaluatedExpression(); - res.setNumber(Math.pow(left.number, right.number)); - res.setRange(expr.range); - return res; - } else if (expr.operator === "==" || expr.operator === "===") { - left = this.evaluateExpression(expr.left); - right = this.evaluateExpression(expr.right); - if (!left || !right) return; - res = new BasicEvaluatedExpression(); - res.setRange(expr.range); - if (left.isString() && right.isString()) { - return res.setBoolean(left.string === right.string); - } else if (left.isNumber() && right.isNumber()) { - return res.setBoolean(left.number === right.number); - } else if (left.isBoolean() && right.isBoolean()) { - return res.setBoolean(left.bool === right.bool); - } - } else if (expr.operator === "!=" || expr.operator === "!==") { - left = this.evaluateExpression(expr.left); - right = this.evaluateExpression(expr.right); - if (!left || !right) return; - res = new BasicEvaluatedExpression(); - res.setRange(expr.range); - if (left.isString() && right.isString()) { - return res.setBoolean(left.string !== right.string); - } else if (left.isNumber() && right.isNumber()) { - return res.setBoolean(left.number !== right.number); - } else if (left.isBoolean() && right.isBoolean()) { - return res.setBoolean(left.bool !== right.bool); - } - } else if (expr.operator === "&") { - left = this.evaluateExpression(expr.left); - right = this.evaluateExpression(expr.right); - if (!left || !right) return; - if (!left.isNumber() || !right.isNumber()) return; - res = new BasicEvaluatedExpression(); - res.setNumber(left.number & right.number); - res.setRange(expr.range); - return res; - } else if (expr.operator === "|") { - left = this.evaluateExpression(expr.left); - right = this.evaluateExpression(expr.right); - if (!left || !right) return; - if (!left.isNumber() || !right.isNumber()) return; - res = new BasicEvaluatedExpression(); - res.setNumber(left.number | right.number); - res.setRange(expr.range); - return res; - } else if (expr.operator === "^") { - left = this.evaluateExpression(expr.left); - right = this.evaluateExpression(expr.right); - if (!left || !right) return; - if (!left.isNumber() || !right.isNumber()) return; - res = new BasicEvaluatedExpression(); - res.setNumber(left.number ^ right.number); - res.setRange(expr.range); - return res; - } else if (expr.operator === ">>>") { - left = this.evaluateExpression(expr.left); - right = this.evaluateExpression(expr.right); - if (!left || !right) return; - if (!left.isNumber() || !right.isNumber()) return; - res = new BasicEvaluatedExpression(); - res.setNumber(left.number >>> right.number); - res.setRange(expr.range); - return res; - } else if (expr.operator === ">>") { - left = this.evaluateExpression(expr.left); - right = this.evaluateExpression(expr.right); - if (!left || !right) return; - if (!left.isNumber() || !right.isNumber()) return; - res = new BasicEvaluatedExpression(); - res.setNumber(left.number >> right.number); - res.setRange(expr.range); - return res; - } else if (expr.operator === "<<") { - left = this.evaluateExpression(expr.left); - right = this.evaluateExpression(expr.right); - if (!left || !right) return; - if (!left.isNumber() || !right.isNumber()) return; - res = new BasicEvaluatedExpression(); - res.setNumber(left.number << right.number); - res.setRange(expr.range); - return res; - } - }); - this.hooks.evaluate.for("UnaryExpression").tap("Parser", expr => { - if (expr.operator === "typeof") { - let res; - let name; - if (expr.argument.type === "Identifier") { - name = - this.scope.renames.get(expr.argument.name) || expr.argument.name; - if (!this.scope.definitions.has(name)) { - const hook = this.hooks.evaluateTypeof.get(name); - if (hook !== undefined) { - res = hook.call(expr); - if (res !== undefined) return res; - } - } - } - if (expr.argument.type === "MemberExpression") { - const exprName = this.getNameForExpression(expr.argument); - if (exprName && exprName.free) { - const hook = this.hooks.evaluateTypeof.get(exprName.name); - if (hook !== undefined) { - res = hook.call(expr); - if (res !== undefined) return res; - } - } - } - if (expr.argument.type === "FunctionExpression") { - return new BasicEvaluatedExpression() - .setString("function") - .setRange(expr.range); - } - const arg = this.evaluateExpression(expr.argument); - if (arg.isString() || arg.isWrapped()) { - return new BasicEvaluatedExpression() - .setString("string") - .setRange(expr.range); - } - if (arg.isNumber()) { - return new BasicEvaluatedExpression() - .setString("number") - .setRange(expr.range); - } - if (arg.isBoolean()) { - return new BasicEvaluatedExpression() - .setString("boolean") - .setRange(expr.range); - } - if (arg.isArray() || arg.isConstArray() || arg.isRegExp()) { - return new BasicEvaluatedExpression() - .setString("object") - .setRange(expr.range); - } - } else if (expr.operator === "!") { - const argument = this.evaluateExpression(expr.argument); - if (!argument) return; - if (argument.isBoolean()) { - return new BasicEvaluatedExpression() - .setBoolean(!argument.bool) - .setRange(expr.range); - } - if (argument.isTruthy()) { - return new BasicEvaluatedExpression() - .setBoolean(false) - .setRange(expr.range); - } - if (argument.isFalsy()) { - return new BasicEvaluatedExpression() - .setBoolean(true) - .setRange(expr.range); - } - if (argument.isString()) { - return new BasicEvaluatedExpression() - .setBoolean(!argument.string) - .setRange(expr.range); - } - if (argument.isNumber()) { - return new BasicEvaluatedExpression() - .setBoolean(!argument.number) - .setRange(expr.range); - } - } else if (expr.operator === "~") { - const argument = this.evaluateExpression(expr.argument); - if (!argument) return; - if (!argument.isNumber()) return; - const res = new BasicEvaluatedExpression(); - res.setNumber(~argument.number); - res.setRange(expr.range); - return res; - } - }); - this.hooks.evaluateTypeof.for("undefined").tap("Parser", expr => { - return new BasicEvaluatedExpression() - .setString("undefined") - .setRange(expr.range); - }); - this.hooks.evaluate.for("Identifier").tap("Parser", expr => { - const name = this.scope.renames.get(expr.name) || expr.name; - if (!this.scope.definitions.has(expr.name)) { - const hook = this.hooks.evaluateIdentifier.get(name); - if (hook !== undefined) { - const result = hook.call(expr); - if (result) return result; - } - return new BasicEvaluatedExpression() - .setIdentifier(name) - .setRange(expr.range); - } else { - const hook = this.hooks.evaluateDefinedIdentifier.get(name); - if (hook !== undefined) { - return hook.call(expr); - } - } - }); - this.hooks.evaluate.for("ThisExpression").tap("Parser", expr => { - const name = this.scope.renames.get("this"); - if (name) { - const hook = this.hooks.evaluateIdentifier.get(name); - if (hook !== undefined) { - const result = hook.call(expr); - if (result) return result; - } - return new BasicEvaluatedExpression() - .setIdentifier(name) - .setRange(expr.range); - } - }); - this.hooks.evaluate.for("MemberExpression").tap("Parser", expression => { - let exprName = this.getNameForExpression(expression); - if (exprName) { - if (exprName.free) { - const hook = this.hooks.evaluateIdentifier.get(exprName.name); - if (hook !== undefined) { - const result = hook.call(expression); - if (result) return result; - } - return new BasicEvaluatedExpression() - .setIdentifier(exprName.name) - .setRange(expression.range); - } else { - const hook = this.hooks.evaluateDefinedIdentifier.get(exprName.name); - if (hook !== undefined) { - return hook.call(expression); - } - } - } - }); - this.hooks.evaluate.for("CallExpression").tap("Parser", expr => { - if (expr.callee.type !== "MemberExpression") return; - if ( - expr.callee.property.type !== - (expr.callee.computed ? "Literal" : "Identifier") - ) - return; - const param = this.evaluateExpression(expr.callee.object); - if (!param) return; - const property = expr.callee.property.name || expr.callee.property.value; - const hook = this.hooks.evaluateCallExpressionMember.get(property); - if (hook !== undefined) { - return hook.call(expr, param); - } - }); - this.hooks.evaluateCallExpressionMember - .for("replace") - .tap("Parser", (expr, param) => { - if (!param.isString()) return; - if (expr.arguments.length !== 2) return; - let arg1 = this.evaluateExpression(expr.arguments[0]); - let arg2 = this.evaluateExpression(expr.arguments[1]); - if (!arg1.isString() && !arg1.isRegExp()) return; - arg1 = arg1.regExp || arg1.string; - if (!arg2.isString()) return; - arg2 = arg2.string; - return new BasicEvaluatedExpression() - .setString(param.string.replace(arg1, arg2)) - .setRange(expr.range); - }); - ["substr", "substring"].forEach(fn => { - this.hooks.evaluateCallExpressionMember - .for(fn) - .tap("Parser", (expr, param) => { - if (!param.isString()) return; - let arg1; - let result, - str = param.string; - switch (expr.arguments.length) { - case 1: - arg1 = this.evaluateExpression(expr.arguments[0]); - if (!arg1.isNumber()) return; - result = str[fn](arg1.number); - break; - case 2: { - arg1 = this.evaluateExpression(expr.arguments[0]); - const arg2 = this.evaluateExpression(expr.arguments[1]); - if (!arg1.isNumber()) return; - if (!arg2.isNumber()) return; - result = str[fn](arg1.number, arg2.number); - break; - } - default: - return; - } - return new BasicEvaluatedExpression() - .setString(result) - .setRange(expr.range); - }); - }); - - /** - * @param {string} kind "cooked" | "raw" - * @param {TODO} templateLiteralExpr TemplateLiteral expr - * @returns {{quasis: BasicEvaluatedExpression[], parts: BasicEvaluatedExpression[]}} Simplified template - */ - const getSimplifiedTemplateResult = (kind, templateLiteralExpr) => { - const quasis = []; - const parts = []; - - for (let i = 0; i < templateLiteralExpr.quasis.length; i++) { - const quasiExpr = templateLiteralExpr.quasis[i]; - const quasi = quasiExpr.value[kind]; - - if (i > 0) { - const prevExpr = parts[parts.length - 1]; - const expr = this.evaluateExpression( - templateLiteralExpr.expressions[i - 1] - ); - const exprAsString = expr.asString(); - if (typeof exprAsString === "string") { - // We can merge quasi + expr + quasi when expr - // is a const string - - prevExpr.setString(prevExpr.string + exprAsString + quasi); - prevExpr.setRange([prevExpr.range[0], quasiExpr.range[1]]); - // We unset the expression as it doesn't match to a single expression - prevExpr.setExpression(undefined); - continue; - } - parts.push(expr); - } - - const part = new BasicEvaluatedExpression() - .setString(quasi) - .setRange(quasiExpr.range) - .setExpression(quasiExpr); - quasis.push(part); - parts.push(part); - } - return { - quasis, - parts - }; - }; - - this.hooks.evaluate.for("TemplateLiteral").tap("Parser", node => { - const { quasis, parts } = getSimplifiedTemplateResult("cooked", node); - if (parts.length === 1) { - return parts[0].setRange(node.range); - } - return new BasicEvaluatedExpression() - .setTemplateString(quasis, parts, "cooked") - .setRange(node.range); - }); - this.hooks.evaluate.for("TaggedTemplateExpression").tap("Parser", node => { - if (this.evaluateExpression(node.tag).identifier !== "String.raw") return; - const { quasis, parts } = getSimplifiedTemplateResult("raw", node.quasi); - if (parts.length === 1) { - return parts[0].setRange(node.range); - } - return new BasicEvaluatedExpression() - .setTemplateString(quasis, parts, "raw") - .setRange(node.range); - }); - - this.hooks.evaluateCallExpressionMember - .for("concat") - .tap("Parser", (expr, param) => { - if (!param.isString() && !param.isWrapped()) return; - - let stringSuffix = null; - let hasUnknownParams = false; - for (let i = expr.arguments.length - 1; i >= 0; i--) { - const argExpr = this.evaluateExpression(expr.arguments[i]); - if (!argExpr.isString() && !argExpr.isNumber()) { - hasUnknownParams = true; - break; - } - - const value = argExpr.isString() - ? argExpr.string - : "" + argExpr.number; - - const newString = value + (stringSuffix ? stringSuffix.string : ""); - const newRange = [ - argExpr.range[0], - (stringSuffix || argExpr).range[1] - ]; - stringSuffix = new BasicEvaluatedExpression() - .setString(newString) - .setRange(newRange); - } - - if (hasUnknownParams) { - const prefix = param.isString() ? param : param.prefix; - return new BasicEvaluatedExpression() - .setWrapped(prefix, stringSuffix) - .setRange(expr.range); - } else if (param.isWrapped()) { - const postfix = stringSuffix || param.postfix; - return new BasicEvaluatedExpression() - .setWrapped(param.prefix, postfix) - .setRange(expr.range); - } else { - const newString = - param.string + (stringSuffix ? stringSuffix.string : ""); - return new BasicEvaluatedExpression() - .setString(newString) - .setRange(expr.range); - } - }); - this.hooks.evaluateCallExpressionMember - .for("split") - .tap("Parser", (expr, param) => { - if (!param.isString()) return; - if (expr.arguments.length !== 1) return; - let result; - const arg = this.evaluateExpression(expr.arguments[0]); - if (arg.isString()) { - result = param.string.split(arg.string); - } else if (arg.isRegExp()) { - result = param.string.split(arg.regExp); - } else { - return; - } - return new BasicEvaluatedExpression() - .setArray(result) - .setRange(expr.range); - }); - this.hooks.evaluate.for("ConditionalExpression").tap("Parser", expr => { - const condition = this.evaluateExpression(expr.test); - const conditionValue = condition.asBool(); - let res; - if (conditionValue === undefined) { - const consequent = this.evaluateExpression(expr.consequent); - const alternate = this.evaluateExpression(expr.alternate); - if (!consequent || !alternate) return; - res = new BasicEvaluatedExpression(); - if (consequent.isConditional()) { - res.setOptions(consequent.options); - } else { - res.setOptions([consequent]); - } - if (alternate.isConditional()) { - res.addOptions(alternate.options); - } else { - res.addOptions([alternate]); - } - } else { - res = this.evaluateExpression( - conditionValue ? expr.consequent : expr.alternate - ); - } - res.setRange(expr.range); - return res; - }); - this.hooks.evaluate.for("ArrayExpression").tap("Parser", expr => { - const items = expr.elements.map(element => { - return element !== null && this.evaluateExpression(element); - }); - if (!items.every(Boolean)) return; - return new BasicEvaluatedExpression() - .setItems(items) - .setRange(expr.range); - }); - } - - getRenameIdentifier(expr) { - const result = this.evaluateExpression(expr); - if (result && result.isIdentifier()) { - return result.identifier; - } - } - - walkClass(classy) { - if (classy.superClass) this.walkExpression(classy.superClass); - if (classy.body && classy.body.type === "ClassBody") { - const wasTopLevel = this.scope.topLevelScope; - this.scope.topLevelScope = false; - for (const methodDefinition of classy.body.body) { - if (methodDefinition.type === "MethodDefinition") { - this.walkMethodDefinition(methodDefinition); - } - } - this.scope.topLevelScope = wasTopLevel; - } - } - - walkMethodDefinition(methodDefinition) { - if (methodDefinition.computed && methodDefinition.key) { - this.walkExpression(methodDefinition.key); - } - if (methodDefinition.value) { - this.walkExpression(methodDefinition.value); - } - } - - // Prewalking iterates the scope for variable declarations - prewalkStatements(statements) { - for (let index = 0, len = statements.length; index < len; index++) { - const statement = statements[index]; - this.prewalkStatement(statement); - } - } - - // Block-Prewalking iterates the scope for block variable declarations - blockPrewalkStatements(statements) { - for (let index = 0, len = statements.length; index < len; index++) { - const statement = statements[index]; - this.blockPrewalkStatement(statement); - } - } - - // Walking iterates the statements and expressions and processes them - walkStatements(statements) { - for (let index = 0, len = statements.length; index < len; index++) { - const statement = statements[index]; - this.walkStatement(statement); - } - } - - prewalkStatement(statement) { - switch (statement.type) { - case "BlockStatement": - this.prewalkBlockStatement(statement); - break; - case "DoWhileStatement": - this.prewalkDoWhileStatement(statement); - break; - case "ExportAllDeclaration": - this.prewalkExportAllDeclaration(statement); - break; - case "ExportDefaultDeclaration": - this.prewalkExportDefaultDeclaration(statement); - break; - case "ExportNamedDeclaration": - this.prewalkExportNamedDeclaration(statement); - break; - case "ForInStatement": - this.prewalkForInStatement(statement); - break; - case "ForOfStatement": - this.prewalkForOfStatement(statement); - break; - case "ForStatement": - this.prewalkForStatement(statement); - break; - case "FunctionDeclaration": - this.prewalkFunctionDeclaration(statement); - break; - case "IfStatement": - this.prewalkIfStatement(statement); - break; - case "ImportDeclaration": - this.prewalkImportDeclaration(statement); - break; - case "LabeledStatement": - this.prewalkLabeledStatement(statement); - break; - case "SwitchStatement": - this.prewalkSwitchStatement(statement); - break; - case "TryStatement": - this.prewalkTryStatement(statement); - break; - case "VariableDeclaration": - this.prewalkVariableDeclaration(statement); - break; - case "WhileStatement": - this.prewalkWhileStatement(statement); - break; - case "WithStatement": - this.prewalkWithStatement(statement); - break; - } - } - - blockPrewalkStatement(statement) { - switch (statement.type) { - case "VariableDeclaration": - this.blockPrewalkVariableDeclaration(statement); - break; - case "ExportDefaultDeclaration": - this.blockPrewalkExportDefaultDeclaration(statement); - break; - case "ExportNamedDeclaration": - this.blockPrewalkExportNamedDeclaration(statement); - break; - case "ClassDeclaration": - this.blockPrewalkClassDeclaration(statement); - break; - } - } - - walkStatement(statement) { - if (this.hooks.statement.call(statement) !== undefined) return; - switch (statement.type) { - case "BlockStatement": - this.walkBlockStatement(statement); - break; - case "ClassDeclaration": - this.walkClassDeclaration(statement); - break; - case "DoWhileStatement": - this.walkDoWhileStatement(statement); - break; - case "ExportDefaultDeclaration": - this.walkExportDefaultDeclaration(statement); - break; - case "ExportNamedDeclaration": - this.walkExportNamedDeclaration(statement); - break; - case "ExpressionStatement": - this.walkExpressionStatement(statement); - break; - case "ForInStatement": - this.walkForInStatement(statement); - break; - case "ForOfStatement": - this.walkForOfStatement(statement); - break; - case "ForStatement": - this.walkForStatement(statement); - break; - case "FunctionDeclaration": - this.walkFunctionDeclaration(statement); - break; - case "IfStatement": - this.walkIfStatement(statement); - break; - case "LabeledStatement": - this.walkLabeledStatement(statement); - break; - case "ReturnStatement": - this.walkReturnStatement(statement); - break; - case "SwitchStatement": - this.walkSwitchStatement(statement); - break; - case "ThrowStatement": - this.walkThrowStatement(statement); - break; - case "TryStatement": - this.walkTryStatement(statement); - break; - case "VariableDeclaration": - this.walkVariableDeclaration(statement); - break; - case "WhileStatement": - this.walkWhileStatement(statement); - break; - case "WithStatement": - this.walkWithStatement(statement); - break; - } - } - - // Real Statements - prewalkBlockStatement(statement) { - this.prewalkStatements(statement.body); - } - - walkBlockStatement(statement) { - this.inBlockScope(() => { - const body = statement.body; - this.blockPrewalkStatements(body); - this.walkStatements(body); - }); - } - - walkExpressionStatement(statement) { - this.walkExpression(statement.expression); - } - - prewalkIfStatement(statement) { - this.prewalkStatement(statement.consequent); - if (statement.alternate) { - this.prewalkStatement(statement.alternate); - } - } - - walkIfStatement(statement) { - const result = this.hooks.statementIf.call(statement); - if (result === undefined) { - this.walkExpression(statement.test); - this.walkStatement(statement.consequent); - if (statement.alternate) { - this.walkStatement(statement.alternate); - } - } else { - if (result) { - this.walkStatement(statement.consequent); - } else if (statement.alternate) { - this.walkStatement(statement.alternate); - } - } - } - - prewalkLabeledStatement(statement) { - this.prewalkStatement(statement.body); - } - - walkLabeledStatement(statement) { - const hook = this.hooks.label.get(statement.label.name); - if (hook !== undefined) { - const result = hook.call(statement); - if (result === true) return; - } - this.walkStatement(statement.body); - } - - prewalkWithStatement(statement) { - this.prewalkStatement(statement.body); - } - - walkWithStatement(statement) { - this.walkExpression(statement.object); - this.walkStatement(statement.body); - } - - prewalkSwitchStatement(statement) { - this.prewalkSwitchCases(statement.cases); - } - - walkSwitchStatement(statement) { - this.walkExpression(statement.discriminant); - this.walkSwitchCases(statement.cases); - } - - walkTerminatingStatement(statement) { - if (statement.argument) this.walkExpression(statement.argument); - } - - walkReturnStatement(statement) { - this.walkTerminatingStatement(statement); - } - - walkThrowStatement(statement) { - this.walkTerminatingStatement(statement); - } - - prewalkTryStatement(statement) { - this.prewalkStatement(statement.block); - } - - walkTryStatement(statement) { - if (this.scope.inTry) { - this.walkStatement(statement.block); - } else { - this.scope.inTry = true; - this.walkStatement(statement.block); - this.scope.inTry = false; - } - if (statement.handler) this.walkCatchClause(statement.handler); - if (statement.finalizer) this.walkStatement(statement.finalizer); - } - - prewalkWhileStatement(statement) { - this.prewalkStatement(statement.body); - } - - walkWhileStatement(statement) { - this.walkExpression(statement.test); - this.walkStatement(statement.body); - } - - prewalkDoWhileStatement(statement) { - this.prewalkStatement(statement.body); - } - - walkDoWhileStatement(statement) { - this.walkStatement(statement.body); - this.walkExpression(statement.test); - } - - prewalkForStatement(statement) { - if (statement.init) { - if (statement.init.type === "VariableDeclaration") { - this.prewalkStatement(statement.init); - } - } - this.prewalkStatement(statement.body); - } - - walkForStatement(statement) { - this.inBlockScope(() => { - if (statement.init) { - if (statement.init.type === "VariableDeclaration") { - this.blockPrewalkVariableDeclaration(statement.init); - this.walkStatement(statement.init); - } else { - this.walkExpression(statement.init); - } - } - if (statement.test) { - this.walkExpression(statement.test); - } - if (statement.update) { - this.walkExpression(statement.update); - } - const body = statement.body; - if (body.type === "BlockStatement") { - // no need to add additional scope - this.blockPrewalkStatements(body.body); - this.walkStatements(body.body); - } else { - this.walkStatement(body); - } - }); - } - - prewalkForInStatement(statement) { - if (statement.left.type === "VariableDeclaration") { - this.prewalkVariableDeclaration(statement.left); - } - this.prewalkStatement(statement.body); - } - - walkForInStatement(statement) { - this.inBlockScope(() => { - if (statement.left.type === "VariableDeclaration") { - this.blockPrewalkVariableDeclaration(statement.left); - this.walkVariableDeclaration(statement.left); - } else { - this.walkPattern(statement.left); - } - this.walkExpression(statement.right); - const body = statement.body; - if (body.type === "BlockStatement") { - // no need to add additional scope - this.blockPrewalkStatements(body.body); - this.walkStatements(body.body); - } else { - this.walkStatement(body); - } - }); - } - - prewalkForOfStatement(statement) { - if (statement.left.type === "VariableDeclaration") { - this.prewalkVariableDeclaration(statement.left); - } - this.prewalkStatement(statement.body); - } - - walkForOfStatement(statement) { - this.inBlockScope(() => { - if (statement.left.type === "VariableDeclaration") { - this.blockPrewalkVariableDeclaration(statement.left); - this.walkVariableDeclaration(statement.left); - } else { - this.walkPattern(statement.left); - } - this.walkExpression(statement.right); - const body = statement.body; - if (body.type === "BlockStatement") { - // no need to add additional scope - this.blockPrewalkStatements(body.body); - this.walkStatements(body.body); - } else { - this.walkStatement(body); - } - }); - } - - // Declarations - prewalkFunctionDeclaration(statement) { - if (statement.id) { - this.scope.renames.set(statement.id.name, null); - this.scope.definitions.add(statement.id.name); - } - } - - walkFunctionDeclaration(statement) { - const wasTopLevel = this.scope.topLevelScope; - this.scope.topLevelScope = false; - this.inFunctionScope(true, statement.params, () => { - for (const param of statement.params) { - this.walkPattern(param); - } - if (statement.body.type === "BlockStatement") { - this.detectMode(statement.body.body); - this.prewalkStatement(statement.body); - this.walkStatement(statement.body); - } else { - this.walkExpression(statement.body); - } - }); - this.scope.topLevelScope = wasTopLevel; - } - - prewalkImportDeclaration(statement) { - const source = statement.source.value; - this.hooks.import.call(statement, source); - for (const specifier of statement.specifiers) { - const name = specifier.local.name; - this.scope.renames.set(name, null); - this.scope.definitions.add(name); - switch (specifier.type) { - case "ImportDefaultSpecifier": - this.hooks.importSpecifier.call(statement, source, "default", name); - break; - case "ImportSpecifier": - this.hooks.importSpecifier.call( - statement, - source, - specifier.imported.name, - name - ); - break; - case "ImportNamespaceSpecifier": - this.hooks.importSpecifier.call(statement, source, null, name); - break; - } - } - } - - enterDeclaration(declaration, onIdent) { - switch (declaration.type) { - case "VariableDeclaration": - for (const declarator of declaration.declarations) { - switch (declarator.type) { - case "VariableDeclarator": { - this.enterPattern(declarator.id, onIdent); - break; - } - } - } - break; - case "FunctionDeclaration": - this.enterPattern(declaration.id, onIdent); - break; - case "ClassDeclaration": - this.enterPattern(declaration.id, onIdent); - break; - } - } - - blockPrewalkExportNamedDeclaration(statement) { - if (statement.declaration) { - this.blockPrewalkStatement(statement.declaration); - } - } - - prewalkExportNamedDeclaration(statement) { - let source; - if (statement.source) { - source = statement.source.value; - this.hooks.exportImport.call(statement, source); - } else { - this.hooks.export.call(statement); - } - if (statement.declaration) { - if ( - !this.hooks.exportDeclaration.call(statement, statement.declaration) - ) { - this.prewalkStatement(statement.declaration); - let index = 0; - this.enterDeclaration(statement.declaration, def => { - this.hooks.exportSpecifier.call(statement, def, def, index++); - }); - } - } - if (statement.specifiers) { - for ( - let specifierIndex = 0; - specifierIndex < statement.specifiers.length; - specifierIndex++ - ) { - const specifier = statement.specifiers[specifierIndex]; - switch (specifier.type) { - case "ExportSpecifier": { - const name = specifier.exported.name; - if (source) { - this.hooks.exportImportSpecifier.call( - statement, - source, - specifier.local.name, - name, - specifierIndex - ); - } else { - this.hooks.exportSpecifier.call( - statement, - specifier.local.name, - name, - specifierIndex - ); - } - break; - } - } - } - } - } - - walkExportNamedDeclaration(statement) { - if (statement.declaration) { - this.walkStatement(statement.declaration); - } - } - - blockPrewalkExportDefaultDeclaration(statement) { - if (statement.declaration.type === "ClassDeclaration") { - this.blockPrewalkClassDeclaration(statement.declaration); - } - } - - prewalkExportDefaultDeclaration(statement) { - this.prewalkStatement(statement.declaration); - if ( - statement.declaration.id && - statement.declaration.type !== "FunctionExpression" && - statement.declaration.type !== "ClassExpression" - ) { - this.hooks.exportSpecifier.call( - statement, - statement.declaration.id.name, - "default" - ); - } - } - - walkExportDefaultDeclaration(statement) { - this.hooks.export.call(statement); - if ( - statement.declaration.id && - statement.declaration.type !== "FunctionExpression" && - statement.declaration.type !== "ClassExpression" - ) { - if ( - !this.hooks.exportDeclaration.call(statement, statement.declaration) - ) { - this.walkStatement(statement.declaration); - } - } else { - // Acorn parses `export default function() {}` as `FunctionDeclaration` and - // `export default class {}` as `ClassDeclaration`, both with `id = null`. - // These nodes must be treated as expressions. - if (statement.declaration.type === "FunctionDeclaration") { - this.walkFunctionDeclaration(statement.declaration); - } else if (statement.declaration.type === "ClassDeclaration") { - this.walkClassDeclaration(statement.declaration); - } else { - this.walkExpression(statement.declaration); - } - if (!this.hooks.exportExpression.call(statement, statement.declaration)) { - this.hooks.exportSpecifier.call( - statement, - statement.declaration, - "default" - ); - } - } - } - - prewalkExportAllDeclaration(statement) { - const source = statement.source.value; - this.hooks.exportImport.call(statement, source); - this.hooks.exportImportSpecifier.call(statement, source, null, null, 0); - } - - prewalkVariableDeclaration(statement) { - if (statement.kind !== "var") return; - this._prewalkVariableDeclaration(statement, this.hooks.varDeclarationVar); - } - - blockPrewalkVariableDeclaration(statement) { - if (statement.kind === "var") return; - const hookMap = - statement.kind === "const" - ? this.hooks.varDeclarationConst - : this.hooks.varDeclarationLet; - this._prewalkVariableDeclaration(statement, hookMap); - } - - _prewalkVariableDeclaration(statement, hookMap) { - for (const declarator of statement.declarations) { - switch (declarator.type) { - case "VariableDeclarator": { - this.enterPattern(declarator.id, (name, decl) => { - let hook = hookMap.get(name); - if (hook === undefined || !hook.call(decl)) { - hook = this.hooks.varDeclaration.get(name); - if (hook === undefined || !hook.call(decl)) { - this.scope.renames.set(name, null); - this.scope.definitions.add(name); - } - } - }); - break; - } - } - } - } - - walkVariableDeclaration(statement) { - for (const declarator of statement.declarations) { - switch (declarator.type) { - case "VariableDeclarator": { - const renameIdentifier = - declarator.init && this.getRenameIdentifier(declarator.init); - if (renameIdentifier && declarator.id.type === "Identifier") { - const hook = this.hooks.canRename.get(renameIdentifier); - if (hook !== undefined && hook.call(declarator.init)) { - // renaming with "var a = b;" - const hook = this.hooks.rename.get(renameIdentifier); - if (hook === undefined || !hook.call(declarator.init)) { - this.scope.renames.set( - declarator.id.name, - this.scope.renames.get(renameIdentifier) || renameIdentifier - ); - this.scope.definitions.delete(declarator.id.name); - } - break; - } - } - this.walkPattern(declarator.id); - if (declarator.init) this.walkExpression(declarator.init); - break; - } - } - } - } - - blockPrewalkClassDeclaration(statement) { - if (statement.id) { - this.scope.renames.set(statement.id.name, null); - this.scope.definitions.add(statement.id.name); - } - } - - walkClassDeclaration(statement) { - this.walkClass(statement); - } - - prewalkSwitchCases(switchCases) { - for (let index = 0, len = switchCases.length; index < len; index++) { - const switchCase = switchCases[index]; - this.prewalkStatements(switchCase.consequent); - } - } - - walkSwitchCases(switchCases) { - for (let index = 0, len = switchCases.length; index < len; index++) { - const switchCase = switchCases[index]; - - if (switchCase.test) { - this.walkExpression(switchCase.test); - } - this.walkStatements(switchCase.consequent); - } - } - - walkCatchClause(catchClause) { - this.inBlockScope(() => { - // Error binding is optional in catch clause since ECMAScript 2019 - if (catchClause.param !== null) { - this.enterPattern(catchClause.param, ident => { - this.scope.renames.set(ident, null); - this.scope.definitions.add(ident); - }); - this.walkPattern(catchClause.param); - } - this.prewalkStatement(catchClause.body); - this.walkStatement(catchClause.body); - }); - } - - walkPattern(pattern) { - switch (pattern.type) { - case "ArrayPattern": - this.walkArrayPattern(pattern); - break; - case "AssignmentPattern": - this.walkAssignmentPattern(pattern); - break; - case "MemberExpression": - this.walkMemberExpression(pattern); - break; - case "ObjectPattern": - this.walkObjectPattern(pattern); - break; - case "RestElement": - this.walkRestElement(pattern); - break; - } - } - - walkAssignmentPattern(pattern) { - this.walkExpression(pattern.right); - this.walkPattern(pattern.left); - } - - walkObjectPattern(pattern) { - for (let i = 0, len = pattern.properties.length; i < len; i++) { - const prop = pattern.properties[i]; - if (prop) { - if (prop.computed) this.walkExpression(prop.key); - if (prop.value) this.walkPattern(prop.value); - } - } - } - - walkArrayPattern(pattern) { - for (let i = 0, len = pattern.elements.length; i < len; i++) { - const element = pattern.elements[i]; - if (element) this.walkPattern(element); - } - } - - walkRestElement(pattern) { - this.walkPattern(pattern.argument); - } - - walkExpressions(expressions) { - for (const expression of expressions) { - if (expression) { - this.walkExpression(expression); - } - } - } - - walkExpression(expression) { - switch (expression.type) { - case "ArrayExpression": - this.walkArrayExpression(expression); - break; - case "ArrowFunctionExpression": - this.walkArrowFunctionExpression(expression); - break; - case "AssignmentExpression": - this.walkAssignmentExpression(expression); - break; - case "AwaitExpression": - this.walkAwaitExpression(expression); - break; - case "BinaryExpression": - this.walkBinaryExpression(expression); - break; - case "CallExpression": - this.walkCallExpression(expression); - break; - case "ClassExpression": - this.walkClassExpression(expression); - break; - case "ConditionalExpression": - this.walkConditionalExpression(expression); - break; - case "FunctionExpression": - this.walkFunctionExpression(expression); - break; - case "Identifier": - this.walkIdentifier(expression); - break; - case "LogicalExpression": - this.walkLogicalExpression(expression); - break; - case "MemberExpression": - this.walkMemberExpression(expression); - break; - case "NewExpression": - this.walkNewExpression(expression); - break; - case "ObjectExpression": - this.walkObjectExpression(expression); - break; - case "SequenceExpression": - this.walkSequenceExpression(expression); - break; - case "SpreadElement": - this.walkSpreadElement(expression); - break; - case "TaggedTemplateExpression": - this.walkTaggedTemplateExpression(expression); - break; - case "TemplateLiteral": - this.walkTemplateLiteral(expression); - break; - case "ThisExpression": - this.walkThisExpression(expression); - break; - case "UnaryExpression": - this.walkUnaryExpression(expression); - break; - case "UpdateExpression": - this.walkUpdateExpression(expression); - break; - case "YieldExpression": - this.walkYieldExpression(expression); - break; - } - } - - walkAwaitExpression(expression) { - this.walkExpression(expression.argument); - } - - walkArrayExpression(expression) { - if (expression.elements) { - this.walkExpressions(expression.elements); - } - } - - walkSpreadElement(expression) { - if (expression.argument) { - this.walkExpression(expression.argument); - } - } - - walkObjectExpression(expression) { - for ( - let propIndex = 0, len = expression.properties.length; - propIndex < len; - propIndex++ - ) { - const prop = expression.properties[propIndex]; - if (prop.type === "SpreadElement") { - this.walkExpression(prop.argument); - continue; - } - if (prop.computed) { - this.walkExpression(prop.key); - } - if (prop.shorthand) { - this.scope.inShorthand = true; - } - this.walkExpression(prop.value); - if (prop.shorthand) { - this.scope.inShorthand = false; - } - } - } - - walkFunctionExpression(expression) { - const wasTopLevel = this.scope.topLevelScope; - this.scope.topLevelScope = false; - const scopeParams = expression.params; - - // Add function name in scope for recursive calls - if (expression.id) { - scopeParams.push(expression.id.name); - } - - this.inFunctionScope(true, scopeParams, () => { - for (const param of expression.params) { - this.walkPattern(param); - } - if (expression.body.type === "BlockStatement") { - this.detectMode(expression.body.body); - this.prewalkStatement(expression.body); - this.walkStatement(expression.body); - } else { - this.walkExpression(expression.body); - } - }); - this.scope.topLevelScope = wasTopLevel; - } - - walkArrowFunctionExpression(expression) { - this.inFunctionScope(false, expression.params, () => { - for (const param of expression.params) { - this.walkPattern(param); - } - if (expression.body.type === "BlockStatement") { - this.detectMode(expression.body.body); - this.prewalkStatement(expression.body); - this.walkStatement(expression.body); - } else { - this.walkExpression(expression.body); - } - }); - } - - walkSequenceExpression(expression) { - if (expression.expressions) this.walkExpressions(expression.expressions); - } - - walkUpdateExpression(expression) { - this.walkExpression(expression.argument); - } - - walkUnaryExpression(expression) { - if (expression.operator === "typeof") { - const exprName = this.getNameForExpression(expression.argument); - if (exprName && exprName.free) { - const hook = this.hooks.typeof.get(exprName.name); - if (hook !== undefined) { - const result = hook.call(expression); - if (result === true) return; - } - } - } - this.walkExpression(expression.argument); - } - - walkLeftRightExpression(expression) { - this.walkExpression(expression.left); - this.walkExpression(expression.right); - } - - walkBinaryExpression(expression) { - this.walkLeftRightExpression(expression); - } - - walkLogicalExpression(expression) { - const result = this.hooks.expressionLogicalOperator.call(expression); - if (result === undefined) { - this.walkLeftRightExpression(expression); - } else { - if (result) { - this.walkExpression(expression.right); - } - } - } - - walkAssignmentExpression(expression) { - const renameIdentifier = this.getRenameIdentifier(expression.right); - if (expression.left.type === "Identifier" && renameIdentifier) { - const hook = this.hooks.canRename.get(renameIdentifier); - if (hook !== undefined && hook.call(expression.right)) { - // renaming "a = b;" - const hook = this.hooks.rename.get(renameIdentifier); - if (hook === undefined || !hook.call(expression.right)) { - this.scope.renames.set(expression.left.name, renameIdentifier); - this.scope.definitions.delete(expression.left.name); - } - return; - } - } - if (expression.left.type === "Identifier") { - const assignedHook = this.hooks.assigned.get(expression.left.name); - if (assignedHook === undefined || !assignedHook.call(expression)) { - this.walkExpression(expression.right); - } - this.scope.renames.set(expression.left.name, null); - const assignHook = this.hooks.assign.get(expression.left.name); - if (assignHook === undefined || !assignHook.call(expression)) { - this.walkExpression(expression.left); - } - return; - } - this.walkExpression(expression.right); - this.walkPattern(expression.left); - this.enterPattern(expression.left, (name, decl) => { - this.scope.renames.set(name, null); - }); - } - - walkConditionalExpression(expression) { - const result = this.hooks.expressionConditionalOperator.call(expression); - if (result === undefined) { - this.walkExpression(expression.test); - this.walkExpression(expression.consequent); - if (expression.alternate) { - this.walkExpression(expression.alternate); - } - } else { - if (result) { - this.walkExpression(expression.consequent); - } else if (expression.alternate) { - this.walkExpression(expression.alternate); - } - } - } - - walkNewExpression(expression) { - const callee = this.evaluateExpression(expression.callee); - if (callee.isIdentifier()) { - const hook = this.hooks.new.get(callee.identifier); - if (hook !== undefined) { - const result = hook.call(expression); - if (result === true) { - return; - } - } - } - - this.walkExpression(expression.callee); - if (expression.arguments) { - this.walkExpressions(expression.arguments); - } - } - - walkYieldExpression(expression) { - if (expression.argument) { - this.walkExpression(expression.argument); - } - } - - walkTemplateLiteral(expression) { - if (expression.expressions) { - this.walkExpressions(expression.expressions); - } - } - - walkTaggedTemplateExpression(expression) { - if (expression.tag) { - this.walkExpression(expression.tag); - } - if (expression.quasi && expression.quasi.expressions) { - this.walkExpressions(expression.quasi.expressions); - } - } - - walkClassExpression(expression) { - this.walkClass(expression); - } - - _walkIIFE(functionExpression, options, currentThis) { - const renameArgOrThis = argOrThis => { - const renameIdentifier = this.getRenameIdentifier(argOrThis); - if (renameIdentifier) { - const hook = this.hooks.canRename.get(renameIdentifier); - if (hook !== undefined && hook.call(argOrThis)) { - const hook = this.hooks.rename.get(renameIdentifier); - if (hook === undefined || !hook.call(argOrThis)) { - return renameIdentifier; - } - } - } - this.walkExpression(argOrThis); - }; - const params = functionExpression.params; - const renameThis = currentThis ? renameArgOrThis(currentThis) : null; - const args = options.map(renameArgOrThis); - const wasTopLevel = this.scope.topLevelScope; - this.scope.topLevelScope = false; - const scopeParams = params.filter((identifier, idx) => !args[idx]); - - // Add function name in scope for recursive calls - if (functionExpression.id) { - scopeParams.push(functionExpression.id.name); - } - - this.inFunctionScope(true, scopeParams, () => { - if (renameThis) { - this.scope.renames.set("this", renameThis); - } - for (let i = 0; i < args.length; i++) { - const param = args[i]; - if (!param) continue; - if (!params[i] || params[i].type !== "Identifier") continue; - this.scope.renames.set(params[i].name, param); - } - if (functionExpression.body.type === "BlockStatement") { - this.detectMode(functionExpression.body.body); - this.prewalkStatement(functionExpression.body); - this.walkStatement(functionExpression.body); - } else { - this.walkExpression(functionExpression.body); - } - }); - this.scope.topLevelScope = wasTopLevel; - } - - walkCallExpression(expression) { - if ( - expression.callee.type === "MemberExpression" && - expression.callee.object.type === "FunctionExpression" && - !expression.callee.computed && - (expression.callee.property.name === "call" || - expression.callee.property.name === "bind") && - expression.arguments.length > 0 - ) { - // (function(…) { }.call/bind(?, …)) - this._walkIIFE( - expression.callee.object, - expression.arguments.slice(1), - expression.arguments[0] - ); - } else if (expression.callee.type === "FunctionExpression") { - // (function(…) { }(…)) - this._walkIIFE(expression.callee, expression.arguments, null); - } else if (expression.callee.type === "Import") { - let result = this.hooks.importCall.call(expression); - if (result === true) return; - - if (expression.arguments) this.walkExpressions(expression.arguments); - } else { - const callee = this.evaluateExpression(expression.callee); - if (callee.isIdentifier()) { - const callHook = this.hooks.call.get(callee.identifier); - if (callHook !== undefined) { - let result = callHook.call(expression); - if (result === true) return; - } - let identifier = callee.identifier.replace(/\.[^.]+$/, ""); - if (identifier !== callee.identifier) { - const callAnyHook = this.hooks.callAnyMember.get(identifier); - if (callAnyHook !== undefined) { - let result = callAnyHook.call(expression); - if (result === true) return; - } - } - } - - if (expression.callee) this.walkExpression(expression.callee); - if (expression.arguments) this.walkExpressions(expression.arguments); - } - } - - walkMemberExpression(expression) { - const exprName = this.getNameForExpression(expression); - if (exprName && exprName.free) { - const expressionHook = this.hooks.expression.get(exprName.name); - if (expressionHook !== undefined) { - const result = expressionHook.call(expression); - if (result === true) return; - } - const expressionAnyMemberHook = this.hooks.expressionAnyMember.get( - exprName.nameGeneral - ); - if (expressionAnyMemberHook !== undefined) { - const result = expressionAnyMemberHook.call(expression); - if (result === true) return; - } - } - this.walkExpression(expression.object); - if (expression.computed === true) this.walkExpression(expression.property); - } - - walkThisExpression(expression) { - const expressionHook = this.hooks.expression.get("this"); - if (expressionHook !== undefined) { - expressionHook.call(expression); - } - } - - walkIdentifier(expression) { - if (!this.scope.definitions.has(expression.name)) { - const hook = this.hooks.expression.get( - this.scope.renames.get(expression.name) || expression.name - ); - if (hook !== undefined) { - const result = hook.call(expression); - if (result === true) return; - } - } - } - - /** - * @deprecated - * @param {any} params scope params - * @param {function(): void} fn inner function - * @returns {void} - */ - inScope(params, fn) { - const oldScope = this.scope; - this.scope = { - topLevelScope: oldScope.topLevelScope, - inTry: false, - inShorthand: false, - isStrict: oldScope.isStrict, - isAsmJs: oldScope.isAsmJs, - definitions: oldScope.definitions.createChild(), - renames: oldScope.renames.createChild() - }; - - this.scope.renames.set("this", null); - - this.enterPatterns(params, ident => { - this.scope.renames.set(ident, null); - this.scope.definitions.add(ident); - }); - - fn(); - - this.scope = oldScope; - } - - inFunctionScope(hasThis, params, fn) { - const oldScope = this.scope; - this.scope = { - topLevelScope: oldScope.topLevelScope, - inTry: false, - inShorthand: false, - isStrict: oldScope.isStrict, - isAsmJs: oldScope.isAsmJs, - definitions: oldScope.definitions.createChild(), - renames: oldScope.renames.createChild() - }; - - if (hasThis) { - this.scope.renames.set("this", null); - } - - this.enterPatterns(params, ident => { - this.scope.renames.set(ident, null); - this.scope.definitions.add(ident); - }); - - fn(); - - this.scope = oldScope; - } - - inBlockScope(fn) { - const oldScope = this.scope; - this.scope = { - topLevelScope: oldScope.topLevelScope, - inTry: oldScope.inTry, - inShorthand: false, - isStrict: oldScope.isStrict, - isAsmJs: oldScope.isAsmJs, - definitions: oldScope.definitions.createChild(), - renames: oldScope.renames.createChild() - }; - - fn(); - - this.scope = oldScope; - } - - // TODO webpack 5: remove this methods - // only for backward-compat - detectStrictMode(statements) { - this.detectMode(statements); - } - - detectMode(statements) { - const isLiteral = - statements.length >= 1 && - statements[0].type === "ExpressionStatement" && - statements[0].expression.type === "Literal"; - if (isLiteral && statements[0].expression.value === "use strict") { - this.scope.isStrict = true; - } - if (isLiteral && statements[0].expression.value === "use asm") { - this.scope.isAsmJs = true; - } - } - - enterPatterns(patterns, onIdent) { - for (const pattern of patterns) { - if (typeof pattern !== "string") { - this.enterPattern(pattern, onIdent); - } else if (pattern) { - onIdent(pattern); - } - } - } - - enterPattern(pattern, onIdent) { - if (!pattern) return; - switch (pattern.type) { - case "ArrayPattern": - this.enterArrayPattern(pattern, onIdent); - break; - case "AssignmentPattern": - this.enterAssignmentPattern(pattern, onIdent); - break; - case "Identifier": - this.enterIdentifier(pattern, onIdent); - break; - case "ObjectPattern": - this.enterObjectPattern(pattern, onIdent); - break; - case "RestElement": - this.enterRestElement(pattern, onIdent); - break; - case "Property": - this.enterPattern(pattern.value, onIdent); - break; - } - } - - enterIdentifier(pattern, onIdent) { - onIdent(pattern.name, pattern); - } - - enterObjectPattern(pattern, onIdent) { - for ( - let propIndex = 0, len = pattern.properties.length; - propIndex < len; - propIndex++ - ) { - const prop = pattern.properties[propIndex]; - this.enterPattern(prop, onIdent); - } - } - - enterArrayPattern(pattern, onIdent) { - for ( - let elementIndex = 0, len = pattern.elements.length; - elementIndex < len; - elementIndex++ - ) { - const element = pattern.elements[elementIndex]; - this.enterPattern(element, onIdent); - } - } - - enterRestElement(pattern, onIdent) { - this.enterPattern(pattern.argument, onIdent); - } - - enterAssignmentPattern(pattern, onIdent) { - this.enterPattern(pattern.left, onIdent); - } - - evaluateExpression(expression) { - try { - const hook = this.hooks.evaluate.get(expression.type); - if (hook !== undefined) { - const result = hook.call(expression); - if (result !== undefined) { - if (result) { - result.setExpression(expression); - } - return result; - } - } - } catch (e) { - console.warn(e); - // ignore error - } - return new BasicEvaluatedExpression() - .setRange(expression.range) - .setExpression(expression); - } - - parseString(expression) { - switch (expression.type) { - case "BinaryExpression": - if (expression.operator === "+") { - return ( - this.parseString(expression.left) + - this.parseString(expression.right) - ); - } - break; - case "Literal": - return expression.value + ""; - } - throw new Error( - expression.type + " is not supported as parameter for require" - ); - } - - parseCalculatedString(expression) { - switch (expression.type) { - case "BinaryExpression": - if (expression.operator === "+") { - const left = this.parseCalculatedString(expression.left); - const right = this.parseCalculatedString(expression.right); - if (left.code) { - return { - range: left.range, - value: left.value, - code: true, - conditional: false - }; - } else if (right.code) { - return { - range: [ - left.range[0], - right.range ? right.range[1] : left.range[1] - ], - value: left.value + right.value, - code: true, - conditional: false - }; - } else { - return { - range: [left.range[0], right.range[1]], - value: left.value + right.value, - code: false, - conditional: false - }; - } - } - break; - case "ConditionalExpression": { - const consequent = this.parseCalculatedString(expression.consequent); - const alternate = this.parseCalculatedString(expression.alternate); - const items = []; - if (consequent.conditional) { - items.push(...consequent.conditional); - } else if (!consequent.code) { - items.push(consequent); - } else { - break; - } - if (alternate.conditional) { - items.push(...alternate.conditional); - } else if (!alternate.code) { - items.push(alternate); - } else { - break; - } - return { - range: undefined, - value: "", - code: true, - conditional: items - }; - } - case "Literal": - return { - range: expression.range, - value: expression.value + "", - code: false, - conditional: false - }; - } - return { - range: undefined, - value: "", - code: true, - conditional: false - }; - } - - parse(source, initialState) { - let ast; - let comments; - if (typeof source === "object" && source !== null) { - ast = source; - comments = source.comments; - } else { - comments = []; - ast = Parser.parse(source, { - sourceType: this.sourceType, - onComment: comments - }); - } - - const oldScope = this.scope; - const oldState = this.state; - const oldComments = this.comments; - this.scope = { - topLevelScope: true, - inTry: false, - inShorthand: false, - isStrict: false, - isAsmJs: false, - definitions: new StackedSetMap(), - renames: new StackedSetMap() - }; - const state = (this.state = initialState || {}); - this.comments = comments; - if (this.hooks.program.call(ast, comments) === undefined) { - this.detectMode(ast.body); - this.prewalkStatements(ast.body); - this.blockPrewalkStatements(ast.body); - this.walkStatements(ast.body); - } - this.scope = oldScope; - this.state = oldState; - this.comments = oldComments; - return state; - } - - evaluate(source) { - const ast = Parser.parse("(" + source + ")", { - sourceType: this.sourceType, - locations: false - }); - // TODO(https://github.com/acornjs/acorn/issues/741) - // @ts-ignore - if (ast.body.length !== 1 || ast.body[0].type !== "ExpressionStatement") { - throw new Error("evaluate: Source is not a expression"); - } - // TODO(https://github.com/acornjs/acorn/issues/741) - // @ts-ignore - return this.evaluateExpression(ast.body[0].expression); - } - - getComments(range) { - return this.comments.filter( - comment => comment.range[0] >= range[0] && comment.range[1] <= range[1] - ); - } - - parseCommentOptions(range) { - const comments = this.getComments(range); - if (comments.length === 0) { - return EMPTY_COMMENT_OPTIONS; - } - let options = {}; - let errors = []; - for (const comment of comments) { - const { value } = comment; - if (value && webpackCommentRegExp.test(value)) { - // try compile only if webpack options comment is present - try { - const val = vm.runInNewContext(`(function(){return {${value}};})()`); - Object.assign(options, val); - } catch (e) { - e.comment = comment; - errors.push(e); - } - } - } - return { options, errors }; - } - - getNameForExpression(expression) { - let expr = expression; - const exprName = []; - while ( - expr.type === "MemberExpression" && - expr.property.type === (expr.computed ? "Literal" : "Identifier") - ) { - exprName.push(expr.computed ? expr.property.value : expr.property.name); - expr = expr.object; - } - let free; - if (expr.type === "Identifier") { - free = !this.scope.definitions.has(expr.name); - exprName.push(this.scope.renames.get(expr.name) || expr.name); - } else if ( - expr.type === "ThisExpression" && - this.scope.renames.get("this") - ) { - free = true; - exprName.push(this.scope.renames.get("this")); - } else if (expr.type === "ThisExpression") { - free = this.scope.topLevelScope; - exprName.push("this"); - } else { - return null; - } - let prefix = ""; - for (let i = exprName.length - 1; i >= 2; i--) { - prefix += exprName[i] + "."; - } - if (exprName.length > 1) { - prefix += exprName[1]; - } - const name = prefix ? prefix + "." + exprName[0] : exprName[0]; - const nameGeneral = prefix; - return { - name, - nameGeneral, - free - }; - } - - static parse(code, options) { - const type = options ? options.sourceType : "module"; - const parserOptions = Object.assign( - Object.create(null), - defaultParserOptions, - options - ); - - if (type === "auto") { - parserOptions.sourceType = "module"; - } else if (parserOptions.sourceType === "script") { - parserOptions.allowReturnOutsideFunction = true; - } - - let ast; - let error; - let threw = false; - try { - ast = acornParser.parse(code, parserOptions); - } catch (e) { - error = e; - threw = true; - } - - if (threw && type === "auto") { - parserOptions.sourceType = "script"; - parserOptions.allowReturnOutsideFunction = true; - if (Array.isArray(parserOptions.onComment)) { - parserOptions.onComment.length = 0; - } - try { - ast = acornParser.parse(code, parserOptions); - threw = false; - } catch (e) { - threw = true; - } - } - - if (threw) { - throw error; - } - - return ast; - } -} - -// TODO remove in webpack 5 -Object.defineProperty(Parser.prototype, "getCommentOptions", { - configurable: false, - value: util.deprecate( - /** - * @deprecated - * @param {TODO} range Range - * @returns {void} - * @this {Parser} - */ - function(range) { - return this.parseCommentOptions(range).options; - }, - "Parser.getCommentOptions: Use Parser.parseCommentOptions(range) instead" - ) -}); - -module.exports = Parser; |