Skip to content

Instantly share code, notes, and snippets.

@hgiesel
Created April 2, 2022 01:32
Show Gist options
  • Save hgiesel/094d83569d2fb79f5e08a6c475a413c7 to your computer and use it in GitHub Desktop.
Save hgiesel/094d83569d2fb79f5e08a6c475a413c7 to your computer and use it in GitHub Desktop.
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