Fix const violations in ESM imports when transformed to CJS (#13258)

This commit is contained in:
overlookmotel 2021-06-22 18:33:46 +01:00 committed by GitHub
parent 47ad54a057
commit 5ac5e3572f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 178 additions and 23 deletions

View File

@ -350,31 +350,33 @@ const rewriteReferencesVisitor: Visitor<RewriteReferencesVisitorState> = {
) {
const { scope, node } = path;
const { left } = node;
const { exported, scope: programScope } = this;
const { exported, imported, scope: programScope } = this;
if (!t.isVariableDeclaration(left)) {
let didTransform = false;
const bodyPath = path.get("body");
const loopBodyScope = bodyPath.scope;
let didTransformExport = false,
importConstViolationName;
const loopBodyScope = path.get("body").scope;
for (const name of Object.keys(t.getOuterBindingIdentifiers(left))) {
if (
exported.get(name) &&
programScope.getBinding(name) === scope.getBinding(name)
) {
didTransform = true;
if (loopBodyScope.hasOwnBinding(name)) {
loopBodyScope.rename(name);
if (programScope.getBinding(name) === scope.getBinding(name)) {
if (exported.has(name)) {
didTransformExport = true;
if (loopBodyScope.hasOwnBinding(name)) {
loopBodyScope.rename(name);
}
}
if (imported.has(name) && !importConstViolationName) {
importConstViolationName = name;
}
}
}
if (!didTransform) {
if (!didTransformExport && !importConstViolationName) {
return;
}
path.ensureBlock();
const bodyPath = path.get("body");
const newLoopId = scope.generateUidIdentifierBasedOnNode(left);
bodyPath.unshiftContainer(
"body",
t.expressionStatement(t.assignmentExpression("=", left, newLoopId)),
);
path
.get("left")
.replaceWith(
@ -383,6 +385,19 @@ const rewriteReferencesVisitor: Visitor<RewriteReferencesVisitorState> = {
]),
);
scope.registerDeclaration(path.get("left"));
if (didTransformExport) {
bodyPath.unshiftContainer(
"body",
t.expressionStatement(t.assignmentExpression("=", left, newLoopId)),
);
}
if (importConstViolationName) {
bodyPath.unshiftContainer(
"body",
t.expressionStatement(buildImportThrow(importConstViolationName)),
);
}
}
},
};

View File

@ -100,12 +100,30 @@ const simpleAssignmentVisitor = {
return;
}
path.node.right = t.binaryExpression(
path.node.operator.slice(0, -1),
t.cloneNode(path.node.left),
path.node.right,
);
path.node.operator = "=";
const operator = path.node.operator.slice(0, -1);
if (t.LOGICAL_OPERATORS.includes(operator)) {
// &&, ||, ??
// (foo &&= bar) => (foo && foo = bar)
path.replaceWith(
t.logicalExpression(
operator,
path.node.left,
t.assignmentExpression(
"=",
t.cloneNode(path.node.left),
path.node.right,
),
),
);
} else {
// (foo += bar) => (foo = foo + bar)
path.node.right = t.binaryExpression(
operator,
t.cloneNode(path.node.left),
path.node.right,
);
path.node.operator = "=";
}
},
},
};

View File

@ -16,7 +16,9 @@ for ([foo, [...foo]] of []) {
let foo;
}
for (foo of []) ;
{
let foo;
for(foo of []) {}
}
}

View File

@ -58,6 +58,11 @@ for (let _ref2 of []) {
let _foo8;
}
for (let _foo9 of []) {
exports.bar = exports.foo = foo = _foo9;
;
}
{
let foo;

View File

@ -15,3 +15,33 @@ Baz = 44;
({prop: Foo} = {});
({prop: Bar} = {});
({prop: Baz} = {});
Foo += 2;
Bar += 2;
Baz += 2;
Foo >>>= 3;
Bar >>>= 3;
Baz >>>= 3;
Foo &&= 4;
Bar &&= 4;
Baz &&= 4;
--Foo;
--Bar;
--Baz;
Foo++;
Bar++;
Baz++;
for (Foo in {}) ;
for (Bar in {}) {}
for (Baz of []) {
let Baz;
}
for ({Foo} in {}) {}
for ([Bar] in {}) {}
for ([...Baz] in {}) {}

View File

@ -47,3 +47,88 @@ _baz.Baz = (44, function () {
} = ({}, function () {
throw new Error('"' + "Baz" + '" is read-only.');
}()));
_foo.default = (_foo.default + 2, function () {
throw new Error('"' + "Foo" + '" is read-only.');
}());
Bar = (Bar + 2, function () {
throw new Error('"' + "Bar" + '" is read-only.');
}());
_baz.Baz = (_baz.Baz + 2, function () {
throw new Error('"' + "Baz" + '" is read-only.');
}());
_foo.default = (_foo.default >>> 3, function () {
throw new Error('"' + "Foo" + '" is read-only.');
}());
Bar = (Bar >>> 3, function () {
throw new Error('"' + "Bar" + '" is read-only.');
}());
_baz.Baz = (_baz.Baz >>> 3, function () {
throw new Error('"' + "Baz" + '" is read-only.');
}());
_foo.default && (_foo.default = (4, function () {
throw new Error('"' + "Foo" + '" is read-only.');
}()));
Bar && (Bar = (4, function () {
throw new Error('"' + "Bar" + '" is read-only.');
}()));
_baz.Baz && (_baz.Baz = (4, function () {
throw new Error('"' + "Baz" + '" is read-only.');
}()));
_foo.default = (_foo.default - 1, function () {
throw new Error('"' + "Foo" + '" is read-only.');
}());
Bar = (Bar - 1, function () {
throw new Error('"' + "Bar" + '" is read-only.');
}());
_baz.Baz = (_baz.Baz - 1, function () {
throw new Error('"' + "Baz" + '" is read-only.');
}());
_foo.default = (_foo.default + 1, function () {
throw new Error('"' + "Foo" + '" is read-only.');
}());
Bar = (Bar + 1, function () {
throw new Error('"' + "Bar" + '" is read-only.');
}());
_baz.Baz = (_baz.Baz + 1, function () {
throw new Error('"' + "Baz" + '" is read-only.');
}());
for (let _Foo in {}) {
(function () {
throw new Error('"' + "Foo" + '" is read-only.');
})();
;
}
for (let _Bar in {}) {
(function () {
throw new Error('"' + "Bar" + '" is read-only.');
})();
}
for (let _Baz of []) {
(function () {
throw new Error('"' + "Baz" + '" is read-only.');
})();
let Baz;
}
for (let _Foo2 in {}) {
(function () {
throw new Error('"' + "Foo" + '" is read-only.');
})();
}
for (let _ref in {}) {
(function () {
throw new Error('"' + "Bar" + '" is read-only.');
})();
}
for (let _ref2 in {}) {
(function () {
throw new Error('"' + "Baz" + '" is read-only.');
})();
}