An open API service indexing awesome lists of open source software.

https://github.com/aminya/mikro-typebox

Generate validation schemas from Mikro-ORM entities. Supports TypeBox, Zod, Valibot, ArkType, Effect, io-ts, Yup, and more.
https://github.com/aminya/mikro-typebox

db json-schema mikro mikro-orm schema ts-to-zod typebox typescript valibot validation yup zod

Last synced: 28 days ago
JSON representation

Generate validation schemas from Mikro-ORM entities. Supports TypeBox, Zod, Valibot, ArkType, Effect, io-ts, Yup, and more.

Awesome Lists containing this project

README

          

# mikro-typebox

Generate validation schemas from Mikro-ORM entities. Supports TypeBox, Zod, Valibot, ArkType, Effect, io-ts, Yup, and more.

## Features

- 🏗️ **Entity Type Generation**: Converts Mikro-ORM entity classes to TypeScript types
- 🔄 **Multiple Validation Libraries**: Supports TypeBox, Zod, Valibot, ArkType, Effect, io-ts, Yup, and more
- 🎯 **Smart Type Resolution**: Automatically resolves entity references depending on the relation graph between entities and sorts them by dependency order
- 🔄 **Circular Reference Handling**: Automatically breaks circular references to avoid infinite recursion
- 🔄 **Partial Types**: Generates partial types for entities with optional properties
- 📦 **Collection Handling**: Handles `Collection` and `Array` with proper type mapping

## Installation

```shell
npm install --save-dev mikro-typebox
```

## CLI Usage

The package includes a command-line interface for easy usage:

Generate typebox schema from `./src/entities` to `./src/entity-validators.ts`
```shell
npx mikro-typebox generate
```

Generate Zod schema from `./src/entities` to `./src/entity-validators.ts`
```shell
npx mikro-typebox generate --target zod
```

Generate Valibot schema from `./src/models` to `./src/validators.ts`
```shell
npx mikro-typebox generate --target valibot --entities ./src/models --output ./src/validators.ts
```

### CLI Options

#### `generate` command

- `-e, --entities `: Directory containing entity files (default: `./src/entities`)
- `-o, --output `: Output file path (default: `./src/entity-validators.ts`)
- `--no-write`: Print the code to the console instead of writing to a file (default: writes to a file)
- `-t, --target `: Target validation library (default: `typebox`)
- `--partials`, `--no-partials`: Generate partial types instead of inline primary key references (default: `true` for `typebox`)

### Supported Validation Libraries

- `typebox` - TypeBox (default)
- `zod` - Zod
- `valibot` - Valibot
- `arktype` - ArkType
- `effect` - Effect
- `io-ts` - io-ts
- `yup` - Yup
- `json-schema` - JSON Schema
- `javascript` - JavaScript
- `typescript` - TypeScript
- `value` - Value

## Programmatic Usage

You can also use the API to generate validation schemas programmatically.

### `generateEntityValidator(options)`

Generates validation schemas from Mikro-ORM entities.

#### Parameters

- `options.entitiesDir` (optional): Directory containing the entity files (default: `"./src/entities"`)
- `options.outputFile` (optional): File path to write the generated code (default: `"./src/entity-validators.ts"`)
- `options.write` (optional): Whether to write the code to a file (default: `true`)
- `options.targetValidationLibrary` (optional): Target validation library (default: `"typebox"`)
- `options.partials` (optional): Whether to generate partial types instead of inline primary key references (default: `true` for `typebox`)

### `generateEntityTypes(code, entityIdTypes)`

Converts Mikro-ORM entity code to TypeScript types.

#### Parameters

- `code`: The entity code as a string
- `entityIdTypes` (optional): Map of entity names to their ID types

### `generateEntityFileTypes(fileContents)`

Processes multiple entity files and generates types with proper entity ID replacement.

#### Parameters

- `fileContents`: Array of entity file contents as strings

## Usage Examples

