import { isSameType } from "zod-compare"; import type { $ZodFunction, $ZodTuple, $ZodType, $ZodUnknown, } from "zod/v4/core"; import { createFilterSphere } from "./filter/index.js"; import { isCompareFn, isFilterFn } from "./fn-helpers.js"; import { createSorterSphere } from "./sort/index.js"; import type { GenericFnSchema, StandardFnSchema } from "./types.js"; export const createFnSphere = () => { type FnSphereState = { fnMap: Record; genericFn: Record; }; const state: FnSphereState = { fnMap: {}, genericFn: {}, }; // TODO: supports genericFn const addFn = (fn: F) => { if (fn.name in state.fnMap || fn.name in state.genericFn) { throw new Error("Duplicate function name: " + fn.name); } state.fnMap[fn.name] = fn; }; const registerFnList = ( fnList: StandardFnSchema>[], ) => { fnList.forEach((fn) => { addFn(fn); }); }; const removeFn = (fnName: string) => { delete state.fnMap[fnName]; }; const getFn = (fnName: string) => { if (fnName in state.fnMap) { return state.fnMap[fnName]; } }; const findFn = < Input extends $ZodTuple = $ZodTuple, Output extends $ZodType = $ZodUnknown, >( maybePredicate: | { input?: Input; output?: Output; } | ((fn: StandardFnSchema) => boolean), ) => { if (typeof maybePredicate === "function") { return Object.values(state.fnMap).filter(maybePredicate); } const { input, output } = maybePredicate; const filterFn = Object.values(state.fnMap).filter((fn) => { return ( (input ? isSameType(input, fn.define._zod.def.input) : true) && (output ? isSameType(output, fn.define._zod.def.output) : true) ); }); return filterFn as StandardFnSchema<$ZodFunction>[]; }; const setupFilter = (schema: $ZodType) => { const filterFn = findFn(isFilterFn); const zFilter = createFilterSphere(schema, filterFn); return zFilter; }; const setupSort = (schema: $ZodType) => { const compareFn = findFn(isCompareFn); const zSort = createSorterSphere(schema, compareFn); return zSort; }; return { _state: state, addFn, registerFnList, getFn, removeFn, findFn, setupFilter, setupSort, }; };