# lint.mjs

## Огляд

Модуль `lint.mjs` — це тонкий адаптер-обгортка, що реалізує CI-крок (контракт `lint(files)`) для правила `text` у складі n-cursor правил репозиторію. Його єдина роль — делегувати виконання у внутрішній CLI правила `text`, який знаходиться поряд у директорії `../lint/lint.mjs`.

Особливості модуля:

- Працює в режимі **whole-repo**: незалежно від того, які файли передає викликаюча сторона (наприклад, обгортка `lint-js` чи CI-оркестратор), аналіз виконується по всьому репозиторію цілком.
- Per-file режиму **немає**: вхідний параметр `files` навмисно ігнорується (підкреслено префіксом `_` у назві аргумента).
- Повертає числовий exit code (Promise), сумісний з конвенцією Unix-процесів: `0` — успіх, ненульовий — помилки лінту.
- Модуль не містить власної логіки перевірки тексту: вся реальна робота (запуск пов’язаних інструментів типу `dotenv-linter`, `shellcheck`, `v8r` тощо) — у `../lint/lint.mjs`.

Файл написаний у форматі **ES Modules** (`.mjs`) з JSDoc-анотаціями для статичної типізації без TypeScript-компіляції.

## Експорти / API

| Експорт | Тип                                                    | Призначення                                                            |
| ------- | ------------------------------------------------------ | ---------------------------------------------------------------------- |
| `lint`  | `async function (files?: string[]) => Promise<number>` | CI-крок-делегат у `runLintTextCli`. Іменований експорт (named export). |

Default-експорту немає. Сторонніх ефектів на рівні модуля (top-level side effects) також немає — лише імпорт залежності.

### Сигнатура

```js
export async function lint(_files): Promise<number>
```

### Контракт CI-кроку

Модуль реалізує загальний інтерфейс CI-крока правил n-cursor:

- Назва експорту: `lint`.
- Сигнатура приймає опціональний `files: string[] | undefined`.
- Повертає `Promise<number>` — exit code.
- Не кидає винятків у нормальному сценарії; помилки сигналізуються через ненульовий exit code, який повертає делегат `runLintTextCli`.

## Функції

### `lint(_files)`

**Сигнатура:** `async function lint(_files: string[] | undefined): Promise<number>`

**Параметри:**

| Ім’я     | Тип                     | Опис                                                                                                                                                                                                                                                        |
| -------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `_files` | `string[] \| undefined` | Список файлів, які теоретично потрібно перевірити. **Ігнорується** — правило `text` працює у whole-repo режимі. Префікс `_` у назві аргументу — конвенція, що позначає невикористаний параметр (зокрема, щоб ESLint/lint-правила не лаялись на unused arg). |

**Повертає:** `Promise<number>` — exit code, отриманий від виклику `runLintTextCli()`. Зазвичай `0` означає, що всі перевірки пройшли успішно, а будь-яке інше число — що знайдено порушення або сталася помилка інструмента.

**Side effects:** Сам по собі `lint` додаткових ефектів не вносить. Усі побічні ефекти (запис у stdout/stderr, читання файлів, запуск зовнішніх процесів) виконуються всередині `runLintTextCli()`, на який делегується виклик.

**Поведінка:**

1. Викликає `runLintTextCli()` без аргументів.
2. Повертає результат як є (через `await` неявно через `return await`-форму — `async`-функція автоматично «розгортає» Promise з тіла).

Логіки трансформації параметрів, фільтрації, перевірки прапорців тощо — немає. Це навмисно мінімалістична функція-адаптер.

## Залежності

### Імпорти

| Що               | Звідки             | Призначення                                                                                                                                                                                                       |
| ---------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `runLintTextCli` | `../lint/lint.mjs` | Запускає реальний CLI-обробник правила `text`. Саме він агрегує запуски під-інструментів (наприклад, `run-dotenv-linter.mjs`, `run-shellcheck.mjs`, `run-v8r.mjs`, які лежать у тій самій директорії `../lint/`). |

### Зовнішні (npm) залежності

Прямих імпортів з npm у файлі немає. Усі npm-залежності (якщо такі є) приховані у транзитивній залежності — `../lint/lint.mjs`.

### Структурний контекст

Файл лежить у `npm/rules/text/js/lint.mjs`. У тій самій директорії розташовані інші CI-крокові модулі правила `text` (наприклад, `formatting.mjs`, `forbidden-prettier.mjs`). Усі вони — однотипні делегати, що реалізують контракт CI-крока.

Бенефіціар:

- `../lint/lint.mjs` — справжній CLI правила `text`, що містить runner-логіку (parsing аргументів, оркестрація під-інструментів, формування звіту, exit code).

## Потік виконання / Використання

### Сценарій 1: виклик через CI-оркестратор правил

1. Оркестратор правил (наприклад, агрегований раннер у `lint-js` чи кореневий `bun run lint`) виявляє правило `text` і знаходить його CI-кроки в `npm/rules/text/js/*.mjs`.
2. Для кожного CI-крока (зокрема `lint.mjs`) оркестратор імпортує named export `lint`.
3. Викликає `await lint(filesArrayOrUndefined)`.
4. Адаптер ігнорує `files`, делегує виклик у `runLintTextCli()`.
5. Реальний CLI робить whole-repo аналіз: запускає `dotenv-linter`, `shellcheck`, `v8r` тощо (відповідно до того, що оголошено в `../lint/lint.mjs`).
6. Повертає exit code.
7. Оркестратор агрегує exit code-и всіх CI-кроків і приймає рішення про загальний успіх/невдачу.

### Сценарій 2: пряме виконання з коду

```js
import { lint } from 'npm/rules/text/js/lint.mjs'

const code = await lint()
process.exit(code)
```

Передача аргументу `files` нічого не змінює (буде проігнорована):

```js
const code = await lint(['some/file.txt']) // _files ігнорується
```

### Чому per-file немає

Правило `text` за своєю природою сканує весь репозиторій (наприклад, перевіряє `.env`-файли, shell-скрипти, JSON Schema-файли через v8r). Для нього передача обмеженого списку файлів від CI не має сенсу — обробляти треба весь робочий простір. Звідси й whole-repo режим, явно зафіксований у JSDoc-коментарі та підкреслений підкресленням у назві параметра.

### Очікувані коди виходу

| Code  | Значення                                                                                            |
| ----- | --------------------------------------------------------------------------------------------------- |
| `0`   | Усі під-перевірки правила `text` пройшли успішно.                                                   |
| ≠ `0` | Знайдено порушення або помилка одного з інструментів. Конкретний код визначається `runLintTextCli`. |

### Обробка помилок

Адаптер не містить `try/catch`. Якщо `runLintTextCli` кине виняток (нештатна ситуація), він пробулькується нагору — до викликаючого. Це навмисний дизайн: оркестратор сам вирішує, як трактувати unhandled rejection.
