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()) {
|
if (violation.isAssignmentExpression()) {
|
||||||
violation
|
const { operator } = violation.node;
|
||||||
.get("right")
|
if (operator === "=") {
|
||||||
.replaceWith(
|
violation.replaceWith(
|
||||||
t.sequenceExpression([throwNode, violation.get("right").node]),
|
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()) {
|
} else if (violation.isUpdateExpression()) {
|
||||||
violation.replaceWith(
|
violation.replaceWith(
|
||||||
t.sequenceExpression([throwNode, violation.node]),
|
t.sequenceExpression([
|
||||||
|
t.unaryExpression("+", violation.get("argument").node),
|
||||||
|
throwNode,
|
||||||
|
]),
|
||||||
);
|
);
|
||||||
} else if (violation.isForXStatement()) {
|
} else if (violation.isForXStatement()) {
|
||||||
violation.ensureBlock();
|
violation.ensureBlock();
|
||||||
|
violation
|
||||||
|
.get("left")
|
||||||
|
.replaceWith(
|
||||||
|
t.variableDeclaration("var", [
|
||||||
|
t.variableDeclarator(
|
||||||
|
violation.scope.generateUidIdentifier(name),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
);
|
||||||
violation.node.body.body.unshift(t.expressionStatement(throwNode));
|
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 () {
|
(function () {
|
||||||
var a = "foo";
|
var a = "foo";
|
||||||
if (false) a = (babelHelpers.readOnlyError("a"), "false");
|
if (false) "false", babelHelpers.readOnlyError("a");
|
||||||
return a;
|
return a;
|
||||||
})();
|
})();
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
var a = 1,
|
var a = 1,
|
||||||
b = 2;
|
b = 2;
|
||||||
a = (babelHelpers.readOnlyError("a"), 3);
|
3, babelHelpers.readOnlyError("a");
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
for (const i = 0; i < 3; i = i + 1) {
|
for (const i = 0; i < 3; i = i + 1) {
|
||||||
console.log(i);
|
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);
|
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;
|
var a = 0;
|
||||||
|
|
||||||
function f() {
|
function f() {
|
||||||
return (babelHelpers.readOnlyError("c"), ++c) + --a;
|
return (+c, babelHelpers.readOnlyError("c")) + --a;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,20 @@
|
|||||||
|
const state1 = {};
|
||||||
expect(function() {
|
expect(function() {
|
||||||
const a = 3;
|
const a = 3;
|
||||||
|
state1.getA = () => a;
|
||||||
|
|
||||||
a = 7;
|
a = 7;
|
||||||
}).toThrow('"a" is read-only');
|
}).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;
|
const MULTIPLIER = 5;
|
||||||
|
|
||||||
MULTIPLIER = "overwrite";
|
MULTIPLIER = "overwrite";
|
||||||
|
|
||||||
|
const a = 5;
|
||||||
|
let b = 0;
|
||||||
|
a = b++;
|
||||||
|
|||||||
@ -1,2 +1,5 @@
|
|||||||
var MULTIPLIER = 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) {
|
function f(arr) {
|
||||||
const MULTIPLIER = 5;
|
const MULTIPLIER = 5;
|
||||||
|
state.getMultiplier = () => MULTIPLIER;
|
||||||
|
|
||||||
for (MULTIPLIER in arr);
|
for (MULTIPLIER in arr);
|
||||||
|
|
||||||
return 'survived';
|
return 'survived';
|
||||||
@ -8,5 +11,6 @@ function f(arr) {
|
|||||||
expect(function() {
|
expect(function() {
|
||||||
f([1,2,3]);
|
f([1,2,3]);
|
||||||
}).toThrow('"MULTIPLIER" is read-only');
|
}).toThrow('"MULTIPLIER" is read-only');
|
||||||
|
expect(state.getMultiplier()).toBe(5); // Assignment did not succeed
|
||||||
|
|
||||||
expect(f([])).toBe('survived');
|
expect(f([])).toBe('survived');
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
var MULTIPLIER = 5;
|
var MULTIPLIER = 5;
|
||||||
|
|
||||||
for (MULTIPLIER in arr) {
|
for (var _MULTIPLIER in arr) {
|
||||||
babelHelpers.readOnlyError("MULTIPLIER");
|
babelHelpers.readOnlyError("MULTIPLIER");
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,23 @@
|
|||||||
|
const state1 = {};
|
||||||
expect(function() {
|
expect(function() {
|
||||||
const a = "str";
|
const a = "str";
|
||||||
|
state1.getA = () => a;
|
||||||
|
|
||||||
--a;
|
--a;
|
||||||
}).toThrow('"a" is read-only');
|
}).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";
|
var a = "str";
|
||||||
babelHelpers.readOnlyError("a"), --a;
|
+a, babelHelpers.readOnlyError("a");
|
||||||
|
|||||||
@ -1,4 +1,23 @@
|
|||||||
|
const state1 = {};
|
||||||
expect(function() {
|
expect(function() {
|
||||||
const foo = 1;
|
const foo = 1;
|
||||||
|
state1.getFoo = () => foo;
|
||||||
|
|
||||||
foo++;
|
foo++;
|
||||||
}).toThrow('"foo" is read-only');
|
}).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;
|
var foo = 1;
|
||||||
babelHelpers.readOnlyError("foo"), foo++;
|
+foo, babelHelpers.readOnlyError("foo");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user