---
docgen:
  source: npm/rules/k8s/fix.mjs
  crc: 12fc1644
---

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

## Огляд

Файл `npm/rules/k8s/fix.mjs` — це **точка входу правила `k8s`** у системі `@nitra/cursor`. Він виконує дві ролі одночасно:

1. **Library mode** — експортує функцію `run(ctx)`, яку імпортує верхньорівневий CLI-оркестратор (`@nitra/cursor`) під час прогону групи правил (`fix`/`lint`-команди). У цьому режимі правило отримує спільний контекст прогону (`RuleContext`), що містить, серед іншого, кеш обходу файлової системи (`walkCache`), і має повертати числовий exit-code без виклику `process.exit`.
2. **Standalone mode** — якщо файл запущено напряму як CLI (`bun rules/k8s/fix.mjs`), він самостійно завантажує конфіг, застосовує whitelist, друкує summary та завершує процес із відповідним exit-code, тобто є повним еквівалентом команди `npx @nitra/cursor fix k8s`.

Сама логіка правила (які саме файли обходити, які `applies`/`JS-concerns`/`policy`/`mdc-refs` перевіряти) у цьому файлі **не описана** — вона делегується універсальному рушію `runStandardRule`, який знаходить артефакти правила за каталогом, переданим через `import.meta.dirname`.

Файл є тонкою адаптерною обгорткою — типовий шаблон `fix.mjs`, що повторюється для всіх правил у `npm/rules/<id>/`.

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

| Експорт | Тип                                      | Призначення                                                                                            |
| ------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `run`   | `(ctx?: RuleContext) => Promise<number>` | Запуск правила в **library mode**. Викликається верхньорівневим CLI під час оркестрації набору правил. |

Файл також має **side-effect блок верхнього рівня** (умовний `process.exit(await runRuleCli(...))`), який спрацьовує **лише** коли модуль є entry-point поточного Node/Bun-процесу. Цей блок не є експортом, але є частиною публічної поведінки файлу як standalone-скрипта.

Інших іменованих чи default-експортів файл не має.

## Функції

### `run(ctx)`

```js
/**
 *
 */
export function run(ctx) {
  return runStandardRule(import.meta.dirname, ctx)
}
```

**Сигнатура:**

```ts
function run(ctx?: RuleContext): Promise<number>
```

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

- `ctx` _(опційно)_ — об'єкт контексту прогону типу `RuleContext` (тип реекспортується з `../../scripts/lib/run-standard-rule.mjs`). У контексті, як зазначено в JSDoc, може передаватися, зокрема, `walkCache` — спільний кеш обходу файлової системи між правилами, щоб не сканувати дерево заново для кожного правила в одній сесії. Якщо параметр не передано, `runStandardRule` працює без зовнішнього кешу.

**Повертає:**

- `Promise<number>` — exit-code результату прогону правила:
  - `0` — OK (порушень немає);
  - `1` — знайдено порушення (`runStandardRule` повертає `1`, коли хоча б одна перевірка дала falsy/негативний результат).

**Side effects:**

- Делегує всю роботу `runStandardRule`, який, своєю чергою:
  - обходить файлову систему за `applies`-патернами правила;
  - запускає підмодулі правила (`applies`, `JS-concerns`, `policy`, `mdc-refs`) — у послідовності, визначеній стандартним рушієм;
  - пише діагностику/виводить порушення у stdout/stderr (точна форма залежить від рушія, не цього файлу).
- Сама функція `run` не торкається `process.exit`, `process.cwd` чи глобального стану — увесь побічний ефект інкапсульовано всередині `runStandardRule`.

**Чому передається `import.meta.dirname`:** це абсолютний шлях до каталогу `npm/rules/k8s/`, в якому лежить даний `fix.mjs`. `runStandardRule` за цим шляхом знаходить решту артефактів правила (наприклад, `k8s.mdc`, `applies.mjs`, `check-*.mjs`, `policy`-файли тощо), не вимагаючи від `fix.mjs` явно перераховувати, які саме перевірки треба виконати.

### Top-level standalone-блок

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

**Призначення:** дозволити запускати правило окремо — `bun npm/rules/k8s/fix.mjs` — і отримати такий самий результат, як від `npx @nitra/cursor fix k8s` (із завантаженням конфігу, застосуванням whitelist та друком summary).

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

- `isRunAsCli(import.meta.url)` повертає `true`, якщо поточний файл є entry-point процесу (а не імпортований модуль). Якщо це бібліотечний імпорт — блок не виконується, побічних ефектів немає.
- `runRuleCli(import.meta.dirname)` — повний CLI-цикл одного правила: завантаження конфігу проєкту, фільтр whitelist, виклик `run`-логіки, друк підсумкового summary; повертає `Promise<number>` — exit-code.
- `process.exit(...)` примусово завершує процес із цим exit-code, щоб CI/IDE могли коректно проінтерпретувати результат прогону.

