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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sleekcms/json-zen

v1.6.0

Published

Easify verify and shape JSON objects using a simplified alternative JSON schema

Readme

JSON Zen

A compact, string-based schema syntax for validating and shaping JSON objects — with far less boilerplate than JSON Schema.

Try it live at json-zen.sleekcms.site.

Installation

npm install @sleekcms/json-zen
// CommonJS
const { verify, check, shape, toSchema, extendTypes } = require('@sleekcms/json-zen');

// ESM / TypeScript
import { verify, check, shape, toSchema, extendTypes } from '@sleekcms/json-zen';

Quick Start

import { verify, check, shape, toSchema } from '@sleekcms/json-zen';

const data = { name: 'Alice', age: 30, tags: ['admin', 'user'] };

// Validate (throws on failure)
verify(data, '{name:s, age:n, tags:[s]}'); // true
// using full type names is equivalent:
verify(data, '{name:string, age:number, tags:[string]}'); // true

// Safe boolean check
check(data, '{name:s, age:s}'); // false

// Generate a schema from an existing object
toSchema(data); // "{name:string,age:number,tags:[string]}"

// Fill in missing fields with typed defaults
shape({ name: 'Bob' }, '{name:s, age:n, active:b}');
// { name: 'Bob', age: 0, active: true }

Schema Syntax

Alt schemas are plain strings. Whitespace is ignored.

Built-in Types

| Shorthand | Full name | Validates | Default (shape) | |-----------|-----------|----------------------|-----------------| | s | string | string | "" | | n | number | number (incl. floats)| 0 | | b | boolean | boolean | true | | — | null | strictly null | null | | ? | — | any value / nullable | null |

Shorthands and full names are interchangeable: {a:s} and {a:string} behave identically.

Objects

{key:type, key:type, ...}
verify({ a: 'hello', b: 42 }, '{a:s, b:n}');           // true — shorthands
verify({ a: 'hello', b: 42 }, '{a:string, b:number}'); // true — full names

Arrays

A single type applies to every element. Multiple comma-separated types cycle by index.

verify([1, 2, 3], '[n]');           // true — all numbers
verify([1, 'x', 2, 'y'], '[n,s]');  // true — alternating number/string

Optional fields (?)

For object properties, suffix the key with ? to make it optional (TypeScript-style). For array elements, prefix the type with ?. A missing or null value passes validation.

verify({ a: 1 }, '{a:n, b?:s}');    // true — b is missing but optional
verify({ a: 1, b: null }, '{a:n, b?:s}'); // true
verify([1, null, 3], '[?n]');       // true — array elements are optional

Presence-only validation

Omit the type to require only that a key exists and is not null/undefined.

verify({ a: 1, b: false }, '{a, b}'); // true
verify({ a: 1, b: null }, '{a, b}');  // throws — b is null

Default values (type:default)

Attach a default after the type, used by shape to fill missing values.

shape({}, '{name:s:anonymous, count:n:0}');
// { name: 'anonymous', count: 0 }

Use quotes for defaults containing spaces:

shape({}, '{title:s:"Hello World"}');
// { title: 'Hello World' }

Wildcard key (*)

*:type matches any key not already listed in the schema.

verify({ a: 1, b: 2, c: 3 }, '{*:n}');         // true
verify({ a: 1, b: '2' }, '{a:n, *:s}');         // true — b matched by wildcard
shape({ x: 1, y: 2, z: 3 }, '{*:n}');           // { x: 1, y: 2, z: 3 }

Nested objects and arrays

const schema = '{user:{name:s, scores:[n]}, active:b}';

verify({ user: { name: 'Alice', scores: [10, 20] }, active: true }, schema); // true

API

verify(json, schema, options?)

Validates json against schema. Returns true on success, throws an ZenError on failure.

verify({ a: 1 }, '{a:s}');
// throws: "json.a: validation failed"

Access all failures at once via error.errors:

try {
  verify({}, '{a:n, b:n}');
} catch (e) {
  console.log(e.message); // "Validation failed: 2 errors found"
  console.log(e.errors);  // [['json.a', 'is required'], ['json.b', 'is required']]
}

