Skip to content

Repository files navigation

json-schema-validator-gen

A lightweight JSON Schema validator generator that creates minimal TypeScript code and type definitions.

Features

  • 🚀 Zero runtime dependencies - Generated validators are standalone
  • 🔍 Type-safe - Full TypeScript support with generated type definitions
  • Fast validation - No runtime schema parsing, direct code execution
  • 🌐 Universal - Works in Node.js and browsers
  • 📋 Detailed errors - Rich error information with path, expected/received values

Installation

npm install -D @speria-jp/json-schema-validator-gen
# or
yarn add -D @speria-jp/json-schema-validator-gen
# or
pnpm add -D @speria-jp/json-schema-validator-gen
# or
bun add -D @speria-jp/json-schema-validator-gen

Usage

CLI

Basic usage:

# Generate from root schema (type name derived from file name)
npx @speria-jp/json-schema-validator-gen -s user-schema.json -o validator.ts

# Generate with custom type name
npx @speria-jp/json-schema-validator-gen -s schema.json -o validator.ts \
  -t 'path=#,name=User'

# Generate from specific definition
npx @speria-jp/json-schema-validator-gen -s schema.json -o validator.ts \
  -t '#/$defs/User'

# Generate multiple types with custom names
npx @speria-jp/json-schema-validator-gen -s schema.json -o types.ts \
  -t 'path=#/$defs/User,name=AppUser' \
  -t 'path=#/$defs/Post,name=BlogPost'

If installed locally, you can also use your package manager directly:

# npm
npx json-schema-validator-gen -s schema.json -o validator.ts

# yarn
yarn json-schema-validator-gen -s schema.json -o validator.ts

# pnpm
pnpm json-schema-validator-gen -s schema.json -o validator.ts

# bun
bun json-schema-validator-gen -s schema.json -o validator.ts

Options:

  • -s, --schema - Path to JSON Schema file (required)
  • -o, --output - Output path for generated code (required)
  • -t, --target - JSON Schema target path (e.g., #/$defs/User). Can be specified multiple times to generate multiple types. Supports custom type names with path=...,name=... format. Defaults to # (root schema)
  • -h, --help - Show help message

Programmatic API

import { generate } from '@speria-jp/json-schema-validator-gen';

// Generate from root schema (default, type name derived from file name)
const result = await generate({
  schemaPath: './user-schema.json',
  outputPath: './validator.ts'
});

// Generate from root with custom type name
const result = await generate({
  schemaPath: './schema.json',
  outputPath: './validator.ts',
  targets: ['path=#,name=User']
});

// Generate from specific targets
const results = await generate({
  schemaPath: './schema.json',
  outputPath: './types.ts',
  targets: ['#/$defs/User', '#/$defs/Post']
});

// Generate with custom type names
const results = await generate({
  schemaPath: './schema.json',
  outputPath: './types.ts',
  targets: [
    'path=#/$defs/User,name=AppUser',
    'path=#/$defs/Post,name=BlogPost'
  ]
});

Example

Given a JSON Schema:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "title": "User",
  "required": ["id", "name", "email"],
  "properties": {
    "id": {
      "type": "integer",
      "minimum": 1
    },
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "email": {
      "type": "string",
      "format": "email",
      "pattern": "^[\\w.-]+@[\\w.-]+\\.[a-z]{2,}$"
    },
    "age": {
      "type": "integer",
      "minimum": 0,
      "maximum": 150
    },
    "tags": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "role": {
      "type": "string",
      "enum": ["admin", "user", "guest"]
    }
  },
  "additionalProperties": false
}

The generator creates:

export type User = {
    id: number;
    name: string;
    email: string;
    age?: number;
    tags?: string[];
    role?: "admin" | "user" | "guest";
};

// Returns ValidationResult with detailed error information
export function validateUser(value: unknown, options?: ValidationOptions): ValidationResult<User> {
    // ... validation logic
}

// Throws an error if validation fails, returns the validated value otherwise
export function unsafeValidateUser(value: unknown): User {
    // ... validation logic
}

Usage:

import { validateUser, unsafeValidateUser, type User } from './validator';

// Using validateUser - returns ValidationResult
const result = validateUser(data);
if (result.success) {
    console.log('Valid user:', result.data);
} else {
    console.log('Validation errors:', result.issues);
    // Each issue contains: code, path, message, expected, received
}

