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

cocochex

v1.0.4

Published

Tiny, dependency-free schema validator and transformer for plain JavaScript objects.

Readme

cocochex

Tiny, dependency-free schema validator and transformer for plain JavaScript objects.

cocochex checks data against a schema and can also transform values through custom validator functions. It supports:

  • primitive type checks (string, number, boolean, object, array, function, null, undefined)
  • exact value matching
  • nested object schemas
  • list validation
  • multi-type (union-like) schemas
  • required key enforcement (including nested keys)
  • default values generated by functions

Installation

npm install cocochex

Quick Start

import cocochex from "cocochex";

const input = {
  a: 1,
  b: "hello",
  c: [1, "two", 3],
  d: { x: 10, y: 20, z: [null, 0, 2] }
};

const output = cocochex(input, {
  a: "number",
  b: "string",
  c: ["string", "number"],   // each item must be a string or number
  d: {
    x: "number",
    y: 20,
    z: [0, v => v || "default"]  // each item: exact 0, or transform via function
  }
});

console.log(output);
// {
//   a: 1,
//   b: 'hello',
//   c: [ 1, 'two', 3 ],
//   d: { x: 10, y: 20, z: [ 'default', 0, 2 ] }
// }

Invalid data throws immediately:

// c contains false — not a string or number
cocochex({ c: [1, 2, false] }, { c: ["string", "number"] });
// throws: false is invalid in "c". allowed types or values are: Type<string>, Type<number>.

API

cocochex(params: any, struct: any, required?: string[]): any
  • params: input value to validate/transform.
  • struct: schema definition.
  • required: list of required key paths. Default is [].

Returns the validated (and possibly transformed) value.

Important Behavior

  • Validation is recursive.
  • Object validation expects plain objects only.
    • Arrays are not accepted where object is expected.
    • null is not accepted as object.
  • The function mutates object and array values in place when applying validators/defaults.
  • Custom validator functions can return a transformed value or throw an error.

Schema Reference

1. Primitive Type Token

Use one of:

  • "string"
  • "number"
  • "boolean"
  • "object" (plain object only)
  • "array"
  • "function"
  • "null"
  • "undefined"

Example:

{ age: "number", name: "string", onChange: "function", deletedAt: "null" }

2. Exact Value

Any non-function, non-schema-list value can be used as an exact match.

{ status: "active", retries: 3, enabled: true }

3. Custom Validator Function

If the schema node is a function, it receives the current value and must:

  • return a value (validated/transformed), or
  • throw an error
{ id: v => {
  if (typeof v !== "string" || v.length < 8) {
    throw new Error("id must be a string with length >= 8");
  }
  return v.toLowerCase();
}}

4. Nested Object Schema

{
  user: {
    name: "string",
    profile: {
      age: "number"
    }
  }
}

5. List of Single-Type/Single-Rule Values

A single-item schema list validates each item in an input array against that one rule.

{ tags: ["string"] }
{ scores: ["number"] }
{ ids: [v => String(v)] }

If the input is not an array, validation fails.

Edge cases:

  • ["string"] means "must be an array, and every item must be string".
  • [v => ...] means "must be an array, and apply this function to every item".
  • [v => ...] does not mean default value.
// Fails: input is not an array
cocochex({ check: 1 }, { check: [v => `given value is ${v}`] });
// throws: Type <number> is invalid in "check". Expected a list.

// Passes: function runs for each array item
cocochex(
  { check: [1, "Hello", false] },
  { check: [v => `given value is ${v}`] }
);
// => { check: ["given value is 1", "given value is Hello", "given value is false"] }

6. Multi-Type (Union-Like) Schema

A multi-item schema list tries each option until one passes.

{ value: ["string", "number"] }
{ token: ["string", null] }
{ payload: [
  { kind: "A", data: { x: "number" } },
  { kind: "B", data: { y: "string" } }
]}

When the input value is an array and the schema is a union of non-list rules (for example ["string", "number"]), each array item is validated against the union. So this schema accepts either:

  • a single scalar value matching one option, or
  • an array where each item matches at least one option.
cocochex({ check: 1 }, { check: ["string", "number"] });
// => { check: 1 }

cocochex({ check: [1, "2"] }, { check: ["string", "number"] });
// => { check: [1, "2"] }

cocochex({ check: [1, "2", true] }, { check: ["string", "number"] });
// throws: true is invalid in "check". allowed types or values are: Type<string>, Type<number>.

7. Default Value via Function (Missing Key)

For object properties only:

  • when a key is missing
  • and that key's schema is a list with more than one item whose last item is a function

then that function is called with no arguments and its return value is set as default.

{
  createdAt: ["string", () => new Date().toISOString()]
}

Important distinction:

  • [type1, type2] means union validation.
  • [type1, fn] means union validation with function fallback (and function default when key is missing).
  • [fn] means list-item rule only; it does not set a default for missing key.
// Missing key + [fn] => no default inserted
cocochex({}, { items: [() => true] });
// => {}

// Missing key + [type, fn] => default inserted via fn()
cocochex({}, { check: ["string", v => `setting default value, ignored given value is ${v}`] });
// => { check: "setting default value, ignored given value is undefined" }

// Existing scalar + [type, fn] => try type first, then fn fallback if type does not match
cocochex({ check: 1 }, { check: ["string", v => `no match. given value is ${v}`] });
// => { check: "no match. given value is 1" }

// Existing array + [type, fn] => per-item union behavior
cocochex({ check: [1, "Hello", false] }, { check: ["string", v => `no match. given value is ${v}`] });
// => { check: ["no match. given value is 1", "Hello", "no match. given value is false"] }

Required Keys

Use the third argument to enforce required keys.

cocochex(data, schema, ["id", "profile[email]"]);

Path format for nested keys uses bracket notation built from the parent path:

  • top-level: id
  • nested: profile[email]
  • deeper nested: profile[address][city]

If a required key is missing, an error is thrown:

Key "profile[email]" is required.

Error Style

Typical failures throw strings or validator-thrown errors, for example:

  • Data schema does not match.
  • Type <string> is invalid in "items". Expected a list of Type <number>.
  • "foo" is invalid in "value". allowed types or values are: Type<number>, "ok".

Recommendation: wrap calls in try/catch and normalize errors in your application layer.

More Examples

Union + Nested

const schema = {
  mode: ["dev", "prod"],
  source: [
    { type: "file", path: "string" },
    { type: "url", href: "string" }
  ]
};

Transform Array Items

const schema = {
  amounts: [v => {
    const n = Number(v);
    if (Number.isNaN(n)) throw new Error("invalid amount");
    return n;
  }]
};

Missing Optional Key with Default

const input = {};
const schema = {
  role: ["string", () => "guest"]
};

cocochex(input, schema); // => { role: "guest" }

TypeScript Notes

The package ships declaration files and can be imported in ESM or CJS environments.

  • ESM import:
import cocochex from "cocochex";
  • CJS require:
const cocochex = require("cocochex");

Current function signature is intentionally generic (any) to allow flexible schemas.