miqro · @miqro/core · @miqro/parser · @miqro/query · @miqro/jsx · @miqro/jsx-dom · @miqro/jsx-node · @miqro/request · @miqro/runner · @miqro/test · @miqro/test-http

@miqro/parser

Schema validation and coercion with full TypeScript inference.

basic usage

import { Parser } from "@miqro/parser";

const parser = new Parser();

// Type is inferred automatically from the schema
const result = parser.parse({ id: "1", title: "hello" }, {
  type: "object",
  properties: {
    id: "integer",
    title: "string",
    published: "boolean?"
  }
});

result.id        // number  (coerced from string)
result.title     // string
result.published // boolean | undefined

If you prefer to declare the schema separately, annotate it with Schema<T> to

carry the explicit type (inference still works on inline schemas without it):

import { Parser, Schema } from "@miqro/parser";

interface Post { id: number; title: string; published?: boolean; }

const PostSchema: Schema<Post> = {
  type: "object",
  properties: { id: "integer", title: "string", published: "boolean?" }
};

const post = parser.parse(raw, PostSchema); // → Post

type string syntax

"string"         required string
"string?"        optional string (undefined if absent)
"number"         required number
"integer"        required integer (coerced)
"boolean"        required boolean ("true"/"false" coerced)
"string[]"       array of strings
"string[]?"      optional array of strings
"string[]!"      force single value into array, always returns string[]
"string[]!?"     optional force-array
"string|number"  string or number (first match wins)
"string|number?" string or optional number

built-in types

string, string1 (non-empty), number, integer, boolean
url, email, regex, regexp, function, any
object, array, dict, enum
decodeHTML, encodeHTML, schema

object schema

const result = parser.parse(raw, {
  type: "object",
  properties: {
    name: "string",
    age: "integer?",
    address: {
      type: "object?",
      properties: {
        city: "string",
        zip: "string?"
      }
    },
    tags: {
      type: "array",
      arrayType: "string"
    }
  }
});

result.name           // string
result.age            // number | undefined
result.address?.city  // string
result.tags           // string[]

mode

mode: "no_extra"     (default) throws if unknown properties are present
mode: "remove_extra" strips unknown properties, returns defined shape only
mode: "add_extra"    keeps unknown properties, type is defined shape & Record<string, unknown>
const result = parser.parse(raw, {
  type: "object",
  mode: "add_extra",
  properties: { id: "integer" }
});

result.id          // number
result["anything"] // unknown

array

// array of primitives
parser.parse(raw, { type: "array", arrayType: "string" }); // string[]

// array of objects — define element shape with co-located properties
const result = parser.parse(raw, {
  type: "array",
  arrayType: "object",
  properties: {
    id: "integer",
    label: "string"
  }
});
result[0].id    // number
result[0].label // string

// array of arrays
parser.parse(raw, { type: "array", arrayType: "number[]" }); // number[][]

enum

const result = parser.parse(raw, {
  type: "enum",
  enumValues: ["a", "b", "c"]
});
// result → "a" | "b" | "c"

dict

// dict of primitives
parser.parse(raw, { type: "dict", dictType: "number" });
// → Record<string, number>

// dict of objects — define value shape with co-located properties
const result = parser.parse(raw, {
  type: "dict",
  dictType: "object",
  properties: { x: "string", y: "number?" }
});
result["key"].x // string
result["key"].y // number | undefined

Aliases: Dict&amp;amp;amp;lt;string&amp;amp;amp;gt;, dict&amp;amp;amp;lt;string&amp;amp;amp;gt; are equivalent as type strings.

allowNull

parser.parse(raw, { type: "string", allowNull: true }); // string | null
parser.parse(raw, { type: "enum", enumValues: ["a", "b"], allowNull: true }); // "a" | "b" | null

InferSchema utility type

Use InferSchema&amp;amp;amp;lt;S&amp;amp;amp;gt; to derive the TypeScript type from a schema definition

without calling parse:

import { InferSchema } from "@miqro/parser";

type T1 = InferSchema<"string?">;                                    // string | undefined
type T2 = InferSchema<"number[]">;                                   // number[]
type T3 = InferSchema<{ type: "object"; properties: { x: "string" } }>; // { x: string }
type T4 = InferSchema<{ type: "enum"; enumValues: readonly ["a","b"] }>; // "a" | "b"
type T5 = InferSchema<{ type: "number"; allowNull: true }>;          // number | null

custom parser

import { Parser } from "@miqro/parser";

const parser = new Parser();
parser.register("uuid", (value) => {
  if (typeof value === "string" && /^[0-9a-f-]{36}$/.test(value)) {
    return value;
  }
  // return undefined or throw ParseOptionsError to fail validation
});

parser.parse("123e4567-...", "uuid"); // → unknown

To get type inference for custom parsers, augment TypeMap in the module

where it is declared:

declare module "@miqro/parser/build/built-in-parsers" {
  interface TypeMap {
    uuid: string;
  }
}

parser.parse("123e4567-...", "uuid");  // → string
parser.parse(raw, "uuid[]");           // → string[]
parser.parse(raw, "dict<uuid>");       // → Record<string, string>