```typescript
import { generateEntityValidator } from "mikro-typebox";

// Generate for TypeBox
await generateEntityValidator({
entitiesDir: "./src/entities",
outputFile: "./src/validators.ts",
write: true,
partials: true,
});

// Generate for Zod
const zodCode = await generateEntityValidator({
entitiesDir: "./src/entities",
targetValidationLibrary: "zod",
outputFile: "./src/zod-validators.ts",
write: true,
});

// Generate for Valibot
const valibotCode = await generateEntityValidator({
entitiesDir: "./src/entities",
targetValidationLibrary: "valibot",
outputFile: "./src/valibot-validators.ts",
write: true,
});
```

### Working with Entity Files

Given a Mikro-ORM entity file like this:

```typescript
// src/entities/User.ts
import {
Entity,
PrimaryKey,
Property,
Collection,
OneToMany,
} from "@mikro-orm/core";
import { Book } from "./Book";

@Entity()
export class User {
@PrimaryKey()
id!: number;

@Property()
name!: string;

@Property()
email!: string;

@OneToMany(() => Book, (book) => book.author)
books = new Collection(this);

constructor({ name, email }: User) {
this.name = name;
this.email = email;
}
}

// src/entities/Book.ts
import { Entity, PrimaryKey, Property, ManyToOne } from "@mikro-orm/core";
import { User } from "./User";

@Entity()
export class Book {
@PrimaryKey()
id!: number;

@Property()
title!: string;

@ManyToOne(() => User)
author!: User;

constructor({ title, author }: Book) {
this.title = title;
this.author = author;
}
}
```

And then generate validation schemas (e.g., with TypeBox):

```typescript
import { Type, Static, TSchema } from "@sinclair/typebox";

export namespace schema {
export type Collection = Static<
ReturnType>
>;
export const Collection = (T: T) =>
Type.Object(
{},
{
additionalProperties: T,
},
);

export type Book = Static;
export const Book = Type.Object({
id: Type.Number(),
title: Type.String(),
author: schema.PartialUser,
});

export type PartialBook = Static;
export const PartialBook = Type.Object({
id: Type.Number(),
title: Type.Optional(Type.String()),
author: Type.Optional(schema.PartialUser),
});

export type User = Static;
export const User = Type.Object({
id: Type.Number(),
name: Type.String(),
email: Type.String(),
books: Type.Union([
Collection(
Type.Object({
id: Type.Number(),
}),
),
Type.Array(
Type.Object({
id: Type.Number(),
}),
),
]),
});

export type PartialUser = Static;
export const PartialUser = Type.Object({
id: Type.Number(),
name: Type.Optional(Type.String()),
email: Type.Optional(Type.String()),
books: Type.Optional(
Type.Union([
Collection(
Type.Object({
id: Type.Number(),
}),
),
Type.Array(
Type.Object({
id: Type.Number(),
}),
),
]),
),
});
}
```

or for Zod

```typescript
import { z } from "zod";

export type schema_Book = z.infer;
export const schema_Book = z.object({
id: z.number(),
title: z.string(),
author: z.object({
id: z.number(),
}),
});

export type schema_User = z.infer;
export const schema_User = z.object({
id: z.number(),
name: z.string(),
email: z.string(),
books: z.union([
z.object({}),
z.array(
z.object({
id: z.number(),
}),
),
]),
});
```

### Programmatic Usage

```typescript
import { generateEntityTypes, generateEntityFileTypes } from "mikro-typebox";

// Process a single entity file
const entityCode = `
import { Entity, PrimaryKey, Property } from '@mikro-orm/core';

@Entity()
export class Product {
@PrimaryKey()
id!: number;

@Property()
name!: string;
}
`;

const types = generateEntityTypes(entityCode);
console.log(types);
// Output: export type Product = { id: number; name: string; };

// Process multiple entity files
const fileContents = [entityCode, anotherEntityCode];
const allTypes = generateEntityFileTypes(fileContents);
```

## How It Works

1. **Entity Discovery**: Scans entity files for classes decorated with `@Entity()`
2. **Type Extraction**: Extracts property types and relationships from entity classes
3. **ID Type Resolution**: Replaces entity references with their primary key types
4. **Collection Conversion**: Converts `Collection` to `Array` with proper type mapping
5. **Code Cleanup**: Removes Mikro-ORM specific imports, decorators, and method calls
6. **Schema Generation**: Converts TypeScript types to validation schemas using the target library

## License

Apache-2.0, Copyright (c) 2025 Amin Yara