limit-once
Advanced tools
Comparing version 0.15.0 to 0.16.0
@@ -1,2 +0,2 @@ | ||
export { OncedFn, once } from './once.js'; | ||
export { OncedAsyncFn, onceAsync } from './once-async.js'; | ||
export { once, type OncedFn } from './once.js'; | ||
export { onceAsync, type OncedAsyncFn } from './once-async.js'; |
@@ -1,6 +0,3 @@ | ||
import { once } from "./once"; | ||
import { onceAsync } from "./once-async"; | ||
export { | ||
once, | ||
onceAsync | ||
}; | ||
export { once } from './once.js'; | ||
export { onceAsync } from './once-async.js'; | ||
//# sourceMappingURL=index.js.map |
type ResultValue<TFunc extends (this: any, ...args: any[]) => Promise<any>> = Awaited<ReturnType<TFunc>>; | ||
type OncedAsyncFn<TFunc extends (this: any, ...args: any[]) => Promise<any>> = { | ||
export type OncedAsyncFn<TFunc extends (this: any, ...args: any[]) => Promise<any>> = { | ||
/** | ||
@@ -25,4 +25,3 @@ * Clear the cached `"fulfilled"` promise. | ||
*/ | ||
declare function onceAsync<TFunc extends (...args: any[]) => Promise<any>>(fn: TFunc): OncedAsyncFn<TFunc>; | ||
export { type OncedAsyncFn, onceAsync }; | ||
export declare function onceAsync<TFunc extends (...args: any[]) => Promise<any>>(fn: TFunc): OncedAsyncFn<TFunc>; | ||
export {}; |
@@ -1,48 +0,65 @@ | ||
function onceAsync(fn) { | ||
let state = { | ||
type: "initial" | ||
}; | ||
function onced(...args) { | ||
if (state.type === "fulfilled") { | ||
return state.promise; | ||
/** | ||
* Creates a new function that will cache the result of it's first call. | ||
* | ||
* @example | ||
* async function getUser() { | ||
* return fetch('/user').json(); | ||
* } | ||
* const getUserOnce = once(getUser); | ||
* | ||
* const user1 = await getUserOnce(); | ||
* // returns "fulfilled" `getUser()` promise value | ||
* | ||
* const user2 = await getUserOnce(); | ||
* // `getUser()` not called, previously "fulfilled" value returned | ||
*/ | ||
export function onceAsync(fn) { | ||
let state = { | ||
type: 'initial', | ||
}; | ||
function onced(...args) { | ||
if (state.type === 'fulfilled') { | ||
return state.promise; | ||
} | ||
if (state.type === 'pending') { | ||
return state.promise; | ||
} | ||
let rejectPendingPromise; | ||
function abort() { | ||
// TODO: should we reject with an error? | ||
rejectPendingPromise?.(); | ||
} | ||
const promise = new Promise((resolve, reject) => { | ||
rejectPendingPromise = reject; | ||
fn.call(this, ...args) | ||
.then((result) => { | ||
state = { | ||
type: 'fulfilled', | ||
promise, | ||
}; | ||
resolve(result); | ||
}) | ||
.catch((...args) => { | ||
// allow the promise to be tried again | ||
state = { type: 'initial' }; | ||
reject(...args); | ||
}); | ||
}); | ||
state = { | ||
type: 'pending', | ||
promise, | ||
abort, | ||
}; | ||
return promise; | ||
} | ||
if (state.type === "pending") { | ||
return state.promise; | ||
} | ||
let rejectPendingPromise; | ||
function abort() { | ||
rejectPendingPromise == null ? void 0 : rejectPendingPromise(); | ||
} | ||
const promise = new Promise((resolve, reject) => { | ||
rejectPendingPromise = reject; | ||
fn.call(this, ...args).then((result) => { | ||
onced.clear = function clear() { | ||
if (state.type === 'pending') { | ||
state.abort(); | ||
} | ||
state = { | ||
type: "fulfilled", | ||
promise | ||
type: 'initial', | ||
}; | ||
resolve(result); | ||
}).catch((...args2) => { | ||
state = { type: "initial" }; | ||
reject(...args2); | ||
}); | ||
}); | ||
state = { | ||
type: "pending", | ||
promise, | ||
abort | ||
}; | ||
return promise; | ||
} | ||
onced.clear = function clear() { | ||
if (state.type === "pending") { | ||
state.abort(); | ||
} | ||
state = { | ||
type: "initial" | ||
}; | ||
}; | ||
return onced; | ||
return onced; | ||
} | ||
export { | ||
onceAsync | ||
}; | ||
//# sourceMappingURL=once-async.js.map |
@@ -1,2 +0,2 @@ | ||
type OncedFn<TFunc extends (this: any, ...args: any[]) => any> = { | ||
export type OncedFn<TFunc extends (this: any, ...args: any[]) => any> = { | ||
/** | ||
@@ -21,4 +21,2 @@ * Clear the cached result. | ||
*/ | ||
declare function once<TFunc extends (...args: any[]) => any>(fn: TFunc): OncedFn<TFunc>; | ||
export { type OncedFn, once }; | ||
export declare function once<TFunc extends (...args: any[]) => any>(fn: TFunc): OncedFn<TFunc>; |
@@ -1,16 +0,26 @@ | ||
function once(fn) { | ||
let cache = null; | ||
function result(...args) { | ||
if (!cache) { | ||
cache = { value: fn.call(this, ...args) }; | ||
/** | ||
* Creates a new function that will cache the result of it's first call. | ||
* | ||
* @example | ||
* function sayHello(name: string): string { | ||
* return `Hello ${name}`; | ||
* } | ||
* const cached = once(sayHello); | ||
* | ||
* cached('Alex'); // returns "Hello Alex" | ||
* cached('Sam'); // returns "Hello Alex" (underlying `sayHello` function not called) | ||
*/ | ||
export function once(fn) { | ||
let cache = null; | ||
function result(...args) { | ||
if (!cache) { | ||
cache = { value: fn.call(this, ...args) }; | ||
} | ||
return cache.value; | ||
} | ||
return cache.value; | ||
} | ||
result.clear = function clear() { | ||
cache = null; | ||
}; | ||
return result; | ||
result.clear = function clear() { | ||
cache = null; | ||
}; | ||
return result; | ||
} | ||
export { | ||
once | ||
}; | ||
//# sourceMappingURL=once.js.map |
{ | ||
"name": "limit-once", | ||
"description": "Remember the first result of a function call", | ||
"version": "0.15.0", | ||
"version": "0.16.0", | ||
"author": "Alex Reardon <alexreardon@gmail.com>", | ||
@@ -10,3 +10,3 @@ "license": "MIT", | ||
"type": "git", | ||
"url": "https://github.com/alexreardon/limit-once.git" | ||
"url": "git+https://github.com/alexreardon/limit-once.git" | ||
}, | ||
@@ -18,15 +18,10 @@ "keywords": [ | ||
"performance", | ||
"memoize", | ||
"memoization" | ||
"rate limit" | ||
], | ||
"sideEffects": false, | ||
"type": "module", | ||
"main": "./dist/index.cjs", | ||
"exports": { | ||
"types": { | ||
"import": "./dist/index.d.ts", | ||
"require": "./dist/index.d.cts" | ||
}, | ||
"import": "./dist/index.js", | ||
"require": "./dist/index.cjs" | ||
".": "./dist/index.js", | ||
"./once": "./dist/once.js", | ||
"./once-async": "./dist/once-async.js" | ||
}, | ||
@@ -41,9 +36,10 @@ "engines": { | ||
"scripts": { | ||
"prepublishOnly": "bun build:dist", | ||
"build:dist": "bun build:clean && bun tsup", | ||
"prepublishOnly": "bun build:all", | ||
"build:all": "bun build:clean && bun build:dist", | ||
"build:dist": "tsc --project ./tsconfig.output.json", | ||
"build:clean": "rimraf ./dist", | ||
"check:all": "bun check:prettier && bun check:typescript && bun check:dist", | ||
"check:all": "bun check:prettier && bun check:typescript", | ||
"check:prettier": "prettier --debug-check src/**/*.ts test/**/*.ts", | ||
"check:typescript": "tsc", | ||
"check:dist": "attw --pack ." | ||
"#check:dist": "attw --pack ." | ||
}, | ||
@@ -54,8 +50,7 @@ "devDependencies": { | ||
"expect-type": "^0.19.0", | ||
"prettier": "^3.2.5", | ||
"rimraf": "^5.0.7", | ||
"prettier": "^3.3.3", | ||
"rimraf": "^5.0.10", | ||
"tiny-invariant": "^1.3.3", | ||
"tsup": "^8.0.2", | ||
"typescript": "^5.4.5" | ||
"typescript": "^5.5.4" | ||
} | ||
} |
@@ -7,7 +7,4 @@ # limit-once | ||
> [!NOTE] | ||
> This package is still under construction | ||
Features | ||
Features: | ||
- [Synchronous variant](#synchronous-variant) (tiny `150B`) | ||
@@ -249,1 +246,7 @@ - [Asynchronous variant for promises](#asynchronous-variant) (tiny `360B`) | ||
``` | ||
## Outputs | ||
- `limit-once` is a [dual package](https://nodejs.org/api/packages.html#dual-commonjses-module-packages) that supports ECMAScript modules (esm) and CommonJS (cjs) | ||
- Distributed files are [compiled to "es6"](https://www.typescriptlang.org/tsconfig/#target) which has [wide support](https://caniuse.com/?search=es6) | ||
- Internet Explorer 11 not supported (it does not support "es6") |
@@ -1,2 +0,2 @@ | ||
export { once, type OncedFn } from './once'; | ||
export { onceAsync, type OncedAsyncFn } from './once-async'; | ||
export { once, type OncedFn } from './once.js'; | ||
export { onceAsync, type OncedAsyncFn } from './once-async.js'; |
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
7
251
19655
15
260