-
-
Notifications
You must be signed in to change notification settings - Fork 5.8k
Description
💻
- Would you like to work on a fix?
How are you using Babel?
@babel/cli
Input code
let isCalled = false;
const fn = () => isCalled = true;
const i = 0;
try {
i = fn();
} catch (e) {
console.log(isCalled);
}Configuration file name
No response
Configuration
No response
Current and expected behavior
Original code logs "true".
But plugin-transform-block-scoping's constant checks produces code with a slightly different behaviour:
function _readOnlyError(name) { throw new TypeError("\"" + name + "\" is read-only"); }
var isCalled = false;
var fn = () => isCalled = true;
var i = 0;
try {
i = (_readOnlyError("i"), fn());
} catch (e) {
console.log(isCalled);
}This logs "false" because _readOnlyError() throws before fn() is evaluated.
Environment
Babel REPL
Possible solution
Order of fn() and _readOnlyError("i") should be reversed:
i = (fn(), _readOnlyError("i"))This order would produce wrong result if _readOnlyError() returned a value, but since we know for sure it'll throw, that's not relevant.
Additional context
There are two other more obscure cases where the above solution is not sufficient to solve the problem:
(I may have time to make a PR for the simple case above, but unlikely I will for these two)
Destructuring
const c = 0;
let x = 1, y = 2;
try {
[x, c, y] = [11, 0, 22];
} catch (e) {
console.log( {x, y} );
}[x, c, y] = [] is transformed to [x, c, y] = (_readOnlyError("c"), [11, 0, 22]).
Original logs {x: 11, y: 2} whereas transpiled code logs {x: 1, y: 2}. It should throw only after x has been assigned, but before y is.
This is tricky to get right. Best solution I can see is:
// NB Assignment to `y` has been omitted
[x] = [11, 0, 22], _readOnlyError("c");Assignment operators
const calls = [];
const fn = () => calls.push('fn');
const i = {
valueOf() {
calls.push('valueOf');
return 1;
}
};
try {
i += fn();
} catch (e) {
console.log(calls);
}Original logs [ 'fn', 'valueOf' ].
Babel transforms i += fn() to i += (_readOnlyError("i"), fn()). So transpiled code logs [].
After reversing fn() and _readOnlyError("i"), it logs [ 'fn' ] (still incorrect).
The correct transpiled output would be:
i + fn(), _readOnlyError("i")NB &&=, ||= and ??= aren't affected by this additional complication, but I think all other assignment operators are.
i++ / ++i should be treated as same as i += 1:
i + 1, _readOnlyError("i")