# fix.mjs — точка входу правила `npm-module`

## Огляд

`fix.mjs` — мінімалістична точка входу (entry-point) для правила з ідентифікатором, що відповідає назві теки, у якій файл розташований (`npm/rules/npm-module/`). Файл виконує дві ролі одночасно:

1. **Library mode** — експортує функцію `run(ctx)`, яку викликає оркестратор `npm/scripts/lib/run-standard-rule.mjs` через стандартний імпорт. Це дозволяє іншому коду (наприклад, агрегатору правил `@nitra/cursor`) виконувати правило у складі загального прогону.
2. **Standalone mode** — якщо файл стартує напряму (наприклад, `bun npm/rules/npm-module/fix.mjs`), він прогорає еквівалент команди `npx @nitra/cursor fix npm-module` через `runRuleCli` із завантаженням конфігу, whitelist та фінальним summary; повертає у процес коректний exit-code для CI/IDE.

Логіки самого правила тут немає — файл лише делегує виконання у стандартний раннер `runStandardRule`, який послідовно проганяє чотири фази правила: `applies` → `JS-concerns` → `policy` → `mdc-refs`.

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

| Назва | Тип                                  | Призначення                                                                                                                                                                                                |
| ----- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `run` | `function (ctx?) => Promise<number>` | Іменований експорт для library-mode. Викликає `runStandardRule` зі шляхом до теки правила та опційним контекстом. Повертає Promise з exit-кодом: `0` — правило не зафіксувало порушень, `1` — є порушення. |

Дефолтних експортів немає. Side-effect верхнього рівня: за умови запуску як CLI, наприкінці модуля викликається `process.exit(...)` з кодом, який повернув `runRuleCli`.

## Функції (сигнатура / параметри / повертає / side effects)

### `run(ctx)`

```js
export function run(ctx)
```

- **Параметри**
  - `ctx` _(опційний)_ — об'єкт типу `RuleContext`, імпортований з `../../scripts/lib/run-standard-rule.mjs`. Може містити, зокрема, `walkCache` (закешований обхід дерева файлів), щоб уникнути повторного walk при паралельному прогоні кількох правил.
- **Повертає** `Promise<number>`:
  - `0` — правило не виявило порушень або не застосовується до поточного workspace.
  - `1` — зафіксовано принаймні одне порушення.
- **Side effects**
  - Жодних прямих побічних ефектів у самій `run`. Усі побічні ефекти (читання файлів, друк summary, мутація `walkCache`) — у `runStandardRule` та підлеглих фазах правила.
- **Реалізація**

  ```js
  return runStandardRule(import.meta.dirname, ctx)
  ```

  `import.meta.dirname` дає абсолютний шлях до теки правила (`.../npm/rules/npm-module/`); цей шлях `runStandardRule` використовує як корінь для пошуку фаз правила (`applies.mjs`, `js/`, `policy.mjs`, `mdc-refs.mjs` тощо).

### Standalone-блок (без іменованої функції)

```js
if (isRunAsCli(import.meta.url)) {
  process.exit(await runRuleCli(import.meta.dirname))
}
```

- **Умова** — `isRunAsCli(import.meta.url)` повертає `true`, якщо модуль є точкою входу процесу (а не імпортується іншим модулем).
- **Дія** — `await runRuleCli(import.meta.dirname)` виконує повний CLI-цикл (config-loading, whitelist, прогін правила, summary) і повертає exit-код. Цей код передається у `process.exit`.
- **Коментар у коді** свідомо вимикає правила лінтера `n/no-process-exit` та `unicorn/no-process-exit`, оскільки standalone-entry-point має повертати exit-код для CI/IDE.

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

Прямі (внутрішні) залежності — два модулі зі спільної бібліотеки скриптів проєкту:

| Шлях імпорту                              | Що бере                                            | Призначення                                                                                                                                                                         |
| ----------------------------------------- | -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `../../scripts/lib/run-rule-cli.mjs`      | `isRunAsCli`, `runRuleCli`                         | Допоміжна логіка для роботи у standalone-режимі: визначення, чи модуль є entry-point процесу, і запуск повного CLI-циклу правила, який є еквівалентом `npx @nitra/cursor fix <id>`. |
| `../../scripts/lib/run-standard-rule.mjs` | `runStandardRule`, тип `RuleContext` (через JSDoc) | Уніфікований раннер чотирифазного правила (`applies → JS-concerns → policy → mdc-refs`). Через нього прогрівається walk-cache і виконуються фази у фіксованому порядку.             |

Зовнішніх (npm) залежностей файл не має. Він спирається на Node.js / Bun рантайм-можливості:

- `import.meta.url` — для визначення, чи модуль запущений як CLI.
- `import.meta.dirname` — для отримання абсолютного шляху до теки правила.
- `process.exit` — для повернення exit-коду у standalone-режимі.

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

### Сценарій A: Library mode (через оркестратор `@nitra/cursor`)

1. Оркестратор імпортує модуль: `const mod = await import('npm/rules/npm-module/fix.mjs')`.
2. `isRunAsCli(import.meta.url)` повертає `false` (модуль не є entry-point) — standalone-блок ігнорується.
3. Оркестратор викликає `await mod.run(ctx)`, передаючи спільний `RuleContext` (наприклад, з заздалегідь побудованим `walkCache`).
4. `run` делегує виконання `runStandardRule(import.meta.dirname, ctx)`, який проганяє чотири фази правила і повертає `0` або `1`.
5. Оркестратор агрегує exit-коди всіх правил у фінальний код процесу.

### Сценарій B: Standalone mode

1. Користувач запускає `bun npm/rules/npm-module/fix.mjs` (еквівалент `npx @nitra/cursor fix npm-module`).
2. Модуль завантажується як entry-point — `isRunAsCli(import.meta.url)` повертає `true`.
3. Виконується `await runRuleCli(import.meta.dirname)`:
   - завантажується конфіг (`.cursor`/проектні налаштування),
   - застосовується whitelist (якщо є),
   - запускається чотирифазне правило,
   - друкується summary з кількістю порушень.
4. Повернутий exit-код передається у `process.exit(...)`, що завершує процес. CI/IDE отримує `0` (успіх) або `1` (порушення).

### Контракт двох ролей

Дизайн «library + standalone в одному файлі» є типовим для правил `@nitra/cursor`:

- Функція `run` — публічний API для оркестратора; вона **не** викликає `process.exit` і не друкує summary, лише повертає код.
- Standalone-блок навпаки відповідає за повноцінний CLI-UX: завантаження конфігу, whitelist, summary, exit-code — усе, що очікується від `fix.mjs` правила, який запускається окремо.

Завдяки цьому контракту той самий файл інтегрується і у пакетний прогін правил, і в локальне налагодження одного правила без дублювання логіки.
