first commit
This commit is contained in:
74
docs/foundation/data/validation/src/utils/coerce.md
Normal file
74
docs/foundation/data/validation/src/utils/coerce.md
Normal 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.
|
||||
51
docs/foundation/data/validation/src/utils/compose.md
Normal file
51
docs/foundation/data/validation/src/utils/compose.md
Normal 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.
|
||||
Reference in New Issue
Block a user