Options:

| Option | Type | Description | |---------|----------|---------------------------------------------------| | _path | string | Override the root label in error messages | | (key) | validator | Inline custom type — see Custom Validators |

verify({ a: 'x' }, '{a:s}', { _path: 'payload' });
// throws: "payload.a: validation failed"

check(json, schema, options?)

Same as verify but returns false instead of throwing. Schema errors still throw.

check({ a: 1, b: 'x' }, '{a:n, b:n}'); // false
check({ a: 1, b: 2 }, '{a:n, b:n}');   // true

shape(json, schema, options?)

Returns a new object shaped to the schema. Values from json are used when valid; otherwise, typed defaults fill in the gaps. Extra keys in json not in the schema are omitted.

shape({ a: 1, extra: 99 }, '{a:n, b:s, c:b}');
// { a: 1, b: '', c: true }

Nested structures are shaped recursively:

shape({ a: {} }, '{a:{x:n, y:s}}');
// { a: { x: 0, y: '' } }

Options:

| Option | Type | Description | |-------------|-----------|--------------------------------------------------------------| | fillNulls | boolean | When true, fill optional (?) fields with defaults instead of null | | (key) | validator | Inline custom type |

shape({}, '{a?:n}');                   // { a: null }
shape({}, '{a?:n}', { fillNulls: true }); // { a: 0 }

toSchema(json, options?)

Generates a schema string from a JSON object. Useful for bootstrapping a schema from a known-good example.

toSchema({ a: 'foo', b: 1, c: [1, 2], d: { e: null } });
// "{a:string,b:number,c:[number],d:{e:?}}"

Options:

| Option | Type | Default | Description | |-----------|-----------|---------|-------------| | default | string | — | A type name to treat as implicit. Object attributes whose inferred type matches this value will omit the :type suffix in the output. | | compact | boolean | false | When true, omits the :type suffix for every scalar attribute in objects (equivalent to setting default to all types at once). |

toSchema({ name: 'Alice', age: 30, active: true });
// "{name:string,age:number,active:boolean}"

// Omit ":string" everywhere — handy when most fields are strings
toSchema({ name: 'Alice', age: 30, active: true }, { default: 'string' });
// "{name,age:number,active:boolean}"

// Strip all :type annotations
toSchema({ name: 'Alice', age: 30, active: true }, { compact: true });
// "{name,age,active}"

extendTypes(validators)

Registers one or more custom types globally. Once registered, the type name can be used in any schema.

The validator function receives the value when checking, and undefined when shape needs a default — return the default value in that case.

import { extendTypes, shape, verify } from '@sleekcms/json-zen';

extendTypes({
  url: (value) => {
    if (value === undefined) return 'https://example.com'; // default for shape
    return typeof value === 'string' && value.startsWith('http');
  }
});

verify({ img: 'https://example.com/pic.jpg' }, '{img:url}'); // true
shape({}, '{img:url}'); // { img: 'https://example.com' }

Custom Validators

Custom validators can be passed inline via options, registered globally via extendTypes, or provided as enum arrays or RegExp patterns.

Inline function

verify({ status: 'active' }, '{status:myType}', {
  myType: (value) => value === 'active' || value === 'inactive'
});

Enum (array)

verify({ role: 'admin' }, '{role:r}', { r: ['admin', 'user', 'guest'] }); // true
verify({ role: 'root' },  '{role:r}', { r: ['admin', 'user', 'guest'] }); // throws

Regex

verify({ slug: 'hello-world' }, '{slug:sl}', { sl: /^[a-z-]+$/ }); // true

Context-aware validator

Validators receive { path, json, parent } as a second argument, enabling cross-field validation:

extendTypes({
  matchesType: (value, { parent }) => {
    if (parent.type === 'number') return typeof value === 'number';
    if (parent.type === 'string') return typeof value === 'string';
    return false;
  }
});

verify(
  [{ type: 'number', value: 42 }, { type: 'string', value: 'hi' }],
  '[{type:s, value:matchesType}]'
); // true

License

MIT © Yusuf Bhabhrawala, SleekSky LLC