Skip to content

Commit

Permalink
update await using behavior to match TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Jun 27, 2024
1 parent c8d1c4e commit 6475aea
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@

In addition, this release increases the minimum required node version for esbuild's JavaScript API from node 12 to node 18. Node 18 is the oldest version of node that is still being supported (see node's [release schedule](https://nodejs.org/en/about/previous-releases) for more information). This increase is because of an incompatibility between the JavaScript that the Go compiler generates for the `esbuild-wasm` package and versions of node before node 17.4 (specifically the `crypto.getRandomValues` function).

* Update `await using` behavior to match TypeScript

TypeScript 5.5 subtly changes the way `await using` behaves. This release updates esbuild to match these changes in TypeScript. You can read more about these changes in [microsoft/TypeScript#58624](https://github.com/microsoft/TypeScript/pull/58624).

## 0.21.5

* Fix `Symbol.metadata` on classes without a class decorator ([#3781](https://github.com/evanw/esbuild/issues/3781))
Expand Down
8 changes: 6 additions & 2 deletions internal/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -505,10 +505,14 @@ func Source(unsupportedJSFeatures compat.JSFeature) logger.Source {
export var __using = (stack, value, async) => {
if (value != null) {
if (typeof value !== 'object' && typeof value !== 'function') __typeError('Object expected')
var dispose
var dispose, inner
if (async) dispose = value[__knownSymbol('asyncDispose')]
if (dispose === void 0) dispose = value[__knownSymbol('dispose')]
if (dispose === void 0) {
dispose = value[__knownSymbol('dispose')]
if (async) inner = dispose
}
if (typeof dispose !== 'function') __typeError('Object not disposable')
if (inner) dispose = function() { try { inner.call(this) } catch (e) { return Promise.reject(e) } }
stack.push([async, dispose, value])
} else if (async) {
stack.push([async])
Expand Down
74 changes: 74 additions & 0 deletions scripts/end-to-end-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -8801,6 +8801,80 @@ for (const flags of [[], '--supported:async-await=false']) {
}
`,
}, { async: true }),

// From https://github.com/microsoft/TypeScript/pull/58624
test(['in.ts', '--outfile=node.js', '--supported:using=false', '--format=esm'].concat(flags), {
'in.ts': `
Symbol.asyncDispose ||= Symbol.for('Symbol.asyncDispose')
Symbol.dispose ||= Symbol.for('Symbol.dispose')
export const output: any[] = [];
export async function main() {
const promiseDispose = new Promise<void>((resolve) => {
setTimeout(() => {
output.push("y dispose promise body");
resolve();
}, 0);
});
{
await using x = {
async [Symbol.asyncDispose]() {
output.push("x asyncDispose body");
},
};
await using y = {
[Symbol.dispose]() {
output.push("y dispose body");
return promiseDispose;
},
};
}
output.push("body");
await promiseDispose;
return output;
}
export let async = async () => {
const output = await main()
const expected = [
"y dispose body",
"x asyncDispose body",
"body",
"y dispose promise body",
]
if (output.join(',') !== expected.join(',')) throw 'fail: ' + output
}
`,
}, { async: true }),
test(['in.ts', '--outfile=node.js', '--supported:using=false', '--format=esm'].concat(flags), {
'in.ts': `
Symbol.dispose ||= Symbol.for('Symbol.dispose')
export const output: any[] = [];
export async function main() {
const interleave = Promise.resolve().then(() => { output.push("interleave"); });
try {
await using x = {
[Symbol.dispose]() {
output.push("dispose");
throw null;
},
};
}
catch {
output.push("catch");
}
await interleave;
return output;
}
export let async = async () => {
const output = await main()
const expected = [
"dispose",
"interleave",
"catch",
]
if (output.join(',') !== expected.join(',')) throw 'fail: ' + output
}
`,
}, { async: true }),
)
}

Expand Down

0 comments on commit 6475aea

Please sign in to comment.