import type { IPlugin } from "./api.js"; /** * Base Higher-Kinded Type for plugin resource augmentation. * * Plugin authors extend this and override `resourceType` / `commandType` * using `this['_TArgs']` and `this['_TData']` to refer to the resource's * type parameters. * * @example * ```ts * interface MyPluginHKT extends PluginHKT { * readonly resourceType: { myHook: (args: this['_TArgs']) => this['_TData'] }; * } * ``` */ export interface PluginHKT { /** @phantom — substituted with the resource/command TArgs at application site */ readonly _TArgs: unknown; /** @phantom — substituted with the resource/command TData at application site */ readonly _TData: unknown; /** @phantom — substituted with the api's TError at application site */ readonly _TError: unknown; /** Override in subinterfaces to declare resource augmentation shape. */ readonly resourceType: {}; /** Override in subinterfaces to declare command augmentation shape. */ readonly commandType: {}; /** * Override in subinterfaces to declare *additional* augmentation for projection * resources (on top of `resourceType`, which projection resources receive too). * `_TData` is the projection item array type (`TItem[]`). */ readonly projectionResourceType: {}; } /** * "Apply" a PluginHKT — substitute TArgs/TData/TError and extract the resource augmentation type. * * Mechanism: intersect the HKT interface with concrete `{ _TArgs: TArgs; _TData: TData; _TError: TError }`. * Because `resourceType` references `this['_TArgs']`/`this['_TData']`/`this['_TError']`, and `this` in the * intersection resolves to the merged type, the phantom parameters become concrete. */ type ApplyPluginResourceHKT = (F & { readonly _TArgs: TArgs; readonly _TData: TData; readonly _TError: TError; })["resourceType"]; type ApplyPluginCommandHKT = (F & { readonly _TArgs: TArgs; readonly _TData: TData; readonly _TError: TError; })["commandType"]; type ApplyPluginProjectionResourceHKT = (F & { readonly _TArgs: TArgs; readonly _TData: TData; readonly _TError: TError; })["projectionResourceType"]; /** * Extract and apply the resource augmentation from a single plugin type. * Returns `{}` if the plugin does not declare an HKT (graceful degradation). * * Uses bounded `infer H extends PluginHKT` to reject `undefined` from optional `_hkt`. */ type ExtractResourceAugment = P extends { readonly _hkt: infer H extends PluginHKT; } ? ApplyPluginResourceHKT : {}; type ExtractCommandAugment = P extends { readonly _hkt: infer H extends PluginHKT; } ? ApplyPluginCommandHKT : {}; type ExtractProjectionResourceAugment = P extends { readonly _hkt: infer H extends PluginHKT; } ? ApplyPluginProjectionResourceHKT : {}; /** Standard union-to-intersection utility. */ type UnionToIntersection = (U extends unknown ? (x: U) => void : never) extends (x: infer I) => void ? I : never; /** * Combine resource augmentations from all plugins in the tuple. * Maps each `TPlugins[number]` through `ExtractResourceAugment`, then intersects the results. * * - `readonly [ReactHooksPlugin, OtherPlugin]` → `{ useResource: ... } & { otherHook: ... }` * - `readonly IPlugin[]` (default) → `{}` (no augmentation) */ export type CombinePluginResourceAugments = UnionToIntersection>; export type CombinePluginCommandAugments = UnionToIntersection>; /** * Combine the *projection-specific* augmentations from all plugins in the tuple. * Applied on top of {@link CombinePluginResourceAugments} for projection resources; * `TData` is the projection item array type (`TItem[]`). */ export type CombinePluginProjectionResourceAugments = UnionToIntersection>; export type { ApplyPluginResourceHKT, ApplyPluginCommandHKT, ApplyPluginProjectionResourceHKT, ExtractResourceAugment, ExtractCommandAugment, ExtractProjectionResourceAugment, UnionToIntersection, };