using System;
using Ban.Sdaid.Notation.Documents;
using Ban.Sdaid.Icd;
namespace Ban.Sdaid.Icd.Arch.Tech.Angular
{
/// <summary>
/// ADR-UI-002: Префикс, именование и базовые конвенции Angular-кода фронтенда ICD.
/// Опирается на стиль Angular 22 (без суффиксов, signals, native control flow) и на
/// переносимость собственного набора компонентов.
/// </summary>
public class ADR_UI_002_NamingAndConventions : IAdrDocument, IFolder<ArchAngularFolder>
{
public string Name => "ADR-UI-002. Префикс, именование и конвенции";
public string Description =>
@"Чтобы исключить коллизии селекторов с другими Angular-приложениями и обеспечить предсказуемый
стиль во всём проекте, нужен **свой префикс** и **единый набор базовых конвенций**. Правила
опираются на актуальный стиль Angular 22 и учитывают переносимость собственного набора компонентов.";
public string Version => "1.1";
public string Status => "accepted";
public string[] Comments => new[]
{
"2026-08-11. Принято следом за ADR-UI-001 при настройке линтера фронтенда.",
"2026-08-12. Уточнён строгий двухуровневый порядок членов класса (роль → видимость); " +
"устранено противоречие «все поля вверху» с сортировкой по видимости.",
};
public Type? Supersedes => null;
public static string S1_Context = """
## Контекст и постановка задачи
Нужен свой префикс (чтобы селекторы и шаблонные идентификаторы не сталкивались с другими
Angular-приложениями и заимствованным кодом) и единый набор конвенций — чтобы стиль был
предсказуем, а будущая автоматизация (skills/codegen) опиралась на стабильные правила.
Учитываем переносимость: собственный набор компонентов (`ui/`) должен выноситься в другой
проект без переписывания. Отсюда — префикс держим там, где он реально нужен (DOM-селекторы), а
имена TypeScript-классов оставляем нейтральными.
""";
public static string S2_DecisionDrivers = """
## Драйверы решения
1. **Отсутствие коллизий** селекторов и шаблонных идентификаторов с другими приложениями.
2. **Единообразие ревью** — стиль предсказуем, мелочи не обсуждаются в каждом PR.
3. **Опора на нативные средства Angular 22** — signals, native control flow, `host` в
декораторе, OnPush по умолчанию.
4. **Переносимость набора** — вынос `ui/` в другой проект меняет минимум (префикс селекторов),
не трогая имена классов.
5. **Автоматизация** — генераторы компонентов/сервисов опираются на явные правила.
""";
public static string S3_ConsideredOptions = """
## Рассмотренные варианты
- **A. Без префикса** — короче, но провоцирует коллизии селекторов с библиотеками и
заимствованным кодом.
- **B. Префикс `icd` в селекторах, классы без префикса** — короткое имя проекта как
DOM-идентификатор; TypeScript-классы нейтральны (изоляция — модульной системой TS).
- **C. Префикс и в классах** (`IcdButton…`) — избыточно для переносимого набора: при выносе
пришлось бы переименовывать все классы.
""";
public static string S4_DecisionOutcome = """
## Решение
Выбран **Вариант B**. Префикс `icd` — только в селекторах компонентов/директив и именах пайпов
(шаблонные идентификаторы). Имена TypeScript-классов — чистый **PascalCase без префикса и без
суффикса** (стиль Angular 22). При выносе `ui/` в библиотеку меняется только префикс селекторов
(в `eslint.config.js` и шаблонах) — классы переносятся нетронутыми.
### Именование (стиль Angular 22 — без суффиксов)
| Сущность | Класс | Селектор / имя | Файл |
|---|---|---|---|
| Компонент | `Button` | `icd-button` (element, kebab-case) | `button.ts` (+ `.html`, `.scss`) |
| Директива | `Highlight` | `[icdHighlight]` (attribute, camelCase) | `highlight.ts` |
| Pipe | `DateYmd` | `icdDateYmd` (в шаблоне) | `date-ymd.ts` |
| Сервис | `AuthStore` | — | `auth-store.ts` |
| Реестр маршрутов | `BaseRoutes` | — | `<feature>.routes.ts` |
| Папка фичи | — | — | `modules/<feature-kebab>/` |
Суффиксы `Component` / `Directive` / `Pipe` / `Service` **не используются** (актуальный стиль
Angular). Файлы именуются по сущности (`button.ts`, не `button.component.ts`). Если имя сервиса
коллизирует с типом/моделью — различаем **смысловым** суффиксом роли (`Store`, `Api`, `Client`),
а не техническим `Service`.
### Разрешение коллизий имён (UI ↔ API)
Имена UI-классов не префиксуются, поэтому теоретически возможно совпадение с типом api-модели
(например, UI-контейнер `Card` и модель `Card`). На практике риск низкий: набор `ui/` — это
generic-виджеты (`Button`, `Table`, `Input`), а api-модели ICD — доменные (`InformationCard`,
`InputPacket`, `FundItem`), пересечений почти нет. Разрешение:
- **По месту** — алиас импорта: `import { Card as CardModel } from '@api/…'` (стандартный
механизм модулей TypeScript).
- **Превентивно** — генерируемые api-модели несут суффикс (`Dto` / `Model`) либо импортируются
через namespace (`import * as Api from '@api/…'`); тогда `CardDto` / `Api.Card` не конфликтуют
с UI-классами в принципе.
Префикс на имена UI-классов **не вводим** (переносимость набора важнее); коллизии закрываются на
стороне api-моделей. Детали контракта api-моделей — в отдельном ADR.
### Базовые конвенции компонентов
- **Standalone** (default в Angular 22 — `standalone: true` не указываем).
- **Change detection** — **OnPush по умолчанию с Angular 22**, явно указывать не нужно; проект
zoneless. `Default` указываем только там, где он осознанно требуется.
- **`inject()`** вместо constructor-injection.
- **`input()` / `output()`** функции вместо декораторов `@Input` / `@Output`.
- **`computed()`** для производного состояния.
- **`host`-объект в декораторе** вместо `@HostBinding` / `@HostListener`.
- **Native control flow** `@if` / `@for` / `@switch`; не `*ngIf` / `*ngFor` / `*ngSwitch`.
- **`class` / `style` bindings** вместо `ngClass` / `ngStyle`.
- **`NgOptimizedImage`** для статических изображений.
- Внешние шаблоны/стили — путь относительно `.ts`-файла компонента.
### Структура класса
Порядок членов класса — **строгий, двухуровневый**:
1. **По роли (внешняя ось):** поля → конструктор → методы. Все поля — вверху класса, до
конструктора; методы — после него.
2. **По области видимости (внутренняя ось, внутри полей и внутри методов):**
`public` → `protected` → `private`.
Итоговая раскладка сверху вниз:
| № | Группа |
|---|---|
| 1 | `public`-поля |
| 2 | `protected`-поля |
| 3 | `private`-поля |
| 4 | конструктор |
| 5 | `public`-методы |
| 6 | `protected`-методы |
| 7 | `private`-методы |
Уточнения: `static`-члены идут перед экземплярными в своей группе; геттеры/сеттеры трактуются как
методы соответствующей видимости. Для Angular-компонентов это ложится естественно: `input()` /
`output()` (`public`-поля) → производное состояние `computed()` (`protected`-поля) → внедрённые
зависимости `inject()` (`private`-поля) → методы.
### Комментарии
- JSDoc (`/** … */`) к методам с непустым именем намерения.
- Не комментировать тривиальные геттеры/сеттеры и «что делает код» — комментарий нужен, когда
не очевидно **почему**.
### TypeScript
- `strict: true`; предпочитать вывод типов, когда он очевиден.
- Избегать `any`; при неопределённости — `unknown`.
- Не кастовать `as Type` / `<Type>`, если тип выводится; каст `<Type>{ … }` — только для
осознанно частичного заполнения.
""";
public static string S5_PositiveConsequences = """
## Положительные следствия
- Префикс в селекторах исключает коллизии в DOM; классы остаются переносимыми без переименования.
- Стиль предсказуем — ревью о сути, а не о форматировании; генераторы опираются на явные правила.
- Опора на нативный Angular 22 (OnPush по умолчанию, signals, control flow) — меньше кода и
шаблонного шума.
""";
public static string S6_NegativeConsequences = """
## Отрицательные следствия и компромиссы
- Префикс `icd-` в каждом селекторе — небольшой визуальный шум в шаблонах (узнаваемость важнее).
- При выносе набора в библиотеку префикс селекторов всё же надо заменить — механическая работа,
но локализованная (конфиг линтера + шаблоны).
- Отказ от суффиксов требует дисциплины при коллизиях имён сервис/модель (решается ролью-суффиксом).
""";
public static string S7_Validation = """
## Проверка
- Линтер `@angular-eslint` настроен (`eslint.config.js`): правила `component-selector` и
`directive-selector` требуют префикс `icd`. `ng lint` проходит на текущем каркасе.
- Любой новый компонент / директива / pipe соответствует таблице именования; спорные мелочи
(порядок членов класса) не обсуждаются — есть однозначное правило.
""";
public static string S99_Related = $"""
## Связанные артефакты
- {nameof(Ban.Sdaid.Icd.Arch.Tech.Angular.ADR_UI_001_Stack)} — Технологический стек фронтенда.
""";
}
}