# Parsec A tiny (<1kb gzipped) library for parsing and validating data in TypeScript. For more comprehensive type modeling, consider [zod](https://zod.dev) ## Install Configure your environment to be aware of @endeavorance packages: ```toml # Bunfig.toml [install.scopes] endeavorance = "https://git.astral.camp/api/packages/endeavorance/npm/" ``` Then install the package: ```sh bun add @endeavorance/parsec ``` ## API Parsec exports the `Parse` constant which contains a set of functions for parsing and validating data. ### Primitives These functions can be invoked directly, passing in the value to parse. - `Parse.unknown(value: unknown): unknown` - `Parse.string(value: unknown): string` - `Parse.number(value: unknown): number` - `Parse.boolean(value: unknown): boolean` - `Parse.null(value: unknown): null` - `Parse.undefined(value: unknown): undefined` - `Parse.bigint(value: unknown): bigint` - `Parse.symbol(value: unknown): symbol` ```ts const num = Parse.number(42); const str = Parse.string("hello"); const wontParse = Parse.number("hello"); // throws ParseError ``` ### Primitive Values These functions can be invoked directly and parse primitive values with additional constraints or specific meaning. - `Parse.int(value: unknown): number` - `Parse.nan(value: unknown): number` ```ts const anInteger = Parse.int(42); const willThrow = Parse.int(42.5); // throws ParseError const itsNan = Parse.nan(NaN); const itsNotNan = Parse.nan(42); // throws ParseError ``` ### Parser Creators These functions return a new parser function that can be used to parse values. These functions each take an optional second parameter: a human-readable string identifying the shape that this parser is for. This is useful for debugging but is not required and will default to an generic version of the parser. - `Parse.arrayOf(parser: Parser): (val: unknown) => T[]` - `Parse.shape(shape: T): (val: unknown) => T` - `Parse.enum(values: readonly E[]): (val: unknown) => E` - `Parse.regex(regex: RegExp): (val: unknown) => string` - `Parse.literal(literal: unknown): (val: unknown) => literal` - `Parse.instanceOf(classDef: Class): (val: unknown) => T` ```ts // An array of strings const arrayOfStrings = Parse.arrayOf(Parse.string)(["hello", "world"]); // A defined object shape const personParser = Parse.shape({ name: Parse.string, age: Parse.number, isCool: Parse.boolean, }, "Person"); const person = personParser({ name: "Alice", age: 42, isCool: true, }); // An element of an enum const MOODS = ["happy", "sad", "angry"] as const; const moodParser = Parse.enum(MOODS); const mood = moodParser("happy"); // A string that matches a regex const allCaps = Parse.regex(/^[A-Z]+$/)("HELLO"); // A literal value const parseHello = Parse.literal("hello"); const parsedHello = parseHello("hello"); const wontWork = parseHello("world"); // throws ParseError // An instance const parseDate = Parse.instanceOf(Date)(new Date()); ``` ### Modifiers Use `Parse.nullable()` and `Parse.optional()` to wrap parsers to allow for `null` or `undefined` respectively: ```ts const numberOrNull = Parse.nullable(Parse.number); const optionalArrayOfStrings = Parse.optional(Parse.arrayOf(Parse.string))); ``` ### Extracting Types from Parsers When composing parsers to create more complex types, you can use the `ReturnType` type helper: ```ts const parsePerson = Parse.shape({ name: Parse.string, age: Parse.number, isCool: Parse.boolean, }); type Person = ReturnType; ``` ## Errors Parsec will throw `ParseError` errors when parsing fails. `ParseError` objects have a string `shape` property which contains the expected type of the value. ## Branding Parsec exports a helper type, `Brand` which brands type T with the label provided in B. This is useful for creating custom types that are primitive types under the hood but have a different name. ```ts import type { Brand } from "@endeavorance/parsec"; type NegativeInteger = Brand; function parseInteger(val: unknown): Integer { if (typeof val !== "number" || !Number.isInteger(val) || val > 0) { throw new ParseTypeMismatch("Integer", val); } return val as NegativeInteger; } ```