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,77 @@
# Validation Utilities
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Type guards and shape-checks shared across the `@suaveplan/bitpacker-validation` validators. These are the cheap, common predicates — "is this an object?", "is this an optional schema?", "is this a valid schema-shaped value?" — that every per-rule validator hits in its hot path. Centralizing them keeps the per-rule logic free of duplicated `typeof` ladders and ensures the predicates evolve in lockstep when new schema shapes ship.
The functions are pure and side-effect-free; they don't throw, they don't allocate, and they don't recurse. Schema-driven recursion is the caller's responsibility — these helpers answer one question at one level of the structure.
## Features
- `isObject(value)` — guards a non-null `object` (excluding arrays)
- `isOptional(value)` — recognizes the `{ _optional: ... }` schema shape
- `isValidSchema(schema)` — quick structural check that a value matches one of the published `BitPackerSchema` shapes
## Usage: Basic Example
```ts
import { isObject, isOptional } from "@suaveplan/bitpacker-validation";
if (isObject(value) && !isOptional(value)) {
// …treat value as a regular object schema or data record…
}
```
## Usage: Advanced Example
```ts
import {
isObject,
isOptional,
isValidSchema,
} from "@suaveplan/bitpacker-validation";
function validateField(schema: unknown, data: unknown, path: string) {
if (!isValidSchema(schema)) {
throw new Error(`Schema at ${path} is malformed`);
}
if (isOptional(schema) && data === undefined) {
return; // missing optional field is fine
}
if (isObject(schema) && isObject(data)) {
// recurse into the nested object
for (const key of Object.keys(schema as Record<string, unknown>)) {
validateField(
(schema as Record<string, unknown>)[key],
(data as Record<string, unknown>)[key],
`${path}.${key}`
);
}
}
}
```
## API Reference
### `isObject(value: unknown): value is object`
Returns `true` if `value` is a non-null object that is not an `Array`. Used everywhere a per-key descent into a schema or data record is appropriate.
### `isOptional(value: unknown): boolean`
Returns `true` if `value` is a non-null object with an `_optional` key. The function does NOT recursively validate the wrapped schema — that's the caller's job.
### `isValidSchema(schema: unknown): boolean`
Returns `true` if `schema` matches one of the published `BitPackerSchema` shapes (number, string, boolean, null, bigint token, array, object, or one of the discriminated wrappers `_enum`/`_optional`/`_oneOf`/`_if`/`_version`/`_ref`/`_bp`/`_customType`). Returns `false` for malformed values like functions, symbols, or unrecognized shapes.
## Implementation Notes
- **No recursion.** Each helper answers one question about one level. Nested validation is the caller's responsibility; making the helpers recursive would couple them to the validator's traversal strategy.
- **`isOptional` does not validate the wrapped schema.** A `{ _optional: <garbage> }` will pass `isOptional` and fail `isValidSchema(value._optional)`. Splitting these checks lets the caller produce more specific error messages.
- **`isValidSchema` is structural, not semantic.** It confirms the shape but does not check that referenced types in `_ref` resolve, that `_oneOf` arrays are non-empty, or that `_version._schemas` is well-ordered. Semantic validation belongs to the validator class.
- **Performance.** All three helpers are `O(1)` in the size of the input. They are safe to call from inside hot-path loops without measurable overhead.