fortify-schema
Version:
TypeScript interface-like schema validation system that's easier to use than Zod
275 lines (257 loc) • 6.59 kB
text/typescript
/**
* TypeScript Interface-like Schema System
*
* The most intuitive way to define schemas - just like TypeScript interfaces!
*
* @example
* ```typescript
* import { Interface } from "fortify-schema";
*
* // Define schema like a TypeScript interface
* const UserSchema = Interface({
* id: "number",
* email: "email",
* name: "string",
* age: "number?", // Optional
* isActive: "boolean?", // Optional
* tags: "string[]?", // Optional array
* role: "admin", // Constant value
* profile: { // Nested object
* bio: "string?",
* avatar: "url?"
* }
* });
*
* // Validate data
* const result = UserSchema.safeParse(userData);
* ```
*/
import { InterfaceSchema } from "./InterfaceSchema";
import {
ConstantValue,
OptionalConstantValue,
OptionalSchemaInterface,
SchemaInterface,
SchemaOptions,
SchemaFieldType,
UnionValue,
} from "../../../types/SchemaValidator.type";
import { InferSchemaType } from "./types/interface.type";
/**
* Create a schema using TypeScript interface-like syntax with full type inference
*
* @param definition - Schema definition using TypeScript-like syntax
* @param options - Optional validation options
* @returns InterfaceSchema instance with inferred types
*
* @example Basic Usage
* ```typescript
* const UserSchema = Interface({
* id: "number",
* email: "email",
* name: "string",
* age: "number?",
* isActive: "boolean?",
* tags: "string[]?"
* });
*
* // result is fully typed as:
* // SchemaValidationResult<{
* // id: number;
* // email: string;
* // name: string;
* // age?: number;
* // isActive?: boolean;
* // tags?: string[];
* // }>
* const result = UserSchema.safeParse(data);
* ```
*
* @example With Constraints
* ```typescript
* const UserSchema = Interface({
* username: "string(3,20)", // 3-20 characters
* age: "number(18,120)", // 18-120 years
* tags: "string[](1,10)?", // 1-10 tags, optional
* });
* ```
*
* @example Nested Objects
* ```typescript
* const OrderSchema = Interface({
* id: "number",
* customer: {
* name: "string",
* email: "email",
* address: {
* street: "string",
* city: "string",
* zipCode: "string"
* }
* },
* items: [{
* name: "string",
* price: "number",
* quantity: "int"
* }]
* });
* ```
*/
export function Interface<const T extends SchemaInterface>(
definition: T,
options?: SchemaOptions
): InterfaceSchema<InferSchemaType<T>> {
return new InterfaceSchema<InferSchemaType<T>>(definition, options);
}
/**
* Type helper for inferring TypeScript types from schema definitions
*
* @example
* ```typescript
* const UserSchema = Interface({
* id: "number",
* email: "email",
* name: "string",
* age: "number?",
* tags: "string[]?"
* });
*
* // Infer the TypeScript type
* type User = InferType<typeof UserSchema>;
* // User = {
* // id: number;
* // email: string;
* // name: string;
* // age?: number;
* // tags?: string[];
* // }
* ```
*/
export type InferType<T extends InterfaceSchema<any>> =
T extends InterfaceSchema<infer U> ? U : never;
// Export the main inference type for direct use
export type { InferSchemaType };
// Re-export types for convenience
export type {
SchemaInterface,
SchemaOptions,
SchemaFieldType,
ConstantValue,
} from "../../../types/SchemaValidator.type";
export { InterfaceSchema } from "./InterfaceSchema";
/**
* Available field types for schema definitions
*/
export const FieldTypes = {
// Basic types
STRING: "string" as const,
STRING_OPTIONAL: "string?" as const,
NUMBER: "number" as const,
NUMBER_OPTIONAL: "number?" as const,
BOOLEAN: "boolean" as const,
BOOLEAN_OPTIONAL: "boolean?" as const,
DATE: "date" as const,
DATE_OPTIONAL: "date?" as const,
ANY: "any" as const,
ANY_OPTIONAL: "any?" as const,
// String formats
EMAIL: "email" as const,
EMAIL_OPTIONAL: "email?" as const,
URL: "url" as const,
URL_OPTIONAL: "url?" as const,
UUID: "uuid" as const,
UUID_OPTIONAL: "uuid?" as const,
PHONE: "phone" as const,
PHONE_OPTIONAL: "phone?" as const,
SLUG: "slug" as const,
SLUG_OPTIONAL: "slug?" as const,
USERNAME: "username" as const,
USERNAME_OPTIONAL: "username?" as const,
// Number types
INT: "int" as const,
INT_OPTIONAL: "int?" as const,
POSITIVE: "positive" as const,
POSITIVE_OPTIONAL: "positive?" as const,
FLOAT: "float" as const,
FLOAT_OPTIONAL: "float?" as const,
// Array types
STRING_ARRAY: "string[]" as const,
STRING_ARRAY_OPTIONAL: "string[]?" as const,
NUMBER_ARRAY: "number[]" as const,
NUMBER_ARRAY_OPTIONAL: "number[]?" as const,
BOOLEAN_ARRAY: "boolean[]" as const,
BOOLEAN_ARRAY_OPTIONAL: "boolean[]?" as const,
INT_ARRAY: "int[]" as const,
INT_ARRAY_OPTIONAL: "int[]?" as const,
EMAIL_ARRAY: "email[]" as const,
EMAIL_ARRAY_OPTIONAL: "email[]?" as const,
URL_ARRAY: "url[]" as const,
URL_ARRAY_OPTIONAL: "url[]?" as const,
// Record types
RECORD_STRING_ANY: "record<string,any>" as const,
RECORD_STRING_ANY_OPTIONAL: "record<string,any>?" as const,
RECORD_STRING_STRING: "record<string,string>" as const,
RECORD_STRING_STRING_OPTIONAL: "record<string,string>?" as const,
RECORD_STRING_NUMBER: "record<string,number>" as const,
RECORD_STRING_NUMBER_OPTIONAL: "record<string,number>?" as const,
} as const;
/**
* Quick schema creation helpers
*/
export const QuickSchemas = {
/**
* User schema with common fields
*/
User: Interface({
id: "number",
email: "email",
name: "string",
createdAt: "date?",
updatedAt: "date?",
}),
/**
* API response schema
*/
APIResponse: Interface({
success: "boolean",
data: "any?",
errors: "string[]?",
timestamp: "date?",
}),
/**
* Pagination schema
*/
Pagination: Interface({
page: "int",
limit: "int",
total: "int",
hasNext: "boolean?",
hasPrev: "boolean?",
}),
/**
* Address schema
*/
Address: Interface({
street: "string",
city: "string",
state: "string?",
zipCode: "string",
country: "string",
}),
/**
* Contact info schema
*/
Contact: Interface({
email: "email?",
phone: "phone?",
website: "url?",
}),
};
/**
* Schema modification utilities - transform and combine schemas
*/
export { Mod } from "../../../utils/Mod";
/**
* Helper functions for creating schema values
*/
export { Make } from "../../../utils/Make";