CheckerBoundaries
Проверяет архитектурные границы импортов: проходит по TypeScript-файлам проекта, резолвит импорты через tsconfig.json и сообщает о запрещенных импортах, группируя нарушения по файлам.
ts | Путь к tsconfig для резолвинга импортов и типов |
ts | Массив расширений файлов для проверки |
ts | Массив правил, каждое из которых содержит:
|
importsInsideScope
none— запрещает импорты внутри той же области, если они явно не разрешены черезallow.imports;all— разрешает любые кросс-импорты внутри области;sameTopLevel— разрешает импорты внутри одного модуля / feature, но запрещает импортировать из соседнего модуля / feature.
Пример: импорты между слоями API и models
API-файлы могут импортировать модели, но не соседние API-файлы. Модели могут импортировать только друг друга; тестовые файлы исключены из проверки
new CheckerBoundaries({
tsconfigPath: path.resolve(rootDir, 'tsconfig.json'),
extensions: ['.ts'],
rules: [
{
entries: ['api/**'],
exclude: /\.test\.ts$/,
allow: {
imports: ['models/**'],
importsInsideScope: 'none',
},
},
{
entries: ['models/**'],
allow: {
imports: [],
importsInsideScope: 'all',
},
},
],
}),
Запустить Sandbox
{
"include": ["**/*.ts"],
"compilerOptions": {
"target": "ES2023",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true
}
}
export type TypeStatus = 'draft' | 'confirmed';
import type { TypeStatus } from './status';
export type TypeOrder = { id: string; status: TypeStatus };
import type { TypeOrder } from '../models/order';
export type TypeResponse = { orders: Array<TypeOrder> };
import type { TypeResponse } from './orders';
export type TypeTestResponse = TypeResponse;
[ARFA-GEN] finished in 0ms
Пример: изоляция feature-модулей
sameTopLevel разрешает импорты внутри одного feature-модуля и из shared, но останавливает прямой импорт соседнего модуля даже через алиас и при широком allow.imports
new CheckerBoundaries({
tsconfigPath: path.resolve(rootDir, 'tsconfig.json'),
extensions: ['.ts'],
rules: [
{
entries: ['features/**'],
allow: {
imports: ['shared/**', 'features/**'],
importsInsideScope: 'sameTopLevel',
},
},
],
}),
Запустить Sandbox
{
"include": ["**/*.ts"],
"compilerOptions": {
"target": "ES2023",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"paths": {
"features/*": ["./features/*"],
"shared/*": ["./shared/*"]
}
}
}
export const formatId = (id: string) => id.toUpperCase();
export type TypeOrder = { id: string };
export type TypeCustomer = { id: string };
import type { TypeOrder } from 'features/orders/model';
import { formatId } from 'shared/formatId';
export const orderLabel = (order: TypeOrder) => formatId(order.id);
[ARFA-GEN] finished in 0ms
Пример: внешние пакеты и Node.js
Серверным файлам разрешены node:* импорты, а клиентским — внешние пакеты. Каждое разрешение действует отдельно
new CheckerBoundaries({
tsconfigPath: path.resolve(rootDir, 'tsconfig.json'),
extensions: ['.ts'],
rules: [
{
entries: ['server/**'],
allow: {
imports: [],
importsInsideScope: 'none',
node: true,
},
},
{
entries: ['client/**'],
allow: {
imports: [],
importsInsideScope: 'none',
external: true,
},
},
],
}),
Запустить Sandbox
{
"include": ["**/*.ts"],
"compilerOptions": {
"target": "ES2023",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true
}
}
import path from 'node:path';
export const reportPath = path.join('reports', 'today');
import type { Ref } from 'vue';
export type TypeValue = Ref<string>;
[ARFA-GEN] finished in 0ms