/* eslint-disable @typescript-eslint/ban-types */ /* eslint-disable @typescript-eslint/no-explicit-any */ // tracing: off import type { Refinement } from "@effect-ts/core/Function" import { LazyGetter } from "@effect-ts/core/Utils" import type * as fc from "fast-check" import type { Parser, ParserEnv } from "../Parser.js" import type * as Th from "../These.js" import type { Annotation } from "./annotation.js" import type { AnyError } from "./error.js" // CompositionE, NamedE, NextE, PrevE, RefinementE export const SchemaSym = Symbol() export type SchemaSym = typeof SchemaSym /** * A `Schema` is a functional representation of a data model of type `ParsedShape` * that can be: * * 1) parsed from a `ParsedShape` starting from an input of type `ParserInput` * maybe failing for a reason `ParserError` * * 2) constructed smartly starting from an input of type `ConstructorInput` * * 3) encoded into an `Encoded` value * * 4) interacted with via `Api` */ /** * @tsplus type ets/Schema/Schema * @tsplus companion ets/Schema/SchemaOps */ export abstract class Schema { readonly [SchemaSym]: SchemaSym = SchemaSym readonly _ParserInput!: (_: ParserInput, env?: ParserEnv) => void readonly _ParserError!: () => any readonly _ParsedShape!: () => ParsedShape readonly _ConstructorInput!: (_: ConstructorInput) => void readonly _ConstructorError!: () => any readonly _Encoded!: () => Encoded abstract readonly Api: Api readonly [">>>"] = ( that: Schema< ParsedShape, ThatParsedShape, ThatConstructorInput, ParsedShape, ThatApi > ): Schema => new SchemaPipe(this, that) readonly annotate = ( identifier: Annotation, meta: Meta ): Schema => new SchemaAnnotated(this, identifier, meta) } export type SchemaAny = Schema export type SchemaUPI = Schema export type Standard = Schema export interface ApiSelfType { _AS: AS } export type GetApiSelfType, D> = unknown extends T["_AS"] ? D : T["_AS"] export const SchemaContinuationSymbol = Symbol() export type SchemaContinuationSymbol = typeof SchemaContinuationSymbol export interface HasContinuation { readonly [SchemaContinuationSymbol]: Schema< unknown, unknown, unknown, unknown, unknown > } export function hasContinuation< ParserInput, ParsedShape, ConstructorInput, Encoded, Api >( schema: Schema ): schema is & Schema & HasContinuation { return SchemaContinuationSymbol in schema } export type ParserInputOf> = [X] extends [ Schema ] ? Y : never export type ParserErrorOf> = [X] extends [ Schema ] ? any /*Y extends AnyError ? Y : never*/ : never export type ConstructorInputOf> = [ X ] extends [Schema] ? Y : never export type ConstructorErrorOf> = [ X ] extends [Schema] ? any /*Y extends AnyError ? Y : never */ : never export type EncodedOf> = [X] extends [ Schema ] ? Y : never export type ParsedShapeOf> = [X] extends [ Schema ] ? Y : never export type ApiOf> = [X] extends [ Schema ] ? Y : never export class SchemaIdentity extends Schema { readonly Api = {} constructor(readonly guard: (_: unknown) => _ is A) { super() } } export class SchemaConstructor< NewConstructorInput, ParserInput, ParsedShape, ConstructorInput, Encoded, Api > extends Schema implements HasContinuation { get Api() { return this.self.Api } readonly [SchemaContinuationSymbol]: SchemaAny constructor( readonly self: Schema, readonly of: (i: NewConstructorInput) => Th.These ) { super() this[SchemaContinuationSymbol] = self } } export class SchemaParser< NewParserInput, ParserInput, ParsedShape, ConstructorInput, Encoded, Api > extends Schema implements HasContinuation { get Api() { return this.self.Api } readonly [SchemaContinuationSymbol]: SchemaAny constructor( readonly self: Schema, readonly parser: Parser ) { super() this[SchemaContinuationSymbol] = self } } export class SchemaArbitrary extends Schema implements HasContinuation { get Api() { return this.self.Api } readonly [SchemaContinuationSymbol]: SchemaAny constructor( readonly self: Schema, readonly arbitrary: (_: typeof fc) => fc.Arbitrary ) { super() this[SchemaContinuationSymbol] = self } } export class SchemaEncoder< ParserInput, ParsedShape, ConstructorInput, Encoded, Api, Encoded2 > extends Schema implements HasContinuation { get Api() { return this.self.Api } readonly [SchemaContinuationSymbol]: SchemaAny constructor( readonly self: Schema, readonly encoder: (_: ParsedShape) => Encoded2 ) { super() this[SchemaContinuationSymbol] = self } } export class SchemaRefinement< E extends AnyError, NewParsedShape extends ParsedShape, ParserInput, ParsedShape, ConstructorInput, Encoded, Api > extends Schema { get Api() { return this.self.Api } constructor( readonly self: Schema, readonly refinement: Refinement, readonly error: (value: ParsedShape) => E ) { super() } } export class SchemaPipe< ParserInput, ParsedShape, ConstructorInput, Encoded, Api, ThatParsedShape, ThatConstructorInput, ThatApi > extends Schema implements HasContinuation { get Api() { return this.that.Api } readonly [SchemaContinuationSymbol]: SchemaAny = this.that constructor( readonly self: Schema, readonly that: Schema< ParsedShape, ThatParsedShape, ThatConstructorInput, ParsedShape, ThatApi > ) { super() } } export class SchemaMapParserError< ParserInput, ParsedShape, ConstructorInput, Encoded, Api > extends Schema implements HasContinuation { get Api() { return this.self.Api } readonly [SchemaContinuationSymbol]: SchemaAny = this.self constructor( readonly self: Schema, readonly mapError: (_: any) => any ) { super() } } export class SchemaMapConstructorError< ParserInput, ParsedShape, ConstructorInput, Encoded, Api > extends Schema implements HasContinuation { get Api() { return this.self.Api } readonly [SchemaContinuationSymbol]: SchemaAny = this.self constructor( readonly self: Schema, readonly mapError: (_: any) => any ) { super() } } export class SchemaMapApi< ParserInput, ParsedShape, ConstructorInput, Encoded, Api, Api2 > extends Schema implements HasContinuation { @LazyGetter() get Api() { return this.mapApi(this.self.Api) } readonly [SchemaContinuationSymbol]: SchemaAny = this.self constructor( readonly self: Schema, readonly mapApi: (_: Api) => Api2 ) { super() } } export class SchemaNamed< ParserInput, ParsedShape, ConstructorInput, Encoded, Api, Name extends string > extends Schema implements HasContinuation { get Api() { return this.self.Api } readonly [SchemaContinuationSymbol]: SchemaAny = this.self constructor( readonly self: Schema, readonly name: Name ) { super() } } export const Identifiable = Symbol() export function isAnnotated( self: Self, annotation: Annotation ): self is Self & { readonly self: Self extends { self: infer X } ? X : SchemaAny readonly annotation: Annotation readonly meta: A } { return ( (typeof self === "object" || typeof self === "function") && self != null && Identifiable in self && self["annotation"] === annotation ) } export function isAnnotatedSchema( self: Self ): self is Self & { readonly self: Self extends { self: infer X } ? X : SchemaAny readonly annotation: Annotation readonly meta: any } { return ( (typeof self === "object" || typeof self === "function") && self != null && Identifiable in self ) } export class SchemaAnnotated< ParserInput, ParsedShape, ConstructorInput, Encoded, Api, Meta > extends Schema implements HasContinuation { get Api() { return this.self.Api } readonly [Identifiable] = Identifiable readonly [SchemaContinuationSymbol]: SchemaAny = this.self constructor( readonly self: Schema, readonly annotation: Annotation, readonly meta: Meta ) { super() } } export class SchemaGuard extends Schema implements HasContinuation { get Api() { return this.self.Api } readonly [SchemaContinuationSymbol]: SchemaAny = this.self constructor( readonly self: Schema, readonly guard: (u: unknown) => u is ParsedShape ) { super() } } export class SchemaLazy extends Schema implements HasContinuation { readonly Api = {} get [SchemaContinuationSymbol](): SchemaAny { return this.lazy } @LazyGetter() get lazy(): Schema { return this.self() } constructor( readonly self: () => Schema< ParserInput, ParsedShape, ConstructorInput, Encoded, Api > ) { super() } }