Fix plugin-transform-block-scoping const violations (#13248)
* Fix plugin-transform-block-scoping const violations Fixes #13245 * Replace `a++` with `+a` where const violation * Remove assignment where const violation * Remove assignment for `&&=`, `||=`, `??=` where const violation * Shorten test
This commit is contained in:
parent
fa01fbe052
commit
f166b7ae58
@ -433,17 +433,49 @@ class BlockScoping {
|
||||
]);
|
||||
|
||||
if (violation.isAssignmentExpression()) {
|
||||
violation
|
||||
.get("right")
|
||||
.replaceWith(
|
||||
t.sequenceExpression([throwNode, violation.get("right").node]),
|
||||
const { operator } = violation.node;
|
||||
if (operator === "=") {
|
||||
violation.replaceWith(
|
||||
t.sequenceExpression([violation.get("right").node, throwNode]),
|
||||
);
|
||||
} else if (["&&=", "||=", "??="].includes(operator)) {
|
||||
violation.replaceWith(
|
||||
t.logicalExpression(
|
||||
operator.slice(0, -1),
|
||||
violation.get("left").node,
|
||||
t.sequenceExpression([violation.get("right").node, throwNode]),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
violation.replaceWith(
|
||||
t.sequenceExpression([
|
||||
t.binaryExpression(
|
||||
operator.slice(0, -1),
|
||||
violation.get("left").node,
|
||||
violation.get("right").node,
|
||||
),
|
||||
throwNode,
|
||||
]),
|
||||
);
|
||||
}
|
||||
} else if (violation.isUpdateExpression()) {
|
||||
violation.replaceWith(
|
||||
t.sequenceExpression([throwNode, violation.node]),
|
||||
t.sequenceExpression([
|
||||
t.unaryExpression("+", violation.get("argument").node),
|
||||
throwNode,
|
||||
]),
|
||||
);
|
||||
} else if (violation.isForXStatement()) {
|
||||
violation.ensureBlock();
|
||||
violation
|
||||
.get("left")
|
||||
.replaceWith(
|
||||
t.variableDeclaration("var", [
|
||||
t.variableDeclarator(
|
||||
violation.scope.generateUidIdentifier(name),
|
||||
),
|
||||
]),
|
||||
);
|
||||
violation.node.body.body.unshift(t.expressionStatement(throwNode));
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,62 @@
|
||||
const state1 = {};
|
||||
expect(function() {
|
||||
const a = 3;
|
||||
let b = 1;
|
||||
state1.getA = () => a;
|
||||
state1.getB = () => b;
|
||||
|
||||
a += b++;
|
||||
}).toThrow('"a" is read-only');
|
||||
expect(state1.getA()).toBe(3); // Assignment did not succeed
|
||||
expect(state1.getB()).toBe(2); // `b++` was evaluated before error thrown
|
||||
|
||||
const state2 = {};
|
||||
expect(function() {
|
||||
const a = {
|
||||
valueOf() {
|
||||
state2.valueOfIsCalled = true;
|
||||
}
|
||||
};
|
||||
state2.a = a;
|
||||
state2.getA = () => a;
|
||||
state2.getB = () => b;
|
||||
|
||||
let b = 1;
|
||||
a += b++;
|
||||
}).toThrow('"a" is read-only');
|
||||
expect(state2.getA()).toBe(state2.a); // Assignment did not succeed
|
||||
expect(state2.getB()).toBe(2); // `b++` was evaluated before error thrown
|
||||
expect(state2.valueOfIsCalled).toBe(true); // `a` was read before error thrown
|
||||
|
||||
const state3 = {};
|
||||
expect(function() {
|
||||
const a = 32;
|
||||
let b = 1;
|
||||
state3.getA = () => a;
|
||||
state3.getB = () => b;
|
||||
|
||||
a >>>= ++b;
|
||||
}).toThrow('"a" is read-only');
|
||||
expect(state3.getA()).toBe(32); // Assignment did not succeed
|
||||
expect(state3.getB()).toBe(2); // `++b` was evaluated before error thrown
|
||||
|
||||
const state4 = {};
|
||||
expect(function() {
|
||||
const a = 1;
|
||||
let b = 1;
|
||||
state4.getA = () => a;
|
||||
state4.getB = () => b;
|
||||
|
||||
a &&= ++b;
|
||||
}).toThrow('"a" is read-only');
|
||||
expect(state4.getA()).toBe(1); // Assignment did not succeed
|
||||
expect(state4.getB()).toBe(2); // `++b` was evaluated before error thrown
|
||||
|
||||
{
|
||||
const a = 1;
|
||||
let b = 1;
|
||||
a ||= ++b;
|
||||
|
||||
expect(a).toBe(1); // Assignment not made
|
||||
expect(b).toBe(1); // `++b` was not evaluated
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
const a = 5;
|
||||
let b = 0;
|
||||
a += b++;
|
||||
a >>>= b++;
|
||||
a ||= b++;
|
||||
a &&= b++;
|
||||
a ??= b++;
|
||||
@ -0,0 +1,7 @@
|
||||
var a = 5;
|
||||
var b = 0;
|
||||
a + b++, babelHelpers.readOnlyError("a");
|
||||
a >>> b++, babelHelpers.readOnlyError("a");
|
||||
a || (b++, babelHelpers.readOnlyError("a"));
|
||||
a && (b++, babelHelpers.readOnlyError("a"));
|
||||
a ?? (b++, babelHelpers.readOnlyError("a"));
|
||||
@ -1,5 +1,5 @@
|
||||
(function () {
|
||||
var a = "foo";
|
||||
if (false) a = (babelHelpers.readOnlyError("a"), "false");
|
||||
if (false) "false", babelHelpers.readOnlyError("a");
|
||||
return a;
|
||||
})();
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
var a = 1,
|
||||
b = 2;
|
||||
a = (babelHelpers.readOnlyError("a"), 3);
|
||||
3, babelHelpers.readOnlyError("a");
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
for (const i = 0; i < 3; i = i + 1) {
|
||||
console.log(i);
|
||||
}
|
||||
|
||||
for (const j = 0; j < 3; j++) {
|
||||
console.log(j);
|
||||
}
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
for (var i = 0; i < 3; i = (babelHelpers.readOnlyError("i"), i + 1)) {
|
||||
for (var i = 0; i < 3; i + 1, babelHelpers.readOnlyError("i")) {
|
||||
console.log(i);
|
||||
}
|
||||
|
||||
for (var j = 0; j < 3; +j, babelHelpers.readOnlyError("j")) {
|
||||
console.log(j);
|
||||
}
|
||||
|
||||
@ -2,5 +2,5 @@ var c = 17;
|
||||
var a = 0;
|
||||
|
||||
function f() {
|
||||
return (babelHelpers.readOnlyError("c"), ++c) + --a;
|
||||
return (+c, babelHelpers.readOnlyError("c")) + --a;
|
||||
}
|
||||
|
||||
@ -1,4 +1,20 @@
|
||||
const state1 = {};
|
||||
expect(function() {
|
||||
const a = 3;
|
||||
state1.getA = () => a;
|
||||
|
||||
a = 7;
|
||||
}).toThrow('"a" is read-only');
|
||||
expect(state1.getA()).toBe(3); // Assignment did not succeed
|
||||
|
||||
const state2 = {};
|
||||
expect(function() {
|
||||
const a = 3;
|
||||
let b = 0;
|
||||
state2.getA = () => a;
|
||||
state2.getB = () => b;
|
||||
|
||||
a = b++;
|
||||
}).toThrow('"a" is read-only');
|
||||
expect(state2.getA()).toBe(3); // Assignment did not succeed
|
||||
expect(state2.getB()).toBe(1); // `b++` was evaluated before error thrown
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
const MULTIPLIER = 5;
|
||||
|
||||
MULTIPLIER = "overwrite";
|
||||
|
||||
const a = 5;
|
||||
let b = 0;
|
||||
a = b++;
|
||||
|
||||
@ -1,2 +1,5 @@
|
||||
var MULTIPLIER = 5;
|
||||
MULTIPLIER = (babelHelpers.readOnlyError("MULTIPLIER"), "overwrite");
|
||||
"overwrite", babelHelpers.readOnlyError("MULTIPLIER");
|
||||
var a = 5;
|
||||
var b = 0;
|
||||
b++, babelHelpers.readOnlyError("a");
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
const state = {};
|
||||
function f(arr) {
|
||||
const MULTIPLIER = 5;
|
||||
state.getMultiplier = () => MULTIPLIER;
|
||||
|
||||
for (MULTIPLIER in arr);
|
||||
|
||||
return 'survived';
|
||||
@ -8,5 +11,6 @@ function f(arr) {
|
||||
expect(function() {
|
||||
f([1,2,3]);
|
||||
}).toThrow('"MULTIPLIER" is read-only');
|
||||
expect(state.getMultiplier()).toBe(5); // Assignment did not succeed
|
||||
|
||||
expect(f([])).toBe('survived');
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
var MULTIPLIER = 5;
|
||||
|
||||
for (MULTIPLIER in arr) {
|
||||
for (var _MULTIPLIER in arr) {
|
||||
babelHelpers.readOnlyError("MULTIPLIER");
|
||||
;
|
||||
}
|
||||
|
||||
@ -1,4 +1,23 @@
|
||||
const state1 = {};
|
||||
expect(function() {
|
||||
const a = "str";
|
||||
state1.getA = () => a;
|
||||
|
||||
--a;
|
||||
}).toThrow('"a" is read-only');
|
||||
expect(state1.getA()).toBe("str"); // Assignment did not succeed
|
||||
|
||||
const state2 = {};
|
||||
expect(function() {
|
||||
const b = {
|
||||
valueOf() {
|
||||
state2.valueOfIsCalled = true;
|
||||
}
|
||||
};
|
||||
state2.b = b;
|
||||
state2.getB = () => b;
|
||||
|
||||
--b;
|
||||
}).toThrow('"b" is read-only');
|
||||
expect(state2.getB()).toBe(state2.b); // Assignment did not succeed
|
||||
expect(state2.valueOfIsCalled).toBe(true); // `bar` was read before error thrown
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
var a = "str";
|
||||
babelHelpers.readOnlyError("a"), --a;
|
||||
+a, babelHelpers.readOnlyError("a");
|
||||
|
||||
@ -1,4 +1,23 @@
|
||||
const state1 = {};
|
||||
expect(function() {
|
||||
const foo = 1;
|
||||
state1.getFoo = () => foo;
|
||||
|
||||
foo++;
|
||||
}).toThrow('"foo" is read-only');
|
||||
expect(state1.getFoo()).toBe(1); // Assignment did not succeed
|
||||
|
||||
const state2 = {};
|
||||
expect(function() {
|
||||
const bar = {
|
||||
valueOf() {
|
||||
state2.valueOfIsCalled = true;
|
||||
}
|
||||
};
|
||||
state2.bar = bar;
|
||||
state2.getBar = () => bar;
|
||||
|
||||
bar++;
|
||||
}).toThrow('"bar" is read-only');
|
||||
expect(state2.getBar()).toBe(state2.bar); // Assignment did not succeed
|
||||
expect(state2.valueOfIsCalled).toBe(true); // `bar` was read before error thrown
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
var foo = 1;
|
||||
babelHelpers.readOnlyError("foo"), foo++;
|
||||
+foo, babelHelpers.readOnlyError("foo");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user