4.0.5 â€Ē Published 7 months ago

@pbinj/pbj-guards v4.0.5

Weekly downloads
-
License
MIT
Repository
github
Last release
7 months ago

@pbinj/pbj-guards

Type-safe runtime validation guards for PBinJ applications.

npm version License: MIT

Features

  • ðŸ›Ąïļ Runtime type validation
  • 📝 TypeScript type inference
  • 🔍 Detailed validation errors
  • ðŸŽŊ Schema-based validation
  • 🔄 Composable guards
  • ðŸŠķ Zero runtime dependencies

Installation

npm install @pbinj/pbj-guards
pnpm add @pbinj/pbj-guards
yarn add @pbinj/pbj-guards

Basic Usage

import { isString, isNumber, isBoolean, shape, array } from "@pbinj/pbj-guards";

// Basic type guards
const str = "hello";
isString(str); // true

// Object shape validation
const userGuard = shape({
  id: isNumber,
  name: isString,
  isActive: isBoolean,
});

const user = {
  id: 1,
  name: "John",
  isActive: true,
};

if (userGuard(user)) {
  // user is typed as { id: number; name: string; isActive: boolean }
  console.log(user.name);
}

Advanced Features

Array Validation

import { array, isString } from "@pbinj/pbj-guards";

const stringArrayGuard = array(isString);

const values = ["a", "b", "c"];
if (stringArrayGuard(values)) {
  // values is typed as string[]
  values.map((v) => v.toUpperCase());
}

Schema Composition

import { shape, array, isString, isNumber, required } from "@pbinj/pbj-guards";

const addressGuard = shape({
  street: required(isString),
  city: required(isString),
  zipCode: isString,
});

const userGuard = shape({
  id: required(isNumber),
  name: required(isString),
  addresses: array(addressGuard),
});

type User = GuardType<typeof userGuard>;
// User is now typed as {
//   id: number;
//   name: string;
//   addresses?: Array<{
//     street: string;
//     city: string;
//     zipCode?: string;
//   }>;
// }

Integration with PBinJ

import { context, pbjKey } from "@pbinj/pbj";
import { shape, isString, required } from "@pbinj/pbj-guards";

const configGuard = shape({
  apiKey: required(isString),
  baseUrl: required(isString),
});

const configKey = pbjKey<Config>("config");

context.register(configKey, () => {
  const config = loadConfig();
  if (!configGuard(config)) {
    throw new Error("Invalid configuration");
  }
  return config;
});

Available Guards

  • isString - Validates strings
  • isNumber - Validates numbers
  • isBoolean - Validates booleans
  • isInteger - Validates integer numbers
  • isNullish - Validates null or undefined values
  • isRequired - Validates non-null values
  • array - Creates array validators
  • shape - Creates object shape validators
  • allOf - Combines multiple guards
  • oneOf - Matches one of several guards
  • $ref - Creates recursive type references

Type Inference

The library provides full TypeScript type inference:

import { shape, isString, isNumber, GuardType } from "@pbinj/pbj-guards";

const personGuard = shape({
  name: isString,
  age: isNumber,
});

type Person = GuardType<typeof personGuard>;
// Person = { name?: string; age?: number }

JSON Schema Compatibility

Converting Guards to JSON Schema

The library provides built-in support for converting guards to JSON Schema (Draft 2020-12):

import { toSchema, shape, isString, isNumber, array } from "@pbinj/pbj-guards";

const userGuard = shape({
  name: isString,
  age: isNumber,
  tags: array(isString),
});

const schema = toSchema(userGuard);
// Outputs:
// {
//   "$schema": "https://json-schema.org/draft/2020-12/schema",
//   "type": "object",
//   "properties": {
//     "name": { "type": "string" },
//     "age": { "type": "number" },
//     "tags": {
//       "type": "array",
//       "items": { "type": "string" }
//     }
//   }
// }

OpenAPI 3.1.0 Compatibility

Guards can be used to generate OpenAPI 3.1.0 compatible schemas:

import { toSchema, shape, isString, isNumber } from "@pbinj/pbj-guards";

const userGuard = shape(
  {
    id: isNumber,
    email: isString,
  },
  {
    description: "A user in the system",
    title: "User",
  },
);

const schema = toSchema(userGuard, {
  // OpenAPI-specific metadata
  deprecated: false,
  example: {
    id: 1,
    email: "user@example.com",
  },
});

Advanced Schema Configuration

You can customize the generated schema with additional JSON Schema keywords:

import { array, isString, toSchema } from "@pbinj/pbj-guards";

const tagsGuard = array(isString, {
  minItems: 1,
  maxItems: 10,
  uniqueItems: true,
});

const schema = toSchema(tagsGuard);
// Outputs:
// {
//   "$schema": "https://json-schema.org/draft/2020-12/schema",
//   "type": "array",
//   "items": { "type": "string" },
//   "minItems": 1,
//   "maxItems": 10,
//   "uniqueItems": true
// }

Custom Formats and Patterns

Support for string formats and patterns:

import { isString, shape, toSchema } from "@pbinj/pbj-guards";

const userGuard = shape({
  email: isString({ format: "email" }),
  phone: isString({ pattern: "^\\+[1-9]\\d{1,14}$" }),
  website: isString({ format: "uri" }),
});

const schema = toSchema(userGuard);

Schema References and Definitions

Support for schema references and definitions:

import { shape, isString, isNumber, $ref, toSchema } from "@pbinj/pbj-guards";

const addressGuard = shape({
  street: isString,
  city: isString,
  country: isString,
});

const userGuard = shape({
  id: isNumber,
  name: isString,
  address: $ref("Address", addressGuard),
});

const schema = toSchema(userGuard);

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT

4.0.5

7 months ago

4.0.4

7 months ago

4.0.3

7 months ago

4.0.1

7 months ago

4.0.0

7 months ago

4.0.0-next.0

7 months ago

3.0.3

7 months ago

3.0.2

7 months ago

3.0.0

9 months ago