import { mapDefined } from "@atp/common"; import { HydrationState } from "./hydration/index.ts"; export type SkeletonFn = ( input: SkeletonFnInput, ) => Promise | Skeleton; export type HydrationFn = ( input: HydrationFnInput, ) => Promise; export type RulesFn = ( input: RulesFnInput, ) => Skeleton; export type PresentationFn = ( input: PresentationFnInput, ) => View; export type PipelineDefinition = { skeleton: SkeletonFn; hydration: HydrationFn; rules?: RulesFn; presentation: PresentationFn; }; export function createPipeline( definition: PipelineDefinition, ): (params: Params, ctx: Context) => Promise; export function createPipeline( definition: PipelineDefinition, ) { const applyRules = definition.rules ?? ((input: RulesFnInput) => input.skeleton); return async (params: Params, ctx: Context) => { const skeleton = await definition.skeleton({ ctx, params }); const hydration = await definition.hydration({ ctx, params, skeleton }); const appliedRules = applyRules({ ctx, params, skeleton, hydration }); return definition.presentation({ ctx, params, skeleton: appliedRules, hydration, }); }; } export type SkeletonFnInput = { ctx: Context; params: Params; }; export type HydrationFnInput = { ctx: Context; params: Params; skeleton: Skeleton; }; export type RulesFnInput = { ctx: Context; params: Params; skeleton: Skeleton; hydration: HydrationState; }; export type PresentationFnInput = { ctx: Context; params: Params; skeleton: Skeleton; hydration: HydrationState; }; type SkeletonListKey = { [K in keyof S]: S[K] extends readonly unknown[] ? K : never; }[keyof S]; type SkeletonListItem = T extends readonly (infer Item)[] ? Item : never; export function filterSkeletonList< Skeleton extends Record, Key extends SkeletonListKey, >( skeleton: Skeleton, key: Key, predicate: (item: SkeletonListItem) => boolean, ): Skeleton { const items = skeleton[key] as SkeletonListItem[]; return { ...skeleton, [key]: items.filter(predicate), } as Skeleton; } export function mapSkeletonList< Skeleton extends Record, Key extends SkeletonListKey, View, >( skeleton: Skeleton, key: Key, mapper: (item: SkeletonListItem) => View | undefined, ): View[] { const items = skeleton[key] as SkeletonListItem[]; return mapDefined(items, mapper); }