import type { IndexError } from "@fncts/schema/ParseError"; import type { Sized } from "@fncts/test/control/Sized"; /** * @tsplus static fncts.schema.SchemaOps list * @tsplus getter fncts.Schema.Schema list */ export function list(value: Schema): Schema> { return Schema.declaration(Vector(value), parser(true), parser(false)) .annotate(ASTAnnotation.Identifier, `List<${value.show()}>`) .annotate(ASTAnnotation.GenHook, gen); } /** * @tsplus static fncts.schema.SchemaOps listFromArray * @tsplus getter fncts.Schema.Schema listFromArray */ export function listFromArray(value: Schema): Schema> { return Schema.array(value).transform( list(value), (input) => List.from(input), (input) => Array.from(input), ); } /** * @tsplus derive fncts.schema.Schema[fncts.List]<_> 10 */ export function deriveList>( ...[value]: [A] extends [List] ? Check>> extends Check.True ? [value: Schema<_A>] : never : never ): Schema { return unsafeCoerce(listFromArray(value)); } function parser(isDecoding: boolean) { return (value: Schema): Parser> => { const schema = list(value); const parseValue = isDecoding ? value.decode : value.encode; return Parser.make((u, options) => { if (!List.is(u)) { return ParseResult.fail(ParseError.TypeError(schema.ast, u)); } const out = new ListBuffer(); const errors = Vector.emptyPushable(); const allErrors = options?.allErrors; let index = 0; for (const v of u) { const t = parseValue(v, options); Either.concrete(t); if (t.isLeft()) { errors.push(ParseError.IndexError(index, t.left)); index++; if (allErrors) { continue; } return ParseResult.fail(ParseError.IterableError(schema.ast, u, errors)); } else { out.append(t.right); } index++; } return errors.isNonEmpty() ? ParseResult.fail(ParseError.IterableError(schema.ast, u, errors)) : ParseResult.succeed(out.toList); }); }; } function gen(value: Gen): Gen> { return Gen.array(value).map((array) => List.from(array)); }