Define readOnlyError helper and use in check-constants plugin

This commit is contained in:
Mauro Bringolf 2017-11-20 16:40:36 +01:00
parent 7064b298d7
commit ba441c5ce4
10 changed files with 42 additions and 46 deletions

View File

@ -627,6 +627,12 @@ helpers.temporalRef = defineHelper(`
} }
`); `);
helpers.readOnlyError = defineHelper(`
export default function _readOnlyError(name) {
throw new Error("\\"" + name + "\\" is read-only");
}
`);
helpers.temporalUndefined = defineHelper(` helpers.temporalUndefined = defineHelper(`
export default {}; export default {};
`); `);

View File

@ -1,50 +1,37 @@
import { types as t } from "@babel/core"; import { types as t } from "@babel/core";
export default function() { export default function() {
/**
* Helper function to run a statement before an expression by replacing it with a comma expression
* and wrapping the statement in an IIFE as the first operand.
*/
function statementBeforeExpression(statement, expression) {
return t.sequenceExpression([
t.callExpression(
t.functionExpression(null, [], t.blockStatement([statement])),
[],
),
expression,
]);
}
return { return {
visitor: { visitor: {
Scope({ scope }) { Scope({ scope }, state) {
for (const name in scope.bindings) { for (const name in scope.bindings) {
const binding = scope.bindings[name]; const binding = scope.bindings[name];
if (binding.kind !== "const") continue; if (binding.kind !== "const") continue;
for (const violation of (binding.constantViolations: Array)) { for (const violation of (binding.constantViolations: Array)) {
const throwNode = t.throwStatement( const readOnlyError = state.addHelper("readOnlyError");
t.newExpression(t.identifier("Error"), [ const throwNode = t.callExpression(readOnlyError, [
t.stringLiteral(`"${name}" is read-only`), t.stringLiteral(name),
]), ]);
);
if (violation.isAssignmentExpression()) { if (violation.isAssignmentExpression()) {
violation violation
.get("right") .get("right")
.replaceWith( .replaceWith(
statementBeforeExpression( t.sequenceExpression([
throwNode, throwNode,
violation.get("right").node, violation.get("right").node,
), ]),
); );
} else if (violation.isUpdateExpression()) { } else if (violation.isUpdateExpression()) {
violation.replaceWith( violation.replaceWith(
statementBeforeExpression(throwNode, violation.node), t.sequenceExpression([throwNode, violation.node]),
); );
} else if (violation.isForXStatement()) { } else if (violation.isForXStatement()) {
violation.ensureBlock(); violation.ensureBlock();
violation.node.body.body.unshift(throwNode); violation.node.body.body.unshift(
t.expressionStatement(throwNode),
);
} }
} }
} }

View File

@ -1,7 +1,7 @@
function _readOnlyError(name) { throw new Error("\"" + name + "\" is read-only"); }
(function () { (function () {
var a = "foo"; var a = "foo";
if (false) a = (function () { if (false) a = (_readOnlyError("a"), "false");
throw new Error("\"a\" is read-only");
}(), "false");
return a; return a;
})(); })();

View File

@ -1,5 +1,5 @@
function _readOnlyError(name) { throw new Error("\"" + name + "\" is read-only"); }
var a = 1, var a = 1,
b = 2; b = 2;
a = (function () { a = (_readOnlyError("a"), 3);
throw new Error("\"a\" is read-only");
}(), 3);

View File

@ -1,5 +1,5 @@
for (var i = 0; i < 3; i = (function () { function _readOnlyError(name) { throw new Error("\"" + name + "\" is read-only"); }
throw new Error("\"i\" is read-only");
}(), i + 1)) { for (var i = 0; i < 3; i = (_readOnlyError("i"), i + 1)) {
console.log(i); console.log(i);
} }

View File

@ -1,8 +1,8 @@
function _readOnlyError(name) { throw new Error("\"" + name + "\" is read-only"); }
var c = 17; var c = 17;
var a = 0; var a = 0;
function f() { function f() {
return (function () { return (_readOnlyError("c"), ++c) + --a;
throw new Error("\"c\" is read-only");
}(), ++c) + --a;
} }

View File

@ -1,4 +1,4 @@
function _readOnlyError(name) { throw new Error("\"" + name + "\" is read-only"); }
var MULTIPLIER = 5; var MULTIPLIER = 5;
MULTIPLIER = (function () { MULTIPLIER = (_readOnlyError("MULTIPLIER"), "overwrite");
throw new Error("\"MULTIPLIER\" is read-only");
}(), "overwrite");

View File

@ -1,6 +1,9 @@
function _readOnlyError(name) { throw new Error("\"" + name + "\" is read-only"); }
var MULTIPLIER = 5; var MULTIPLIER = 5;
for (MULTIPLIER in arr) { for (MULTIPLIER in arr) {
throw new Error("\"MULTIPLIER\" is read-only"); _readOnlyError("MULTIPLIER");
; ;
} }

View File

@ -1,4 +1,4 @@
function _readOnlyError(name) { throw new Error("\"" + name + "\" is read-only"); }
var a = "str"; var a = "str";
(function () { _readOnlyError("a"), --a;
throw new Error("\"a\" is read-only");
})(), --a;

View File

@ -1,4 +1,4 @@
function _readOnlyError(name) { throw new Error("\"" + name + "\" is read-only"); }
var foo = 1; var foo = 1;
(function () { _readOnlyError("foo"), foo++;
throw new Error("\"foo\" is read-only");
})(), foo++;