Created
April 2, 2022 01:32
-
-
Save hgiesel/094d83569d2fb79f5e08a6c475a413c7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface TaggedHookCallback<T> { | |
type: "hook"; | |
callback: HookCallback<T>; | |
} | |
type FilterCallback<T, U> = (input: T) => Promise<U> | U; | |
interface TaggedFilterCallback<T, U> { | |
type: "filter"; | |
callback: FilterCallback<T, U>; | |
} | |
type FilterCallbackSum<T, U> = TaggedHookCallback<T> | TaggedFilterCallback<T, U>; | |
type Reconstruct<Whole, Part> = (oldWhole: Whole, newPart: Part) => Whole; | |
function isHook<T, U>( | |
callback: FilterCallbackSum<T, U>, | |
): callback is TaggedHookCallback<T> { | |
return callback.type === "hook"; | |
} | |
export interface FiltersAPI<T, U> extends HooksAPI<T> { | |
filter(callback: FilterCallback<T, U>): Callback; | |
} | |
type RunFilters<T> = (input: T) => Promise<T>; | |
export function filters<Whole, Part>( | |
reconstruct: Reconstruct<Whole, Part>, | |
): [FiltersAPI<Whole, Part>, RunFilters<Whole>] { | |
const filtersList: FilterCallbackSum<Whole, Part>[] = []; | |
function hook(callback: HookCallback<Whole>): Callback { | |
const tagged: TaggedHookCallback<Whole> = { type: "hook", callback }; | |
filtersList.push(tagged); | |
return () => removeItem(filtersList, tagged); | |
} | |
function filter(callback: FilterCallback<Whole, Part>): Callback { | |
const tagged: TaggedFilterCallback<Whole, Part> = { type: "filter", callback }; | |
filtersList.push(tagged); | |
return () => removeItem(filtersList, tagged); | |
} | |
async function run(input: Whole): Promise<Whole> { | |
const promises: (void | Promise<void>)[] = []; | |
let next = Promise.resolve(input); | |
for (const item of filtersList) { | |
if (isHook(item)) { | |
const { callback: hook } = item; | |
try { | |
const value = await next; | |
const result = hook(value); | |
promises.push(result); | |
} catch (error) { | |
console.log("Hook failed: ", error); | |
} | |
} else { | |
const { callback: filter } = item; | |
const oldWhole = await next; | |
const newPart = await Promise.resolve(filter(oldWhole)); | |
next = Promise.resolve(reconstruct(oldWhole, newPart)); | |
} | |
} | |
await Promise.allSettled(promises); | |
return next; | |
} | |
const filtersApi = { | |
hook, | |
filter, | |
}; | |
return [filtersApi, run]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment