export type AddOnMap = { [name in string]: T | null | undefined | false } export type PluginHook = (context: C) => R type PluginHandle = { results: { ownerId: string result: R }[] getKeyedAddons: (field: F) => KeydMappedAddon[] } export type Plugin = { register: (hook: PluginHook) => void usePluginHooks: (context: C) => PluginHandle } type KeydAddon = T & { key: string } type KeydMappedAddon = A extends AddOnMap ? KeydAddon : KeydAddon export type PluginHookResult

> = P extends Plugin ? R : never export function pluginCreator(getPluginOwnerId: (hook: PluginHook) => string) { return createPlugin function createPlugin(): Plugin { const plugins: { hook: PluginHook; ownerId: string }[] = [] return { register, usePluginHooks, } function register(hook: PluginHook) { plugins.push({ hook, ownerId: getPluginOwnerId(hook), }) } function usePluginHooks(context: C) { const results = plugins.map(({ hook, ownerId }) => ({ ownerId, result: hook(context) })) return { results, getKeyedAddons, } function getKeyedAddons(field: F): KeydMappedAddon[] { return results .map[]>(({ ownerId, result }) => { const addonsMap = result[field] if (typeof addonsMap !== 'object' || !addonsMap) return [] return Object.entries(addonsMap).reduce((acc, [addonName, addon]) => { if (addon) { acc.push({ ...addon, key: `${ownerId}::${addonName}` }) } return acc }, [] as KeydMappedAddon[]) }) .flat() } } } }