Skip to content

Commit 1d4546b

Browse files
authored
Preserve class id when transforming using declarations with exported class (#17257)
1 parent 5addf13 commit 1d4546b

27 files changed

Lines changed: 320 additions & 8 deletions

File tree

packages/babel-helper-module-transforms/src/normalize-and-load-metadata.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,10 @@ function getLocalExportMetadata(
447447
): Map<string, LocalExportMetadata> {
448448
const bindingKindLookup = new Map();
449449

450-
programPath.get("body").forEach((child: NodePath) => {
450+
const programScope = programPath.scope;
451+
const programChildren = programPath.get("body");
452+
453+
programChildren.forEach((child: NodePath) => {
451454
let kind: ModuleBindingKind;
452455
if (child.isImportDeclaration()) {
453456
kind = "import";
@@ -495,7 +498,12 @@ function getLocalExportMetadata(
495498
let metadata = localMetadata.get(localName);
496499

497500
if (!metadata) {
498-
const kind = bindingKindLookup.get(localName);
501+
// If localName is not found in the bindingKindLookup generated
502+
// from top level declarations, it could be a reference to a var
503+
// declaration defined within block statement or switch case
504+
const kind: ModuleBindingKind =
505+
bindingKindLookup.get(localName) ??
506+
(programScope.getBinding(localName)?.kind as "var" | undefined);
499507

500508
if (kind === undefined) {
501509
throw idPath.buildCodeFrameError(
@@ -512,7 +520,7 @@ function getLocalExportMetadata(
512520
return metadata;
513521
};
514522

515-
programPath.get("body").forEach(child => {
523+
programChildren.forEach(child => {
516524
if (
517525
child.isExportNamedDeclaration() &&
518526
(initializeReexports || !child.node.source)

packages/babel-plugin-proposal-explicit-resource-management/src/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,10 @@ export default declare(api => {
290290
let varId;
291291
if (t.isClassDeclaration(declaration)) {
292292
varId = declaration.id;
293-
declaration.id = null;
293+
// Move the class id to the var binding such that the scope binding
294+
// info is correct. Then we clone one to ensure inner class reference
295+
// will stay same if the outer binding is mutated.
296+
declaration.id = t.cloneNode(varId);
294297
declaration = t.toExpression(declaration);
295298
} else if (!t.isExpression(declaration)) {
296299
continue;
@@ -332,7 +335,7 @@ export default declare(api => {
332335

333336
if (t.isClassDeclaration(node)) {
334337
const { id } = node;
335-
node.id = null;
338+
node.id = t.cloneNode(id);
336339
innerBlockBody.push(
337340
t.variableDeclaration("var", [
338341
t.variableDeclarator(id, t.toExpression(node)),
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { doSomething } from "somewhere";
2+
export * from "somewhere else";
3+
export * as ns from "somewhere else";
4+
5+
function f() { a; B; }
6+
function h() { b; A; }
7+
export function g() { c; }
8+
9+
doSomething();
10+
11+
export { f };
12+
export let { b } = {};
13+
14+
let c = 2;
15+
class A {}
16+
export class B {}
17+
18+
using x = null;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"sourceType": "module",
3+
"plugins": ["transform-modules-commonjs", "transform-export-namespace-from", "proposal-explicit-resource-management"]
4+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"use strict";
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
var _exportNames = {
7+
g: true,
8+
f: true,
9+
b: true,
10+
B: true,
11+
ns: true
12+
};
13+
exports.b = exports.B = void 0;
14+
exports.f = f;
15+
exports.g = g;
16+
exports.ns = void 0;
17+
var _somewhere = require("somewhere");
18+
var _ns = babelHelpers.interopRequireWildcard(require("somewhere else"));
19+
exports.ns = _ns;
20+
Object.keys(_ns).forEach(function (key) {
21+
if (key === "default" || key === "__esModule") return;
22+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
23+
if (key in exports && exports[key] === _ns[key]) return;
24+
Object.defineProperty(exports, key, {
25+
enumerable: true,
26+
get: function () {
27+
return _ns[key];
28+
}
29+
});
30+
});
31+
function f() {
32+
a;
33+
B;
34+
}
35+
function h() {
36+
b;
37+
A;
38+
}
39+
function g() {
40+
c;
41+
}
42+
try {
43+
var _usingCtx = babelHelpers.usingCtx();
44+
(0, _somewhere.doSomething)();
45+
var {
46+
b
47+
} = {};
48+
var c = 2;
49+
var A = class A {};
50+
var B = class B {};
51+
var x = _usingCtx.u(null);
52+
} catch (_) {
53+
_usingCtx.e = _;
54+
} finally {
55+
_usingCtx.d();
56+
}

packages/babel-plugin-proposal-explicit-resource-management/test/fixtures/transform-top-level/hoisting-default-class/output.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ export { C as default };
22
try {
33
var _usingCtx = babelHelpers.usingCtx();
44
var x = _usingCtx.u(null);
5-
var C = class {};
5+
var C = class C {};
66
} catch (_) {
77
_usingCtx.e = _;
88
} finally {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export class A { static get self() { return A } }
2+
3+
using x = null;
4+
5+
export class B { static get self() { return B } }
6+
7+
const AO = A, BO = B;
8+
A = B = null;
9+
10+
expect(AO.self).toBe(AO);
11+
expect(BO.self).toBe(BO);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export class A { static get self() { return A } }
2+
3+
using x = null;
4+
5+
export class B { static get self() { return B } }
6+
7+
A = B = null;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"sourceType": "module",
3+
"plugins": ["transform-modules-commonjs", "proposal-explicit-resource-management"]
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"use strict";
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
exports.B = exports.A = void 0;
7+
try {
8+
var _usingCtx = babelHelpers.usingCtx();
9+
var A = class A {
10+
static get self() {
11+
return A;
12+
}
13+
};
14+
var x = _usingCtx.u(null);
15+
var B = class B {
16+
static get self() {
17+
return B;
18+
}
19+
};
20+
exports.A = A = exports.B = B = null;
21+
} catch (_) {
22+
_usingCtx.e = _;
23+
} finally {
24+
_usingCtx.d();
25+
}

0 commit comments

Comments
 (0)