**Top-level `await`:** доступний у файлі завдяки тому, що `.mjs` є ES-модулем — це обов'язкова умова для коректної роботи `await runRuleCli(...)` поза `async`-функцією.

**ESLint-директива:** коментар `// eslint-disable-next-line n/no-process-exit, unicorn/no-process-exit` свідомо вимикає правила, що забороняють `process.exit`, тому що standalone entry-point **повинен** повертати exit-code (це і пояснює коментар-`-- ...` після назв правил).

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

### Внутрішні

- `../../scripts/lib/run-rule-cli.mjs` (`npm/scripts/lib/run-rule-cli.mjs`) — імпортуються два named-експорти:
  - `isRunAsCli(metaUrl)` — детектор того, чи запущений файл як CLI-entry, а не як імпортований модуль (стандартний ESM-патерн «main module detection» через `import.meta.url`);
  - `runRuleCli(ruleDir)` — повний цикл standalone-прогону одного правила (config-loading + whitelist + виклик `run` + summary).
- `../../scripts/lib/run-standard-rule.mjs` (`npm/scripts/lib/run-standard-rule.mjs`) — імпортується:
  - `runStandardRule(ruleDir, ctx?)` — універсальний рушій «стандартного» правила, що знаходить за `ruleDir` усі артефакти (`applies`, `JS-concerns`, `policy`, `mdc-refs`) і запускає їх у правильному порядку;
  - реекспортує тип `RuleContext` (використовується у JSDoc `@param`).

### Зовнішні

- Глобальні Node-runtime API: `process.exit` (умовний виклик), `import.meta.dirname`, `import.meta.url`. Окремих npm-залежностей цей файл не має.

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

### Сценарій 1. Library mode (типове використання)

1. Верхньорівневий CLI-оркестратор `@nitra/cursor` (наприклад, команда `fix`) збирає список активних правил.
2. Для правила `k8s` він робить динамічний імпорт цього файлу (`import('npm/rules/k8s/fix.mjs')`).
3. Оркестратор формує спільний `ctx: RuleContext` (зокрема `walkCache`, який буде поділено між правилами однієї сесії) і викликає `await mod.run(ctx)`.
4. `run` делегує виклик `runStandardRule(import.meta.dirname, ctx)`, який:
   - читає артефакти правила з каталогу `npm/rules/k8s/`;
   - обходить FS відповідно до `applies`-патернів (використовуючи `ctx.walkCache`, якщо переданий);
   - послідовно виконує перевірки `applies → JS-concerns → policy → mdc-refs`;
   - повертає `0` (OK) або `1` (порушення).
5. Оркестратор агрегує exit-коди з усіх правил у фінальний exit-code сесії.

### Сценарій 2. Standalone mode (запуск одного правила вручну)

1. Користувач запускає `bun npm/rules/k8s/fix.mjs` (або еквівалент через інший Node-runtime з підтримкою `import.meta.dirname`).
2. ESM-завантажувач виконує файл як entry-point: визначення `run` потрапляє у scope модуля, але оркестратор ззовні його не викликає.
3. Виконується top-level `if (isRunAsCli(import.meta.url))` — умова `true`, оскільки `import.meta.url` збігається з entry-point процесу.
4. Викликається `await runRuleCli(import.meta.dirname)`:
   - підвантажується конфіг проєкту;
   - застосовується whitelist (якщо налаштований);
   - всередині `runRuleCli` запускається та сама логіка правила (через ту саму експортовану функцію `run` / `runStandardRule`), що й у library mode;
   - друкується summary з кількістю перевірених файлів і знайдених порушень.
5. Отриманий `exit-code` передається в `process.exit(...)` — процес завершується із цим кодом, що дозволяє CI/IDE коректно реагувати на результат.

### Сценарій 3. Імпорт як модуля без виклику `run`

Якщо файл імпортується суто для інтроспекції (`import * as fixK8s from '.../k8s/fix.mjs'`), `isRunAsCli(import.meta.url)` поверне `false` (`import.meta.url` модуля не співпаде з URL entry-point процесу), і standalone-блок не виконається. Жодних побічних ефектів імпорт не має — це **безпечно** для тулзів типу docgen чи статичного аналізу.

### Замітки про шаблон

- Файл є **взаємозамінним** із аналогічними `fix.mjs` у сусідніх каталогах `npm/rules/<id>/` — відрізняється лише розташуванням (а отже — `import.meta.dirname`), і завдяки цьому той самий рушій `runStandardRule` обслуговує всі правила без копіювання логіки.
- Жодна k8s-специфічна логіка тут **не** жорстко закодована — вона лежить у сусідніх файлах правила (`k8s.mdc`, `applies.mjs`, `check-*.mjs`, `policy`-артефакти), які знаходить `runStandardRule` за каталогом.
- Для додавання нового правила достатньо створити каталог `npm/rules/<new-id>/` і покласти туди такий самий `fix.mjs` — без жодних модифікацій (за умови, що структура артефактів стандартна).
