feat: `bigint` for the `DefinePlugin` plugin

This commit is contained in:
evilebottnawi 2020-02-28 20:09:59 +03:00 committed by Tobias Koppers
parent b9dbc095f8
commit 1308ae7e8e
8 changed files with 215 additions and 50 deletions

View File

@ -86,6 +86,9 @@ const toCode = (code, parser) => {
if (typeof code === "object") {
return stringifyObj(code, parser);
}
if (typeof code === "bigint") {
return `${code}n`;
}
return code + "";
};

View File

@ -17,6 +17,7 @@ const TypeConstArray = 8;
const TypeIdentifier = 9;
const TypeWrapped = 10;
const TypeTemplateString = 11;
const TypeBigInt = 12;
class BasicEvaluatedExpression {
constructor() {
@ -26,6 +27,7 @@ class BasicEvaluatedExpression {
this.truthy = false;
this.bool = undefined;
this.number = undefined;
this.bigint = undefined;
this.regExp = undefined;
this.string = undefined;
this.quasis = undefined;
@ -54,6 +56,10 @@ class BasicEvaluatedExpression {
return this.type === TypeNumber;
}
isBigInt() {
return this.type === TypeBigInt;
}
isBoolean() {
return this.type === TypeBoolean;
}
@ -101,6 +107,7 @@ class BasicEvaluatedExpression {
if (this.isNull()) return false;
if (this.isString()) return this.string !== "";
if (this.isNumber()) return this.number !== 0;
if (this.isBigInt()) return this.bigint !== BigInt(0);
if (this.isRegExp()) return true;
if (this.isArray()) return true;
if (this.isConstArray()) return true;
@ -122,6 +129,7 @@ class BasicEvaluatedExpression {
if (this.isNull()) return "null";
if (this.isString()) return this.string;
if (this.isNumber()) return `${this.number}`;
if (this.isBigInt()) return `${this.bigint}n`;
if (this.isRegExp()) return `${this.regExp}`;
if (this.isArray()) {
let array = [];
@ -162,6 +170,12 @@ class BasicEvaluatedExpression {
return this;
}
setBigInt(bigint) {
this.type = TypeBigInt;
this.bigint = bigint;
return this;
}
setBoolean(bool) {
this.type = TypeBoolean;
this.bool = bool;

View File

@ -289,6 +289,15 @@ class JavascriptParser extends Parser {
return new BasicEvaluatedExpression()
.setNumber(expr.value)
.setRange(expr.range);
case "bigint":
return new BasicEvaluatedExpression()
.setBigInt(
BigInt(
// @ts-ignore The `bigint` property doesn't exists
expr.bigint
)
)
.setRange(expr.range);
case "string":
return new BasicEvaluatedExpression()
.setString(expr.value)
@ -384,6 +393,10 @@ class JavascriptParser extends Parser {
} else {
return;
}
} else if (left.isBigInt()) {
if (right.isBigInt()) {
res.setBigInt(left.bigint + right.bigint);
}
} else if (left.isWrapped()) {
if (left.postfix && left.postfix.isString() && right.isString()) {
// ("prefix" + inner + "postfix") + "right"
@ -474,38 +487,63 @@ class JavascriptParser extends Parser {
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;
if (left.isNumber() && right.isNumber()) {
res = new BasicEvaluatedExpression();
res.setNumber(left.number - right.number);
res.setRange(expr.range);
return res;
} else if (left.isBigInt() && right.isBigInt()) {
res = new BasicEvaluatedExpression();
res.setBigInt(left.bigint - right.bigint);
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;
if (left.isNumber() && right.isNumber()) {
res = new BasicEvaluatedExpression();
res.setNumber(left.number * right.number);
res.setRange(expr.range);
return res;
} else if (left.isBigInt() && right.isBigInt()) {
res = new BasicEvaluatedExpression();
res.setBigInt(left.bigint * right.bigint);
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;
if (left.isNumber() && right.isNumber()) {
res = new BasicEvaluatedExpression();
res.setNumber(left.number / right.number);
res.setRange(expr.range);
return res;
} else if (left.isBigInt() && right.isBigInt()) {
res = new BasicEvaluatedExpression();
res.setBigInt(left.bigint / right.bigint);
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;
if (left.isNumber() && right.isNumber()) {
res = new BasicEvaluatedExpression();
res.setNumber(left.number ** right.number);
res.setRange(expr.range);
return res;
} else if (left.isBigInt() && right.isBigInt()) {
res = new BasicEvaluatedExpression();
res.setBigInt(left.bigint ** right.bigint);
res.setRange(expr.range);
return res;
}
} else if (expr.operator === "==" || expr.operator === "===") {
left = this.evaluateExpression(expr.left);
right = this.evaluateExpression(expr.right);
@ -516,8 +554,12 @@ class JavascriptParser extends Parser {
return res.setBoolean(left.string === right.string);
} else if (left.isNumber() && right.isNumber()) {
return res.setBoolean(left.number === right.number);
} else if (left.isBigInt() && right.isBigInt()) {
return res.setBoolean(left.bigint === right.bigint);
} else if (left.isBoolean() && right.isBoolean()) {
return res.setBoolean(left.bool === right.bool);
} else if (left.isNull() && right.isNull()) {
return res.setBoolean(true);
}
} else if (expr.operator === "!=" || expr.operator === "!==") {
left = this.evaluateExpression(expr.left);
@ -529,36 +571,58 @@ class JavascriptParser extends Parser {
return res.setBoolean(left.string !== right.string);
} else if (left.isNumber() && right.isNumber()) {
return res.setBoolean(left.number !== right.number);
} else if (left.isBigInt() && right.isBigInt()) {
return res.setBoolean(left.bigint !== right.bigint);
} else if (left.isBoolean() && right.isBoolean()) {
return res.setBoolean(left.bool !== right.bool);
} else if (left.isNull() && right.isNull()) {
return res.setBoolean(false);
}
} 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;
if (left.isNumber() && right.isNumber()) {
res = new BasicEvaluatedExpression();
res.setNumber(left.number & right.number);
res.setRange(expr.range);
return res;
} else if (left.isBigInt() && right.isBigInt()) {
res = new BasicEvaluatedExpression();
res.setBigInt(left.bigint & right.bigint);
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;
if (left.isNumber() && right.isNumber()) {
res = new BasicEvaluatedExpression();
res.setNumber(left.number | right.number);
res.setRange(expr.range);
return res;
} else if (left.isBigInt() && right.isBigInt()) {
res = new BasicEvaluatedExpression();
res.setBigInt(left.bigint | right.bigint);
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;
if (left.isNumber() && right.isNumber()) {
res = new BasicEvaluatedExpression();
res.setNumber(left.number ^ right.number);
res.setRange(expr.range);
return res;
} else if (left.isBigInt() && right.isBigInt()) {
res = new BasicEvaluatedExpression();
res.setBigInt(left.bigint ^ right.bigint);
res.setRange(expr.range);
return res;
}
} else if (expr.operator === ">>>") {
left = this.evaluateExpression(expr.left);
right = this.evaluateExpression(expr.right);
@ -572,20 +636,32 @@ class JavascriptParser extends Parser {
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;
if (left.isNumber() && right.isNumber()) {
res = new BasicEvaluatedExpression();
res.setNumber(left.number >> right.number);
res.setRange(expr.range);
return res;
} else if (left.isBigInt() && right.isBigInt()) {
res = new BasicEvaluatedExpression();
res.setBigInt(left.bigint >> right.bigint);
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;
if (left.isNumber() && right.isNumber()) {
res = new BasicEvaluatedExpression();
res.setNumber(left.number << right.number);
res.setRange(expr.range);
return res;
} else if (left.isBigInt() && right.isBigInt()) {
res = new BasicEvaluatedExpression();
res.setBigInt(left.bigint << right.bigint);
res.setRange(expr.range);
return res;
}
}
});
this.hooks.evaluate
@ -621,11 +697,21 @@ class JavascriptParser extends Parser {
.setString("string")
.setRange(expr.range);
}
if (arg.isNull()) {
return new BasicEvaluatedExpression()
.setString("object")
.setRange(expr.range);
}
if (arg.isNumber()) {
return new BasicEvaluatedExpression()
.setString("number")
.setRange(expr.range);
}
if (arg.isBigInt()) {
return new BasicEvaluatedExpression()
.setString("bigint")
.setRange(expr.range);
}
if (arg.isBoolean()) {
return new BasicEvaluatedExpression()
.setString("boolean")

View File

@ -30,7 +30,7 @@
},
"devDependencies": {
"@babel/core": "^7.7.2",
"@types/estree": "0.0.39",
"@types/estree": "0.0.42",
"@types/node": "^12.6.9",
"@yarnpkg/lockfile": "^1.1.0",
"babel-loader": "^8.0.6",

View File

@ -414,6 +414,27 @@ describe("JavascriptParser", () => {
"!0": "bool=true",
"!-0": "bool=true",
"!+0": "bool=true",
"20n": "bigint=20",
"10n + 10n": "bigint=20",
"10n - 5n": "bigint=5",
"10n * 5n": "bigint=50",
"10n / 5n": "bigint=2",
"5n ** 2n": "bigint=25",
"5n == 5n": "bool=true",
"5n === 5n": "bool=true",
"5n != 5n": "bool=false",
"5n !== 5n": "bool=false",
"5n != 1n": "bool=true",
"5n !== 1n": "bool=true",
"5n & 3n": "bigint=1",
"5n | 2n": "bigint=7",
"5n ^ 2n": "bigint=7",
"5n >> 2n": "bigint=1",
"5n << 2n": "bigint=20",
"null == null": "bool=true",
"null === null": "bool=true",
"null != null": "bool=false",
"null !== null": "bool=false",
"true === false": "bool=false",
"false !== false": "bool=false",
"true == true": "bool=true",
@ -448,6 +469,10 @@ describe("JavascriptParser", () => {
"typeof b.Number": "string=number",
"typeof b['Number']": "string=number",
"typeof b[Number]": "",
"typeof true": "string=boolean",
"typeof null": "string=object",
"typeof 1": "string=number",
"typeof 1n": "string=bigint",
"b.Number": "number=123",
"b['Number']": "number=123",
"b[Number]": "",
@ -532,6 +557,7 @@ describe("JavascriptParser", () => {
const result = [];
if (evalExpr.isString()) result.push("string=" + evalExpr.string);
if (evalExpr.isNumber()) result.push("number=" + evalExpr.number);
if (evalExpr.isBigInt()) result.push("bigint=" + evalExpr.bigint);
if (evalExpr.isBoolean()) result.push("bool=" + evalExpr.bool);
if (evalExpr.isRegExp()) result.push("regExp=" + evalExpr.regExp);
if (evalExpr.isConditional())

View File

@ -17,10 +17,41 @@ it("should define FUNCTION", function() {
expect((typeof FUNCTION)).toBe("function");
if(typeof FUNCTION !== "function") require("fail");
});
it("should define NULL", function() {
expect(NULL).toBeNull();
if(NULL) require("fail");
if(NULL !== null) require("fail");
if(typeof NULL !== "object") require("fail");
});
it("should define UNDEFINED", function() {
expect((typeof UNDEFINED)).toBe("undefined");
if(typeof UNDEFINED !== "undefined") require("fail");
});
it("should define NUMBER", function() {
expect(NUMBER).toBe(100.05);
expect((typeof NUMBER)).toBe("number");
if(NUMBER !== 100.05) require("fail");
if(typeof NUMBER !== "number") require("fail");
});
it("should define ZERO", function() {
expect(ZERO).toBe(0);
expect((typeof ZERO)).toBe("number");
if(ZERO !== 0) require("fail");
if(typeof ZERO !== "number") require("fail");
});
it("should define ONE", function() {
expect(ONE).toBe(1);
expect((typeof ONE)).toBe("number");
expect(42 / ONE).toBe(42);
if(ONE !== 1) require("fail");
if(typeof ONE !== "number") require("fail");
});
it("should define BIGINT", function() {
expect(BIGINT).toBe(9007199254740991n);
expect((typeof BIGINT)).toBe("bigint");
if(BIGINT !== 9007199254740991n) require("fail");
if(typeof BIGINT !== "bigint") require("fail");
});
it("should define POSITIVE_ZERO", function() {
expect(POSITIVE_ZERO).toBe(+0);
expect(POSITIVE_ZERO).toBe(0);

View File

@ -5,7 +5,12 @@ module.exports = {
new DefinePlugin({
TRUE: true,
FALSE: false,
NULL: null,
UNDEFINED: undefined,
NUMBER: 100.05,
ZERO: 0,
ONE: 1,
BIGINT: 9007199254740991n,
POSITIVE_ZERO: +0,
NEGATIVE_ZER0: -0,
NEGATIVE_NUMBER: -100.25,

View File

@ -410,10 +410,10 @@
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
"@types/estree@0.0.39":
version "0.0.39"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
"@types/estree@0.0.42":
version "0.0.42"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.42.tgz#8d0c1f480339efedb3e46070e22dd63e0430dd11"
integrity sha512-K1DPVvnBCPxzD+G51/cxVIoc2X8uUVl1zpJeE6iKcgHMj4+tbat5Xu4TjV7v2QSDbIeAfLi2hIk+u2+s0MlpUQ==
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
version "2.0.1"