Skip to content

PluginValidators ​

Генерирует схемы валидации из TypeScript-контрактов через библиотеку api-contract-check. Плагин читает входные API-файлы, находит типы запроса и ответа, строит сериализуемые схемы валидации и записывает их в targetFolder. При удалении API-файла соответствующая схема валидации автоматически удаляется.

Плагин работает инкрементально в watch-режиме благодаря хранению обратной карты зависимостей.

Целевой путь строится как targetFolder + relativePathFromRootDir. Если исходник находится в src/api/orders.ts, а targetFolder — на src/validators, результат будет записан в src/validators/api/orders.ts. Для удобства можно также использовать PluginReexport в папке validators.

Не забудьте подключить realtime-валидацию, как описано в разделе Валидация данных.

ts
entries: Array<string>

Массив с glob-паттернами поиска папок внутри rootDir

ts
exclude?: RegExp

Регулярное выражение для исключения файлов из обработки

ts
requestDeclaration: string

Имя декларации типа запроса (например, Request)

ts
responseDeclaration: string

Имя декларации типа ответа (например, Response)

ts
targetFolder: string

Папка, куда будут сгенерированы файлы со схемами валидации

ts
tsconfigPath: string

Путь к tsconfig для поиска ts-алиасов и резолвинга путей

ts
formatContent: (params: {
  schema: TypeBuilderOutputFile['schema'];
  sourcePath: string;
  targetPath: string;
}) => string

Функция форматирования содержимого файла со схемой валидации

ts
getDegraded?: (degraded: Array<string>) => void

Колбэк для получения списка деградировавших до any типов. Вызывается до ошибки при bailOnDegraded: true

ts
bailOnDegraded?: boolean

По умолчанию false: деградации не прерывают генерацию. При true после вызова getDegraded плагин выбрасывает ошибку со списком деградаций. Для завершения всей генерации с ошибкой включите также ci: true у FileGenerator

Пример: API-контракты в общей папке

Для файлов в папке api генерируются схемы валидации в validators/api. Изменение общего типа обновляет зависящие от него схемы валидации

ts
new PluginValidators([
  {
    entries: ['api'],
    exclude: /(^_|\.test\.ts$|package\.json$)/,
    targetFolder: path.resolve(rootDir, 'validators'),
    tsconfigPath: path.resolve(rootDir, 'tsconfig.json'),
    requestDeclaration: 'TypeRequest',
    responseDeclaration: 'TypeResponse',
    formatContent({ schema, targetPath }) {
      return `export const ${path.parse(targetPath).name} = ${JSON.stringify(schema, null, 2)} as const;\n`;
    },
  },
]),
Запустить Sandbox
USER: tsconfig.json создан с содержимым:
json
{
  "include": ["**/*.ts"],
  "compilerOptions": {
    "target": "ES2023",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true
  }
}
USER: models/order.ts создан с содержимым:
ts
export type TypeOrder = {
  id: string;
  status: 'draft' | 'confirmed';
};
USER: api/orders.ts создан с содержимым:
ts
import type { TypeOrder } from '../models/order';

export type TypeRequest = { status?: TypeOrder['status'] };
export type TypeResponse = { orders: Array<TypeOrder> };
ARFA Generator выводит логи:
txt
[ARFA-GEN] [write] validators/api/orders.ts
[ARFA-GEN] finished in 0ms
ARFA Generator сгенерировал файлы:
ts
// this file is generated

export const orders = {
  "request": {
    "status": [
      "optional",
      [
        "union",
        [
          "literal",
          "draft"
        ],
        [
          "literal",
          "confirmed"
        ]
      ]
    ]
  },
  "response": {
    "orders": [
      "array",
      {
        "id": "string",
        "status": [
          "union",
          [
            "literal",
            "draft"
          ],
          [
            "literal",
            "confirmed"
          ]
        ]
      }
    ]
  }
} as const;

Пример: API-контракты внутри feature-модулей

Плагин находит папки features/*/api и сохраняет структуру модулей в validators/features

ts
new PluginValidators([
  {
    entries: ['features/*/api'],
    exclude: /(^_|\.test\.ts$|package\.json$)/,
    targetFolder: path.resolve(rootDir, 'validators'),
    tsconfigPath: path.resolve(rootDir, 'tsconfig.json'),
    requestDeclaration: 'TypeRequest',
    responseDeclaration: 'TypeResponse',
    formatContent({ schema, targetPath }) {
      return `export const ${path.parse(targetPath).name} = ${JSON.stringify(schema, null, 2)} as const;\n`;
    },
  },
]),
Запустить Sandbox
USER: tsconfig.json создан с содержимым:
json
{
  "include": ["**/*.ts"],
  "compilerOptions": {
    "target": "ES2023",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true
  }
}
USER: features/orders/api/listOrders.ts создан с содержимым:
ts
export type TypeRequest = { status?: 'draft' | 'confirmed' };
export type TypeResponse = { orders: Array<{ id: string; status: string }> };
USER: features/profile/api/getProfile.ts создан с содержимым:
ts
export type TypeRequest = { profileId: string };
export type TypeResponse = { name: string };
ARFA Generator выводит логи:
txt
[ARFA-GEN] [write] validators/features/orders/api/listOrders.ts
[ARFA-GEN] [write] validators/features/profile/api/getProfile.ts
[ARFA-GEN] finished in 0ms
ARFA Generator сгенерировал файлы:
ts
// this file is generated

export const listOrders = {
  "request": {
    "status": [
      "optional",
      [
        "union",
        [
          "literal",
          "draft"
        ],
        [
          "literal",
          "confirmed"
        ]
      ]
    ]
  },
  "response": {
    "orders": [
      "array",
      {
        "id": "string",
        "status": "string"
      }
    ]
  }
} as const;

MIT License