npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@codeandmoney/belikto

v0.0.0-rc.1

Published

Convert Valibot schemas to/from a stable serialized AST

Downloads

113

Readme

belikto

Serialize / deserialize Valibot schemas, including "to code" for dep-free tree-shaking.

npm Tests coverage semantic-release TypeScript MIT License

Quick Start

// On JSR, it's @valibot/valibot and @codeandmoney/belikto
import * as v from "valibot";
import * as belikto from "belikto";

const LoginSchema = v.object( { email: v.string(), password: v.string() } );

const serialized = belikto.fromValibot( LoginSchema );
const NewLoginSchema = belikto.toValibot( serialized );

// { email: '[email protected]', password: '12345678' }
const parsed = v.parse( NewLoginSchema, { email: "[email protected]", password: "password" } );

// Write this to a file to benefit from dep-free tree-shaking
const code = belikto.toCode( serialized );
// "v.object({email:v.string(),password:v.string()});"

See CLI Usage section for quick no-code usage.

Important Notes

  • Obviously transforms and callbacks can't be serialized. You should store these elsewhere and apply after deserialization.

  • To avoid requiring belikto as a (non-dev) dependency and pulling in the entire valibot library, use toCode instead of toValibot and write the results to a file. This way you'll still benefit tree-shaking. See CLI below for a code-free way to scan a directory and auto-write modules for each detected schema.

  • This is a new project (mid September, 2025) - please let us know if anything doesn't work as expected.

Motivation

I use drizzle-valibot to create validation schemas (valibot) from my database schemas (drizzle-orm / postgresql), which works great, but, sometimes I want them on the client side too without bundling drizzle and pg. This way, we can use a small script to create dep-free versions of those schemas.

CLI

belikto

Scan files for supported exports (valibot schema or drizzle tables) and generate static code to recreate them that works with tree-shaking.

Suggested usage: put it in your package.json:

{ "scripts": { "schema:gen": "belikto --include 'src/db/schema/*.ts' --outDir src/db/valibot/generated" } }

belikto --help for all options. You can also import "belikto/belikto" and run it programatically. Formatters like prettier, biome or deno will be used if found.

Alternative ways to run:

$ npx -p belikto belikto
$ deno run --allow-read --allow-write jsr:@codeandmoney/belikto/belikto

Sample input:

import { integer, pgTable, text } from "drizzle-orm/pg-core";
export const users = pgTable( "users", { id: integer().primaryKey() /* ... */ } );

Sample output:

export const usersSelect = v.object( { name: v.string() /*...*/ } );
export const usersInsert = v.object( { id: v.pipe( v.number() /*...*/ ) } );
export const usersUpdate = v.object( { name: v.optiona( v.string() ) /*...*/ } );
export type UsersSelect = v.InferOutput<typeof usersSelect>;
export type UsersInsert = v.InferInput<typeof usersInsert>;
export type UsersUpdate = v.InferInput<typeof usersUpdate>;

If you don't like this opinionated output structure for drizzle tables, simply use drizzle-valibot yourself and export the structure you like. Or use the programatic API (by simply importing "belikto/belikto").

We also suggest to auto-load in watch-mode with e.g. .vscode/tasks.json:

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "schema watch",
      "command": "npm",
      "args": ["run", "schema:gen", "--watch"],
      "isBackground": true,
      "type": "shell",
      "runOptions": { "runOn": "folderOpen" },
      "presentation": { "echo": true, "reveal": "always", "focus": false, "panel": "shared", "showReuseMessage": true, "clear": false }
    }
  ]
}

FAQ:

  • Should I commit generated files to git/vcs?

    Totally up to you. No problem to generate at build time, but also nice to have them for clear, easy viewing in your repo.

Other Miscellaneous things we might not keep

Is anything here useful? Anything else you'd like?

Convert a serialized AST (read from stdin) to JSON Schema:

echo
'{"kind":"schema","vendor":"valibot","version":1,"format":1,"node":{"type":"object","entries":{"a":{"type":"string"}},"policy":"strict"}}'\
| deno task tojson

Outputs a JSON Schema for the data shape.

~~Generate Valibot builder code from a serialized AST (read from stdin):~~

// Removed for now. If you'd find this useful, please open an issue. echo
'{"kind":"schema","vendor":"valibot","version":1,"format":1,"node":{"type":"object","entries":{"email":{"type":"string"},"password":{"type":"string"}}}}'\
| deno task tocode

Outputs:

v.object({email:v.string(),password:v.string()});

API

  • fromValibot(schema: v.BaseSchema): SerializedSchema
    • Encodes a Valibot schema to a JSON‑serializable AST with { kind, vendor, version, format, node }.
  • toValibot(data: SerializedSchema): v.BaseSchema
    • Decodes the AST back to a Valibot schema.
  • isSerializedSchema(x: unknown): x is SerializedSchema
    • Runtime type guard for the AST envelope.
  • serializedSchemaJson
    • JSON Schema for the AST envelope and node variants (useful to validate serialized payloads).
  • toJsonSchema(serialized: SerializedSchema): JsonSchema
    • Best‑effort conversion from our AST to JSON Schema (Draft 2020‑12) for data validation.
  • fromJsonSchema(json: JsonSchemaLike): SerializedSchema
    • Basic, lossy converter from a subset of JSON Schema → our AST (strings/numbers/booleans/literals/arrays/objects/enums/unions/tuples/sets/maps approximations).
  • toCode(serialized: SerializedSchema): string
    • Emits concise Valibot builder code for the given AST (no imports), ending with a semicolon. Intended for code‑gen/export; format it as you like.

