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));
}
});
};
}