@ambrosia-unce/validator
v1.0.3
Published
Type-safe compile-time validation for Ambrosia framework
Maintainers
Readme
@ambrosia-unce/validator
Type-safe compile-time validation for Ambrosia framework using Bun plugin system and TypeScript Compiler API.
Features
- ✅ Zero runtime overhead - Validation code generated at compile-time
- ✅ Type-safe - Full TypeScript type inference
- ✅ No decorators - Just TypeScript types
- ✅ No schema duplication - Types are the schema
- ✅ Branded types - Email, UUID, PositiveInt, and more
- ✅ JSDoc constraints - @minLength, @pattern, etc.
- ✅ Bun native - Uses Bun plugin system
Installation
bun add @ambrosia-unce/validatorSetup
Add to your bunfig.toml:
preload = ["@ambrosia-unce/validator/preload"]That's it! The plugin is now active.
Usage
Basic validation
import { validate, assert, is } from '@ambrosia-unce/validator';
interface User {
name: string;
email: string;
age: number;
}
// validate<T>() - Returns result object
const result = validate<User>(data);
if (result.success) {
console.log(result.data.name);
} else {
console.error(result.errors);
}
// assert<T>() - Throws on error
try {
const user = assert<User>(data);
console.log(user.name);
} catch (error) {
console.error(error);
}
// is<T>() - Type guard
if (is<User>(data)) {
// data is User here
console.log(data.name);
}Branded types
import type { Email, UUID, PositiveInt } from '@ambrosia-unce/validator/types';
interface User {
id: UUID;
email: Email;
age: PositiveInt;
name: string;
}
const user = assert<User>({
id: "550e8400-e29b-41d4-a716-446655440000",
email: "[email protected]",
age: 25,
name: "Alice"
});Available branded types:
Email- RFC 5322 emailUUID- UUID v4URL- Valid HTTP/HTTPS URLPositiveInt- Integer > 0NonNegativeInt- Integer >= 0DateString- ISO 8601 dateDateTime- ISO 8601 datetimePhoneNumber- E.164 formatIPv4,IPv6- IP addressesHexColor- #RRGGBB or #RGB- And more...
JSDoc constraints
interface UpdateUserDto {
/**
* @minLength 3
* @maxLength 50
* @pattern ^[a-zA-Z0-9_]+$
*/
name?: string;
/**
* @format email
*/
email?: string;
/**
* @minimum 18
* @maximum 120
*/
age?: number;
}
const dto = assert<UpdateUserDto>(data);With Ambrosia HTTP
import { Controller, Post, Body } from '@ambrosia-unce/http';
import { assert } from '@ambrosia-unce/validator';
interface CreateUserDto {
name: string;
email: string;
}
@Controller('/users')
export class UserController {
@Post('/')
async create(@Body() data: unknown) {
const dto = assert<CreateUserDto>(data);
// dto is validated and typed!
return this.userService.create(dto);
}
}How it works
The plugin uses TypeScript Compiler API to:
- Find all
validate<T>(),assert<T>(),is<T>()calls - Analyze the type
Tusing TypeScript's type checker - Generate optimized inline validation code
- Replace the function call with generated code
Before transformation:
const user = assert<User>(data);After transformation:
const user = ((data) => {
if (typeof data !== "object" || data === null)
throw new ValidationError("must be an object");
if (typeof data.name !== "string")
throw new ValidationError("name must be string");
if (typeof data.email !== "string")
throw new ValidationError("email must be string");
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email))
throw new ValidationError("email must be valid");
if (typeof data.age !== "number")
throw new ValidationError("age must be number");
return data;
})(data);Configuration
Custom plugin options:
// validator-config.ts
import { plugin } from "bun";
import { createValidatorPlugin } from "@ambrosia-unce/validator/plugin";
plugin(createValidatorPlugin({
debug: true, // Enable debug logging
include: /\.ts$/, // File patterns to include
exclude: /node_modules/, // File patterns to exclude
}));Then in bunfig.toml:
preload = ["./validator-config.ts"]License
MIT
