Skip to content

Commit 5addf13

Browse files
authored
fix: support named evaluation for using declaration (#17317)
* fix: support named evaluation for using declaration * test: mark tdz evaluation test as node 12+ * simplify output
1 parent 2def6ef commit 5addf13

6 files changed

Lines changed: 66 additions & 2 deletions

File tree

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

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,25 @@ const enum USING_KIND {
77
AWAIT,
88
}
99

10+
// https://tc39.es/ecma262/#sec-isanonymousfunctiondefinition
11+
// We don't test anonymous function / arrow function because they must not be disposable
12+
function isAnonymousFunctionDefinition(
13+
node: t.Node,
14+
): node is t.ClassExpression {
15+
return t.isClassExpression(node) && !node.id;
16+
}
17+
18+
function emitSetFunctionNameCall(
19+
state: PluginPass,
20+
expression: t.Expression,
21+
name: string,
22+
) {
23+
return t.callExpression(state.addHelper("setFunctionName"), [
24+
expression,
25+
t.stringLiteral(name),
26+
]);
27+
}
28+
1029
export default declare(api => {
1130
api.assertVersion(REQUIRED_VERSION("^7.22.0"));
1231

@@ -45,10 +64,11 @@ export default declare(api => {
4564
if (process.env.BABEL_8_BREAKING || state.availableHelper("usingCtx")) {
4665
let ctx: t.Identifier | null = null;
4766
let needsAwait = false;
67+
const scope = path.scope;
4868

4969
for (const node of path.node.body) {
5070
if (!isUsingDeclaration(node)) continue;
51-
ctx ??= path.scope.generateUidIdentifier("usingCtx");
71+
ctx ??= scope.generateUidIdentifier("usingCtx");
5272
const isAwaitUsing =
5373
node.kind === "await using" ||
5474
TOP_LEVEL_USING.get(node) === USING_KIND.AWAIT;
@@ -58,12 +78,18 @@ export default declare(api => {
5878
node.kind = "const";
5979
}
6080
for (const decl of node.declarations) {
81+
const currentInit = decl.init;
6182
decl.init = t.callExpression(
6283
t.memberExpression(
6384
t.cloneNode(ctx),
6485
isAwaitUsing ? t.identifier("a") : t.identifier("u"),
6586
),
66-
[decl.init],
87+
[
88+
isAnonymousFunctionDefinition(currentInit) &&
89+
t.isIdentifier(decl.id)
90+
? emitSetFunctionNameCall(state, currentInit, decl.id.name)
91+
: currentInit,
92+
],
6793
);
6894
}
6995
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
expect(() => {
2+
using fooTDZ = class { static self = fooTDZ }
3+
}).toThrow("Cannot access 'fooTDZ' before initialization")
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"plugins": [
3+
"proposal-explicit-resource-management"
4+
],
5+
"minNodeVersion": "12.0.0"
6+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
let log = [];
2+
let Symbol$dispose = Symbol.dispose || Symbol.for("Symbol.dispose");
3+
{
4+
using foo = class { static [Symbol$dispose]() { log.push(`${foo.name} is disposed`) } }
5+
log.push(foo.name);
6+
}
7+
8+
expect(log).toEqual(["foo", "foo is disposed"])
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
let log = [];
2+
let Symbol$dispose = Symbol.dispose || Symbol.for("Symbol.dispose");
3+
{
4+
using foo = class { static [Symbol$dispose]() { log.push(`${foo.name} is disposed`) } }
5+
log.push(foo.name);
6+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
let log = [];
2+
let Symbol$dispose = Symbol.dispose || Symbol.for("Symbol.dispose");
3+
try {
4+
var _usingCtx = babelHelpers.usingCtx();
5+
const foo = _usingCtx.u(babelHelpers.setFunctionName(class {
6+
static [Symbol$dispose]() {
7+
log.push(`${foo.name} is disposed`);
8+
}
9+
}, "foo"));
10+
log.push(foo.name);
11+
} catch (_) {
12+
_usingCtx.e = _;
13+
} finally {
14+
_usingCtx.d();
15+
}

0 commit comments

Comments
 (0)