Module Structure

  • Each Valibot schema kind is implemented in its own module under src/types/. For example: string.ts, number.ts, object.ts, enum.ts, and picklist.ts. This keeps detection/encode/decode/codegen/JSON‑Schema logic focused and easy to maintain. When adding support for a new schema, prefer creating src/types/<kind>.ts and export it via src/types/index.ts.

Supported nodes and flags (AST)

  • string with:
    • lengths: minLength, maxLength, exact length
    • patterns: pattern (+ patternFlags), startsWith, endsWith
    • formats/validators: email, rfcEmail, url, uuid, ip, ipv4, ipv6, hexColor, slug, digits, emoji, hexadecimal, creditCard, imei, mac, mac48, mac64, base64, ids ulid, nanoid, cuid2, ISO time/date variants isoDate, isoDateTime, isoTime, isoTimeSecond, isoTimestamp, isoWeek
    • counters: minGraphemes, maxGraphemes, minWords, maxWords
    • transforms: trim, trimStart, trimEnd, toUpperCase, toLowerCase, normalize
  • number with min, max, gt, lt, integer, safeInteger, multipleOf, finite
  • boolean, literal
  • array with item + minLength, maxLength, length
  • object with entries, optionalKeys hint, policy (loose/strict), rest, minEntries, maxEntries
  • optional, nullable, nullish
  • union, tuple (+ rest), record
  • enum with values
  • picklist with values (string options)
  • set with value, minSize, maxSize
  • map with key, value, minSize, maxSize
  • date, file (minSize, maxSize, mimeTypes), blob (minSize, maxSize, mimeTypes)

Notes

  • The AST is independent of Valibot internals and versioned (format: 1).
  • Some validators don’t map cleanly to JSON Schema and are approximated (e.g., word counts, ISO formats, IDs) using patterns.
  • Complex constructs (custom transforms/effects) are intentionally unsupported and fail fast on fromValibot.
  • fromJsonSchema is intentionally minimal and lossy; prefer authoring schemas in Valibot and using fromValibot as the source of truth.

JSON Schema conversion

This was never a main goal for the project especially since other, mature tools exist for this purpose (i.e. @valibot/to-json-schema and json-schema-to-valibot, however, the AI offered to implement it and I said why not :) Let us know if you find it useful.

  • toJsonSchema converts:
    • Strings to string schemas, mapping common formats and adding regexes for selected validators (see notes).
      • IDs approximated: ulid, nanoid, cuid2 via patterns.
      • Validators approximated: creditCard, imei, mac, mac48, mac64, base64 via patterns.
    • Numbers, booleans, arrays, objects, tuples, enums, unions, sets/maps (approximate), records (as additionalProperties), date/file/blob as strings (binary for file/blob).
    • Union of literals becomes an enum.
  • fromJsonSchema converts back a subset:
    • type string/number/integer/boolean, const (literal), enum, array/object, tuple (prefixItems), union (anyOf), and anyOf of constants → picklist (all strings) or enum (mixed types).
    • Recognizes string format/email/uri/uuid/ipv4/ipv6, and common patterns produced by toJsonSchema for startsWith/endsWith, hexColor, slug, digits, hexadecimal, ids (ulid, nanoid, cuid2) and sets flags accordingly.

Compatibility mapping (selected)

| Valibot/AST | toJsonSchema | fromJsonSchema back | | -------------------------- | ------------------------------------- | ------------------- | | string.email | type: string, format: email | email: true | | string.url | type: string, format: uri | url: true | | string.uuid | type: string, format: uuid | uuid: true | | string.ipv4/ipv6 | format: ipv4/ipv6 | ipv4/ipv6: true | | string.ip | anyOf [ipv4, ipv6] | ip: true | | string.startsWith/endsWith | pattern/allOf anchored | starts/ends: true | | string.hexColor | regex | hexColor: true | | string.slug | regex | slug: true | | string.digits/hexadecimal | regex | digits/hexadecimal | | ulid/nanoid/cuid2 | regex | flags: true | | creditCard/imei/mac/... | regex | flags: true | | number min/max/gt/lt | min/max/exclusiveMin/Max | fields restored | | array min/max/len | minItems/maxItems | fields restored | | object min/max entries | minProperties/maxProperties | fields restored | | union of literals | enum | enum node | | enum values | enum | enum node | | set/map | array uniqueItems / object additional | approximated | | tuple/rest | prefixItems (+ items/rest) | fields restored | | date | string (format: date-time) | approximated | | file/blob | string binary (+ mediaType) | approximated |

Creation Notes

This was "vibe-coded" (with AI) over a weekend. I set up minimalist structure with a test case for how I wanted the code to work, and some empty functions with signatures. I then asked OpenAI Codex to complete the code.

Codex did so, and consistently gave some great suggestions on what to do next, and I kept saying yes to see where it would go. Eventually then I moved on to prompts for cleanup, refactoring, project structure, etc. The CLI tool was written by hand.

Please do bring any weird issues to our attention, and feel free to request clearer docs, examples, etc. Working on that next.

Relevant issues / discussions on valibot repo:

Development

See CONTRIBUTING.md for project layout, test naming, and workflow conventions.

License

MIT