Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 13.7k
Support using and await using declarations#54505
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
0cb73b306478568f082fc688771f80d0a84a17aead25a2fd340f546be0b9c7308f41bd7360338587a1a43be9cf00b77050bba71b12d4e506ae6cbafafa64ca5b6adea7964b5f0435db0246a9a321b3e034a5ca67b763f8208a14342fc9bcf1e8f0453dc40118ad153a51870e1df5e591558a502File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Diff view
Diff view
Uh oh!
There was an error while loading. Please reload this page.
There are no files selected for viewing
Large diffs are not rendered by default.
Uh oh!
There was an error while loading. Please reload this page.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -451,18 +451,14 @@ | ||
| "category": "Error", | ||
| "code": 1149 | ||
| }, | ||
| "'const' declarations must be initialized.": { | ||
| "'{0}' declarations must be initialized.": { | ||
| "category": "Error", | ||
| "code": 1155 | ||
| }, | ||
| "'const' declarations can only be declared inside a block.": { | ||
| "'{0}' declarations can only be declared inside a block.": { | ||
| "category": "Error", | ||
| "code": 1156 | ||
| }, | ||
| "'let' declarations can only be declared inside a block.": { | ||
| "category": "Error", | ||
| "code": 1157 | ||
| }, | ||
| "Unterminated template literal.": { | ||
| "category": "Error", | ||
| "code": 1160 | ||
| @@ -1601,6 +1597,26 @@ | ||
| "category": "Error", | ||
| "code": 1490 | ||
| }, | ||
| "'{0}' modifier cannot appear on a 'using' declaration.": { | ||
| "category": "Error", | ||
| "code": 1491 | ||
| }, | ||
| "'{0}' declarations may not have binding patterns.": { | ||
| "category": "Error", | ||
| "code": 1492 | ||
| }, | ||
| "The left-hand side of a 'for...in' statement cannot be a 'using' declaration.": { | ||
| "category": "Error", | ||
| "code": 1493 | ||
| }, | ||
| "The left-hand side of a 'for...in' statement cannot be an 'await using' declaration.": { | ||
| "category": "Error", | ||
| "code": 1494 | ||
| }, | ||
| "'{0}' modifier cannot appear on an 'await using' declaration.": { | ||
| "category": "Error", | ||
| "code": 1495 | ||
| }, | ||
| "The types of '{0}' are incompatible between these types.": { | ||
| "category": "Error", | ||
| @@ -3623,6 +3639,26 @@ | ||
| "category": "Error", | ||
| "code": 2849 | ||
| }, | ||
| "The initializer of a 'using' declaration must be either an object with a '[Symbol.dispose]()' method, or be 'null' or 'undefined'.": { | ||
| "category": "Error", | ||
| "code": 2850 | ||
| }, | ||
| "The initializer of an 'await using' declaration must be either an object with a '[Symbol.asyncDispose]()' or '[Symbol.dispose]()' method, or be 'null' or 'undefined'.": { | ||
| "category": "Error", | ||
| "code": 2851 | ||
| }, | ||
| "'await using' statements are only allowed within async functions and at the top levels of modules.": { | ||
| "category": "Error", | ||
| "code": 2852 | ||
| }, | ||
rbuckton marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| "'await using' statements are only allowed at the top level of a file when that file is a module, but this file has no imports or exports. Consider adding an empty 'export {}' to make this file a module.": { | ||
| "category": "Error", | ||
| "code": 2853 | ||
| }, | ||
| "Top-level 'await using' statements are only allowed when the 'module' option is set to 'es2022', 'esnext', 'system', 'node16', or 'nodenext', and the 'target' option is set to 'es2017' or higher.": { | ||
| "category": "Error", | ||
| "code": 2854 | ||
| }, | ||
| "Import declaration '{0}' is using private name '{1}'.": { | ||
| "category": "Error", | ||
| @@ -7749,11 +7785,11 @@ | ||
| "category": "Error", | ||
| "code": 18036 | ||
| }, | ||
| "Await expression cannot be used inside a class static block.": { | ||
| "'await' expression cannot be used inside a class static block.": { | ||
| "category": "Error", | ||
| "code": 18037 | ||
| }, | ||
| "'For await' loops cannot be used inside a class static block.": { | ||
| "'for await' loops cannot be used inside a class static block.": { | ||
| "category": "Error", | ||
| "code": 18038 | ||
| }, | ||
| @@ -7812,5 +7848,9 @@ | ||
| "Its type '{0}' is not a valid JSX element type.": { | ||
| "category": "Error", | ||
| "code": 18053 | ||
| }, | ||
| "'await using' statements cannot be used inside a class static block.": { | ||
| "category": "Error", | ||
| "code": 18054 | ||
| } | ||
rbuckton marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -136,6 +136,9 @@ export interface EmitHelperFactory { | ||
| createClassPrivateFieldGetHelper(receiver: Expression, state: Identifier, kind: PrivateIdentifierKind, f: Identifier | undefined): Expression; | ||
| createClassPrivateFieldSetHelper(receiver: Expression, state: Identifier, value: Expression, kind: PrivateIdentifierKind, f: Identifier | undefined): Expression; | ||
| createClassPrivateFieldInHelper(state: Identifier, receiver: Expression): Expression; | ||
| // 'using' helpers | ||
| createAddDisposableResourceHelper(envBinding: Expression, value: Expression, async: boolean): Expression; | ||
| createDisposeResourcesHelper(envBinding: Expression): Expression; | ||
| } | ||
| /** @internal */ | ||
| @@ -183,7 +186,10 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel | ||
| // Class Fields Helpers | ||
| createClassPrivateFieldGetHelper, | ||
| createClassPrivateFieldSetHelper, | ||
| createClassPrivateFieldInHelper | ||
| createClassPrivateFieldInHelper, | ||
| // 'using' helpers | ||
| createAddDisposableResourceHelper, | ||
| createDisposeResourcesHelper, | ||
| }; | ||
| /** | ||
| @@ -666,6 +672,20 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel | ||
| context.requestEmitHelper(classPrivateFieldInHelper); | ||
| return factory.createCallExpression(getUnscopedHelperName("__classPrivateFieldIn"), /*typeArguments*/ undefined, [state, receiver]); | ||
| } | ||
| function createAddDisposableResourceHelper(envBinding: Expression, value: Expression, async: boolean): Expression { | ||
| context.requestEmitHelper(addDisposableResourceHelper); | ||
| return factory.createCallExpression( | ||
| getUnscopedHelperName("__addDisposableResource"), | ||
| /*typeArguments*/ undefined, | ||
| [envBinding, value, async ? factory.createTrue() : factory.createFalse()] | ||
| ); | ||
| } | ||
| function createDisposeResourcesHelper(envBinding: Expression) { | ||
| context.requestEmitHelper(disposeResourcesHelper); | ||
| return factory.createCallExpression(getUnscopedHelperName("__disposeResources"), /*typeArguments*/ undefined, [envBinding]); | ||
| } | ||
| } | ||
| /** @internal */ | ||
| @@ -1367,6 +1387,71 @@ export const classPrivateFieldInHelper: UnscopedEmitHelper = { | ||
| };` | ||
| }; | ||
| /** | ||
| * @internal | ||
| */ | ||
| export const addDisposableResourceHelper: UnscopedEmitHelper = { | ||
| name: "typescript:addDisposableResource", | ||
| importName: "__addDisposableResource", | ||
| scoped: false, | ||
| text: ` | ||
| var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) { | ||
| if (value !== null && value !== void 0) { | ||
| if (typeof value !== "object") throw new TypeError("Object expected."); | ||
| var dispose; | ||
| if (async) { | ||
| if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); | ||
| dispose = value[Symbol.asyncDispose]; | ||
| } | ||
| if (dispose === void 0) { | ||
| if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); | ||
| dispose = value[Symbol.dispose]; | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In Babel we use classMyResource{[Symbol.dispose||Symbol.for("Symbol.dispose")](){}}and they will be usable both natively and in older environments. It might be great to align on this. ContributorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TypeScript helpers generally don't polyfill/shim Symbols in this way. We usually depend on the developer to introduce any necessary global shim instead. I'm curious if Daniel Rosenwasser (@DanielRosenwasser) has any thoughts on this approach, however. ContributorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We discussed this in design meeting and don't believe TypeScript should support Babel supporting for While I think it is commendable to support users' efforts to avoid global scope modifications, I don't think this is an approach TypeScript can take here. I'd even go so far as to recommend that Babel not provide such support, but given that Babel's support for I'll also note that, since the native | ||
| } | ||
| if (typeof dispose !== "function") throw new TypeError("Object not disposable."); | ||
| env.stack.push({ value: value, dispose: dispose, async: async }); | ||
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unrelated: at what point will it be OK for us to use es6 features like object shorthands in our esnext downlevel helpers? ContributorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If our helpers were an AST instead of a string, then we could arguably downlevel them on demand. Unfortunately, that wouldn't work for | ||
| } | ||
| else if (async) { | ||
| env.stack.push({ async: true }); | ||
| } | ||
| return value; | ||
| };` | ||
| }; | ||
| /** | ||
| * @internal | ||
| */ | ||
| export const disposeResourcesHelper: UnscopedEmitHelper = { | ||
| name: "typescript:disposeResources", | ||
| importName: "__disposeResources", | ||
| scoped: false, | ||
| text: ` | ||
| var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) { | ||
| return function (env) { | ||
| function fail(e) { | ||
| env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e; | ||
| env.hasError = true; | ||
| } | ||
| function next() { | ||
| while (env.stack.length) { | ||
| var rec = env.stack.pop(); | ||
| try { | ||
| var result = rec.dispose && rec.dispose.call(rec.value); | ||
| if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); }); | ||
| } | ||
| catch (e) { | ||
| fail(e); | ||
| } | ||
| } | ||
| if (env.hasError) throw env.error; | ||
| } | ||
| return next(); | ||
| }; | ||
| })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { | ||
| var e = new Error(message); | ||
| return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; | ||
| });` | ||
| }; | ||
| let allUnscopedEmitHelpers: ReadonlyMap<string, UnscopedEmitHelper> | undefined; | ||
| /** @internal */ | ||
| @@ -1399,7 +1484,9 @@ export function getAllUnscopedEmitHelpers() { | ||
| classPrivateFieldSetHelper, | ||
| classPrivateFieldInHelper, | ||
| createBindingHelper, | ||
| setModuleDefaultHelper | ||
| setModuleDefaultHelper, | ||
| addDisposableResourceHelper, | ||
| disposeResourcesHelper, | ||
| ], helper => helper.name)); | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.