import { expandGroupedArgumentValues, flattenGroupedArgumentDefinitions, hasArgumentGroups, } from "../arguments.ts"; import type { ArgumentDefinitions, ArgumentPath, ArgumentValue, FlatArgumentDefinitions, InferArguments, ParsedArgumentDraft, TypedCommandRefinement, TypedCommandRefinementContext, } from "../types.ts"; import type { TypedCommandHandler } from "../pi/command-types.ts"; function expandValidatedGroupedValues( values: InferArguments, definitions: TDefinitions, ): InferArguments; function expandValidatedGroupedValues( values: ParsedArgumentDraft, definitions: TDefinitions, ): ParsedArgumentDraft; function expandValidatedGroupedValues( values: InferArguments | ParsedArgumentDraft, definitions: TDefinitions, ): InferArguments | ParsedArgumentDraft { let expanded: Readonly> = values; if (hasArgumentGroups(definitions)) { expanded = expandGroupedArgumentValues(values, definitions); } // SAFETY: overload inputs are parser/refinement values already validated against the compiled // flat definitions. Expansion changes only keys according to the same source definition tree; // total handler input remains total, while draft input remains optional. // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- SAFETY: validated leaves are regrouped through their matching definition tree. return expanded as InferArguments | ParsedArgumentDraft; } function expandRefinementValues( values: ParsedArgumentDraft, definitions: TDefinitions, ): ParsedArgumentDraft { const projected: Record = {}; for (const key of Object.keys(flattenGroupedArgumentDefinitions(definitions))) { if (Object.hasOwn(values, key)) { projected[key] = values[key]; } } return expandValidatedGroupedValues(projected, definitions); } function isGroupedArgumentPath( definitions: TDefinitions, path: string, ): path is ArgumentPath { return Object.hasOwn(flattenGroupedArgumentDefinitions(definitions), path); } function refinementContext( definitions: TDefinitions, context: TypedCommandRefinementContext, ): TypedCommandRefinementContext { const provided = new Set>(); for (const path of context.provided) { if (isGroupedArgumentPath(definitions, path)) { provided.add(path); } } return { provided }; } /** Adapt grouped refinement callbacks to the parser's flat dotted-value representation. */ export function maybeWrapGroupedRefinement( definitions: TDefinitions, refine: TypedCommandRefinement | undefined, ): TypedCommandRefinement | undefined { if (refine === undefined) { return undefined; } return (args, context) => refine(expandRefinementValues(args, definitions), refinementContext(definitions, context)); } /** Adapt grouped command handlers to the parser's flat dotted-value representation. */ export function maybeWrapGroupedHandler( definitions: TDefinitions, handler: TypedCommandHandler, ): TypedCommandHandler { return (args, ctx) => handler(expandValidatedGroupedValues(args, definitions), ctx); }