first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
# Coerce Utilities
## Purpose
The coerce utilities allow schemas to accept a broader range of input types by converting them before validation. They bridge the gap between raw HTTP parameters (always strings), form data, and strongly-typed schema expectations. Each coerce function is pure and never throws — failures return `null`. The higher-order `coerce(schema)` wrapper applies the appropriate coercion strategy for string inputs and falls back to the raw schema if no coercion path works.
## Features
- `coerceString(input)` — always succeeds via `String(input)`
- `coerceNumber(input)` — via `Number(input)`, returns `null` for NaN
- `coerceBoolean(input)` — handles `"true"/"false"/"1"/"0"/1/0/true/false`
- `coerceDate(input)` — converts ISO strings and timestamps to `Date`
- `coerce(schema)` — wraps any schema with automatic string coercion
## Usage: Basic Example
```typescript
import { coerce, number } from "@suaveplan/validation";
const ageSchema = coerce(number().int().min(0));
ageSchema.parse("25"); // 25 (string coerced to number)
ageSchema.parse(25); // 25 (passthrough)
```
## Usage: Advanced Example
```typescript
import { coerce, boolean, date, object } from "@suaveplan/validation";
// Query parameter parsing (all values arrive as strings)
const QueryParams = object({
active: coerce(boolean()),
since: coerce(date()),
limit: coerce(number().int().max(100)),
});
QueryParams.parse({
active: "true",
since: "2024-01-01",
limit: "50",
});
```
## API Reference
### `coerceString(input: unknown): string`
Calls `String(input)`. Always succeeds; never returns null.
### `coerceNumber(input: unknown): number | null`
Calls `Number(input)`. Returns `null` if the result is `NaN`.
### `coerceBoolean(input: unknown): boolean | null`
Recognises `true/false` (booleans passthrough), `"true"/"1"/1` → `true`, `"false"/"0"/0` → `false`. Returns `null` for unrecognised input.
### `coerceDate(input: unknown): Date | null`
Passes through existing `Date` instances. Converts strings and numbers via `new Date(input)`. Returns `null` if the result is an invalid date.
### `coerce<T>(schema: BaseSchema<unknown, T>): CoercedSchema<T>`
Returns a `CoerceWrapperSchema` that attempts string coercions in order (number → boolean → date) for string inputs, falling back to the raw schema if none succeed.
### `type CoercedSchema<T>`
Alias for `BaseSchema<unknown, T>`.
## Implementation Notes
- `coerce(schema)` clears `ctx.issues` between coercion attempts so that intermediate failures don't pollute the final error list.
- Coercion order for string inputs is: numeric → boolean → date → raw. The first successful conversion is used.
- For non-string inputs, `coerce(schema)` delegates directly to the inner schema with no transformation.

View File

@@ -0,0 +1,51 @@
# Compose Utilities
## Purpose
The compose utilities provide functional combinators for working with validation results and schemas. `mergeResults` aggregates multiple `ParseResult<T>` values into a single `ParseResult<T[]>`, collecting all issues from failures. `pipe` composes a schema with one or more transform functions into a new pipeline schema, enabling clean left-to-right data transformation chains without manual wrapping.
## Features
- `mergeResults<T>(results)` — aggregate array of results, collecting all failures
- `pipe<T, U>(schema, ...transforms)` — compose schema with sequential transforms
## Usage: Basic Example
```typescript
import { pipe, string } from "@suaveplan/validation";
const trimmedLength = pipe(
string(),
(v: unknown) => (v as string).trim(),
(v: unknown) => (v as string).length,
);
trimmedLength.parse(" hello "); // 5
```
## Usage: Advanced Example
```typescript
import { mergeResults, number } from "@suaveplan/validation";
const n = number().min(0);
const results = [1, 2, -3, 4].map((v) => n.safeParse(v));
const merged = mergeResults(results);
// merged.success === false, merged.error.issues has one issue for -3
```
## API Reference
### `mergeResults<T>(results: ParseResult<T>[]): ParseResult<T[]>`
If all results are successes, returns `{ success: true, data: T[] }`.
If any result is a failure, returns `{ success: false, error: ValidationError }` with all issues aggregated from all failures.
### `pipe<T, U>(schema: BaseSchema<unknown, T>, ...transforms: TransformFn<unknown, unknown>[]): BaseSchema<unknown, U>`
Chains `schema` with each transform in order using `TransformSchema`. Each transform receives the previous stage's output as `unknown` (type-cast by the caller). Returns a new schema producing type `U`.
## Implementation Notes
- `mergeResults` with an empty array returns `{ success: true, data: [] }`.
- `pipe` with no transforms returns the original schema (zero iterations of the loop).
- Transform functions in `pipe` accept `unknown` to avoid TypeScript variance issues across the chain; callers must cast appropriately.