// Using unsafeValidateUser - throws on invalid input
try {
    const user = unsafeValidateUser(data);
    console.log('Valid user:', user);
} catch (error) {
    console.log('Validation failed:', error.message);
}

// Abort early option - stop on first error
const result = validateUser(data, { abortEarly: true });

Multiple Types Example

You can generate multiple types from a single JSON Schema file using the --target option:

# Generate User and Post types from $defs (type names derived from path)
npx json-schema-validator-gen -s schema.json -o types.ts \
  -t '#/$defs/User' -t '#/$defs/Post'

Given a JSON Schema with $defs:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$defs": {
    "Address": {
      "type": "object",
      "properties": {
        "street": { "type": "string" },
        "city": { "type": "string" },
        "zipCode": { "type": "string" }
      },
      "required": ["street", "city"]
    },
    "User": {
      "type": "object",
      "properties": {
        "id": { "type": "string" },
        "name": { "type": "string" },
        "email": { "type": "string" },
        "address": { "$ref": "#/$defs/Address" }
      },
      "required": ["id", "name", "email"]
    },
    "Post": {
      "type": "object",
      "properties": {
        "id": { "type": "string" },
        "title": { "type": "string" },
        "authorId": { "type": "string" }
      },
      "required": ["id", "title", "authorId"]
    }
  }
}

The generator automatically collects dependencies and creates all necessary types in a single file. Note that Address is also generated because it's referenced by User, but it's not exported since it wasn't specified in --target:

// Address type (generated as dependency, not exported)
type Address = {
    street: string;
    city: string;
    zipCode?: string;
};

// User type uses type reference instead of inline expansion
export type User = {
    id: string;
    name: string;
    email: string;
    address?: Address;
};

export type Post = {
    id: string;
    title: string;
    authorId: string;
};

// Dependency validator (not exported)
function validateAddress(value: unknown): ValidationResult<Address> { /* ... */ }

// Exported validators for User and Post
export function validateUser(value: unknown): ValidationResult<User> { /* ... */ }
export function unsafeValidateUser(value: unknown): User { /* ... */ }

export function validatePost(value: unknown): ValidationResult<Post> { /* ... */ }
export function unsafeValidatePost(value: unknown): Post { /* ... */ }

Validation Result

Generated validators return a ValidationResult<T> discriminated union:

type ValidationResult<T> =
  | { success: true; data: T }
  | { success: false; issues: ValidationIssue[] };

interface ValidationIssue {
  code: ValidationIssueCode;
  path: (string | number)[];  // e.g., ["address", "zipCode"] or ["items", 0]
  message: string;
  expected: string;
  received: string;
}

Error Codes

Code Description Example
invalid_type Value has wrong type Expected string, received number
missing_key Required property is missing Missing email property
too_small Value below minimum Number < minimum, string length < minLength
too_big Value above maximum Number > maximum, string length > maxLength
invalid_string String doesn't match pattern Email pattern mismatch
invalid_value Value not in allowed set Enum value not in list
not_integer Number is not an integer 25.5 instead of 25
not_unique Array has duplicate items ["a", "a"] with uniqueItems: true
unrecognized_key Unknown property Extra property with additionalProperties: false

Supported JSON Schema Features

  • Basic types: string, number, integer, boolean, null, array, object
  • Type constraints:
    • Numbers: minimum, maximum
    • Strings: minLength, maxLength, pattern, format
    • Arrays: items validation
    • Integers: proper integer validation
  • Object validation: required properties, additionalProperties
  • Array validation: items schema validation
  • Enums and const values: Full enum support
  • Union types: Full support for oneOf and anyOf with validation
  • References: $ref support for local definitions (#/definitions/ and #/$defs/)
  • Optional properties: Proper handling of required vs optional fields

Security Considerations

For general security considerations when working with JSON Schema validation, please refer to the Ajv Security Guidelines. While this tool generates code at build time rather than runtime, many of the same principles apply regarding input validation and schema design.

Development

# Install dependencies
bun install

# Run development CLI
bun run dev

# Build the project
bun run build

# Run tests
bun test

# Type checking
bun run typecheck

# Linting
bun run lint
bun run lint:fix

License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages