586 lines
20 KiB
TypeScript
586 lines
20 KiB
TypeScript
import { BigDecimal, DateTime, Duration, HashMap, Option, Redacted, Result, Schema } from "effect"
|
|
import { describe, it } from "vitest"
|
|
import { strictEqual } from "../utils/assert.ts"
|
|
|
|
describe("toFormatter", () => {
|
|
it("Never", () => {
|
|
const format = Schema.toFormatter(Schema.Never)
|
|
strictEqual(format(1 as never), "never")
|
|
})
|
|
|
|
it("Any", () => {
|
|
const format = Schema.toFormatter(Schema.Any)
|
|
strictEqual(format(1), "1")
|
|
strictEqual(format("a"), `"a"`)
|
|
strictEqual(format(true), "true")
|
|
strictEqual(format(false), "false")
|
|
strictEqual(format(null), "null")
|
|
strictEqual(format(undefined), "undefined")
|
|
strictEqual(format({ a: 1 }), `{"a":1}`)
|
|
strictEqual(format([1, 2, 3]), `[1,2,3]`)
|
|
})
|
|
|
|
it("Unknown", () => {
|
|
const format = Schema.toFormatter(Schema.Unknown)
|
|
strictEqual(format(1), "1")
|
|
strictEqual(format("a"), `"a"`)
|
|
strictEqual(format(true), "true")
|
|
strictEqual(format(false), "false")
|
|
strictEqual(format(null), "null")
|
|
strictEqual(format(undefined), "undefined")
|
|
strictEqual(format({ a: 1 }), `{"a":1}`)
|
|
strictEqual(format([1, 2, 3]), `[1,2,3]`)
|
|
})
|
|
|
|
it("Void", () => {
|
|
const format = Schema.toFormatter(Schema.Void)
|
|
strictEqual(format(undefined), "void")
|
|
})
|
|
|
|
it("Null", () => {
|
|
const format = Schema.toFormatter(Schema.Null)
|
|
strictEqual(format(null), "null")
|
|
})
|
|
|
|
it("String", () => {
|
|
const format = Schema.toFormatter(Schema.String)
|
|
strictEqual(format("a"), `"a"`)
|
|
})
|
|
|
|
it("Number", () => {
|
|
const format = Schema.toFormatter(Schema.Number)
|
|
strictEqual(format(1), "1")
|
|
})
|
|
|
|
it("Boolean", () => {
|
|
const format = Schema.toFormatter(Schema.Boolean)
|
|
strictEqual(format(true), "true")
|
|
strictEqual(format(false), "false")
|
|
})
|
|
|
|
it("BigInt", () => {
|
|
const format = Schema.toFormatter(Schema.BigInt)
|
|
strictEqual(format(1n), "1n")
|
|
})
|
|
|
|
it("Symbol", () => {
|
|
const format = Schema.toFormatter(Schema.Symbol)
|
|
strictEqual(format(Symbol.for("a")), "Symbol(a)")
|
|
})
|
|
|
|
it("UniqueSymbol", () => {
|
|
const format = Schema.toFormatter(Schema.UniqueSymbol(Symbol.for("a")))
|
|
strictEqual(format(Symbol.for("a")), "Symbol(a)")
|
|
})
|
|
|
|
it("ObjectKeyword", () => {
|
|
const format = Schema.toFormatter(Schema.ObjectKeyword)
|
|
strictEqual(format({}), "{}")
|
|
strictEqual(format({ a: 1 }), `{"a":1}`)
|
|
strictEqual(format([1, 2, 3]), `[1,2,3]`)
|
|
})
|
|
|
|
describe("Literal", () => {
|
|
it("string", () => {
|
|
const format = Schema.toFormatter(Schema.Literal("a"))
|
|
strictEqual(format("a"), `"a"`)
|
|
})
|
|
|
|
it("number", () => {
|
|
const format = Schema.toFormatter(Schema.Literal(1))
|
|
strictEqual(format(1), "1")
|
|
})
|
|
|
|
it("boolean", () => {
|
|
const format = Schema.toFormatter(Schema.Literal(true))
|
|
strictEqual(format(true), "true")
|
|
})
|
|
|
|
it("bigint", () => {
|
|
const format = Schema.toFormatter(Schema.Literal(1n))
|
|
strictEqual(format(1n), "1n")
|
|
})
|
|
})
|
|
|
|
it("Literals", () => {
|
|
const format = Schema.toFormatter(Schema.Literals(["a", "b", "c"]))
|
|
strictEqual(format("a"), `"a"`)
|
|
strictEqual(format("b"), `"b"`)
|
|
strictEqual(format("c"), `"c"`)
|
|
})
|
|
|
|
it("TemplateLiteral", () => {
|
|
const format = Schema.toFormatter(Schema.TemplateLiteral([Schema.Literal("a"), Schema.String]))
|
|
strictEqual(format("a"), `"a"`)
|
|
strictEqual(format("ab"), `"ab"`)
|
|
})
|
|
|
|
describe("Enum", () => {
|
|
it("Numeric enum", () => {
|
|
enum Fruits {
|
|
Apple,
|
|
Banana
|
|
}
|
|
const format = Schema.toFormatter(Schema.Enum(Fruits))
|
|
strictEqual(format(Fruits.Apple), "0")
|
|
})
|
|
|
|
it("String enum", () => {
|
|
enum Fruits {
|
|
Apple = "apple",
|
|
Banana = "banana",
|
|
Cantaloupe = 0
|
|
}
|
|
const format = Schema.toFormatter(Schema.Enum(Fruits))
|
|
strictEqual(format(Fruits.Apple), `"apple"`)
|
|
})
|
|
|
|
it("Const enum", () => {
|
|
const Fruits = {
|
|
Apple: "apple",
|
|
Banana: "banana",
|
|
Cantaloupe: 3
|
|
} as const
|
|
const format = Schema.toFormatter(Schema.Enum(Fruits))
|
|
strictEqual(format(Fruits.Apple), `"apple"`)
|
|
})
|
|
})
|
|
|
|
it("Union", () => {
|
|
const format = Schema.toFormatter(Schema.Union([Schema.String, Schema.Number]))
|
|
strictEqual(format("a"), `"a"`)
|
|
strictEqual(format(1), "1")
|
|
})
|
|
|
|
describe("Tuple", () => {
|
|
it("empty", () => {
|
|
const format = Schema.toFormatter(Schema.Tuple([]))
|
|
strictEqual(format([]), "[]")
|
|
})
|
|
|
|
it("elements", () => {
|
|
const format = Schema.toFormatter(Schema.Tuple([Schema.Option(Schema.String)]))
|
|
strictEqual(format([Option.some("a")]), `[some("a")]`)
|
|
strictEqual(format([Option.none()]), `[none()]`)
|
|
})
|
|
})
|
|
|
|
it("Array", () => {
|
|
const format = Schema.toFormatter(Schema.Array(Schema.Option(Schema.String)))
|
|
strictEqual(format([Option.some("a")]), `[some("a")]`)
|
|
strictEqual(format([Option.none()]), `[none()]`)
|
|
})
|
|
|
|
it("TupleWithRest", () => {
|
|
const format = Schema.toFormatter(
|
|
Schema.TupleWithRest(Schema.Tuple([Schema.Option(Schema.Boolean)]), [
|
|
Schema.Option(Schema.Number),
|
|
Schema.Option(Schema.String)
|
|
])
|
|
)
|
|
strictEqual(format([Option.some(true), Option.some(1), Option.some("a")]), `[some(true), some(1), some("a")]`)
|
|
strictEqual(format([Option.none(), Option.none(), Option.some("a")]), `[none(), none(), some("a")]`)
|
|
})
|
|
|
|
it("TupleWithRest with multiple post-rest elements", () => {
|
|
const format = Schema.toFormatter(
|
|
Schema.TupleWithRest(Schema.Tuple([Schema.String]), [
|
|
Schema.String,
|
|
Schema.Number,
|
|
Schema.Boolean,
|
|
Schema.String
|
|
])
|
|
)
|
|
strictEqual(format(["head", "tail", 1, true, "last"]), `["head", "tail", 1, true, "last"]`)
|
|
})
|
|
|
|
describe("Struct", () => {
|
|
it("empty", () => {
|
|
const format = Schema.toFormatter(Schema.Struct({}))
|
|
strictEqual(format({}), "{}")
|
|
strictEqual(format(1), "1")
|
|
strictEqual(format("a"), `"a"`)
|
|
strictEqual(format(true), "true")
|
|
strictEqual(format(false), "false")
|
|
strictEqual(format({ a: 1 }), `{"a":1}`)
|
|
strictEqual(format([1, 2, 3]), `[1,2,3]`)
|
|
})
|
|
|
|
it("required fields", () => {
|
|
const format = Schema.toFormatter(Schema.Struct({
|
|
a: Schema.Option(Schema.String)
|
|
}))
|
|
strictEqual(format({ a: Option.some("a") }), `{ "a": some("a") }`)
|
|
strictEqual(format({ a: Option.none() }), `{ "a": none() }`)
|
|
})
|
|
|
|
it("required field with undefined", () => {
|
|
const format = Schema.toFormatter(Schema.Struct({
|
|
a: Schema.Option(Schema.UndefinedOr(Schema.String))
|
|
}))
|
|
strictEqual(format({ a: Option.some("a") }), `{ "a": some("a") }`)
|
|
strictEqual(format({ a: Option.some(undefined) }), `{ "a": some(undefined) }`)
|
|
strictEqual(format({ a: Option.none() }), `{ "a": none() }`)
|
|
})
|
|
|
|
it("optionalKey field", () => {
|
|
const format = Schema.toFormatter(Schema.Struct({
|
|
a: Schema.optionalKey(Schema.Option(Schema.String))
|
|
}))
|
|
strictEqual(format({ a: Option.some("a") }), `{ "a": some("a") }`)
|
|
strictEqual(format({ a: Option.none() }), `{ "a": none() }`)
|
|
strictEqual(format({}), `{}`)
|
|
})
|
|
|
|
it("optional field", () => {
|
|
const format = Schema.toFormatter(Schema.Struct({
|
|
a: Schema.optional(Schema.Option(Schema.String))
|
|
}))
|
|
strictEqual(format({ a: Option.some("a") }), `{ "a": some("a") }`)
|
|
strictEqual(format({ a: Option.none() }), `{ "a": none() }`)
|
|
strictEqual(format({ a: undefined }), `{ "a": undefined }`)
|
|
strictEqual(format({}), `{}`)
|
|
})
|
|
})
|
|
|
|
describe("Record", () => {
|
|
it("Record(String, Option(Number))", () => {
|
|
const format = Schema.toFormatter(Schema.Record(Schema.String, Schema.Option(Schema.Number)))
|
|
strictEqual(format({ a: Option.some(1) }), `{ "a": some(1) }`)
|
|
strictEqual(format({ a: Option.none() }), `{ "a": none() }`)
|
|
})
|
|
|
|
it("Record(String.check, Option(Number)) should use the key checks to select keys", () => {
|
|
const format = Schema.toFormatter(Schema.Record(
|
|
Schema.String.check(Schema.isPattern(/^a/)),
|
|
Schema.Option(Schema.Number)
|
|
))
|
|
strictEqual(format({ a: Option.some(1), b: Option.some(2) }), `{ "a": some(1) }`)
|
|
})
|
|
|
|
it("Record(Symbol, Option(Number))", () => {
|
|
const format = Schema.toFormatter(Schema.Record(Schema.Symbol, Schema.Option(Schema.Number)))
|
|
strictEqual(format({ [Symbol.for("a")]: Option.some(1) }), `{ Symbol(a): some(1) }`)
|
|
strictEqual(format({ [Symbol.for("a")]: Option.none() }), `{ Symbol(a): none() }`)
|
|
})
|
|
})
|
|
|
|
it("StructWithRest", () => {
|
|
const format = Schema.toFormatter(Schema.StructWithRest(
|
|
Schema.Struct({ a: Schema.Number }),
|
|
[Schema.Record(Schema.String, Schema.Number)]
|
|
))
|
|
strictEqual(format({ a: 1, b: 2 }), `{ "a": 1, "b": 2 }`)
|
|
})
|
|
|
|
it("Class", () => {
|
|
class A extends Schema.Class<A>("A")({
|
|
a: Schema.Option(Schema.String)
|
|
}) {}
|
|
const format = Schema.toFormatter(A)
|
|
strictEqual(format({ a: Option.some("a") }), `A({ "a": some("a") })`)
|
|
strictEqual(format({ a: Option.none() }), `A({ "a": none() })`)
|
|
})
|
|
|
|
describe("suspend", () => {
|
|
it("Tuple", () => {
|
|
const Rec = Schema.suspend((): Schema.Codec<unknown> => schema)
|
|
const schema = Schema.Tuple([
|
|
Schema.Number,
|
|
Schema.NullOr(Rec)
|
|
])
|
|
const format = Schema.toFormatter(schema)
|
|
strictEqual(format([1, null]), `[1, null]`)
|
|
strictEqual(format([1, [2, null]]), `[1, [2, null]]`)
|
|
})
|
|
|
|
it("Array", () => {
|
|
const Rec = Schema.suspend((): Schema.Codec<unknown> => schema)
|
|
const schema: any = Schema.Array(Schema.Union([Schema.String, Rec]))
|
|
const format = Schema.toFormatter(schema)
|
|
strictEqual(format(["a"]), `["a"]`)
|
|
})
|
|
|
|
it("Struct", () => {
|
|
const Rec = Schema.suspend((): Schema.Codec<unknown> => schema)
|
|
const schema = Schema.Struct({
|
|
a: Schema.String,
|
|
as: Schema.Array(Rec)
|
|
})
|
|
const format = Schema.toFormatter(schema)
|
|
strictEqual(
|
|
format({ a: "a", as: [{ a: "b", as: [] }, { a: "c", as: [] }] }),
|
|
`{ "a": "a", "as": [{ "a": "b", "as": [] }, { "a": "c", "as": [] }] }`
|
|
)
|
|
})
|
|
|
|
it("Record", () => {
|
|
const Rec = Schema.suspend((): Schema.Codec<unknown> => schema)
|
|
const schema = Schema.Record(Schema.String, Rec)
|
|
const format = Schema.toFormatter(schema)
|
|
strictEqual(format({ a: { a: { a: {} } } }), `{ "a": { "a": { "a": {} } } }`)
|
|
})
|
|
|
|
it("optional", () => {
|
|
const Rec = Schema.suspend((): Schema.Codec<unknown> => schema)
|
|
const schema: any = Schema.Struct({
|
|
a: Schema.optional(Rec)
|
|
})
|
|
const format = Schema.toFormatter(schema)
|
|
strictEqual(format({ a: "a" }), `{ "a": "a" }`)
|
|
})
|
|
|
|
it("Array + Array", () => {
|
|
const Rec = Schema.suspend((): Schema.Codec<unknown> => schema)
|
|
const schema: any = Schema.Struct({
|
|
a: Schema.Array(Rec),
|
|
b: Schema.Array(Rec)
|
|
})
|
|
const format = Schema.toFormatter(schema)
|
|
strictEqual(
|
|
format({
|
|
a: [{ a: [{ a: [], b: [] }], b: [] }],
|
|
b: [{ a: [], b: [] }]
|
|
}),
|
|
`{ "a": [{ "a": [{ "a": [], "b": [] }], "b": [] }], "b": [{ "a": [], "b": [] }] }`
|
|
)
|
|
})
|
|
|
|
it("optional + Array", () => {
|
|
const Rec = Schema.suspend((): Schema.Codec<unknown> => schema)
|
|
const schema: any = Schema.Struct({
|
|
a: Schema.optional(Rec),
|
|
b: Schema.Array(Rec)
|
|
})
|
|
const format = Schema.toFormatter(schema)
|
|
strictEqual(format({ a: "a", b: [{ a: "b", b: [] }] }), `{ "a": "a", "b": [{ "a": "b", "b": [] }] }`)
|
|
})
|
|
|
|
it("mutually suspended schemas", () => {
|
|
interface Expression {
|
|
readonly type: "expression"
|
|
readonly value: number | Operation
|
|
}
|
|
|
|
interface Operation {
|
|
readonly type: "operation"
|
|
readonly operator: "+" | "-"
|
|
readonly left: Expression
|
|
readonly right: Expression
|
|
}
|
|
|
|
const Expression = Schema.Struct({
|
|
type: Schema.Literal("expression"),
|
|
value: Schema.Union([Schema.Finite, Schema.suspend((): Schema.Codec<Operation> => Operation)])
|
|
})
|
|
|
|
const Operation = Schema.Struct({
|
|
type: Schema.Literal("operation"),
|
|
operator: Schema.Literals(["+", "-"]),
|
|
left: Expression,
|
|
right: Expression
|
|
})
|
|
const format = Schema.toFormatter(Operation)
|
|
strictEqual(
|
|
format({
|
|
type: "operation",
|
|
operator: "+",
|
|
left: { type: "expression", value: 1 },
|
|
right: { type: "expression", value: 2 }
|
|
}),
|
|
`{ "type": "operation", "operator": "+", "left": { "type": "expression", "value": 1 }, "right": { "type": "expression", "value": 2 } }`
|
|
)
|
|
})
|
|
|
|
it("Option", () => {
|
|
const Rec = Schema.suspend((): Schema.Codec<unknown> => schema)
|
|
const schema = Schema.Struct({
|
|
a: Schema.String,
|
|
as: Schema.Option(Rec)
|
|
})
|
|
const format = Schema.toFormatter(schema)
|
|
strictEqual(
|
|
format({ a: "a", as: Option.some({ a: "b", as: Option.none() }) }),
|
|
`{ "a": "a", "as": some({ "a": "b", "as": none() }) }`
|
|
)
|
|
})
|
|
|
|
it("ReadonlySet", () => {
|
|
const Rec = Schema.suspend((): Schema.Codec<unknown> => schema)
|
|
const schema = Schema.ReadonlySet(Rec)
|
|
const format = Schema.toFormatter(schema)
|
|
strictEqual(format(new Set()), `ReadonlySet(0) {}`)
|
|
strictEqual(format(new Set([new Set([new Set()])])), `ReadonlySet(1) { ReadonlySet(1) { ReadonlySet(0) {} } }`)
|
|
})
|
|
|
|
it("ReadonlyMap", () => {
|
|
const Rec = Schema.suspend((): Schema.Codec<unknown> => schema)
|
|
const schema = Schema.ReadonlyMap(Schema.String, Rec)
|
|
const format = Schema.toFormatter(schema)
|
|
strictEqual(format(new Map()), `ReadonlyMap(0) {}`)
|
|
strictEqual(
|
|
format(new Map([["a", new Map([["b", new Map()]])]])),
|
|
`ReadonlyMap(1) { "a" => ReadonlyMap(1) { "b" => ReadonlyMap(0) {} } }`
|
|
)
|
|
})
|
|
|
|
it("HashMap", () => {
|
|
const Rec = Schema.suspend((): Schema.Codec<unknown> => schema)
|
|
const schema = Schema.HashMap(Schema.String, Rec)
|
|
const format = Schema.toFormatter(schema)
|
|
strictEqual(format(HashMap.empty()), `HashMap(0) {}`)
|
|
strictEqual(
|
|
format(HashMap.make(["a", HashMap.make(["b", HashMap.empty()])])),
|
|
`HashMap(1) { "a" => HashMap(1) { "b" => HashMap(0) {} } }`
|
|
)
|
|
})
|
|
})
|
|
|
|
it("Date", () => {
|
|
const format = Schema.toFormatter(Schema.Date)
|
|
strictEqual(format(new Date(0)), "1970-01-01T00:00:00.000Z")
|
|
})
|
|
|
|
it("URL", () => {
|
|
const format = Schema.toFormatter(Schema.URL)
|
|
strictEqual(format(new URL("https://www.example.com")), "https://www.example.com/")
|
|
})
|
|
|
|
it("RegExp", () => {
|
|
const format = Schema.toFormatter(Schema.RegExp)
|
|
strictEqual(format(/a/), `/a/`)
|
|
strictEqual(format(/a/i), `/a/i`)
|
|
})
|
|
|
|
it("Option(String)", () => {
|
|
const format = Schema.toFormatter(Schema.Option(Schema.String))
|
|
strictEqual(format(Option.some("a")), `some("a")`)
|
|
strictEqual(format(Option.none()), "none()")
|
|
})
|
|
|
|
it("Result(Number, String)", () => {
|
|
const format = Schema.toFormatter(Schema.Result(Schema.Number, Schema.String))
|
|
strictEqual(format(Result.succeed(1)), `success(1)`)
|
|
strictEqual(format(Result.fail("a")), `failure("a")`)
|
|
})
|
|
|
|
it("ReadonlyMap(String, Option(Number))", () => {
|
|
const format = Schema.toFormatter(Schema.ReadonlyMap(Schema.String, Schema.Option(Schema.Number)))
|
|
strictEqual(format(new Map([["a", Option.some(1)]])), `ReadonlyMap(1) { "a" => some(1) }`)
|
|
strictEqual(format(new Map([["a", Option.none()]])), `ReadonlyMap(1) { "a" => none() }`)
|
|
})
|
|
|
|
it("HashMap(String, Option(Number))", () => {
|
|
const format = Schema.toFormatter(Schema.HashMap(Schema.String, Schema.Option(Schema.Number)))
|
|
strictEqual(format(HashMap.make(["a", Option.some(1)])), `HashMap(1) { "a" => some(1) }`)
|
|
strictEqual(format(HashMap.make(["a", Option.none()])), `HashMap(1) { "a" => none() }`)
|
|
})
|
|
|
|
describe("Redacted", () => {
|
|
it("Redacted(String)", () => {
|
|
const format = Schema.toFormatter(Schema.Redacted(Schema.String))
|
|
strictEqual(format(Redacted.make("a")), `<redacted>`)
|
|
})
|
|
|
|
it("with label", () => {
|
|
const format = Schema.toFormatter(Schema.Redacted(Schema.String, { label: "password" }))
|
|
strictEqual(format(Redacted.make("a", { label: "password" })), `<redacted:password>`)
|
|
})
|
|
})
|
|
|
|
it("Duration", () => {
|
|
const format = Schema.toFormatter(Schema.Duration)
|
|
strictEqual(format(Duration.millis(100)), `100 millis`)
|
|
strictEqual(format(Duration.nanos(1000n)), `1000 nanos`)
|
|
strictEqual(format(Duration.infinity), "Infinity")
|
|
strictEqual(format(Duration.negativeInfinity), "-Infinity")
|
|
})
|
|
|
|
it("BigDecimal", () => {
|
|
const format = Schema.toFormatter(Schema.BigDecimal)
|
|
strictEqual(format(BigDecimal.fromStringUnsafe("123.45")), "123.45")
|
|
strictEqual(format(BigDecimal.fromStringUnsafe("-5")), "-5")
|
|
strictEqual(format(BigDecimal.fromStringUnsafe("0")), "0")
|
|
})
|
|
|
|
it("DateTimeUtc", () => {
|
|
const format = Schema.toFormatter(Schema.DateTimeUtc)
|
|
strictEqual(format(DateTime.makeUnsafe("2021-01-01T00:00:00.000Z")), "DateTime.Utc(2021-01-01T00:00:00.000Z)")
|
|
})
|
|
|
|
it("TimeZoneOffset", () => {
|
|
const format = Schema.toFormatter(Schema.TimeZoneOffset)
|
|
strictEqual(format(DateTime.zoneMakeOffset(3 * 60 * 60 * 1000)), "+03:00")
|
|
})
|
|
|
|
it("TimeZoneNamed", () => {
|
|
const format = Schema.toFormatter(Schema.TimeZoneNamed)
|
|
strictEqual(format(DateTime.zoneMakeNamedUnsafe("Europe/London")), "Europe/London")
|
|
})
|
|
|
|
it("TimeZone", () => {
|
|
const format = Schema.toFormatter(Schema.TimeZone)
|
|
strictEqual(format(DateTime.zoneMakeOffset(3 * 60 * 60 * 1000)), "+03:00")
|
|
strictEqual(format(DateTime.zoneMakeNamedUnsafe("Europe/London")), "Europe/London")
|
|
})
|
|
|
|
it("DateTimeZoned", () => {
|
|
const format = Schema.toFormatter(Schema.DateTimeZoned)
|
|
const zoned = DateTime.makeZonedUnsafe("2024-01-01T00:00:00.000Z", { timeZone: "Europe/London" })
|
|
strictEqual(format(zoned), DateTime.formatIsoZoned(zoned))
|
|
})
|
|
|
|
it("custom class", () => {
|
|
class A {
|
|
constructor(readonly a: string) {}
|
|
}
|
|
const schema = Schema.instanceOf(A)
|
|
const format = Schema.toFormatter(schema)
|
|
strictEqual(format(new A("a")), `A({"a":"a"})`)
|
|
})
|
|
|
|
it("custom class with a toString() method", () => {
|
|
class A {
|
|
constructor(readonly a: string) {}
|
|
toString() {
|
|
return `A(${this.a})`
|
|
}
|
|
}
|
|
const schema = Schema.instanceOf(A)
|
|
const format = Schema.toFormatter(schema)
|
|
strictEqual(format(new A("a")), `A(a)`)
|
|
})
|
|
|
|
describe("Annotations", () => {
|
|
describe("overrideToFormatter", () => {
|
|
it("String", () => {
|
|
const schema = Schema.String.pipe(Schema.overrideToFormatter(() => (s) => s.toUpperCase()))
|
|
const format = Schema.toFormatter(schema)
|
|
strictEqual(format("a"), "A")
|
|
})
|
|
|
|
it("String & isMinLength(1)", () => {
|
|
const schema = Schema.String.check(Schema.isMinLength(1)).pipe(
|
|
Schema.overrideToFormatter(() => (s) => s.toUpperCase())
|
|
)
|
|
const format = Schema.toFormatter(schema)
|
|
strictEqual(format("a"), "A")
|
|
})
|
|
})
|
|
})
|
|
|
|
it("should allow for ast-level overrides", () => {
|
|
const toFormatter = <S extends Schema.Constraint>(schema: S) =>
|
|
Schema.toFormatter(schema, {
|
|
onBefore: (ast) => {
|
|
if (ast._tag === "Boolean") {
|
|
return (b: boolean) => b ? "True" : "False"
|
|
}
|
|
}
|
|
})
|
|
strictEqual(toFormatter(Schema.Boolean)(true), `True`)
|
|
const schema = Schema.Tuple([Schema.String, Schema.Boolean])
|
|
strictEqual(toFormatter(schema)(["a", true]), `["a", True]`)
|
|
})
|
|
})
|