import type { KeyError } from "@fncts/schema/ParseError"; import type { Sized } from "@fncts/test/control/Sized"; /** * @tsplus static fncts.schema.SchemaOps map */ export function set(value: Schema): Schema> { return Schema.declaration(Vector(value), setParser(true), setParser(false)) .annotate(ASTAnnotation.Identifier, `Set<${value.show()}>`) .annotate(ASTAnnotation.GenHook, gen); } /** * @tsplus static fncts.schema.SchemaOps mapFromRecord */ export function setFromArray(value: Schema): Schema> { return Schema.array(value).transform( set(value), (input) => { return new Set(input); }, (input) => { return Array.from(input); }, ); } /** * @tsplus derive fncts.schema.Schema[fncts.Set]<_> 10 */ export function deriveSet>( ...[value]: [A] extends [Set] ? Check>> extends Check.True ? [value: Schema] : never : never ): Schema { return unsafeCoerce(setFromArray(value)); } function setParser(isDecoding: boolean) { return (value: Schema): Parser> => { const schema = set(value); const parseValue = isDecoding ? value.decode : value.encode; return Parser.make((u, options) => { if (!(u instanceof Set)) { return ParseResult.fail(ParseError.TypeError(schema.ast, u)); } const allErrors = options?.allErrors; const errors = Vector.emptyPushable(); const out = new Set(); for (const v of u) { const tv = parseValue(v, options); Either.concrete(tv); if (tv.isLeft()) { errors.push(ParseError.KeyError(value.ast, v, tv.left)); if (!allErrors) { return ParseResult.fail(ParseError.IterableError(schema.ast, u, errors)); } continue; } out.add(tv.right); } return errors.isNonEmpty() ? ParseResult.fail(ParseError.IterableError(schema.ast, u, errors)) : ParseResult.succeed(out); }); }; } function gen(value: Gen): Gen> { return Gen.array(value).map((values) => new Set(values)); }