{"id":21423163,"url":"https://github.com/skyleague/therefore","last_synced_at":"2025-07-14T08:31:21.041Z","repository":{"id":56806160,"uuid":"524008156","full_name":"skyleague/therefore","owner":"skyleague","description":"Therefore, the JSON Schema toolkit for TypeScript.","archived":false,"fork":false,"pushed_at":"2025-07-08T11:09:06.000Z","size":4584,"stargazers_count":6,"open_issues_count":2,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-07-08T11:38:24.150Z","etag":null,"topics":["json-schema","skyleague","typescript"],"latest_commit_sha":null,"homepage":"https://skyleague.github.io/therefore/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skyleague.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-08-12T08:16:25.000Z","updated_at":"2025-07-08T11:06:27.000Z","dependencies_parsed_at":"2024-01-03T14:25:51.045Z","dependency_job_id":"dcc51c0d-a43e-460d-8a11-29fa5c344e81","html_url":"https://github.com/skyleague/therefore","commit_stats":{"total_commits":74,"total_committers":6,"mean_commits":"12.333333333333334","dds":"0.33783783783783783","last_synced_commit":"b9c129394ffabc8289f5fd09d2e70ec873232411"},"previous_names":[],"tags_count":161,"template":false,"template_full_name":null,"purl":"pkg:github/skyleague/therefore","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skyleague%2Ftherefore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skyleague%2Ftherefore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skyleague%2Ftherefore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skyleague%2Ftherefore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skyleague","download_url":"https://codeload.github.com/skyleague/therefore/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skyleague%2Ftherefore/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265262598,"owners_count":23736427,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json-schema","skyleague","typescript"],"created_at":"2024-11-22T21:14:36.607Z","updated_at":"2025-07-14T08:31:21.031Z","avatar_url":"https://github.com/skyleague.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# [∴ Therefore](https://skyleague.github.io/therefore/)\n\n\u003cp align=\"center\"\u003e\n  \u003cimg alt=\"Downloads\" src=\"https://img.shields.io/npm/dm/@skyleague/therefore\" /\u003e\n  \u003cimg alt=\"Version\" src=\"https://img.shields.io/npm/v/@skyleague/therefore\" /\u003e\n  \u003cimg src=\"https://img.shields.io/node/v/@skyleague/therefore\" /\u003e\n  \u003ca href=\"#\" target=\"_blank\"\u003e\n    \u003cimg alt=\"License: MIT\" src=\"https://img.shields.io/badge/License-MIT-yellow.svg\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003c!-- panels:start --\u003e\n\n\u003c!-- div:left-panel --\u003e\nTherefore is a schema-centric tool that deeply understands and works with data schemas. It enables you to:\n\n**Schema Definition \u0026 Conversion**\n- Define schemas in multiple formats (Zod, Therefore Schema Language, JSON Schema)\n- Convert between different schema formats while preserving semantics\n\n**Code \u0026 Data Generation**\n- Generate code (TypeScript, JSON Schema, API clients)\n- Create test data through schema-based arbitraries\n\n**Schema Composition**\n- Compose and transform schemas\n- Reference and reuse schema components\n\n\u003c!-- div:right-panel --\u003e\n\n```mermaid\ngraph LR\n    subgraph Input\n        A[Zod Schemas]\n        B[JSON Schema]\n        C[OpenAPI Spec]\n        D[Therefore Schemas]\n        E[GraphQL Schema]\n    end\n\n    T[Therefore]\n\n    subgraph Output\n        F[JSON Schema]\n        G[TypeScript Types]\n        H[API Clients]\n        I[Validation Code]\n        J[GraphQL Types]\n        K[Test Data]\n    end\n\n    A --\u003e T\n    B --\u003e T\n    C --\u003e T\n    D --\u003e T\n    E --\u003e T\n    T --\u003e F\n    T --\u003e G\n    T --\u003e H\n    T --\u003e I\n    T --\u003e J\n    T --\u003e K\n```\n\n\u003c!-- panels:end --\u003e\n\n## Core Concepts\n\n\u003c!-- panels:start --\u003e\n\n\u003c!-- div:left-panel --\u003e\n### Schema Understanding\n\nTherefore deeply understands schemas and their relationships:\n\n**Type System**\n- Type hierarchies and relationships\n- Cross-format compatibility\n\n**Validation \u0026 Composition**\n- Validation rules and constraints\n- Schema composition patterns\n\n\u003c!-- div:right-panel --\u003e\n### Schema Operations\n\nTherefore can perform various operations on schemas:\n\n**Format Handling**\n- Convert between Zod, JSON Schema, OpenAPI, and GraphQL\n- Preserve validation rules and type information\n- Handle complex type relationships\n\n**Schema Management**\n- Reference and combine schemas\n- Handle circular dependencies\n- Support modular schema design\n\n**Output Generation**\n- Generate TypeScript types and validation\n- Create API clients from OpenAPI specs\n- Build GraphQL schemas and resolvers\n\n**Testing Support**\n- Create arbitrary test data from schemas\n- Support property-based testing\n- Generate realistic mock data\n\n\u003c!-- panels:end --\u003e\n\n## Why Use Therefore?\n\n\u003c!-- panels:start --\u003e\n\n\u003c!-- div:title-panel --\u003e\n### The Problem\n\n\u003c!-- div:left-panel --\u003e\nWhen building modern applications, you often need to:\n\n**Schema Management**\n- Work with multiple schema formats\n- Convert between different formats\n- Maintain schema semantics\n\n**Development Needs**\n- Generate consistent types\n- Create validation code\n- Build test data\n\nTraditional approaches require manually maintaining multiple schema definitions or writing complex conversion code by hand.\n\n\u003c!-- div:right-panel --\u003e\n### The Solution\n\n**1. Schema Format Support**\n- Define schemas in your preferred format (Zod recommended)\n- Import existing JSON Schema and OpenAPI specs\n- Convert between formats while preserving semantics\n- Keep all your schemas in sync\n\n**2. Schema Operations**\n- Convert between different schema formats\n- Generate test data from your schemas\n- Compose and transform schemas\n- Reference and reuse schema components\n\n**3. Code Generation**\n- Generate TypeScript types from any supported format\n- Create API clients from OpenAPI specs\n- Build GraphQL schemas and resolvers\n- Zero runtime overhead\n\n\u003c!-- panels:end --\u003e\n\n### When to Use\n\nUse Therefore when you:\n- Work with multiple schema formats (OpenAPI, JSON Schema)\n- Want to generate type-safe API clients\n- Need to convert between different schema formats\n- Want consistent types and validation in TypeScript\n\nDon't use Therefore if you:\n- Only need simple TypeScript types\n- Don't need schema conversion or code generation\n- Don't work with multiple schema formats\n\n## Getting Started with Therefore\n\n\u003c!-- panels:start --\u003e\n\n\u003c!-- div:left-panel --\u003e\n### Choose Your Path\n\nTherefore offers multiple ways to work with schemas. Here's how to choose the right approach:\n\n**1. Using Zod (Recommended)**\n```typescript\n// Define your schema with Zod\nconst user = z.object({\n    name: z.string(),\n    age: z.number()\n})\n\n// Therefore will generate types and more\n```\nBest for:\n- New TypeScript projects\n- Projects already using Zod\n- When you need runtime validation\n\n**2. Using OpenAPI**\n```typescript\n// Define your OpenAPI spec\nconst api = $restclient({\n    openapi: '3.1.0',\n    info: {\n        title: 'User API',\n        version: '1.0.0'\n    },\n    paths: {\n        '/users': {\n            get: {\n                responses: {\n                    '200': {\n                        content: {\n                            'application/json': {\n                                schema: { type: 'array', items: { $ref: '#/components/schemas/User' } }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}, {\n    validator: 'zod'\n})\n\n// Therefore will generate a type-safe client\n```\nBest for:\n- Working with REST APIs\n- When you have existing OpenAPI specs\n- Building API clients\n\n**3. Using JSON Schema**\n```typescript\n// Import existing JSON Schema\nconst schema = $jsonschema({\n    type: 'object',\n    properties: {\n        name: { type: 'string' },\n        age: { type: 'number' }\n    },\n    required: ['name']\n})\n\n// Therefore will generate TypeScript types\n```\nBest for:\n- Projects with existing JSON Schema\n- Cross-language schema sharing\n- Legacy system integration\n\n\u003c!-- div:right-panel --\u003e\n\n### Quick Decision Guide\n\nChoose based on your primary need:\n\n**TypeScript Development**\n↳ Use Zod approach\n- Full TypeScript support\n- Runtime validation\n- Best developer experience\n\n**API Integration**\n↳ Use OpenAPI approach\n- Type-safe API clients\n- Request/response validation\n- API documentation\n\n**Schema Conversion**\n↳ Use JSON Schema approach\n- Cross-language compatibility\n- Legacy system support\n- Schema standardization\n\n**Not Sure?**\nStart with the Zod approach - it's the most flexible and can be converted to other formats later if needed.\n\n\u003c!-- panels:end --\u003e\n\n### Installation\n\n```terminal\n# Using npm\nnpm install @skyleague/therefore --save-dev\n\n# Using yarn\nyarn add -D @skyleague/therefore\n\n# Using pnpm\npnpm add -D @skyleague/therefore\n```\n\nTherefore is a development tool with zero runtime dependencies - it generates code at build time.\n\n### Quick Start\n\n\u003c!-- panels:start --\u003e\n\n\u003c!-- div:title-panel --\u003e\n\n#### Define Your Schema\n\n\u003c!-- div:left-panel --\u003e\n\nTherefore looks for schema definitions in `.schema.ts` files. You can:\n- Define data structures with Zod\n- Import existing JSON Schema files\n- Use OpenAPI specifications\n- Reference other schemas\n\nTherefore will use these definitions to generate all the code you need.\n\n\u003c!-- div:right-panel --\u003e\n\n\u003c!-- tabs:start --\u003e\n\n#### **Schema Definition**\n\n**src/schemas/user.schema.ts**\n\n[examples/docs/01-basic-zod.schema.ts](examples/docs/01-basic-zod.schema.ts ':include :type=code')\n\n#### **Generated Types**\n\n**src/schemas/user.type.ts**\n\n[examples/docs/01-basic-zod.type.ts](examples/docs/01-basic-zod.type.ts ':include :type=code')\n\n\u003c!-- tabs:end --\u003e\n\n\u003c!-- panels:end --\u003e\n\n\u003c!-- panels:start --\u003e\n\n\u003c!-- div:title-panel --\u003e\n\n#### Generate Code\n\n\u003c!-- div:left-panel --\u003e\n\nRun Therefore to process your schemas. It will:\n- Find all `.schema.ts` files\n- Generate TypeScript types and validation\n- Create JSON Schema files\n- Build API clients if using OpenAPI\n- Set up type guards and helpers\n\nAll generated code is type-safe and has zero runtime dependencies.\n\n\u003c!-- div:right-panel --\u003e\n\n```terminal\nnpx therefore -f src\n```\n\n\u003c!-- panels:end --\u003e\n\n\u003c!-- panels:start --\u003e\n\n\u003c!-- div:title-panel --\u003e\n\n#### Use Generated Code\n\n\u003c!-- div:left-panel --\u003e\n\nTherefore creates everything you need to work with your data:\n- Validate data at runtime with Zod\n- Use generated TypeScript types\n- Share JSON Schema with other services\n- Make type-safe API calls\n\nThe generated code is ready to use with no additional setup needed.\n\n\u003c!-- div:right-panel --\u003e\n\n```typescript\nimport { User } from './user.type'\nimport { user } from './user.schema'\n\n// Runtime validation\nconst data: unknown = JSON.parse(userInput)\nif (user.safeParse(data).success) {\n    // data is typed as User\n    console.log(`Valid user: ${data.name}`)\n}\n\n// Type guard usage\nif (User.is(data)) {\n    // data is typed as User here\n    console.log(data.name)\n}\n```\n\n\u003c!-- panels:end --\u003e\n\n## Schema Definition\n\nTherefore provides a rich set of primitives for defining schemas that can be used for both code generation and schema conversion.\n\n### Primitive Types\n\n#### String Type\n\n```typescript\n// Create a string schema\n$string()\n\n// Length validation\n$string().min(length: number)         // Minimum string length\n$string().max(length: number)         // Maximum string length\n$string().length(length: number)      // Exact string length\n$string().regex(pattern: RegExp|string) // Match regular expression\n\n// Format validation\n$string().email()      // Email address (e.g. \"user@example.com\")\n$string().uri()        // URI/URL (e.g. \"https://example.com\")\n$string().uuid()       // UUID v4 (e.g. \"123e4567-e89b-12d3-a456-426614174000\")\n$string().datetime()   // ISO datetime (e.g. \"2024-03-20T15:30:00Z\")\n$string().date()       // ISO date (e.g. \"2024-03-20\")\n$string().time()       // ISO time (e.g. \"15:30:00\")\n$string().duration()   // ISO duration (e.g. \"P1DT2H\")\n$string().ulid()       // ULID (e.g. \"01ARZ3NDEKTSV4RRFFQ69G5FAV\")\n$string().base64()     // Base64 (e.g. \"aGVsbG8=\")\n$string().hostname()   // Hostname (e.g. \"example.com\")\n$string().ipv4()       // IPv4 (e.g. \"192.168.1.1\")\n$string().ipv6()       // IPv6 (e.g. \"2001:db8::1\")\n```\n\n#### Number Type\n\n```typescript\n// Create a number schema\n$number()\n\n// Range validation\n$number().min(value: number)         // Minimum value (inclusive)\n$number().max(value: number)         // Maximum value (inclusive)\n$number().exclusiveMin(value: number) // Minimum value (exclusive)\n$number().exclusiveMax(value: number) // Maximum value (exclusive)\n\n// Type validation\n$number().integer()                  // Must be an integer\n$number().multipleOf(base: number)   // Must be multiple of base (e.g. 0.01 for cents)\n```\n\n#### Integer Type\n\n```typescript\n// Create an integer schema\n$integer()\n\n// Range validation\n$integer().min(value: number)         // Minimum value (inclusive)\n$integer().max(value: number)         // Maximum value (inclusive)\n$integer().exclusiveMin(value: number) // Minimum value (exclusive)\n$integer().exclusiveMax(value: number) // Maximum value (exclusive)\n$integer().multipleOf(base: number)   // Must be multiple of base\n```\n\n#### Boolean Type\n\n```typescript\n// Create a boolean schema\n$boolean()\n```\n\n#### Null Type\n\n```typescript\n// Create a null schema\n$null()  // Type that only accepts null\n```\n\n#### Const Type\n\n```typescript\n// Create a const schema\n$const(42)              // Type that only accepts 42\n$const('active')        // Type that only accepts 'active'\n$const(true)           // Type that only accepts true\n```\n\n#### Unknown Type\n\n```typescript\n// Create an unknown schema\n$unknown()  // Type that accepts any value\n```\n\n### Container Types\n\n#### Array Type\n\n```typescript\n// Create an array schema\n$array($string())                    // Array of strings\n$array($number())                    // Array of numbers\n$array($object({...}))              // Array of objects\n\n// Length validation\n$array().min(length: number)        // Minimum array length\n$array().max(length: number)        // Maximum array length\n$array().length(length: number)     // Exact array length\n$array().unique()                   // All items must be unique\n```\n\n#### Tuple Type\n\n```typescript\n// Create a tuple schema\n$tuple([$string(), $number()])      // [string, number]\n$tuple([$boolean(), $string(), $number()]) // [boolean, string, number]\n```\n\n#### Object Type\n\n```typescript\n// Create an object schema\n$object({\n    prop1: $string(),\n    prop2: $number(),\n    nested: $object({...})\n})\n\n// Schema modification\n$object().strict()                    // Disallow additional properties\n$object().extend({ newProp: $string() })  // Add new properties\n$object().merge(otherObject)          // Merge with another object schema\n$object().keyof()                     // Get enum of property names\n\n// Property selection\n$object().pick('prop1', 'prop2')      // Keep only specified properties\n$object().omit('prop1', 'prop2')      // Remove specified properties\n$object().partial()                   // Make all properties optional\n$object().partial('prop1', 'prop2')   // Make specific properties optional\n$object().required()                  // Make all properties required\n$object().required('prop1', 'prop2')  // Make specific properties required\n```\n\n#### Record Type\n\n```typescript\n// Create a record schema\n$record($string())                   // Record with string values\n$record($number())                   // Record with number values\n$record($object({...}))             // Record with object values\n```\n\n### Type Combinators\n\n#### Enum Type\n\n```typescript\n// Create an enum from array of strings\n$enum(['draft', 'published'])          // String literal union\n$enum(['low', 'medium', 'high'])      // Priority levels\n\n// Create an enum from record (string values only)\n$enum({\n    DRAFT: 'draft',\n    PUBLISHED: 'published',\n    ARCHIVED: 'archived'\n})\n```\n\n#### Union Type\n\n```typescript\n// Create a union schema\n$union([schema1, schema2])           // Union of two schemas\n$union([schema1, schema2, schema3])  // Union of multiple schemas\n\n// Example: Common use cases\nconst stringOrNumber = $union([\n    $string(),\n    $number()\n])\n\nconst status = $union([\n    $string().literal('loading'),\n    $object({\n        state: $string().literal('error'),\n        message: $string()\n    }),\n    $object({\n        state: $string().literal('success'),\n        data: $array($string())\n    })\n])\n```\n\n#### Intersection Type\n\n```typescript\n// Create an intersection schema\n$intersection([schema1, schema2])     // Must satisfy both schemas\n$intersection([schema1, schema2, schema3])  // Must satisfy all schemas\n\n// Example: Common use cases\nconst withTimestamps = $intersection([\n    $object({\n        id: $string().uuid(),\n        name: $string()\n    }),\n    $object({\n        createdAt: $string().datetime(),\n        updatedAt: $string().datetime()\n    })\n])\n```\n\n### Type Modifiers\n\n```typescript\n// Optional\nschema.optional()      // Makes schema optional (type | undefined)\n$string().optional()   // string | undefined\n$number().optional()   // number | undefined\n\n// Nullable\nschema.nullable()      // Makes schema nullable (type | null)\n$string().nullable()   // string | null\n$number().nullable()   // number | null\n\n// Default values\nschema.default(value)  // Provides default value if undefined\n$string().default('') // string (defaults to '')\n$number().default(0)  // number (defaults to 0)\n\n// Array conversion\nschema.array()        // Converts to array of schema\n$string().array()     // string[]\n$number().array()     // number[]\n\n// Combinations\n$string()\n  .nullable()\n  .optional()         // string | null | undefined\n\n$number()\n  .array()\n  .optional()         // number[] | undefined\n```\n\n### References\n\n```typescript\n// Reference another schema\n$ref(schema)                // Reference to schema in same file\n$moduleRef('./user', 'User') // Reference to schema in another file\n\n// Example: Schema references\nconst address = $object({\n    street: $string(),\n    city: $string()\n})\n\nconst user = $object({\n    name: $string(),\n    address: $ref(address),\n    team: $moduleRef('./team', 'Team')\n})\n```\n\n## Validation\n\nTherefore provides powerful runtime validation capabilities through the `.validator()` method. This allows you to generate type-safe validation code with zero runtime overhead.\n\n### Validation Strategies\n\nTherefore supports two validation strategies:\n\n**1. Ajv (Default)**\n- High-performance JSON Schema validation\n- Pre-compiled validation code\n- Optimized for runtime performance\n- Best for server-side validation with complex schemas\n\n**2. Zod**\n- Rich TypeScript-first validation\n- Better developer experience\n- More flexible validation rules\n- Best for client-side validation\n\n### Using Validators\n\n```typescript\n// Basic validation\nconst user = $object({\n    name: $string,\n    age: $number,\n}).validator()\n\n// With options\nconst user = $object({\n    name: $string,\n    age: $number,\n}).validator({\n    type: 'ajv',           // 'ajv' | 'zod'\n    compile: true,         // Pre-compile validation code\n    formats: true,         // Enable format validation\n    parse: true,           // Generate parse functions\n})\n```\n\n### Generated Validation API\n\nWhen using Ajv validation, Therefore generates a validator object with the following interface:\n\n```typescript\ninterface ValidatorType\u003cT\u003e {\n    // Validate data against the schema\n    validate: ValidateFunction\u003cT\u003e\n    \n    // Access the underlying JSON Schema (getter)\n    get schema(): JsonSchema\n    \n    // Access validation errors from last validation (getter)\n    get errors(): DefinedError[] | undefined\n    \n    // Type guard for TypeScript type narrowing\n    is(o: unknown): o is T\n    \n    // Optional: Parse with Either-style error handling (if parse: true)\n    parse?(o: unknown): { right: T } | { left: DefinedError[] }\n}\n```\n\n!\u003e When using Zod validation, Therefore only generates TypeScript types by default. You'll use Zod's native validation methods directly on the schema.\n\n### Validation Options\n\n#### Ajv Options (Default)\n```typescript\n{\n    type: 'ajv',\n    compile?: boolean,      // Pre-compile validation code (default: true)\n    formats?: boolean,      // Enable format validation (default: true)\n    parse?: boolean,        // Generate parse functions (default: true)\n    coerce?: boolean,       // Enable type coercion (default: false)\n    ajv?: AjvOptions,      // Custom Ajv options\n    output?: {\n        jsonschema?: string // Custom JSON Schema output path\n    }\n}\n```\n\n#### Zod Options\n```typescript\n{\n    type: 'zod',\n    types?: boolean,       // Generate TypeScript types (default: true)\n    output?: {\n        jsonschema?: string // Custom JSON Schema output path\n    }\n}\n```\n\n### Best Practices\n\n1. **Choose the Right Validator**\n   - Use Ajv for high-performance server-side validation\n   - Use Zod for client-side validation and better DX\n\n2. **Pre-compilation**\n   - Enable `compile: true` for Ajv in production\n   - This generates standalone validation code\n   - Results in better runtime performance\n\n3. **Error Handling**\n   - Always check validation results\n   - Use `parse()` for better error handling\n   - Use type guards for runtime safety\n\n4. **Type Safety**\n   - Use the generated type guards\n   - TypeScript will narrow types automatically\n   - Validation ensures runtime type safety\n\n### Example: Complete Validation Flow\n\n```typescript\n// Define schema with validation\nexport const user = $object({\n    id: $string().uuid(),\n    email: $string().email(),\n    age: $number().min(0),\n}).validator()\n\n// Using Ajv validation\nfunction processUserAjv(data: unknown) {\n    // Type guard usage\n    if (user.is(data)) {\n        // data is typed as User here\n        console.log(data.email)\n        return\n    }\n    \n    // Error handling\n    console.error('Invalid user:', user.errors)\n}\n\n// Using Zod validation\nfunction processUserZod(data: unknown) {\n    const result = user.safeParse(data)\n    if (result.success) {\n        // data is typed as User here\n        console.log(result.data.email)\n        return\n    }\n    \n    // Error handling with detailed issues\n    console.error('Invalid user:', result.error.issues)\n}\n```\n\n## Code Generation\n\nTherefore can generate various types of code from your schemas:\n\n1. **TypeScript Types**: Generate TypeScript interfaces and types\n2. **JSON Schema**: Generate JSON Schema definitions\n3. **API Clients**: Generate type-safe API clients from OpenAPI specs\n4. **GraphQL Types**: Generate GraphQL type definitions\n\nExample:\n```bash\nnpx therefore -f src\n```\n\nThis will generate:\n- TypeScript types in `src/**/*.type.ts`\n- JSON Schema files in `schemas/`\n- API clients in `src/**/*.client.ts`\n\n## Schema Conversion\n\n\u003c!-- panels:start --\u003e\n\n\u003c!-- div:title-panel --\u003e\n### Converting Between Schema Formats\n\n\u003c!-- div:left-panel --\u003e\n\nTherefore enables seamless conversion between different schema formats while preserving all schema features:\n\n**Supported Conversions**\n- Zod ↔ JSON Schema\n- OpenAPI ↔ TypeScript\n- Therefore ↔ Zod\n\n**Preserved Features**\n- Validation rules\n- Type information\n- Documentation\n- Custom formats\n- Default values\n- Optional fields\n\n\u003c!-- div:right-panel --\u003e\n\n\u003c!-- tabs:start --\u003e\n\n#### **Zod to JSON Schema**\n\n**examples/docs/05-zod-to-jsonschema.schema.ts**\n\n[examples/docs/05-zod-to-jsonschema.schema.ts](examples/docs/05-zod-to-jsonschema.schema.ts ':include :type=code')\n\n#### **Generated JSON Schema**\n\n**examples/docs/schemas/product.schema.json**\n\n[examples/docs/schemas/product.schema.json](examples/docs/schemas/product.schema.json ':include :type=code')\n\n\u003c!-- tabs:end --\u003e\n\n\u003c!-- panels:end --\u003e\n\n## Test Data Generation\n\n\u003c!-- panels:start --\u003e\n\n\u003c!-- div:title-panel --\u003e\n### Generating Test Data from Schemas\n\n\u003c!-- div:left-panel --\u003e\n\nConvert schemas into arbitraries for testing:\n\n```typescript\nimport { arbitrary } from '@skyleague/therefore'\n\n// Convert a schema into an arbitrary\nconst userArbitrary = arbitrary(user)\n\n// Generate test data\nconst testUser = userArbitrary.sample()\n```\n\n\u003c!-- div:right-panel --\u003e\n\n**Use Cases**\n- Property-based testing\n- Mock data generation\n- API testing\n- Load testing\n- Edge case validation\n\n\u003c!-- panels:end --\u003e\n\n## OpenAPI Client Generation\n\n\u003c!-- panels:start --\u003e\n\n\u003c!-- div:title-panel --\u003e\n\nGenerate fully type-safe API clients from OpenAPI/Swagger specifications with built-in validation and error handling.\n\n\u003c!-- div:left-panel --\u003e\n\n### Basic Usage\n\n```typescript\nimport { $restclient } from '@skyleague/therefore'\nimport type { OpenapiV3 } from '@skyleague/therefore'\n\nconst apiSpec: OpenapiV3 = {\n    openapi: '3.1.1',\n    info: {\n        title: 'Todo API',\n        version: '1.0.0',\n    },\n    ...rest\n}\n\nexport const client = $restclient(apiSpec, {\n    validator: 'zod',\n    client: 'got',\n})\n```\n\n### Configuration\n\nThe `$restclient` primitive accepts these options:\n\n#### Validation\n- `validator?: 'zod' | 'ajv'` - Choose validation library (default: 'ajv')\n- `strict?: boolean` - Enable strict validation (default: false)\n- `formats?: boolean` - Validate string formats (default: true)\n- `compile?: boolean` - Pre-compile validators for better performance\n\n#### Client Behavior  \n- `client?: 'got' | 'ky'` - HTTP client library (default: 'got')\n  - `got`: Node.js focused client\n  - `ky`: Browser focused client, uses fetch internally\n- `useEither?: boolean` - Return Either type for responses (default: true)\n- `explicitContentNegotiation?: boolean` - Always include content-type (default: false)\n\n#### Schema Handling\n- `optionalNullable?: boolean` - Toggles whether optional fields will be allowed to be null. Some Rest APIs implicitly return null on optional fields. (default: false)\n- `allowIntersectionTypes?: boolean` - Support intersection types (default: false)\n- `preferOperationId?: boolean` - Use operationId for method names (default: true)\n\n#### Advanced\n- `transformOpenapi?: (spec: OpenapiV3) =\u003e OpenapiV3` - Transform spec before processing\n- `filename?: string` - Custom output filename\n\n### Features\n\nThe generated client provides:\n\n- **Type Safety**\n  - Full TypeScript types for requests/responses\n  - Automatic path parameter handling\n  - Type-safe error handling\n\n- **Validation**\n  - Runtime request/response validation\n  - Support for Zod or Ajv validators\n  - Pre-compiled validators for performance\n\n- **Authentication**\n  - Built-in auth scheme support\n  - Automatic header injection\n  - Multiple auth methods per endpoint\n\n- **Developer Experience**\n  - Automatic content negotiation\n  - Error handling with type refinements\n  - Promise-based API\n\n\u003c!-- div:right-panel --\u003e\n\n\u003c!-- tabs:start --\u003e\n\n#### **Client Config**\n\n**src/api/todo.schema.ts**\n\n[examples/docs/02-openapi-client.schema.ts](examples/docs/02-openapi-client.schema.ts ':include :type=code')\n\n#### **OpenAPI Spec**\n\n**src/api/todo-api.yaml**\n\n[examples/docs/todo-api.yaml](examples/docs/todo-api.yaml ':include :type=code')\n\n#### **Generated Client**\n\n**src/api/todo.client.ts**\n\n[examples/docs/02-openapi-client.client.ts](examples/docs/02-openapi-client.client.ts ':include :type=code')\n\n#### **Generated Types**\n\n**src/api/todo.zod.ts**\n\n[examples/docs/02-openapi-client.zod.ts](examples/docs/02-openapi-client.zod.ts ':include :type=code')\n\n\u003c!-- tabs:end --\u003e\n\n\u003c!-- panels:end --\u003e\n\n\n## GraphQL Support\n\n\u003c!-- panels:start --\u003e\n\n\u003c!-- div:title-panel --\u003e\n!\u003e GraphQL support is currently in an experimental phase. The API and functionality may undergo significant changes in future releases. While usable, we recommend carefully evaluating it for production use. We welcome feedback and contributions to help stabilize this feature.\n\n\n\u003c!-- div:left-panel --\u003e\n\nGenerate type-safe GraphQL schemas using Therefore's schema language:\n- Define schemas with type safety\n- Automatic resolver type generation\n- Circular references support\n- Schema composition and reuse\n\n\u003c!-- div:right-panel --\u003e\n\n\u003c!-- tabs:start --\u003e\n\n#### **Schema Definition**\n\n**src/schema/user.schema.ts**\n\n[examples/docs/04-graphql.schema.ts](examples/docs/04-graphql.schema.ts ':include :type=code')\n\n#### **Generated Types**\n\n**src/schema/user.type.ts**\n\n[examples/docs/04-graphql.type.ts](examples/docs/04-graphql.type.ts ':include :type=code')\n\n#### **Generated GraphQL Schema**\n\n**src/schema/user.graphql**\n\n[examples/docs/04-graphql.graphql](examples/docs/04-graphql.graphql ':include :type=code')\n\n\u003c!-- tabs:end --\u003e\n\n\u003c!-- panels:end --\u003e\n\n## Development Guide\n\n### CLI Options\n\n```bash\nnpx therefore [options]\n\nOptions:\n  -f, --files           Globs to scan for schemas (required)\n  -i, --ignore-pattern  Globs to exclude [default: [\"**/*.d.ts\",\"node_modules\"]]\n  --clean              Clean output directory before generation [default: true]\n  --migrate-to         Migrate schemas to specified validator [choices: \"zod\"]\n```\n\n### Security\n\nThe security considerations depend on your chosen validation strategy:\n\n**When Using Ajv (Default)**\n- Security considerations are a superset of [`Ajv`](https://github.com/ajv-validator/ajv#security-considerations)\n- Therefore implements strict validation by default\n- No additional properties allowed unless explicitly enabled\n- All properties required unless marked optional\n\n**When Using Zod**\n- Security considerations are inherited from [Zod](https://github.com/colinhacks/zod)\n- Runtime type checking is performed by Zod's validation engine\n- Strict type checking enabled by default\n- Custom validation rules are executed in order defined\n\nIn both cases, Therefore itself does not perform validation - it generates the validation code that uses either Ajv or Zod. The security of your validation depends on:\n1. The validation strategy you choose\n2. The validation options you configure\n3. How you handle validation errors in your code\n\n### Advanced Examples\n\n\u003c!-- panels:start --\u003e\n\n\u003c!-- div:title-panel --\u003e\n#### Circular References\n\n\u003c!-- div:left-panel --\u003e\n\nTherefore supports complex data types with circular references. A common example is the JSON data type, which can contain nested objects and arrays that reference themselves:\n\n```typescript\n// Define a JSON type that can contain nested JSON values\nexport const json = $validator(\n    $union([\n        $string, \n        $null, \n        $boolean, \n        $number, \n        $record($ref(() =\u003e json)), \n        $array($ref(() =\u003e json))\n    ])\n)\n```\n\n\u003c!-- div:right-panel --\u003e\n\nThe generated TypeScript types handle circular references correctly:\n\n```typescript\nexport type Json =\n    | string\n    | null\n    | boolean\n    | number\n    | { [k: string]: Json | undefined }\n    | Json[]\n```\n\n\u003c!-- panels:end --\u003e\n\n## Enterprise Support\n\nSkyLeague provides Enterprise Support for Therefore. Visit [skyleague.io](https://skyleague.io) for:\n- Custom integrations\n- Implementation support\n- Training and consulting\n- Priority issue resolution\n\n## License\n\nCopyright (c) 2025, SkyLeague Technologies B.V.. 'SkyLeague' and the astronaut logo are trademarks of SkyLeague Technologies, registered at Chamber of Commerce in The Netherlands under number 86650564.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskyleague%2Ftherefore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskyleague%2Ftherefore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskyleague%2Ftherefore/lists"}