import type { Expand, ParsedArgs } from '@cli-forge/parser'; import { CLI } from './public-api'; /** * Extracts the TChildren type parameter from a CLI type. */ export type ExtractChildren = T extends CLI ? C : never; /** * Extracts the TArgs type parameter from a CLI type. */ export type ExtractArgs = T extends CLI ? A : never; /** * Type for a composable builder function that transforms a CLI. * Used with `chain` to compose multiple builders. */ export type ComposableBuilder< TArgs2 extends ParsedArgs, TAddedChildren = {}, TAddedProviders = {} > = ( init: CLI ) => CLI, THandlerReturn, TChildren & TAddedChildren, TParent, TProviders & TAddedProviders>; /** * Creates a composable builder function that can be used with `chain`. * Can be used to add options, commands, or any other CLI modifications. * Children added by the builder function are properly tracked in the type. * * The builder function runs once at creation time against a recording Proxy. * Subsequent applications replay the captured operations, ensuring inline * middleware closures have stable references for Set-based deduplication. * * @typeParam TArgs2 - The args type after the builder runs * @typeParam TChildren2 - The children type added by the builder * @typeParam TProviders2 - The providers type added by the builder */ export function makeComposableBuilder< TArgs2 extends ParsedArgs, TChildren2 = {}, TProviders2 = {} >( fn: ( init: CLI ) => CLI ) { // Run builder once against a recording proxy to capture operations. // Replaying these ensures inline closures (e.g. middleware) keep stable // references across applications, enabling Set-based deduplication. const operations: { method: string; args: any[] }[] = []; const proxy = new Proxy({} as CLI, { get(_target, prop) { return (...args: any[]) => { operations.push({ method: prop as string, args }); return proxy; }; }, }); fn(proxy); return ( init: CLI ) => { let current: any = init; for (const op of operations) { current = current[op.method](...op.args); } return current as unknown as CLI< Expand, THandlerReturn, TChildren & TChildren2, TParent, TProviders & TProviders2 >; }; }