From 8b354be7d19eedbc6229a345d73377edfb1841ec Mon Sep 17 00:00:00 2001 From: Matthew Costabile Date: Thu, 17 Oct 2024 12:54:43 +0000 Subject: [PATCH 1/2] polyfill for Promise.withResolvers --- src/index.ts | 2 ++ src/promise-withResolvers.ts | 30 ++++++++++++++++++++++++++ test/promise-withResolvers.js | 40 +++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 src/promise-withResolvers.ts create mode 100644 test/promise-withResolvers.js diff --git a/src/index.ts b/src/index.ts index ac1003d..4c14a1a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ import * as clipboardItem from './clipboarditem.js' import * as elementCheckVisibility from './element-checkvisibility.js' import * as navigatorClipboard from './navigator-clipboard.js' +import * as withResolvers from './promise-withResolvers.js' import * as requestIdleCallback from './requestidlecallback.js' let supportsModalPseudo = false @@ -47,6 +48,7 @@ export const polyfills = { elementCheckVisibility, navigatorClipboard, requestIdleCallback, + withResolvers, } export function isSupported() { diff --git a/src/promise-withResolvers.ts b/src/promise-withResolvers.ts new file mode 100644 index 0000000..62d4252 --- /dev/null +++ b/src/promise-withResolvers.ts @@ -0,0 +1,30 @@ +/*#__PURE__*/ +export function withResolvers(this: PromiseConstructor) { + const out = {} as { + promise: Promise + resolve: (value: T | PromiseLike) => void + // eslint-disable-next-line @typescript-eslint/no-explicit-any + reject: (reason?: any) => void + } + out.promise = new Promise((resolve, reject) => { + out.resolve = resolve + out.reject = reject + }) + return out +} + +/*#__PURE__*/ +export function isSupported(): boolean { + return 'withResolvers' in Promise && typeof Promise.withResolvers === 'function' +} + +/*#__PURE__*/ +export function isPolyfilled(): boolean { + return 'withResolvers' in Promise && Promise.withResolvers === withResolvers +} + +export function apply(): void { + if (!('withResolvers' in Promise)) { + Object.assign(Promise, {withResolvers}) + } +} diff --git a/test/promise-withResolvers.js b/test/promise-withResolvers.js new file mode 100644 index 0000000..a817cf9 --- /dev/null +++ b/test/promise-withResolvers.js @@ -0,0 +1,40 @@ +import {apply, isPolyfilled, isSupported, withResolvers} from '../lib/promise-withResolvers.js' + +describe('withResolvers', () => { + it('has standard isSupported, isPolyfilled, apply API', () => { + expect(isSupported).to.be.a('function') + expect(isPolyfilled).to.be.a('function') + expect(apply).to.be.a('function') + expect(isSupported()).to.be.a('boolean') + expect(isPolyfilled()).to.equal(false) + }) + + it('resolves to first resolving value', async () => { + const arg = withResolvers() + expect(Object.keys(arg).sort()).to.eql(['promise', 'reject', 'resolve']) + expect(arg).to.have.property('promise').to.be.a('promise') + expect(arg).to.have.property('resolve').to.be.a('function') + expect(arg).to.have.property('reject').to.be.a('function') + + arg.resolve(1) + expect(await arg.promise).to.be.eql(1) + }) + + it('rejects to first rejecting reason', async () => { + const arg = withResolvers() + expect(Object.keys(arg).sort()).to.eql(['promise', 'reject', 'resolve']) + expect(arg).to.have.property('promise').to.be.a('promise') + expect(arg).to.have.property('resolve').to.be.a('function') + expect(arg).to.have.property('reject').to.be.a('function') + + const err = new Error('rejected') + + try { + arg.reject(err) + await arg.promise + expect.fail('should fail') + } catch (e) { + expect(e).to.be.eql(err) + } + }) +}) From 3a29ef565943ed01aff0ffa7d3c64426c067d122 Mon Sep 17 00:00:00 2001 From: Matthew Costabile Date: Thu, 17 Oct 2024 13:21:06 +0000 Subject: [PATCH 2/2] use is supported check --- src/promise-withResolvers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/promise-withResolvers.ts b/src/promise-withResolvers.ts index 62d4252..04be228 100644 --- a/src/promise-withResolvers.ts +++ b/src/promise-withResolvers.ts @@ -24,7 +24,7 @@ export function isPolyfilled(): boolean { } export function apply(): void { - if (!('withResolvers' in Promise)) { + if (!isSupported()) { Object.assign(Promise, {withResolvers}) } }