adriano2teixeira / beff

Efficient validators from Typescript types generated by a blazing fast compiler

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

🪄 Beff

Efficient validators from Typescript types generated by a blazing fast compiler.

  • Typescript Efficient: Unlike zod, io-ts and similar, beff doesn't generate any extra work for the typescript compiler. Get a fast editor and fast compile times.
  • Fast: Beff is written in Rust and compiled to WASM. It is supported by every OS and should work for you!
  • Really fast: Beff compiles a hello-world project in 5ms. A big project with +200 types is compiled in 200ms.
  • Compatible: Beff uses the Typescript compiler for path resolution. If your editor can find the types, so can beff.
  • Efficient generated code: Beff generates optimal validator code, applying many optimizations to it at compile time.
  • Helpful: Beff generates clear error messages at compile time and at validation time.
  • Powerful: Beff supports recursive types, generic types, mapped types, conditional types, Omit, Exclude, Partial, Required, Record and a lot more. If it makes sense to have a runtime validator for that type, beff will understand it.

Getting Started

1. Install

Install @beff/cli and @beff/client from npm.

npm i @beff/cli @beff/client

2. Configure

Create a json file to configure beff. The file can have any name, but it's standard practice to name if beff.json.

{
  "parser": "./src/parser.ts",
  "outputDir": "./src/generated"
}

3. Create the parser file

Create a typescript file that lists the types for which beff should generate validator for.

It's standard practice to call it parser.ts

import parse from "./generated/parser";

type User = {
  name: string;
  age: number;
};

export const Parsers = parse.buildParsers<{
  User: User;
}>();

4. Generate the parser code

@beff/cli install a beff binary.

npx beff -p beff.json

5. Use the validators

import { Parsers } from "./parser.ts";

const user1 = Parsers.User.parse({
  name: "John Doe",
  age: 42,
});

const maybeUser = Parser.User.safeParse(null);

CLI Options

The beff binary can run in watch mode, too.

$ npx beff -h
Usage: beff [options]

Generate validators from typescript types

Options:
  -p, --project <string>  Path to the project file
  -v, --verbose           Print verbose output
  -w, --watch             Watch for file changes
  -h, --help              display help for command

Extra Features

Custom String Formats

Configure your beff.json

{
  "parser": "./src/parser.ts",
  "outputDir": "./src/generated",
  "customFormats": [
    {
      "name": "ValidCurrency"
    }
  ]
}

Use the helper StringFormat to create the type. It creates a branded typescript type. Define the runtime validator in the build parsers call.

import parse from "./generated/parser";
import { StringFormat } from "@beff/cli";
export type ValidCurrency = StringFormat<"ValidCurrency">;

export const Parsers = parse.buildParsers<{
  ValidCurrency: ValidCurrency;
}>({
  customFormats: {
    ValidCurrency: (input: string) => {
      if (VALID_CURRENCIES.include(input)) {
        return true;
      }
      return false;
    },
  },
});

Ad-hoc, one-off validator generator

Beff supports a type creation API similar to zod, io-ts and similar.

However, Beff's type creation API is very limited and only supports a few types.

With Beff, complex types should be generated by compiling Typescript types.

Types generated with the ad-hoc API have the same properties and methods as regular compiled types.

import { b } from "@beff/client";

const AdHocItem = b.Object({
  str: b.String(),
  num: b.Number(),
  bool: b.Boolean(),
  undefined: b.Undefined(),
  null: b.Null(),
  any: b.Any(),
  unknown: b.Unknown(),
});

const AdHocList = b.Array(AdHocItem);

const ls = AdHocList.parse([]);

Json Schema

Validator have a .jsonSchema property with a flattened JSON Schema.

Recursive types are not supported and become the equivalent of any in the second time they appear.

import { Parsers } from "./parser.ts";
import { z } from "zod";

const userSchema = Parsers.User.jsonSchema;

Zod Compatibility

Call .zod() on a parser to create a zod type.

Useful for gradually migrating from zod.

import { Parsers } from "./parser.ts";
import { z } from "zod";

const users = z.array(Parsers.User.zod()).parse({
  name: "John Doe",
  age: 42,
});

Contributing

Please read CONTRIBUTING.md

About

Efficient validators from Typescript types generated by a blazing fast compiler


Languages

Language:Rust 76.9%Language:JavaScript 12.0%Language:TypeScript 10.9%Language:Dockerfile 0.1%