# Validation Utilities _(no submodules)_ ## 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)) { validateField( (schema as Record)[key], (data as Record)[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: }` 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.