Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,132 @@
# OpenSpec Change: enterprise-validation
- **Change ID**: enterprise-validation
- **Package**: `@suaveplan/validation`
- **Category**: universal
- **Target path**: `packages/universal/validation`
- **Status**: IN PROGRESS
- **Date**: 2026-04-18
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/validation.md`
## Summary
Greenfield implementation of `@suaveplan/validation` for the genesis branch. The existing main-branch validation package provides the baseline public-API surface to preserve; this change delivers a runtime schema-validation library with a Zod-compatible API surface, exhaustive schema types (string, number, boolean, date, array, object, union, intersection, literal, enum, nullable, optional, record, tuple, coerce), async refinements, hooks, structured errors, property-based tests, and benchmarks. The library is entirely self-contained — it does NOT depend on Zod; it is its own parser, used alongside Zod at the monorepo level for other packages.
## Current-state audit (genesis)
The package does not exist on genesis yet — this is a fresh build.
## Available workspace deps on genesis
| Package | Available |
|---------|-----------|
| `@suaveplan/error` | ✅ |
| `@suaveplan/types` | ✅ |
| `@suaveplan/events` | ✅ |
| `@suaveplan/opentelemetry` | ❌ not yet built — use `@opentelemetry/api` directly |
| `@suaveplan/feature-flags` | ❌ not yet built — skip |
| `@suaveplan/schema-registry` | ❌ not yet built — skip |
External deps (via catalog):
- `@opentelemetry/api` → `catalog:observability`
- `tslib` → `catalog:build`
Dev deps (via catalog):
- `vitest`, `@vitest/coverage-istanbul` → `catalog:testing`
- `fast-check` → `catalog:testing`
- `mitata` → `catalog:testing`
## Preserved public API surface (from main branch)
### Core
- `BaseSchema<TInput, TOutput>` — abstract base class with `.parse(input)`, `.safeParse(input)`, `.parseAsync(input)`, `.safeParseAsync(input)`, `.refine(fn, msg?)`, `.transform(fn)`, `.optional()`, `.nullable()`, `.describe(description)`
### Types
- `AnySchema`, `SchemaInput<S>`, `SchemaOutput<S>` — utility type extractors
- `Infer<S>`, `InferInput<S>` — schema type inference helpers
- `ParseResult<T>` — `ParseSuccess<T> | ParseFailure`
- `ParseSuccess<T>` — `{ success: true; data: T }`
- `ParseFailure` — `{ success: false; error: ValidationError }`
- `ParseContext` — internal traversal context
- `ValidationIssue` — `{ code: ValidationCode; path: (string | number)[]; message: string; input?: unknown }`
- `ValidationCode` — string union of all built-in issue codes
- `FlattenedErrors` — `{ formErrors: string[]; fieldErrors: Record<string, string[]> }`
- `RefineFn<T>`, `AsyncRefineFn<T>`, `TransformFn<T, U>`, `CustomRule<T>`
- `StringRuleOptions`, `NumberRuleOptions`, `ObjectShape`
### Errors
- `ValidationError` extends `SuaveplanError` — `.flatten()`, `.issues` getter, `.format()`
- `ValidationErrorOptions` — constructor options
- `FlattenedErrors` — return type of `.flatten()`
### Schema factories
- `string()` → `StringSchema` — `.min(n)`, `.max(n)`, `.length(n)`, `.regex(r)`, `.email()`, `.url()`, `.uuid()`, `.startsWith(s)`, `.endsWith(s)`, `.includes(s)`, `.trim()`, `.toLowerCase()`, `.toUpperCase()`
- `number()` → `NumberSchema` — `.min(n)`, `.max(n)`, `.int()`, `.positive()`, `.negative()`, `.multipleOf(n)`, `.finite()`
- `boolean()` → `BooleanSchema`
- `date()` → `DateSchema` — `.min(d)`, `.max(d)`
- `array(schema)` → `ArraySchema` — `.min(n)`, `.max(n)`, `.length(n)`, `.nonempty()`
- `object(shape)` → `ObjectSchema` — `.strict()`, `.passthrough()`, `.strip()`, `.pick(keys)`, `.omit(keys)`, `.partial()`, `.required()`, `.extend(shape)`, `.merge(other)`
- `union(schemas)` → `UnionSchema`
- `intersection(a, b)` → `IntersectionSchema`
- `literal(value)` → `LiteralSchema`
- `enumeration(values)` → `EnumSchema`
- `nullable(schema)` → `NullableSchema`
- `optional(schema)` → `OptionalSchema`
- `record(schema)` → `RecordSchema`
- `tuple(schemas)` → `TupleSchema`
### Coerce utilities
- `coerce(schema)` → `CoercedSchema` — wraps any schema with string→type coercion
- `coerceString(input)` → `string`
- `coerceNumber(input)` → `number`
- `coerceBoolean(input)` → `boolean`
- `coerceDate(input)` → `Date`
- `CoercedSchema<T>` (type)
### Compose utilities
- `mergeResults(results)` — merges multiple `ParseResult` arrays into one
- `pipe(schema, ...transforms)` — sequential schema pipeline
### Hook types
- `ValidationHookMap` — lifecycle hooks: `beforeValidate`, `afterValidate`, `onError`
- `ValidationHookData<T>` — data passed to each hook
- `ValidationValidatingHandler` — handler signature
## New additions for genesis
### Structured errors
- `ValidationError` extends `SuaveplanError` with codes under `VALIDATION.*` namespace
- Codes: `VALIDATION.STRING.*`, `VALIDATION.NUMBER.*`, `VALIDATION.ARRAY.*`, `VALIDATION.OBJECT.*`, `VALIDATION.UNION.NO_MATCH`, `VALIDATION.CUSTOM.REFINEMENT`
### OTel instrumentation
- Counters: `validation.parse.success`, `validation.parse.failure`
- Histogram: `validation.parse.duration_ms` (per schema type label)
### Property-based tests (fast-check)
- Round-trip: `schema.parse(schema.parse(x)) === schema.parse(x)` (idempotency)
- Error propagation: any invalid input to `.parse()` always returns `ParseFailure` (never throws)
- Union exhaustiveness: input matching none of the union arms always fails
### Benchmarks (mitata)
- `object(shape).parse(data)` for 10-field object — 100k iterations
- `array(string()).parse(arr)` for 1 000-element array
- `union` with 10 arms — best-case and worst-case branch
## Impact
- Adds one new package: `packages/universal/validation`
- Adds one new spec capability: `validation`
- No existing package consumers on genesis yet