Files
2026-05-27 23:47:53 +01:00

2.9 KiB

schemas/schemas.ts — Zod options schema

(no submodules)

Purpose

This module owns the runtime validation surface for @suaveplan/emblem-solver. It exposes ConvertOptionsSchema, a Zod schema that mirrors the static ConvertOptions interface, applies sensible defaults, and rejects unknown keys. convert() runs every caller-supplied options object through safeParse so typos or out-of-range values fail loudly with EmblemSolverError(INVALID_OPTIONS) rather than silently degrading the solver.

Features

  • layerOrder defaults to "auto" and is validated as a closed enum over the five supported strategies.
  • maxPermutations defaults to 40320 = 8! — the threshold beyond which exhaustive permutation search is abandoned in favour of heuristics + random sampling. The schema enforces int().min(1) so a zero or negative value is rejected at the boundary.
  • rng is an optional () => number validated with z.custom<…>(). It is the only injection point for the package — supplying it makes the heuristic + sampling path fully deterministic.
  • .strict() rejects unknown keys, so misspelled options never silently succeed.

Usage: Basic

import { ConvertOptionsSchema } from "@suaveplan/emblem-solver/schemas";

const parsed = ConvertOptionsSchema.parse({ layerOrder: "area-desc" });
parsed.maxPermutations; // 40320 (default applied)

Usage: Advanced

import { ConvertOptionsSchema } from "@suaveplan/emblem-solver/schemas";
import { EMBLEM_SOLVER_CODES, EmblemSolverError } from
    "@suaveplan/emblem-solver/errors";

function safeOptions(raw: unknown) {
    const r = ConvertOptionsSchema.safeParse(raw);
    if (!r.success) {
        throw new EmblemSolverError(
            EMBLEM_SOLVER_CODES.INVALID_OPTIONS,
            `bad options: ${r.error.issues
                .map((i) => `${i.path.join(".")}: ${i.message}`)
                .join("; ")}`
        );
    }
    return r.data;
}

API Reference

Symbol Kind Description
ConvertOptionsSchema z.ZodObject Strict schema for ConvertOptions
ConvertOptionsParsed type Post-defaults shape of the parsed result

Implementation Notes

The schema lives in its own module so the rest of the package does not pay the Zod cost at import time when consumers do not need validation (e.g. hot-loop callers that constructed options at startup). convert() always runs through this schema, but downstream tooling can call ConvertOptionsSchema.parse ahead of time and pass the parsed result into its own caching layer. We use z.custom<() => number> rather than z.function() because Zod 4 deprecated runtime function validation in favour of a custom predicate; this matches the catalog zod ^4.x. The rng field stays optional (rather than defaulting to Math.random) so the test harness can detect whether a caller injected a deterministic source.