-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Changes from all commits
0cb73b3
0647856
8f082fc
688771f
80d0a84
a17aead
25a2fd3
40f546b
e0b9c73
08f41bd
7360338
587a1a4
3be9cf0
0b77050
bba71b1
2d4e506
ae6cbaf
afa64ca
5b6adea
7964b5f
0435db0
246a9a3
21b3e03
4a5ca67
b763f82
08a1434
2fc9bcf
1e8f045
3dc4011
8ad153a
51870e1
df5e591
558a502
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
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]; | ||
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 class MyResource {
[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. 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 @DanielRosenwasser has any thoughts on this approach, however. 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 }); | ||
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? 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.