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,84 @@
# `validate`
## Purpose
Walk a decoded CBOR value against a parsed CDDL schema and report the first
mismatch (with a JSON-pointer-like path). The validator is the run-time
counterpart to the parser — given a typed AST and a value, return
`{ valid, errors }` describing whether the value conforms.
## Features
- All primitive prelude types: `uint`, `nint`, `int`, `bstr`, `tstr`, `bool`,
`nil`, `null`, `undefined`, `any`, `number`, `text`, `bytes`, `float` /
`float16` / `float32` / `float64`, `tdate` (RFC 3339 string), `time`
(number or bigint epoch).
- Literal-value matching: text, byte, integer (signed and unsigned),
bool, null, undefined.
- Range types: inclusive (`..`) and exclusive (`...`).
- Choice: tries each alternative in isolation; first match wins.
- Arrays: positional `exact`-occurrence entries, optional, one-or-more,
zero-or-more, and `M*N` ranges. Extra entries past the schema are rejected.
- Maps: text and integer keys; required (`exact`) and optional (`?`) keys;
reports the missing key in error messages.
- Tagged items via `#6.<n>(T)` parse syntax → typed `{ kind: "tagged" }` AST.
- Named references: walks `name = T` rules transparently; entry rule is
selectable via `options.rule`.
- Control operators: `.size <int|range>` (string or bytes length),
`.regexp "pattern"` (RegExp match on text), `.cbor T` (left side is bytes).
Unknown control operators pass through (treated as informational
rather than fail-closed).
## Usage: Basic Example
```ts
import { validateCbor } from "@suaveplan/cbor/cddl";
const r = validateCbor({ iss: "alice", exp: 1700000000 }, `
cwt = { iss: tstr, ? exp: int }
`);
console.log(r.valid); // true
```
## Usage: Advanced Example
```ts
import { parseCddl, validateCbor } from "@suaveplan/cbor/cddl";
const schema = parseCddl(`
message = #6.18(cose-sign1)
cose-sign1 = [ bstr, { * any => any }, bstr / nil, bstr ]
`);
import { decode } from "@suaveplan/cbor";
import { Tagged } from "@suaveplan/cbor/tags";
const value = decode(wireBytes, { tagHandling: "raw" });
const r = validateCbor(value, schema, { rule: "message" });
if (!r.valid) {
for (const err of r.errors) {
console.error(`at ${err.path.join(".")}: expected ${err.expected}, got ${err.got}`);
}
}
```
## API Reference
- `validateCbor(value: unknown, schema: CddlAst | string, options?: { rule?: string }): CddlValidationResult`
- `interface CddlValidationResult { valid: boolean; errors: CddlValidationError[] }`
- `interface CddlValidationError { path: (string | number)[]; expected: string; got: string }`
Throws `CborError(CDDL_RULE_NOT_FOUND)` if `options.rule` names a rule
that doesn't exist; throws `CborError(CDDL_UNDEFINED_REFERENCE)` if a rule
body references an undefined name.
## Implementation Notes
The walk is a recursive AST switch dispatching on `type.kind`. Choice
validation runs each alternative against a fresh sub-context — the first
alternative whose walk produces zero errors wins. Map validation accepts
both `Map` instances and plain objects; the latter is wrapped via
`Object.entries` for uniform key lookup. Array entries are matched
greedily within their occurrence-range bound — no backtracking — which
is correct for the schemas this package targets but a future extension
could add limited backtracking for more permissive schemas.