import type { Check } from "@fncts/typelevel"; /** * @tsplus static fncts.schema.SchemaOps maybe * @tsplus getter fncts.schema.Schema maybe */ export function maybe(value: Schema): Schema> { return Schema.declaration(Vector(value), maybeParser(true), maybeParser(false)).annotate( ASTAnnotation.Identifier, `Maybe<${value.show()}>`, ); } /** * @tsplus static fncts.schema.SchemaOps maybeFromNullable * @tsplus getter fncts.schema.Schema maybeFromNullable */ export function maybeFromNullable(value: Schema): Schema> { return Schema.union(Schema.undefined, value.nullable).transform(value.maybe, Maybe.fromNullable, (input) => input.getOrElse(null), ); } /** * @tsplus derive fncts.schema.Schema[fncts.Maybe]<_> 10 */ export function deriveMaybe>( ...[value]: [A] extends [Maybe] ? Check>> extends Check.True ? [value: Schema<_A>] : never : never ): Schema { return unsafeCoerce(maybeFromNullable(value)); } function maybeParser(isDecoding: boolean) { return (value: Schema): Parser> => { const schema = maybe(value); const parseValue = isDecoding ? value.decode : value.encode; return Parser.make((u, options) => { if (!Maybe.isMaybe(u)) { return ParseResult.fail(ParseError.TypeError(schema.ast, u)); } Maybe.concrete(u); if (u.isNothing()) { return ParseResult.succeed(Nothing()); } else { return parseValue(u.value, options).map((a) => Just(a)); } }); }; }