| 1 | import * as Str from "effect/String" |
| 2 | import assert from "node:assert/strict" |
| 3 | import * as v from "valibot" |
| 4 | |
| 5 | const person = () => v.object({ name: v.string(), age: v.number(), active: v.boolean() }) |
| 6 | const input = { name: "Ada", age: 37, active: true } |
| 7 | const small = person() |
| 8 | const arraySchema = v.array(person()) |
| 9 | const arrayInput = Array.from({ length: 32 }, () => ({ ...input })) |
| 10 | const recordSchema = v.record(v.string(), person()) |
| 11 | const recordInput = Object.fromEntries(arrayInput.map((value, i) => [String(i), value])) |
| 12 | const transformedKeyRecordSchema = v.record( |
| 13 | v.pipe(v.string(), v.transform(Str.snakeToCamel)), |
| 14 | v.string() |
| 15 | ) |
| 16 | const transformedKeyRecordInput = Object.fromEntries( |
| 17 | Array.from({ length: 32 }, (_, i) => [`field_${i}_value`, String(i)]) |
| 18 | ) |
| 19 | const transformedKeyRecordOutput = Object.fromEntries( |
| 20 | Array.from({ length: 32 }, (_, i) => [`field${i}Value`, String(i)]) |
| 21 | ) |
| 22 | const unionSchema = v.variant( |
| 23 | "tag", |
| 24 | Array.from({ length: 8 }, (_, i) => v.object({ tag: v.literal(i), value: v.number() })) |
| 25 | ) |
| 26 | const transformedSchema = v.object( |
| 27 | Object.fromEntries( |
| 28 | Array.from({ length: 32 }, (_, i) => [`v${i}`, v.pipe(v.string(), v.transform(Number))]) |
| 29 | ) |
| 30 | ) |
| 31 | const transformedInput = Object.fromEntries(Array.from({ length: 32 }, (_, i) => [`v${i}`, String(i)])) |
| 32 | const transformedOutput = Object.fromEntries(Array.from({ length: 32 }, (_, i) => [`v${i}`, i])) |
| 33 | const defaultsSchema = v.object( |
| 34 | Object.fromEntries(Array.from({ length: 32 }, (_, i) => [`v${i}`, v.optional(v.number(), i)])) |
| 35 | ) |
| 36 | |
| 37 | type Case = { |
| 38 | readonly schema: v.BaseSchema<unknown, unknown, v.BaseIssue<unknown>> |
| 39 | readonly input: unknown |
| 40 | readonly expected: unknown |
| 41 | readonly operation?: "is" | "make" |
| 42 | readonly invalid?: boolean |
| 43 | } |
| 44 | |
| 45 | const cases: Record<string, Case> = { |
| 46 | parseValid: { schema: small, input, expected: input }, |
| 47 | parseInvalid: { schema: small, input: { ...input, age: "bad" }, expected: true, invalid: true }, |
| 48 | isValid: { schema: small, input, expected: true, operation: "is" }, |
| 49 | isInvalid: { schema: small, input: { ...input, age: "bad" }, expected: false, operation: "is" }, |
| 50 | array: { schema: arraySchema, input: arrayInput, expected: arrayInput }, |
| 51 | record: { schema: recordSchema, input: recordInput, expected: recordInput }, |
| 52 | recordTransformedKeys: { |
| 53 | schema: transformedKeyRecordSchema, |
| 54 | input: transformedKeyRecordInput, |
| 55 | expected: transformedKeyRecordOutput |
| 56 | }, |
| 57 | union: { schema: unionSchema, input: { tag: 7, value: 1 }, expected: { tag: 7, value: 1 } }, |
| 58 | transform: { schema: transformedSchema, input: transformedInput, expected: transformedOutput }, |
| 59 | makeStruct: { schema: defaultsSchema, input: {}, expected: transformedOutput, operation: "make" }, |
| 60 | makeArray: { schema: arraySchema, input: arrayInput, expected: arrayInput, operation: "make" } |
| 61 | } |
| 62 | |
| 63 | const fixture = (name: string) => { |
| 64 | const { schema, input, expected, operation, invalid } = cases[name] |
| 65 | const parse = operation === "is" |
| 66 | ? (input: unknown) => v.is(schema, input) |
| 67 | : (input: unknown) => v.parse(schema, input) |
| 68 | return { |
| 69 | run: invalid |
| 70 | ? () => { |
| 71 | try { |
| 72 | parse(input) |
| 73 | return false |
| 74 | } catch { |
| 75 | return true |
| 76 | } |
| 77 | } |
| 78 | : () => parse(input), |
| 79 | validate: (result: unknown) => assert.deepEqual(result, expected) |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | export const parseValid = () => fixture("parseValid") |
| 84 | export const parseInvalid = () => fixture("parseInvalid") |
| 85 | export const isValid = () => fixture("isValid") |
| 86 | export const isInvalid = () => fixture("isInvalid") |
| 87 | export const array = () => fixture("array") |
| 88 | export const record = () => fixture("record") |
| 89 | export const recordTransformedKeys = () => fixture("recordTransformedKeys") |
| 90 | export const union = () => fixture("union") |
| 91 | export const transform = () => fixture("transform") |
| 92 | export const makeStruct = () => fixture("makeStruct") |
| 93 | export const makeArray = () => fixture("makeArray") |