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(`
export default {};
`);

View File

@ -1,50 +1,37 @@
import { types as t } from "@babel/core";
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 {
visitor: {
Scope({ scope }) {
Scope({ scope }, state) {
for (const name in scope.bindings) {
const binding = scope.bindings[name];
if (binding.kind !== "const") continue;
for (const violation of (binding.constantViolations: Array)) {
const throwNode = t.throwStatement(
t.newExpression(t.identifier("Error"), [
t.stringLiteral(`"${name}" is read-only`),
]),
);
const readOnlyError = state.addHelper("readOnlyError");
const throwNode = t.callExpression(readOnlyError, [
t.stringLiteral(name),
]);
if (violation.isAssignmentExpression()) {
violation
.get("right")
.replaceWith(
statementBeforeExpression(
t.sequenceExpression([
throwNode,
violation.get("right").node,
),
]),
);
} else if (violation.isUpdateExpression()) {
violation.replaceWith(
statementBeforeExpression(throwNode, violation.node),
t.sequenceExpression([throwNode, violation.node]),
);
} else if (violation.isForXStatement()) {
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 () {
var a = "foo";
if (false) a = (function () {
throw new Error("\"a\" is read-only");
}(), "false");
if (false) a = (_readOnlyError("a"), "false");
return a;
})();

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,9 @@
function _readOnlyError(name) { throw new Error("\"" + name + "\" is read-only"); }
var MULTIPLIER = 5;
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";
(function () {
throw new Error("\"a\" is read-only");
})(), --a;
_readOnlyError("a"), --a;

View File

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