@js-bits/xpromise
Advanced tools
Comparing version 0.3.3 to 1.0.0
@@ -5,2 +5,5 @@ /* eslint-disable no-console */ | ||
/** | ||
* @extends {ExtendablePromise<number>} | ||
*/ | ||
class MyPromise extends ExtendablePromise { | ||
@@ -7,0 +10,0 @@ // do whatever you need |
@@ -5,4 +5,6 @@ /* eslint-disable import/no-extraneous-dependencies, no-console */ | ||
describe('Examples', () => { | ||
/** @type {any} */ | ||
let consoleLog; | ||
beforeEach(() => { | ||
jest.spyOn(console, 'log'); | ||
consoleLog = jest.spyOn(console, 'log'); | ||
}); | ||
@@ -17,7 +19,7 @@ afterEach(() => { | ||
// await require('./example1.js'); | ||
expect(console.log).toHaveBeenCalledTimes(3); | ||
expect(console.log.mock.calls[0]).toEqual([true]); | ||
expect(console.log.mock.calls[1]).toEqual(['executed', expect.any(Function), expect.any(Function)]); | ||
expect(console.log.mock.calls[2]).toEqual([123]); | ||
expect(consoleLog).toHaveBeenCalledTimes(3); | ||
expect(consoleLog.mock.calls[0]).toEqual([true]); | ||
expect(consoleLog.mock.calls[1]).toEqual(['executed', expect.any(Function), expect.any(Function)]); | ||
expect(consoleLog.mock.calls[2]).toEqual([123]); | ||
}); | ||
}); |
65
index.js
@@ -7,26 +7,53 @@ import enumerate from '@js-bits/enumerate'; | ||
// TODO: replace with #privateField syntax when it gains wide support | ||
const ø = enumerate` | ||
const ø = enumerate.ts(` | ||
executor | ||
resolve | ||
reject | ||
`; | ||
`); | ||
const ERRORS = enumerate(Prefix('ExtendablePromise|'))` | ||
/** | ||
* @typedef {{ | ||
* InstantiationError: 'ExtendablePromise|InstantiationError', | ||
* ExecutionError: 'ExtendablePromise|ExecutionError' | ||
* }} ErrorsEnum | ||
*/ | ||
/** @type {ErrorsEnum} */ | ||
const ERRORS = enumerate.ts( | ||
` | ||
InstantiationError | ||
ExecutionError | ||
`; | ||
`, | ||
Prefix('ExtendablePromise|') | ||
); | ||
/** | ||
* @class | ||
* @extends {Promise} | ||
* @template T | ||
* @typedef {(value: T | PromiseLike<T>, ...rest:unknown[]) => void} Resolve | ||
*/ | ||
/** | ||
* @typedef {(reason?: Error) => void} Reject | ||
*/ | ||
/** | ||
* @template T | ||
* @extends {Promise<T>} | ||
*/ | ||
class ExtendablePromise extends Promise { | ||
static InstantiationError = ERRORS.InstantiationError; | ||
static ExecutionError = ERRORS.ExecutionError; | ||
/** | ||
* @param {Function} executor | ||
* @param {(resolve:Resolve<T>, reject:Reject, ...rest:unknown[]) => void} executor | ||
*/ | ||
constructor(executor) { | ||
/** @type {Resolve<T>} */ | ||
let resolve; | ||
/** @type {Reject} */ | ||
let reject; | ||
super((...args) => { | ||
[resolve, reject] = args; | ||
super((res, rej) => { | ||
resolve = res; | ||
reject = rej; | ||
}); | ||
@@ -51,4 +78,4 @@ this[ø.resolve] = resolve; | ||
/** | ||
* @param {...any} args | ||
* @returns {Promise} | ||
* @param {...unknown} args | ||
* @returns {ExtendablePromise<T>} | ||
*/ | ||
@@ -71,7 +98,7 @@ execute(...args) { | ||
/** | ||
* @param {any} result | ||
* @returns {Promise} | ||
* @param {T} result | ||
* @returns {ExtendablePromise<T>} | ||
*/ | ||
resolve(...args) { | ||
this[ø.resolve](...args); | ||
resolve(result) { | ||
this[ø.resolve](result); | ||
return this; | ||
@@ -82,6 +109,6 @@ } | ||
* @param {Error} reason | ||
* @returns {Promise} | ||
* @returns {ExtendablePromise<T>} | ||
*/ | ||
reject(...args) { | ||
this[ø.reject](...args); | ||
reject(reason) { | ||
this[ø.reject](reason); | ||
return this; | ||
@@ -91,4 +118,2 @@ } | ||
Object.assign(ExtendablePromise, ERRORS); | ||
// https://stackoverflow.com/a/60328122 | ||
@@ -95,0 +120,0 @@ Object.defineProperty(ExtendablePromise, Symbol.species, { get: () => Promise }); |
@@ -8,3 +8,5 @@ /* eslint-disable max-classes-per-file, import/no-extraneous-dependencies, no-unused-vars */ | ||
describe('ExtendablePromise', () => { | ||
/** @type {jest.Mock<() => void>} */ | ||
let executorFunc; | ||
/** @type {ExtendablePromise<string | number>} */ | ||
let promise; | ||
@@ -50,2 +52,3 @@ beforeEach(() => { | ||
try { | ||
// @ts-expect-error Argument of type 'number' is not assignable to parameter of type 'Function'. | ||
promise = new ExtendablePromise(123); | ||
@@ -64,6 +67,7 @@ } catch (error) { | ||
expect.assertions(3); | ||
/** @extends {ExtendablePromise<string>} */ | ||
class MyPromise extends ExtendablePromise { | ||
constructor() { | ||
super((resolve, reject) => { | ||
reject('async error'); | ||
reject(new Error('async error')); | ||
}); | ||
@@ -77,5 +81,5 @@ this.execute(); | ||
promise = new MyPromise(); | ||
result = await promise; | ||
result = /** @type {string} */ (await promise); | ||
} catch (error) { | ||
expect(error).toEqual('async error'); | ||
expect(error.message).toEqual('async error'); | ||
} | ||
@@ -89,2 +93,3 @@ expect(promise).toEqual(expect.any(ExtendablePromise)); | ||
expect.assertions(2); | ||
/** @extends {ExtendablePromise<string>} */ | ||
class MyPromise extends ExtendablePromise { | ||
@@ -141,3 +146,3 @@ constructor() { | ||
test('should reject the promise', async () => { | ||
expect.assertions(7); | ||
expect.assertions(8); | ||
expect(executorFunc).not.toHaveBeenCalled(); | ||
@@ -152,2 +157,3 @@ executorFunc.mockImplementation(() => { | ||
expect(error.name).toEqual('ExtendablePromise|ExecutionError'); | ||
expect(error.name).toEqual(ExtendablePromise.ExecutionError); | ||
expect(error.message).toEqual('Promise execution failed. See "cause" property for details'); | ||
@@ -175,3 +181,3 @@ expect(error.cause).toEqual(expect.any(Error)); | ||
}) | ||
.finally(result => { | ||
.finally((/** @type {unknown} */ result) => { | ||
expect(result).toBeUndefined(); | ||
@@ -194,2 +200,3 @@ }); | ||
expect.assertions(1); | ||
// @ts-expect-error Expected 1 arguments, but got 3. | ||
return promise.resolve(11, 22, 33).then((...args) => { | ||
@@ -236,7 +243,7 @@ expect(args).toEqual([11]); | ||
expect.assertions(2); | ||
expect(promise.reject('async error')).toBe(promise); | ||
expect(promise.reject(new Error('async error'))).toBe(promise); | ||
try { | ||
await promise; | ||
} catch (error) { | ||
expect(error).toEqual('async error'); | ||
expect(error.message).toEqual('async error'); | ||
} | ||
@@ -247,5 +254,5 @@ }); | ||
expect.assertions(4); | ||
let reject; | ||
const anotherPromise = new Promise((...args) => { | ||
[, reject] = args; | ||
let /** @type {{(reason?: any): void}} */ reject; | ||
const anotherPromise = new Promise((res, rej) => { | ||
reject = rej; | ||
}); | ||
@@ -290,13 +297,14 @@ reject('error'); | ||
const resolveFunc = jest.fn(); | ||
/** @extends {ExtendablePromise<boolean>} */ | ||
class ResolvedPromise extends ExtendablePromise { | ||
constructor(...args) { | ||
constructor() { | ||
super((resolve, reject) => { | ||
resolve(true); | ||
}, ...args); | ||
}); | ||
this.execute(); | ||
} | ||
resolve(...args) { | ||
resolveFunc(...args); | ||
super.resolve(...args); | ||
resolve(/** @type {boolean} */ result) { | ||
resolveFunc(result); | ||
return super.resolve(result); | ||
} | ||
@@ -313,15 +321,16 @@ } | ||
test('reject', async () => { | ||
expect.assertions(2); | ||
expect.assertions(3); | ||
const rejectFunc = jest.fn(); | ||
/** @extends {ExtendablePromise<boolean>} */ | ||
class RejectedPromise extends ExtendablePromise { | ||
constructor(...args) { | ||
constructor() { | ||
super((resolve, reject) => { | ||
reject(new Error('Rejected Promise')); | ||
}, ...args); | ||
}); | ||
this.execute(); | ||
} | ||
reject(...args) { | ||
rejectFunc(...args); | ||
super.reject(...args); | ||
reject(/** @type {Error} */ reason) { | ||
rejectFunc(reason); | ||
return super.reject(reason); | ||
} | ||
@@ -332,2 +341,3 @@ } | ||
expect(reason.message).toEqual('Rejected Promise'); | ||
expect(rejectFunc).toHaveBeenCalledWith(expect.any(Error)); | ||
expect(rejectFunc).toHaveBeenCalledTimes(1); | ||
@@ -376,2 +386,3 @@ }); | ||
expect.assertions(1); | ||
// @ts-expect-error Expected 0-1 arguments, but got 3. | ||
const promise = Promise.resolve(1, 2, 3); | ||
@@ -378,0 +389,0 @@ return promise.then((...args) => { |
{ | ||
"name": "@js-bits/xpromise", | ||
"version": "0.3.3", | ||
"version": "1.0.0", | ||
"description": "Extendable Promise", | ||
@@ -15,2 +15,3 @@ "keywords": [ | ||
"module": "./index.js", | ||
"types": "./dist/index.d.ts", | ||
"exports": { | ||
@@ -23,7 +24,8 @@ ".": { | ||
"scripts": { | ||
"build": "rollup ./index.js --format cjs --file dist/index.cjs --exports default", | ||
"build": "rimraf ./dist && yarn build:dts && rollup ./index.js --format cjs --file dist/index.cjs --exports default", | ||
"build:dts": "tsc ./index.js --allowJs --emitDeclarationOnly --declaration --outDir dist", | ||
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --verbose", | ||
"test-cjs": "jest --verbose", | ||
"test-watch": "yarn test --watch", | ||
"lint": "eslint '**/*.{js,jsx}'", | ||
"lint": "tsc --noEmit && eslint '**/*.{js,jsx}'", | ||
"prepare": "husky install" | ||
@@ -40,7 +42,9 @@ }, | ||
"@js-bits/log-in-color": "^0.3.1", | ||
"@types/jest": "^29.5.1", | ||
"@types/jest": "29.4.3", | ||
"husky": "^8.0.3", | ||
"jest": "^29.5.0", | ||
"jest-environment-jsdom": "^29.5.0", | ||
"rollup": "^3.23.0" | ||
"rimraf": "^5.0.1", | ||
"rollup": "^3.23.0", | ||
"typescript": "^4.8.4" | ||
}, | ||
@@ -67,4 +71,4 @@ "engines": { | ||
"dependencies": { | ||
"@js-bits/enumerate": "^0.10.0" | ||
"@js-bits/enumerate": "^1.0.9" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
25798
14
692
1
9
+ Added@js-bits/enumerate@1.0.20(transitive)
+ Added@js-bits/log-in-color@1.0.2(transitive)
+ Added@js-bits/typedef-utils@1.0.7(transitive)
- Removed@js-bits/enumerate@0.10.0(transitive)
Updated@js-bits/enumerate@^1.0.9