import type { Operator } from "./types/Operator" import { id } from "tsafe/id"; import { compose } from "./util/compose"; import { typeGuard } from "tsafe/typeGuard" import type { CtxLike, Handler } from "./types"; export function matchAll() { return true; } const canBeOperator = (p: undefined | CtxLike | Operator): boolean => { return ( p !== undefined && typeGuard>(p, true) && ( typeof p === "function" || typeof p[0] === "function" ) ); }; const defaultParams: Handler.PropsFromArgs = { "op": matchAll, "ctx": undefined, "timeout": undefined, "callback": undefined }; export function parsePropsFromArgs( inputs: readonly any[], methodName: "waitFor" | "attach*" | "pipe" ): Handler.PropsFromArgs { type Out = Handler.PropsFromArgs; switch (methodName) { case "pipe": { //[] //[undefined] ( not valid but user would expect it to work ) //[ ctx, ...op[] ] //[ ...op[] ] const getOpWrap = (ops: [Operator, ...Operator[]]) => ops.length === 0 ? {} : { "op": ops.length === 1 ? ops[0] : compose(...ops) } ; if (canBeOperator(inputs[0])) { //[ ...op[] ] return id({ ...defaultParams, ...getOpWrap(inputs as any) }); } else { //[] //[ ctx, ...Operator.fλ[] ] const [ctx, ...rest] = inputs; return id({ ...defaultParams, ...(ctx !== undefined ? { ctx } : {}), ...getOpWrap(rest as any) }); } } break; case "waitFor": { //[ op, ctx, timeout ] //[ op, ctx, undefined ] //[ op, ctx ] //[ op, timeout ] //[ op, undefined ] //[ ctx, timeout ] //[ ctx, undefined ] //[ op ] //[ ctx ] //[ timeout ] //[ undefined ] //[ callback ] return parsePropsFromArgs( [ //If the last element is undefined, remove it. ...inputs.filter( (value, index) => !( index === inputs.length - 1 && value === undefined ) ), defaultParams.callback ], "attach*" ); } break; case "attach*": { //NOTE: when callback is undefined call has been forward from waitFor. //[ op, ctx, timeout, callback ] //[ op, ctx, timeout, undefined ] //[ op, ctx, callback ] //[ op, ctx, undefined ] //[ op, timeout, callback ] //[ op, timeout, undefined ] //[ ctx, timeout, callback ] //[ ctx, timeout, undefined ] //[ op, callback ] //[ op, undefined ] //[ ctx, callback ] //[ ctx, undefined ] //[ timeout, callback ] //[ timeout, undefined ] //[ callback ] //[ undefined ] const n = inputs.length as 4 | 3 | 2 | 1 | 0; switch (n) { case 4: { //[ op, ctx, timeout, callback ] const [p1, p2, p3, p4] = inputs; return id({ ...defaultParams, "op": p1, "ctx": p2, "timeout": p3, "callback": p4 }); } case 3: { //[ op, ctx, callback ] //[ op, timeout, callback ] //[ ctx, timeout, callback ] const [p1, p2, p3] = inputs; if (typeof p2 === "number") { //[ op, timeout, callback ] //[ ctx, timeout, callback ] const timeout: Out["timeout"] = p2; const callback: Out["callback"] = p3; if (canBeOperator(p1)) { //[ op, timeout, callback ] return id({ ...defaultParams, timeout, callback, "op": p1 }); } else { //[ ctx, timeout, callback ] return id({ ...defaultParams, timeout, callback, "ctx": p1 }); } } else { //[ op, ctx, callback ] return id({ ...defaultParams, "op": p1, "ctx": p2, "callback": p3 }); } } case 2: { //[ op, callback ] //[ ctx, callback ] //[ timeout, callback ] const [p1, p2] = inputs; if (typeof p1 === "number") { //[ timeout, callback ] return id({ ...defaultParams, "timeout": p1, "callback": p2 }); } else { //[ op, callback ] //[ ctx, callback ] const callback: Out["callback"] = p2; if (canBeOperator(p1)) { return id({ ...defaultParams, callback, "op": p1 }); } else { return id({ ...defaultParams, callback, "ctx": p1 }); } } } case 1: { //[ callback ] const [p] = inputs; return id({ ...defaultParams, "callback": p }); } case 0: { return id({ ...defaultParams }); } } } break; } }