@naviary-sanctuary/schema-gen
v0.3.0
Published
Automatically generate validation schemas from TypeScript class definitions
Downloads
210
Maintainers
Readme
schema-gen
CLI tool to automatically generate validation schemas from TypeScript class definitions
Why?
When building APIs with validation, you often define classes for your DTOs (or domain models) and then have to manually write validation schemas:
// 1. You write your class
class User {
id: string;
name: string;
email: string;
createdAt: Date;
}
// 2. Then you manually write the schema again
const userSchema = t.Object({
id: t.String(),
name: t.String(),
email: t.String(),
createdAt: t.Date(),
});This is:
- ❌ Repetitive and error-prone
- ❌ Hard to maintain (changes need to be synced)
- ❌ Time-consuming
schema-gen automatically generates validation schemas from your TypeScript classes, keeping them in sync with a single command.
Features
- 🚀 Generate schemas from TypeScript classes
- 📦 Multiple schema libraries: Elysia, TypeBox, and Zod
- 📝 Separate file generation (inline mode coming soon)
- ⚙️ Flexible configuration via
schema-gen.config.json - 🎯 Optimized for Bun, compatible with Node.js
- 🔧 CLI flags override config for one-off cases
Installation
Choose your preferred installation method:
Homebrew (macOS/Linux)
brew tap Naviary-Sanctuary/schema-gen
brew install schema-genBun (Recommended)
bun install -g @naviary-sanctuary/schema-genNode.js / npm
This package supports Node.js >= 18.0.0.
npm install -g @naviary-sanctuary/schema-genQuick Install Script
curl -fsSL https://raw.githubusercontent.com/Naviary-Sanctuary/schema-gen/main/install.sh | bashManual Installation
Download the latest binary from GitHub Releases:
# macOS (ARM64)
curl -L https://github.com/Naviary-Sanctuary/schema-gen/releases/latest/download/schema-gen-macos-arm64 -o schema-gen
chmod +x schema-gen
sudo mv schema-gen /usr/local/bin/
# Linux (x64)
curl -L https://github.com/Naviary-Sanctuary/schema-gen/releases/latest/download/schema-gen-linux-x64 -o schema-gen
chmod +x schema-gen
sudo mv schema-gen /usr/local/bin/Quick Start
1. Initialize Configuration
schema-gen initThis creates a schema-gen.config.json file:
{
"mappings": [
{
"include": ["src/**/*.ts"],
"output": {
"pattern": "schemas/{filename}.schema.ts"
}
}
],
"generator": "elysia",
"exclude": ["**/*.test.ts", "**/*.spec.ts"]
}2. Create Your Classes
// src/models/user.ts
export class User {
id: string;
name: string;
email: string;
age?: number;
tags: string[];
createdAt: Date;
}3. Generate Schemas
schema-gen generate4. Result
// schemas/user.schema.ts
import { t } from 'elysia';
export const userSchema = t.Object({
id: t.String(),
name: t.String(),
email: t.String(),
age: t.Optional(t.Number()),
tags: t.Array(t.String()),
createdAt: t.Date(),
});CLI Commands
init
Create a default configuration file:
schema-gen initgenerate
Generate schemas from your classes:
schema-gen generate
# With custom config path
schema-gen generate -c custom-config.json
# For specific file only (ignores "include" patterns)
schema-gen generate --target src/models/user.tsConfiguration
Basic Configuration
{
"mappings": [
{
"include": ["src/**/*.ts"],
"output": {
"pattern": "schemas/{filename}.schema.ts"
}
}
],
"generator": "elysia",
"exclude": ["**/*.test.ts", "**/*.spec.ts"]
}Configuration Options
| Option | Type | Required | Description |
| ----------- | ------------------------ | -------- | ----------------------------------------------------------- |
| mappings | MappingRule[] | ✓ | Array of mapping rules defining input/output patterns |
| generator | "elysia" \| "typebox" \| "zod" | ✓ | Schema generator to use |
| exclude | string[] | ✗ | Global exclude patterns |
| overwrite | boolean | ✗ | Whether to overwrite existing files (default: false) |
| mode | "separate" \| "inline" | ✗ | Generation mode (default: "separate", inline coming soon) |
Mapping Rule
Each mapping rule defines which files to process and where to output schemas:
{
"include": string[]; // Glob patterns for files to process
"output": {
"pattern": string; // Output path pattern with variables
},
"variables": { // [Optional] Custom variables
[key: string]: string | { regex: string };
}
}Output Pattern Variables
Use these variables in your output patterns:
{filename}: Filename without extension (e.g.,userfromuser.ts){dirname}: Directory path (e.g.,src/modelsfromsrc/models/user.ts){extension}: File extension (e.g.,.ts)
Custom Variables
You can define custom variables for each mapping rule. These can be static strings or dynamic values extracted from the source file path using regular expressions.
Static Variables
{
"include": ["src/**/*.ts"],
"output": { "pattern": "generated/{version}/{filename}.ts" },
"variables": {
"version": "v1"
}
}Dynamic Extraction (Regex)
Extract parts of the source path using the first capturing group of a regular expression:
{
"include": ["src/modules/*/domain/*.ts"],
"output": { "pattern": "generated/{module}/{filename}.schema.ts" },
"variables": {
"module": { "regex": "src/modules/([^/]+)/" }
}
}If the source file is src/modules/user/domain/model.ts, the {module} variable will be user.
[!TIP] Custom variables can also be used to override built-in variables like
{filename}or{dirname}if you define them with the same name.
Advanced Configuration Examples
Multiple Mappings
Process different source directories to different outputs:
{
"mappings": [
{
"include": ["src/models/**/*.ts"],
"output": {
"pattern": "src/route/{filename}/schema.ts"
}
},
{
"include": ["src/dto/**/*.ts"],
"output": {
"pattern": "src/api/schemas/{filename}.schema.ts"
}
}
],
"generator": "elysia"
}Result:
src/models/user.ts → src/route/user/schema.ts
src/dto/product.dto.ts → src/api/schemas/product.dto.schema.tsPreserve Directory Structure
Keep the original directory structure in output:
{
"mappings": [
{
"include": ["src/**/*.ts"],
"output": {
"pattern": "{dirname}/schemas/{filename}.schema.ts"
}
}
],
"generator": "typebox"
}Result:
src/models/user.ts → src/models/schemas/user.schema.ts
src/models/domain/product.ts → src/models/domain/schemas/product.schema.tsNegative Patterns
Exclude specific patterns from processing:
{
"mappings": [
{
"include": ["src/**/*.ts", "!src/draft/**", "!src/internal/**"],
"output": {
"pattern": "schemas/{filename}.schema.ts"
}
}
],
"generator": "elysia",
"exclude": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"]
}Supported Types
schema-gen supports a wide range of TypeScript types:
Primitives
string,number,boolean,Datenull,undefined,any
Arrays
tags: string[] // → t.Array(t.String())
matrix: number[][] // → t.Array(t.Array(t.Number()))Objects
address: {
street: string;
city: string;
}
// → t.Object({ street: t.String(), city: t.String() })Unions & Literals
status: 'active' | 'inactive'; // → t.UnionEnum(['active', 'inactive'])
priority: 1 | 2 | 3; // → t.UnionEnum([1, 2, 3])
value: string | number; // → t.Union([t.String(), t.Number()])Optional Properties
age?: number // → t.Optional(t.Number())Schema Generators
Elysia
Uses Elysia's built-in t utility:
import { t } from 'elysia';
export const userSchema = t.Object({
id: t.String(),
name: t.String(),
});TypeBox
Uses standalone TypeBox library:
import { Type as t } from '@sinclair/typebox';
export const userSchema = t.Object({
id: t.String(),
name: t.String(),
});Development
# Install dependencies
bun install
# Run in development
bun run dev
# Build
bun run build
# Run tests
bun test
# Type checking
bun run typecheck
# Linting
bun run lint
# Formatting
bun run formatContributing
This project follows the Contributor Covenant Code of Conduct.
See CONTRIBUTING.md for contribution guidelines.
