Skip to content

Commit

Permalink
add tests, refactor how optional chaining handles
Browse files Browse the repository at this point in the history
  • Loading branch information
vankop committed Jul 26, 2020
1 parent 236e763 commit fb561e9
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 66 deletions.
40 changes: 24 additions & 16 deletions lib/ConstPlugin.js
Expand Up @@ -375,21 +375,32 @@ class ConstPlugin {
}
);
parser.hooks.optionalChaining.tap("ConstPlugin", expr => {
/** @type {ExpressionNode[]} */
const optionalExpressionsStack = [];
/** @type {ExpressionNode|SuperNode} */
let next;
let next = expr.expression;

if (expr.expression.type === "CallExpression") {
next = expr.expression.callee;
} else {
next = expr.expression;
}

while (next.type === "MemberExpression") {
if (next.optional) {
optionalExpressionsStack.push(next.object);
while (
next.type === "MemberExpression" ||
next.type === "CallExpression"
) {
if (next.type === "MemberExpression") {
if (next.optional) {
// SuperNode can not be optional
optionalExpressionsStack.push(
/** @type {ExpressionNode} */ (next.object)
);
}
next = next.object;
} else {
if (next.optional) {
// SuperNode can not be optional
optionalExpressionsStack.push(
/** @type {ExpressionNode} */ (next.callee)
);
}
next = next.callee;
}
next = next.object;
}

while (optionalExpressionsStack.length) {
Expand All @@ -405,14 +416,11 @@ class ConstPlugin {
//
// the generated code is:
//
// null; // or undefined; if evaluated to undefined
// undefined;
//
// ------------------------------------------
//
const dep = new ConstDependency(
evaluated.isUndefined() ? "undefined" : "null",
expr.range
);
const dep = new ConstDependency(" undefined", expr.range);
dep.loc = expr.loc;
parser.state.module.addPresentationalDependency(dep);
return true;
Expand Down
46 changes: 24 additions & 22 deletions lib/javascript/JavascriptParser.js
Expand Up @@ -1230,40 +1230,42 @@ class JavascriptParser extends Parser {
.for("ChainExpression")
.tap("JavascriptParser", _expr => {
const expr = /** @type {ChainExpressionNode} */ (_expr);
let result = this.evaluateExpression(expr.expression);
if (result) return result;

/** @type {ExpressionNode[]} */
const stack = [];
const optionalExpressionsStack = [];
/** @type {ExpressionNode|SuperNode} */
let next;

if (expr.expression.type === "CallExpression") {
next = expr.expression.callee;
} else {
next = expr.expression.object;
}
let next = expr.expression;

while (next.type === "MemberExpression") {
if (next.optional) {
stack.push(/** @type {ExpressionNode} */ (next.object));
while (
next.type === "MemberExpression" ||
next.type === "CallExpression"
) {
if (next.type === "MemberExpression") {
if (next.optional) {
// SuperNode can not be optional
optionalExpressionsStack.push(
/** @type {ExpressionNode} */ (next.object)
);
}
next = next.object;
} else {
if (next.optional) {
// SuperNode can not be optional
optionalExpressionsStack.push(
/** @type {ExpressionNode} */ (next.callee)
);
}
next = next.callee;
}

next = next.object;
}

while (stack.length) {
const expression = stack.pop();
while (optionalExpressionsStack.length > 0) {
const expression = optionalExpressionsStack.pop();
const evaluated = this.evaluateExpression(expression);

if (evaluated && evaluated.asNullish()) {
return evaluated.setRange(_expr.range);
}
}

return new BasicEvaluatedExpression()
.setRange(_expr.range)
.setExpression(_expr);
});
}

Expand Down
36 changes: 18 additions & 18 deletions test/__snapshots__/StatsTestCases.test.js.snap
Expand Up @@ -837,9 +837,9 @@ external \\"test\\" 42 bytes [built]"
`;

exports[`StatsTestCases should print correct stats for filter-warnings 1`] = `
"Hash: 73a3198368d23afbbd6573a3198368d23afbbd6573a3198368d23afbbd6573a3198368d23afbbd6573a3198368d23afbbd6573a3198368d23afbbd6573a3198368d23afbbd6573a3198368d23afbbd6573a3198368d23afbbd6573a3198368d23afbbd6573a3198368d23afbbd6573a3198368d23afbbd6573a3198368d23afbbd65
"Hash: 2220740a2bcff63070922220740a2bcff63070922220740a2bcff63070922220740a2bcff63070922220740a2bcff63070922220740a2bcff63070922220740a2bcff63070922220740a2bcff63070922220740a2bcff63070922220740a2bcff63070922220740a2bcff63070922220740a2bcff63070922220740a2bcff6307092
Child undefined:
Hash: 73a3198368d23afbbd65
Hash: 2220740a2bcff6307092
Time: X ms
Built at: 1970-04-20 12:42:42
Asset Size
Expand Down Expand Up @@ -869,49 +869,49 @@ Child undefined:
WARNING in Terser Plugin: Dropping unused function someUnUsedFunction5 [webpack://./index.js:12,0]
Child Terser:
Hash: 73a3198368d23afbbd65
Hash: 2220740a2bcff6307092
Time: X ms
Built at: 1970-04-20 12:42:42
Asset Size
bundle1.js 556 bytes [emitted] [name: main]
Entrypoint main = bundle1.js
Child /Terser/:
Hash: 73a3198368d23afbbd65
Hash: 2220740a2bcff6307092
Time: X ms
Built at: 1970-04-20 12:42:42
Asset Size
bundle2.js 556 bytes [emitted] [name: main]
Entrypoint main = bundle2.js
Child warnings => true:
Hash: 73a3198368d23afbbd65
Hash: 2220740a2bcff6307092
Time: X ms
Built at: 1970-04-20 12:42:42
Asset Size
bundle3.js 556 bytes [emitted] [name: main]
Entrypoint main = bundle3.js
Child [Terser]:
Hash: 73a3198368d23afbbd65
Hash: 2220740a2bcff6307092
Time: X ms
Built at: 1970-04-20 12:42:42
Asset Size
bundle4.js 556 bytes [emitted] [name: main]
Entrypoint main = bundle4.js
Child [/Terser/]:
Hash: 73a3198368d23afbbd65
Hash: 2220740a2bcff6307092
Time: X ms
Built at: 1970-04-20 12:42:42
Asset Size
bundle5.js 556 bytes [emitted] [name: main]
Entrypoint main = bundle5.js
Child [warnings => true]:
Hash: 73a3198368d23afbbd65
Hash: 2220740a2bcff6307092
Time: X ms
Built at: 1970-04-20 12:42:42
Asset Size
bundle6.js 556 bytes [emitted] [name: main]
Entrypoint main = bundle6.js
Child should not filter:
Hash: 73a3198368d23afbbd65
Hash: 2220740a2bcff6307092
Time: X ms
Built at: 1970-04-20 12:42:42
Asset Size
Expand Down Expand Up @@ -941,7 +941,7 @@ Child should not filter:
WARNING in Terser Plugin: Dropping unused function someUnUsedFunction5 [webpack://./index.js:12,0]
Child /should not filter/:
Hash: 73a3198368d23afbbd65
Hash: 2220740a2bcff6307092
Time: X ms
Built at: 1970-04-20 12:42:42
Asset Size
Expand Down Expand Up @@ -971,7 +971,7 @@ Child /should not filter/:
WARNING in Terser Plugin: Dropping unused function someUnUsedFunction5 [webpack://./index.js:12,0]
Child warnings => false:
Hash: 73a3198368d23afbbd65
Hash: 2220740a2bcff6307092
Time: X ms
Built at: 1970-04-20 12:42:42
Asset Size
Expand Down Expand Up @@ -1001,7 +1001,7 @@ Child warnings => false:
WARNING in Terser Plugin: Dropping unused function someUnUsedFunction5 [webpack://./index.js:12,0]
Child [should not filter]:
Hash: 73a3198368d23afbbd65
Hash: 2220740a2bcff6307092
Time: X ms
Built at: 1970-04-20 12:42:42
Asset Size
Expand Down Expand Up @@ -1031,7 +1031,7 @@ Child [should not filter]:
WARNING in Terser Plugin: Dropping unused function someUnUsedFunction5 [webpack://./index.js:12,0]
Child [/should not filter/]:
Hash: 73a3198368d23afbbd65
Hash: 2220740a2bcff6307092
Time: X ms
Built at: 1970-04-20 12:42:42
Asset Size
Expand Down Expand Up @@ -1061,7 +1061,7 @@ Child [/should not filter/]:
WARNING in Terser Plugin: Dropping unused function someUnUsedFunction5 [webpack://./index.js:12,0]
Child [warnings => false]:
Hash: 73a3198368d23afbbd65
Hash: 2220740a2bcff6307092
Time: X ms
Built at: 1970-04-20 12:42:42
Asset Size
Expand Down Expand Up @@ -2750,9 +2750,9 @@ Entrypoint main = main.js
`;
exports[`StatsTestCases should print correct stats for side-effects-optimization 1`] = `
"Hash: 74f7a18156dea6b050585bee8a28eec71e4d3a65
"Hash: 823f2b592b9f43b765a06b883114fc98eebb250e
Child
Hash: 74f7a18156dea6b05058
Hash: 823f2b592b9f43b765a0
Time: X ms
Built at: 1970-04-20 12:42:42
Asset Size
Expand All @@ -2774,7 +2774,7 @@ Child
ModuleConcatenation bailout: Module is not an ECMAScript module
+ 2 hidden modules
Child
Hash: 5bee8a28eec71e4d3a65
Hash: 6b883114fc98eebb250e
Time: X ms
Built at: 1970-04-20 12:42:42
Asset Size
Expand Down Expand Up @@ -3905,7 +3905,7 @@ require.include() is deprecated and will be removed soon.
`;
exports[`StatsTestCases should print correct stats for warnings-terser 1`] = `
"Hash: 9d4799d2d13af78e55f1
"Hash: cd0e45210124426e6feb
Time: X ms
Built at: 1970-04-20 12:42:42
Asset Size
Expand Down
1 change: 0 additions & 1 deletion test/cases/parsing/optional-chaining/a.js
@@ -1 +0,0 @@
module.exports = 1;
18 changes: 14 additions & 4 deletions test/cases/parsing/optional-chaining/index.js
@@ -1,5 +1,15 @@
it("should handle optional members", () => {
expect(
module.hot?.accept((() => {throw new Error("fail")})())
).toBe(null);
it("should evaluate optional members", () => {
if (!module.hot) {
expect(
module.hot?.accept((() => {throw new Error("fail")})())
).toBe(undefined);
}
});

it("should evaluate optional chaining as a part of statement", () => {
if (module.hot?.accept) {
module.hot?.accept("./a.js");
} else {
expect(module.hot).toBe(undefined);
}
});
12 changes: 12 additions & 0 deletions test/cases/parsing/optional-chaining/test.filter.js
@@ -0,0 +1,12 @@
const supportsOptionalChaining = require("../../../helpers/supportsOptionalChaining");

/**
* @param {import("../../../../").Configuration} config
* @returns {boolean}
*/
module.exports = function (config) {
if (config.mode === "production") return false;
if (config.optimization && config.optimization.minimizer) return false;

return supportsOptionalChaining();
};
5 changes: 5 additions & 0 deletions test/configCases/parsing/optional-chaining/test.filter.js
@@ -0,0 +1,5 @@
var supportsOptionalChaining = require("../../../helpers/supportsOptionalChaining");

module.exports = function (config) {
return supportsOptionalChaining();
};
2 changes: 1 addition & 1 deletion test/helpers/supportsNullishCoalescing.js
@@ -1,4 +1,4 @@
module.exports = function supportsObjectDestructuring() {
module.exports = function supportsNullishCoalescing() {
try {
var f = eval("(function f() { return null ?? true; })");
return f();
Expand Down
8 changes: 8 additions & 0 deletions test/helpers/supportsOptionalChaining.js
@@ -0,0 +1,8 @@
module.exports = function supportsOptionalChaining() {
try {
var f = eval("(function f() { return ({a: true}) ?.a })");
return f();
} catch (e) {
return false;
}
};
1 change: 0 additions & 1 deletion test/hotCases/parsing/hot-api-optional-chaining/b.js

This file was deleted.

3 changes: 0 additions & 3 deletions test/hotCases/parsing/hot-api-optional-chaining/index.js
@@ -1,7 +1,4 @@
it("should run module.hot.accept(…)", function() {
module?.hot?.accept("./a", function() {});
});

it("should skip rest members", function() {
module?.hot.accept();
});

0 comments on commit fb561e9

Please sign in to comment.