Декларативный язык схем → NestJS кодогенератор
ForgerAPI превращает описание API на DSL schema.forger в готовый NestJS код: Prisma схему, DTO, CRUD-сервисы, контроллеры, guards и модули. Без рантайма — только компиляция.
model User {
id: uuid @id @default(uuid)
email: string @unique
name: string
role: Role
posts: Post[]
}
module Auth {
route: "/auth"
models: User
guards: AuthGuard
action Login {
route: "/login"
method: POST
input: [email: string, password: string]
steps: validateUser signToken
}
}
schema.forger файл
│
▼
┌─────────────┐
│ Lexer │ ← разбивает текст на токены
└──────┬──────┘
│
▼
┌─────────────┐
│ Parser │ ← строит AST (ForgerSchema)
└──────┬──────┘
│
▼
┌──────────────────┐
│ Semantic Analyzer│ ← проверяет типы, связи, дубликаты
└──────┬───────────┘
│
▼
┌─────────────┐
│ Codegen │ ← генерирует файлы в src/ и prisma/
└─────────────┘
Принимает сырой текст schema.forger, возвращает массив Token[].
| Токен | Пример | Описание |
|---|---|---|
keyword |
model, enum, action, module, guard |
Ключевые слова языка |
type |
string, uuid, boolean |
Примитивные типы |
identifier |
User, email, Role |
Имена сущностей и полей |
symbol |
{, }, :, (, ), [, ] |
Символы пунктуации |
annotation |
@id, @unique, @default(uuid) |
Аннотации полей |
string |
"/auth", "@nestjs/passport" |
Строковые литералы |
eof |
— | Конец файла |
Рекурсивный спуск. Принимает Token[], возвращает ForgerSchema.
| Функция | Описание |
|---|---|
parseSchema() |
Корневая — парсит enums → models → guards → actions → modules |
parseEnum() |
enum Name { VAL1 VAL2 } |
parseModel() |
model Name { fields } |
parseField() |
name: type @constraints |
parseFieldType() |
Определяет тип поля + связь |
parseConstraints() |
Парсит @id, @unique, @default(value) |
parseRelationField() |
Парсит @relation(fieldName) |
parseAction() |
action Name { route/method/input/steps/emits } |
parseGuard() |
guard Name { import: "..." } |
parseModule() |
module Name { route/models/guards/actions } |
Проходит по AST после парсинга. Проверяет:
| Проверка | Ошибка |
|---|---|
| Дубликаты имён моделей | Duplicate model name: User |
| Дубликаты имён enum | Duplicate enum name: Role |
| Дубликаты значений enum | Duplicate value ADMIN in enum Role |
| Пустой enum | Enum Role has no values |
| Relation target не найден | Model Post: relation target 'User' not found |
| Relation field не найден | Model Post: relation field 'authorId' not found |
@id не на uuid поле |
@id field 'id' must be uuid type |
| Guard без import | Guard X has no import |
| Модель в module не найдена | Module X: model 'Y' not found |
Принимает ForgerSchema + ForgerConfig, создаёт файлы на диске.
| Генератор | Создаёт |
|---|---|
prisma.ts |
schema.prisma целиком |
dto.ts |
Create/Update/Response DTO с @ApiProperty |
service.ts |
CRUD-сервис |
controller.ts |
REST контроллер + Swagger |
module.ts |
NestJS Module |
enum.ts |
TS enum |
forger generate # парсит schema.forger → генерирует NestJS код
forger watch # вотчер с авто-генерацией
forger help # справкаnpm install -g @forgerapi/cliИз монорепозитория:
npm run build
npx forger generateenum Role {
USER
ADMIN
MODERATOR
}
model User {
id: uuid @id @default(uuid)
email: string @unique
name: string
role: Role
posts: Post[]
}
<name>: <type> [@constraints] [@relation(field)]
| Тип | TS | Prisma |
|---|---|---|
string |
string |
String |
number |
number |
Int |
boolean |
boolean |
Boolean |
uuid |
string |
String + @default(uuid()) |
datetime |
Date |
DateTime |
Аннотации:
@id— первичный ключ (только наuuid)@unique— уникальный индекс@default(uuid | now | true | false)— значение по умолчанию
Связи:
Role— ссылка на enum/modelPost[]— hasMany связьauthor: User @relation(authorId)— belongsTo с явным FK
action CreatePost {
route: "/posts"
method: POST
input: [title: string, content: string, authorId: uuid]
guards: AuthGuard
steps: validateInput saveToDb
emits: PostCreated
}
| Ключ | Описание |
|---|---|
route |
HTTP путь |
method |
GET / POST / PUT / PATCH / DELETE |
input |
Типизированные параметры [name: type, ...] |
guards |
Список guards |
steps |
Имена шагов-методов |
emits |
События, которые порождает action |
guard AuthGuard { import: "@nestjs/passport" }
Группирует модели, guards и actions под общим HTTP префиксом.
module Blog {
route: "/blog"
models: User Post
guards: AuthGuard
action ListPosts {
route: "/"
method: GET
steps: queryPosts
}
action CreatePost {
route: "/"
method: POST
input: [title: string, content: string]
steps: validate save
}
}
forger.config.json:
{
"outDir": "./src",
"prismaSchema": "./prisma/schema.prisma",
"prisma": true,
"swagger": true,
"deleteOrphans": true
}| Поле | По умолчанию | Описание |
|---|---|---|
outDir |
./src |
Куда генерировать NestJS код |
prismaSchema |
./prisma/schema.prisma |
Путь к Prisma схеме |
prisma |
true |
Генерировать Prisma schema, PrismaModule/Service и Prisma-реализации |
swagger |
true |
Добавлять @ApiTags, @ApiOperation, @ApiProperty |
deleteOrphans |
true |
Удалять папки模型, которых нет в schema.forger |
Если forger.config.json нет — используются значения по умолчанию.
Например, чтобы сгенерировать проект без Prisma и Swagger:
{
"prisma": false,
"swagger": false
}При prisma: false вместо Prisma-реализаций создаются одноразовые заглушки с
NotImplementedException, которые можно заменить своей реализацией хранилища.
src/{model}/
dto/
create-{model}.dto.ts
update-{model}.dto.ts
{model}-response.dto.ts
{model}.service.ts ← abstract CRUD service
{model}.controller.ts ← CRUD controller + Swagger
{model}.module.ts ← NestJS Module
impl/
{model}.impl.ts ← Prisma implementation (создаётся 1 раз)
src/{action}/
{action}.action-dto.ts
{action}.action-service.ts ← abstract service с execute()
{action}.action-controller.ts ← POST endpoint
{action}.action-module.ts
{action}.action-event.ts ← на каждый emits (создаётся 1 раз)
impl/
{action}.action-impl.ts ← stub шагов (создаётся 1 раз)
src/{module}/
{module}.module.ts
actions/{action}/
{action}.action-dto.ts
{action}.action-service.ts
{action}.action-controller.ts
impl/{action}.action-impl.ts
events/{action}.action-event.ts
src/common/
enums/{name}.enum.ts ← TS enum
prisma/prisma.service.ts ← PrismaClient wrapper
prisma/prisma.module.ts ← Global Prisma module
guards/{name}.guard.ts ← guard stub (только если нет import)
src/forger-modules.module.ts ← агрегатор всех модулей
prisma/schema.prisma ← полная Prisma схема
packages/
ast/ @forgerapi/ast — AST типы (интерфейсы)
parser/ @forgerapi/parser — лексер + парсер + анализатор
codegen/ @forgerapi/codegen — генераторы NestJS-кода
cli/ @forgerapi/cli — CLI точка входа
| Пакет | npm |
|---|---|
@forgerapi/ast |
|
@forgerapi/parser |
|
@forgerapi/codegen |
|
@forgerapi/cli |
v0.1:
- DSL парсер (model, enum, field)
- AST генерация
v0.2:
- Constraints (@id, @unique, @default)
- Relations
- Semantic analyzer
- NestJS codegen (DTO, Service, Controller, Module, Enum, Prisma)
- Swagger декораторы
- Guard declaration
- Module declaration with nested actions
v0.3 (planned):
- Action codegen (endpoints из action-деклараций)
- Watch mode
- Плагины (кастомные генераторы)
- CLI polish
v1.0 (goal):
- Language Server Protocol
- VS Code extension
- Full schema validation
Forger описывает только что есть данные и какие операции над ними. Всё остальное — бизнес-логика, guards, pipes, middleware — остаётся в TypeScript.
Никакого рантайма. ForgerAPI — это компилятор. Он прочитал schema.forger, сгенерировал код, закончил работу. В продакшне никаких зависимостей от ForgerAPI.
Разработчик описывает API → Система генерирует код
(schema.forger файл) (NestJS + Prisma)