@nitra/cursor 5.3.4 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/.claude-template/settings.template.json +2 -2
  2. package/.pi-template/extensions/n-cursor-adr/docs/index.md +13 -24
  3. package/CHANGELOG.md +21 -0
  4. package/bin/n-cursor.js +47 -24
  5. package/lib/docs/models.md +29 -18
  6. package/lib/docs/omlx-trace.md +51 -0
  7. package/lib/docs/omlx.md +31 -15
  8. package/lib/omlx.mjs +2 -5
  9. package/package.json +1 -1
  10. package/rules/abie/docs/fix.md +17 -11
  11. package/rules/adr/docs/fix.md +25 -140
  12. package/rules/bun/docs/fix.md +18 -151
  13. package/rules/capacitor/docs/fix.md +16 -13
  14. package/rules/capacitor/js/docs/platforms.md +31 -43
  15. package/rules/changelog/docs/fix.md +25 -169
  16. package/rules/ci4/docs/fix.md +11 -14
  17. package/rules/doc-files/doc-files.mdc +60 -0
  18. package/rules/doc-files/docs/fix.md +31 -0
  19. package/rules/doc-files/fix.mjs +19 -0
  20. package/{skills → rules}/doc-files/js/docgen-extract.mjs +42 -19
  21. package/{skills → rules}/doc-files/js/docgen-files-batch.mjs +18 -5
  22. package/{skills → rules}/doc-files/js/docgen-gen.mjs +46 -5
  23. package/{skills → rules}/doc-files/js/docgen-ignore.mjs +2 -1
  24. package/{skills → rules}/doc-files/js/docgen-scan.mjs +11 -3
  25. package/{skills → rules}/doc-files/js/docs/docgen-crc.md +1 -1
  26. package/{skills → rules}/doc-files/js/docs/docgen-extract-anchors.md +1 -1
  27. package/{skills → rules}/doc-files/js/docs/docgen-extract.md +2 -2
  28. package/{skills → rules}/doc-files/js/docs/docgen-files-batch.md +2 -2
  29. package/{skills → rules}/doc-files/js/docs/docgen-gen.md +2 -2
  30. package/{skills → rules}/doc-files/js/docs/docgen-ignore.md +4 -4
  31. package/rules/doc-files/js/docs/docgen-prompts.md +39 -0
  32. package/rules/doc-files/js/docs/docgen-scan.md +54 -0
  33. package/rules/doc-files/js/docs/lint.md +36 -0
  34. package/rules/doc-files/js/docs/units-js.md +31 -0
  35. package/rules/doc-files/js/docs/units-rs.md +35 -0
  36. package/rules/doc-files/js/docs/units.md +30 -0
  37. package/rules/doc-files/js/lint.mjs +96 -0
  38. package/{skills → rules}/doc-files/js/units-rs.mjs +37 -17
  39. package/rules/doc-files/lint/docs/lint.md +37 -0
  40. package/rules/doc-files/lint/lint.mjs +105 -0
  41. package/rules/doc-files/meta.json +1 -0
  42. package/rules/docker/docs/fix.md +21 -161
  43. package/rules/efes/docs/fix.md +23 -194
  44. package/rules/feedback/docs/fix.md +10 -8
  45. package/rules/ga/docs/fix.md +10 -5
  46. package/rules/ga/meta.json +1 -1
  47. package/rules/graphql/docs/fix.md +23 -119
  48. package/rules/hasura/docs/fix.md +19 -5
  49. package/rules/hasura/js/docs/internal_urls.md +34 -307
  50. package/rules/image-avif/docs/fix.md +16 -127
  51. package/rules/image-compress/docs/fix.md +20 -141
  52. package/rules/image-compress/js/docs/package_setup.md +22 -182
  53. package/rules/js-bun-db/docs/fix.md +23 -139
  54. package/rules/js-bun-db/js/docs/safety.md +33 -221
  55. package/rules/js-bun-redis/docs/fix.md +25 -114
  56. package/rules/js-bun-redis/js/docs/imports.md +18 -166
  57. package/rules/js-lint/docs/fix.md +30 -108
  58. package/rules/js-lint/js/docs/lint-findings.md +37 -17
  59. package/rules/js-lint/js/docs/lint.md +22 -238
  60. package/rules/js-lint/js/docs/tooling.md +34 -331
  61. package/rules/js-lint/js/lint.mjs +19 -12
  62. package/rules/js-lint/js-lint.mdc +1 -1
  63. package/rules/js-lint/meta.json +1 -1
  64. package/rules/js-lint-ci/docs/fix.md +16 -149
  65. package/rules/js-lint-ci/js/docs/lint.md +16 -136
  66. package/rules/js-lint-ci/js-lint-ci.mdc +1 -1
  67. package/rules/js-lint-ci/meta.json +1 -1
  68. package/rules/js-mssql/docs/fix.md +18 -123
  69. package/rules/js-mssql/js/docs/deps.md +28 -251
  70. package/rules/js-run/docs/fix.md +23 -138
  71. package/rules/js-run/js/docs/runtime.md +24 -378
  72. package/rules/k8s/docs/fix.md +18 -123
  73. package/rules/nginx-default-tpl/docs/fix.md +22 -118
  74. package/rules/nginx-default-tpl/js/docs/template.md +38 -360
  75. package/rules/npm-module/docs/fix.md +27 -89
  76. package/rules/npm-module/js/docs/header_doc_pointer.md +15 -15
  77. package/rules/npm-module/js/docs/package_structure.md +36 -258
  78. package/rules/npm-module/js/docs/rule_meta.md +25 -127
  79. package/rules/npm-module/js/docs/skill_meta.md +18 -180
  80. package/rules/npm-module/js/rule_meta.mjs +3 -3
  81. package/rules/php/docs/fix.md +21 -98
  82. package/rules/php/js/docs/tooling.md +20 -143
  83. package/rules/python/docs/fix.md +25 -157
  84. package/rules/python/js/docs/applies.md +20 -98
  85. package/rules/python/js/docs/tooling.md +27 -144
  86. package/rules/rego/docs/fix.md +24 -112
  87. package/rules/rego/js/docs/applies.md +20 -164
  88. package/rules/rego/js/docs/lint.md +15 -110
  89. package/rules/rego/meta.json +1 -1
  90. package/rules/release/docs/fix.md +16 -114
  91. package/rules/rust/docs/fix.md +24 -119
  92. package/rules/rust/js/docs/applies.md +20 -129
  93. package/rules/security/docs/fix.md +21 -78
  94. package/rules/security/js/docs/sample_secret.md +23 -182
  95. package/rules/security/js/docs/trufflehog.md +19 -128
  96. package/rules/security/meta.json +1 -1
  97. package/rules/style-lint/docs/fix.md +16 -150
  98. package/rules/style-lint/js/docs/lint.md +21 -172
  99. package/rules/style-lint/js/docs/tooling.md +19 -184
  100. package/rules/style-lint/js/lint.mjs +4 -3
  101. package/rules/style-lint/meta.json +1 -1
  102. package/rules/tauri/docs/fix.md +26 -152
  103. package/rules/tauri/js/docs/cargo_mutants_config.md +21 -159
  104. package/rules/tauri/js/docs/tooling.md +20 -217
  105. package/rules/test/docs/fix.md +19 -127
  106. package/rules/test/js/data/stryker_config/docs/stryker.config.baseline.md +15 -127
  107. package/rules/test/js/data/stryker_config/docs/stryker.config.vue.baseline.md +17 -153
  108. package/rules/test/js/docs/cargo_mutants_config.md +24 -164
  109. package/rules/test/js/docs/location.md +24 -126
  110. package/rules/test/js/docs/no-process-chdir.md +20 -151
  111. package/rules/test/js/docs/no-relative-fs-path.md +24 -261
  112. package/rules/test/js/docs/stryker_config.md +48 -148
  113. package/rules/test/js/docs/vitest-config-pool-forks.md +21 -164
  114. package/rules/text/docs/fix.md +25 -113
  115. package/rules/text/js/docs/forbidden-prettier.md +21 -132
  116. package/rules/text/js/docs/formatting.md +60 -251
  117. package/rules/text/js/docs/lint.md +17 -114
  118. package/rules/text/js/lint.mjs +5 -3
  119. package/rules/text/lint/docs/lint.md +1 -1
  120. package/rules/text/lint/docs/run-dotenv-linter.md +1 -1
  121. package/rules/text/lint/docs/run-shellcheck.md +1 -1
  122. package/rules/text/lint/lint.mjs +13 -9
  123. package/rules/text/lint/run-dotenv-linter.mjs +13 -10
  124. package/rules/text/lint/run-shellcheck.mjs +10 -6
  125. package/rules/text/meta.json +1 -1
  126. package/rules/vue/docs/fix.md +25 -118
  127. package/rules/vue/js/docs/packages.md +25 -323
  128. package/rules/worktree/docs/fix.md +31 -150
  129. package/scripts/coverage-classify/docs/index.md +23 -209
  130. package/scripts/coverage-classify/docs/verdict-schema.md +14 -159
  131. package/scripts/dispatcher/docs/trace.md +35 -0
  132. package/scripts/docs/auto-rules.md +37 -361
  133. package/scripts/docs/lint-cli.md +12 -13
  134. package/scripts/docs/post-tool-use-fix.md +16 -15
  135. package/scripts/docs/skills-cli.md +26 -23
  136. package/scripts/docs/sync-claude-config.md +94 -34
  137. package/scripts/docs/worktree-cli.md +11 -34
  138. package/scripts/lib/docs/assert-project-root.md +14 -16
  139. package/scripts/lib/docs/changed-files.md +24 -139
  140. package/scripts/lib/docs/discover-check-rules-from-cursor.md +14 -146
  141. package/scripts/lib/docs/rule-meta.md +1 -1
  142. package/scripts/lib/docs/rule-predicates.md +20 -17
  143. package/scripts/lib/docs/run-rule-cli.md +14 -18
  144. package/scripts/lib/docs/run-rule.md +13 -20
  145. package/scripts/lib/docs/run-standard-rule.md +12 -15
  146. package/scripts/lib/docs/sync-gitignore-worktree.md +15 -18
  147. package/scripts/lib/rule-meta.mjs +10 -6
  148. package/scripts/lib/rule-predicates.mjs +1 -1
  149. package/scripts/lint-cli.mjs +28 -20
  150. package/scripts/sync-claude-config.mjs +4 -1
  151. package/scripts/utils/docs/with-lock.md +19 -12
  152. package/scripts/utils/with-lock.mjs +4 -2
  153. package/skills/doc-aggregate/SKILL.md +2 -2
  154. package/skills/doc-aggregate/js/docgen-ignore.mjs +6 -6
  155. package/skills/doc-aggregate/js/docs/docgen-ignore.md +1 -1
  156. package/skills/doc-aggregate/js/docs/docgen-scan.md +78 -0
  157. package/skills/doc-files/.changes/260612-0031.md +5 -0
  158. package/skills/doc-files/.changes/260612-0036.md +5 -0
  159. package/skills/doc-files/.changes/260612-0114.md +5 -0
  160. package/skills/doc-files/SKILL.md +6 -6
  161. package/skills/fix/js/docs/llm-worker.md +17 -15
  162. package/skills/fix/js/docs/orchestrator.md +30 -23
  163. package/skills/fix/js/docs/t0.md +26 -16
  164. package/skills/start-check/js/docs/check.md +26 -22
  165. package/skills/taze/js/docs/diff.md +44 -20
  166. package/skills/doc-files/js/docs/docgen-prompts.md +0 -32
  167. package/skills/doc-files/js/docs/docgen-scan.md +0 -25
  168. package/skills/doc-files/js/docs/units-rs.md +0 -35
  169. /package/{skills → rules}/doc-files/js/docgen-crc.mjs +0 -0
  170. /package/{skills → rules}/doc-files/js/docgen-extract-anchors.mjs +0 -0
  171. /package/{skills → rules}/doc-files/js/docgen-prompts.mjs +0 -0
  172. /package/{skills → rules}/doc-files/js/units-js.mjs +0 -0
  173. /package/{skills → rules}/doc-files/js/units.mjs +0 -0
@@ -1,141 +1,30 @@
1
1
  ---
2
2
  docgen:
3
3
  source: npm/rules/image-avif/fix.mjs
4
- crc: 12fc1644
4
+ crc: 38cf876b
5
+ score: 100
5
6
  ---
6
7
 
7
- # `fix.mjs` — entry-point правила `image-avif`
8
+ # fix.mjs
8
9
 
9
10
  ## Огляд
10
11
 
11
- Файл `npm/rules/image-avif/fix.mjs` — це **подвійний entry-point** одного з правил пакета `@nitra/cursor`. Він входить до інфраструктури «standard rules», де кожне правило живе в окремій теці (`npm/rules/<id>/`) і складається з:
12
+ Обробляє JS-занепокоєні до політики для MDC-референсів на основі наданого контексту прогону та повертає результат
12
13
 
13
- - `fix.mjs` — тонкий wrapper-orchestrator (цей файл);
14
- - `meta.json` — метадані (наприклад, `auto`-залежності, тут `{"auto": ["vue", "image-compress"]}`);
15
- - `<id>.mdc` — людино-зрозумілий опис правила для Cursor;
16
- - підтек `js/` (concerns на рівні JS-AST/тексту) і `policy/` (rego-policy).
14
+ ## Поведінка
17
15
 
18
- Конкретно цей файл виконує дві ролі:
16
+ 1. Запуск правила.
17
+ * Приймає контекст прогону.
18
+ * Виконує застосування JS-занепокоєних до політики до MDC-референсів.
19
+ * Повертає результат.
19
20
 
20
- 1. **Library-режим.** Експортує функцію `run(ctx)`, яку CLI-orchestrator вищого рівня (`@nitra/cursor fix`) імпортує й викликає для прогону правила в межах загального пайплайну (з кешем walk-обходу й спільним підсумком).
21
- 2. **Standalone-режим.** Якщо файл запущено напряму (`bun npm/rules/image-avif/fix.mjs` або еквівалент), він самостійно піднімає повний CLI-цикл (`runRuleCli`) — з підвантаженням конфігурації, whitelist та виведенням підсумку — і завершує процес кодом 0/1.
21
+ ## Публічний API
22
22
 
23
- Сам файл **не містить** логіки перевірки контенту: уся робота делегується в `runStandardRule`, який послідовно проганяє чотири фази правила — `applies → JS-concerns → policy → mdc-refs`.
23
+ run запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
24
+ Library mode — викликається CLI orchestration через `import + run`.
24
25
 
25
- ## Експорти / API
26
+ ## Гарантії поведінки
26
27
 
27
- | Експорт | Тип | Призначення |
28
- | ------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
29
- | `run` | `function (ctx?: RuleContext) => Promise<number>` | Library-точка входу правила. Викликається CLI-orchestratorом для запуску правила `image-avif`. Повертає exit-код (`0` — OK, `1` — є порушення). |
30
-
31
- Інших іменованих чи default-експортів файл не має.
32
-
33
- Окрім експорту, у файлі є **top-level side-effect**: блок `if (isRunAsCli(import.meta.url)) { … process.exit(await runRuleCli(...)) }`. Він спрацьовує **лише** коли цей `.mjs` запущено як CLI-entry (а не імпортовано як модуль), і завершує процес кодом, який повернув `runRuleCli`.
34
-
35
- ## Функції
36
-
37
- ### `run(ctx)`
38
-
39
- ```js
40
- /**
41
- *
42
- */
43
- export function run(ctx) {
44
- return runStandardRule(import.meta.dirname, ctx)
45
- }
46
- ```
47
-
48
- - **Сигнатура:** `run(ctx?: RuleContext): Promise<number>`.
49
- - **Параметри:**
50
- - `ctx` — необов'язковий контекст прогону (`RuleContext`), імпортується з `../../scripts/lib/run-standard-rule.mjs`. У документації самого файла зазначено, що в `ctx` передається, наприклад, `walkCache` — спільний кеш обходу файлової системи, щоб не повторювати walk між правилами в межах одного CLI-прогону. Якщо `ctx` не передано, `runStandardRule` сам ініціалізує необхідне.
51
- - **Повертає:** `Promise<number>` — числовий exit-код:
52
- - `0` — правило виконано без порушень;
53
- - `1` — знайдені порушення (несумісність із `image-avif`).
54
- - **Що робить усередині:** єдиним викликом делегує всю роботу в `runStandardRule(dir, ctx)`. Перший аргумент — `import.meta.dirname`, тобто **абсолютний шлях до теки `npm/rules/image-avif/`** на диску. Саме цей шлях `runStandardRule` використовує, щоб знайти сусідні `meta.json`, теку `js/` (JS-concerns) та теку `policy/` (rego-policy) і прогнати їх по конвеєру.
55
- - **Side effects:** прямих side-effects сама функція не виконує. Усі ефекти (читання файлів, виклик `opa`, форматування звіту) інкапсульовано в `runStandardRule`. Функція асинхронна (повертає `Promise`), бо `runStandardRule` повертає `Promise`.
56
-
57
- ### Top-level CLI-блок (не функція, але важливий side-effect)
58
-
59
- ```js
60
- if (isRunAsCli(import.meta.url)) {
61
- // eslint-disable-next-line n/no-process-exit
62
- process.exit(await runRuleCli(import.meta.dirname))
63
- }
64
- ```
65
-
66
- - **Умова входу:** `isRunAsCli(import.meta.url)` повертає `true`, лише якщо файл стартовано напряму як скрипт (Node.js/Bun), а не імпортовано як модуль. Це класичний `__main__`-патерн для ESM.
67
- - **Що робить:** викликає `runRuleCli(import.meta.dirname)` — повноцінний CLI-обгортувач, який, на відміну від `runStandardRule`, додатково підтягує конфігурацію проєкту, застосовує whitelist і друкує summary (як коментар у файлі: «повний еквівалент `npx @nitra/cursor fix <id>`»). Результатом є `Promise<number>` із exit-кодом.
68
- - **Завершення:** `process.exit(...)` примусово завершує процес із отриманим exit-кодом. Це навмисно — для CI/IDE інтеграцій, які зчитують exit-код. Через це поряд стоять директиви `eslint-disable-next-line n/no-process-exit, unicorn/no-process-exit` із поясненням («standalone entry-point має повертати exit-code для CI/IDE»).
69
- - **`await` на top-level:** доступний завдяки тому, що файл є ESM-модулем (`.mjs`) і виконується в середовищі з підтримкою top-level await (Node.js ≥ 14.8 / Bun).
70
-
71
- ## Залежності
72
-
73
- ### Імпорти з сусідніх модулів пакета
74
-
75
- | Імпорт | Звідки | Призначення |
76
- | ----------------- | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
77
- | `isRunAsCli` | `../../scripts/lib/run-rule-cli.mjs` | Предикат: чи поточний модуль виконано напряму як CLI (порівнює `import.meta.url` зі скриптом, який стартував процес). |
78
- | `runRuleCli` | `../../scripts/lib/run-rule-cli.mjs` | Standalone CLI-обгортка: завантажує конфігурацію, формує whitelist, прогоняє правило (через той самий `runStandardRule` усередині) і повертає exit-код. |
79
- | `runStandardRule` | `../../scripts/lib/run-standard-rule.mjs` | Стандартний пайплайн правила: послідовно виконує фази **applies → JS-concerns → policy → mdc-refs**, базуючись на структурі теки правила (передано через `dirname`). |
80
-
81
- Шляхи відносні: `../../scripts/lib/...` означає `npm/scripts/lib/...` (з огляду на розташування файла в `npm/rules/image-avif/`).
82
-
83
- ### JSDoc-залежності типів
84
-
85
- У JSDoc вказано тип `import('../../scripts/lib/run-standard-rule.mjs').RuleContext` для параметра `ctx`. Це **type-only** імпорт: на runtime він не існує, лише підказує IDE/типчекеру форму об'єкта контексту.
86
-
87
- ### Сусідні артефакти правила (не імпортуються тут, але необхідні `runStandardRule`)
88
-
89
- - `npm/rules/image-avif/meta.json` — `{ "auto": ["vue", "image-compress"] }`. Поле `auto` декларує, які інші правила автоматично «тягнуться» разом із `image-avif`.
90
- - `npm/rules/image-avif/js/` — каталог JS-concerns (тек з функціями перевірки/трансформації).
91
- - `npm/rules/image-avif/policy/` — каталог rego-policy для фази `policy`.
92
- - `npm/rules/image-avif/image-avif.mdc` — людинозрозумілий опис правила (для Cursor) — використовується у фазі `mdc-refs`.
93
-
94
- ### Зовнішні залежності
95
-
96
- Прямих імпортів зовнішніх npm-пакетів у файлі немає. Усі залежності — внутрішні до пакета `@nitra/cursor`.
97
-
98
- ## Потік виконання / Використання
99
-
100
- ### Сценарій 1. Library-режим (через CLI-orchestrator)
101
-
102
- Коли користувач запускає `npx @nitra/cursor fix` (або відповідну скіл-команду на кшталт `/n-fix`), верхньорівневий orchestrator:
103
-
104
- 1. Обходить теку `npm/rules/`, знаходить правило `image-avif`.
105
- 2. Динамічно імпортує `npm/rules/image-avif/fix.mjs` як ESM-модуль. У цей момент top-level `if (isRunAsCli(...))` повертає `false` (файл не запущено напряму), тож `process.exit` **не** викликається.
106
- 3. Викликає `run(ctx)`, передаючи спільний контекст (наприклад, із заздалегідь побудованим `walkCache`).
107
- 4. Усередині `run` делегує в `runStandardRule(import.meta.dirname, ctx)`, який послідовно проходить чотири фази:
108
- - **applies** — визначає, до яких файлів проєкту правило взагалі застосовне;
109
- - **JS-concerns** — запускає функції з теки `js/` для AST/текстових перевірок;
110
- - **policy** — викликає `opa` з rego-файлами з `policy/`;
111
- - **mdc-refs** — звіряє посилання у `.mdc`.
112
- 5. Отримує `0`/`1`, передає назад orchestratorу, який агрегує результати всіх правил у спільний summary.
113
-
114
- ### Сценарій 2. Standalone-режим (для дебагу/CI)
115
-
116
- Користувач (або IDE/CI) запускає файл напряму:
117
-
118
- ```bash
119
- bun npm/rules/image-avif/fix.mjs
120
- ```
121
-
122
- 1. Бунт/Node стартує файл як ESM-скрипт. Виконуються імпорти.
123
- 2. Експорт `run` зареєстровано, але **не викликається** — поза CLI-orchestratorом нікому його смикати.
124
- 3. Виконується top-level `if`: `isRunAsCli(import.meta.url)` повертає `true`.
125
- 4. Викликається `await runRuleCli(import.meta.dirname)` — повний еквівалент `npx @nitra/cursor fix image-avif`: завантаження конфігурації проєкту, whitelist, прогін правила (через той самий `runStandardRule` усередині `runRuleCli`), друк summary.
126
- 5. `process.exit(<exitCode>)` завершує процес із кодом, який бачить CI/IDE.
127
-
128
- ### Дизайн-патерн: dual-role entry-point
129
-
130
- У коментарі автор файла прямо називає цей патерн: «Дві ролі fix.mjs: library (run) + standalone (main)». Це повторюваний патерн для всіх правил пакета — кожне правило має свій `fix.mjs` із такою ж двоїстою структурою. Завдяки цьому:
131
-
132
- - CLI-orchestrator може **переюзати** ту саму функцію `run`, не дублюючи виклик `process.exit`;
133
- - розробник може **локально дебажити** одне правило, запустивши його `fix.mjs` напряму;
134
- - логіка пайплайну живе в одному місці (`runStandardRule`), а entry-point залишається тонким.
135
-
136
- ### Що цей файл **не** робить
137
-
138
- - Не визначає, **які саме** файли проєкту порушують `image-avif` — це робить тека `js/` і `policy/`.
139
- - Не парсить аргументи CLI — це робить `runRuleCli`.
140
- - Не пише в stdout/stderr напряму — увесь вивід формує `runStandardRule`/`runRuleCli`.
141
- - Не модифікує файли проєкту — назва `fix` тут історична (контракт стандартного правила); фактична семантика — це check + (потенційно) auto-fix усередині concerns, але сам `fix.mjs` лише оркеструє.
28
+ - Read-only: файл не виконує операцій запису у файлову систему.
29
+ - Кешує результати в межах одного прогону.
30
+ - Не звертається до мережі.
@@ -1,150 +1,29 @@
1
- # fix.mjs — entry-point правила `image-compress`
1
+ ---
2
+ docgen:
3
+ source: npm/rules/image-compress/fix.mjs
4
+ crc: 38cf876b
5
+ score: 100
6
+ ---
2
7
 
3
- ## Огляд
4
-
5
- Файл `npm/rules/image-compress/fix.mjs` — це уніфікована точка входу (entry-point) для правила `image-compress` із набору правил `@nitra/cursor`. Він виконує дві ролі одночасно:
6
-
7
- 1. **Library mode** — експортує функцію `run(ctx)`, яку викликає CLI-оркестратор `@nitra/cursor` (через динамічний `import` модуля та виклик `run(ctx)`) разом з іншими правилами в межах одного загального прогону (з конфіг-завантаженням, whitelist та підсумковим звітом).
8
- 2. **Standalone mode** — якщо файл запущено напряму через `bun rules/image-compress/fix.mjs` (тобто є точкою входу процесу), він самостійно піднімає повний CLI-оркестратор для цього єдиного правила і завершує процес кодом виходу, придатним для CI/IDE.
9
-
10
- Уся логіка правила (виявлення `applies`, перевірка JS-concerns, policy, валідація mdc-refs) делегується у `runStandardRule` зі спільної бібліотеки `scripts/lib/run-standard-rule.mjs`. Тобто сам `fix.mjs` правила `image-compress` не містить власної бізнес-логіки — він лише прив’язує спільний “стандартний” пайплайн правил до конкретної директорії цього правила через `import.meta.dirname`.
11
-
12
- Правило `image-compress` належить до родини стандартних правил `@nitra/cursor`, де кожне правило живе у власній теці `npm/rules/<id>/` і має однаковий каркас: `fix.mjs` (цей файл), `check-*.mjs` (детектори порушень), `*.mdc` (людинозрозумілий опис правила) та інші артефакти, які `runStandardRule` автоматично знаходить за домовленостями про шляхи.
13
-
14
- ## Експорти / API
15
-
16
- Модуль має один іменований експорт.
17
-
18
- ### `run(ctx?) → Promise<number>`
19
-
20
- Function, що повертає `Promise<number>` — exit-code прогону правила:
21
-
22
- - `0` — правило відпрацювало без порушень (OK).
23
- - `1` — знайдено порушення політики/перевірок правила.
24
-
25
- Параметри:
26
-
27
- - `ctx` (необов’язковий) — об’єкт `RuleContext` з `scripts/lib/run-standard-rule.mjs`. Використовується для спільного стану між правилами в межах одного прогону, зокрема для кешу обходу файлової системи (`walkCache`) та інших оркестраційних метаданих. Якщо не передано — `runStandardRule` сам ініціалізує внутрішній контекст.
28
-
29
- Призначення: викликається CLI-оркестратором `@nitra/cursor` як library API. Зовнішній код виконує `import { run } from '<абсолютний шлях>/npm/rules/image-compress/fix.mjs'` і потім `await run(ctx)`. Це дозволяє запускати багато правил в одному процесі з єдиним конфіг-завантаженням і єдиним звітом.
30
-
31
- Модуль не має `export default`, не експортує жодних інших символів, констант чи типів.
32
-
33
- ## Функції
34
-
35
- ### `run(ctx)`
36
-
37
- **Сигнатура:**
38
-
39
- ```js
40
- export function run(ctx)
41
- ```
42
-
43
- **JSDoc-тип (як у вихідному файлі):**
44
-
45
- - `@param {import('../../scripts/lib/run-standard-rule.mjs').RuleContext} [ctx]` — контекст прогону (наприклад, `walkCache`); параметр опціональний.
46
- - `@returns {Promise<number>}` — `0` означає OK, `1` — порушення.
47
-
48
- **Параметри:**
49
-
50
- - `ctx?: RuleContext` — необов’язковий контекст із зовнішнього оркестратора; пробрасується далі без модифікації.
51
-
52
- **Що робить:**
53
-
54
- 1. Звертається до `import.meta.dirname` — це абсолютний шлях до директорії, у якій лежить сам `fix.mjs` (тобто до `npm/rules/image-compress/`).
55
- 2. Викликає `runStandardRule(import.meta.dirname, ctx)` — стандартну реалізацію пайплайну правила: applies → JS-concerns → policy → mdc-refs.
56
- 3. Повертає `Promise<number>`, який вирішить exit-code від `runStandardRule`.
57
-
58
- **Повертає:** `Promise<number>` — exit-code пайплайна (`0` або `1`).
8
+ # fix.mjs
59
9
 
60
- **Side effects:** прямих сайд-ефектів у самій функції немає; усі сайд-ефекти (читання файлів проєкту, виведення в `stdout`/`stderr`, формування підсумків звіту тощо) інкапсульовані всередині `runStandardRule`. Сама `run` лише делегує виклик.
61
-
62
- ### Standalone-блок (не функція, а top-level код)
63
-
64
- **Сигнатура:**
65
-
66
- ```js
67
- if (isRunAsCli(import.meta.url)) {
68
- process.exit(await runRuleCli(import.meta.dirname))
69
- }
70
- ```
71
-
72
- **Що робить:**
73
-
74
- 1. `isRunAsCli(import.meta.url)` повертає `true`, якщо поточний модуль завантажено як точку входу процесу (а не як імпортовану бібліотеку). Це стандартний для Node/Bun спосіб розпізнати, що файл стартував напряму.
75
- 2. Якщо так — викликає `runRuleCli(import.meta.dirname)`, який реалізує повний CLI-оркестратор саме для цього правила: завантаження конфігу, обчислення whitelist, виконання правила, друк підсумків. Він повертає `Promise<number>` — exit-code.
76
- 3. `await` чекає виконання promise. Це — top-level `await`, що дозволено в ES-модулях.
77
- 4. `process.exit(<code>)` передає отриманий exit-code операційній системі / CI / IDE. ESLint-правила `n/no-process-exit` і `unicorn/no-process-exit` тут свідомо вимкнено коментарем, оскільки standalone entry-point правомірно завершує процес явним кодом.
78
-
79
- **Параметри / повертає:** немає (це side-effect блок верхнього рівня модуля).
80
-
81
- **Side effects:**
82
-
83
- - Якщо файл імпортовано як бібліотеку — гілка не виконується, бо `isRunAsCli` поверне `false`.
84
- - Якщо файл запущено напряму — повний CLI-оркестратор виконує власні I/O (читання конфігу, обхід проєкту, друк звіту) і потім завершує процес через `process.exit`.
85
-
86
- ## Залежності
87
-
88
- ### Внутрішні модулі проєкту
89
-
90
- - `../../scripts/lib/run-rule-cli.mjs` — постачає:
91
- - `isRunAsCli(metaUrl)` — детектор, чи модуль є entry-point процесу (за `import.meta.url`).
92
- - `runRuleCli(ruleDirname)` — standalone CLI-оркестратор для одного правила: конфіг + whitelist + summary + exit-code. Аналогічний за поведінкою до `npx @nitra/cursor fix <id>`.
93
- - `../../scripts/lib/run-standard-rule.mjs` — постачає:
94
- - `runStandardRule(ruleDirname, ctx?)` — стандартний пайплайн правила: applies → JS-concerns → policy → mdc-refs.
95
- - Тип `RuleContext` (через JSDoc-`import('...')`), який описує спільний контекст прогону (зокрема `walkCache`).
96
-
97
- Шляхи відносні: `../../scripts/lib/...` з директорії `npm/rules/image-compress/` веде до `npm/scripts/lib/...`.
98
-
99
- ### Платформенні API
100
-
101
- - `import.meta.dirname` — стандартна властивість ES-модулів у сучасних рантаймах (Node.js та Bun), містить абсолютну директорію поточного модуля.
102
- - `import.meta.url` — стандартна властивість ES-модулів; URL-форма шляху поточного модуля; використовується для розпізнавання запуску як CLI.
103
- - `process.exit(code)` — глобальний Node/Bun API завершення процесу з кодом виходу.
104
- - Top-level `await` — підтримується в ESM.
105
-
106
- ### Зовнішні npm-пакети
107
-
108
- Прямих імпортів зовнішніх npm-пакетів у файлі немає. Уся залежність на зовнішнє API проходить транзитивно через `run-rule-cli.mjs` та `run-standard-rule.mjs`.
109
-
110
- ### ESLint-директиви
111
-
112
- У файлі присутній один inline-disable: `n/no-process-exit, unicorn/no-process-exit` навколо `process.exit(...)`. Він локалізований лише до одного рядка і обґрунтований у коментарі: standalone entry-point має повертати exit-code для CI/IDE.
113
-
114
- ## Потік виконання / Використання
115
-
116
- ### Сценарій A: library-режим (через CLI `@nitra/cursor`)
117
-
118
- 1. CLI `@nitra/cursor` (наприклад, `npx @nitra/cursor fix` без аргументу-id) збирає список правил, серед яких є `image-compress`.
119
- 2. Оркестратор робить `import` модуля `npm/rules/image-compress/fix.mjs` і отримує іменований експорт `run`.
120
- 3. Викликає `await run(ctx)`, передаючи спільний `RuleContext` (з `walkCache` тощо).
121
- 4. `run` делегує виконання в `runStandardRule(import.meta.dirname, ctx)`, який виконує стандартний пайплайн правила (applies → JS-concerns → policy → mdc-refs) для теки `npm/rules/image-compress/`.
122
- 5. `run` повертає `Promise<number>`; оркестратор агрегує exit-коди всіх правил у загальний підсумок.
123
-
124
- У цьому сценарії гілка `if (isRunAsCli(...))` НЕ виконується — `process.exit` не викликається, оскільки модуль завантажено як бібліотеку, а не як entry-point процесу.
125
-
126
- ### Сценарій B: standalone-режим (`bun rules/image-compress/fix.mjs`)
127
-
128
- 1. Користувач/CI запускає файл напряму: `bun rules/image-compress/fix.mjs` (або еквівалентна команда рантайму).
129
- 2. Виконується top-level код модуля, у тому числі гілка `if (isRunAsCli(import.meta.url))`.
130
- 3. Оскільки модуль — entry-point процесу, `isRunAsCli` повертає `true`.
131
- 4. Викликається `await runRuleCli(import.meta.dirname)`, який повністю відтворює оркестрацію `@nitra/cursor fix <id>` для саме цього правила: завантажує конфіг, обчислює whitelist, прогонить правило, друкує summary, повертає exit-code.
132
- 5. `process.exit(<code>)` завершує процес із цим кодом — придатним для CI-пайплайнів та IDE-інтеграцій.
10
+ ## Огляд
133
11
 
134
- Експорт `run` у цьому сценарії існує, але не викликається з самого файлу — він залишається доступним для зовнішніх імпортів.
12
+ Файл виконує запуск правила. Він приймає контекст прогону і повертає отриманий результат.
135
13
 
136
- ### Як файл вписаний у репозиторій
14
+ ## Поведінка
137
15
 
138
- - Тека `npm/rules/image-compress/` — це “контейнер” правила: разом із `fix.mjs` тут (за конвенцією родини стандартних правил) лежать `check-*.mjs` детектори, `.mdc`-опис та інші артефакти, які `runStandardRule` зчитує за відомими шаблонами імен.
139
- - Усі стандартні правила пакета `@nitra/cursor` мають однаковий каркас `fix.mjs` із цим самим патерном (експорт `run` + standalone-блок). Тобто цей файл — фактично шаблонний адаптер між конкретним правилом і спільною бібліотекою прогону.
16
+ 1. Запуск правила.
17
+ * Приймає контекст прогону.
18
+ * Повертає результат прогону.
140
19
 
141
- ### Rebuild Test (відтворюваність документації)
20
+ ## Публічний API
142
21
 
143
- За цією документацією без перегляду початкового коду можна відновити поведінку файлу:
22
+ run запускає правило: applies JS-concerns policy mdc-refs (через runStandardRule).
23
+ Library mode — викликається CLI orchestration через `import + run`.
144
24
 
145
- - Експортує лише функцію `run(ctx?)` з делегуванням у `runStandardRule(import.meta.dirname, ctx)` і поверненням `Promise<number>` (`0|1`).
146
- - Standalone-гілка: `if (isRunAsCli(import.meta.url)) process.exit(await runRuleCli(import.meta.dirname))` — з inline-disable для `n/no-process-exit, unicorn/no-process-exit`.
147
- - Імпортує `isRunAsCli` та `runRuleCli` зі `../../scripts/lib/run-rule-cli.mjs`, і `runStandardRule` зі `../../scripts/lib/run-standard-rule.mjs`.
148
- - Жодних інших експортів, констант чи побічних дій верхнього рівня.
25
+ ## Гарантії поведінки
149
26
 
150
- Цього достатньо, щоб точно відтворити структуру та контракт оригінального файлу.
27
+ - Read-only: файл не виконує операцій запису у файлову систему.
28
+ - Кешує результати в межах одного прогону.
29
+ - Не звертається до мережі.
@@ -1,191 +1,31 @@
1
- # `package_setup.mjs` — перевірка вимог правила `image-compress.mdc`
1
+ ---
2
+ docgen:
3
+ source: npm/rules/image-compress/js/package_setup.mjs
4
+ crc: 13f6d8f3
5
+ score: 95
6
+ ---
2
7
 
3
- ## Огляд
4
-
5
- Модуль `package_setup.mjs` реалізує `check`-функцію для правила `image-compress.mdc`. Правило вимагає, щоб у проєкті була налаштована оптимізація raster/SVG-зображень через CLI `@nitra/minify-image` ≥ 3.2.0 (запускається локально через `npx`).
6
-
7
- У цьому файлі лишилися лише **FS / cross-file**-перевірки, які важко або незручно виразити декларативно у Rego:
8
-
9
- - наявність `package.json` у корені репозиторію;
10
- - `.n-minify-image.tsv` (committed source of truth split-cache 3.2.0 з полями sha1 / originalSize / size) **не** перебуває у `.gitignore` — файл має жити в git;
11
- - застарілий `.minify-image-cache.tsv` (4-колонковий кеш з `@nitra/minify-image` < 3.2) видалений як з диска, так і з `.gitignore`.
12
-
13
- Структурні вимоги до `package.json` (наявність `scripts.lint-image` з правильним викликом `npx @nitra/minify-image --src=. --write` без `--avif`, включення `bun run lint-image` в агрегований `lint`, відсутність `@nitra/minify-image` у `dependencies`/`devDependencies`) перевіряються Rego-політикою у `npm/rules/image-compress/policy/package_json/` і автофіксяться через `npx @nitra/cursor fix`.
14
-
15
- CI-workflow для image-лінту правилом **не** вимагається — оптимізація відбувається лише локально перед комітом.
16
-
17
- ## Експорти / API
18
-
19
- | Експорт | Тип | Призначення |
20
- | ------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
21
- | `check(cwd?)` | `async function` | Публічна точка входу. Виконує перевірки правила `image-compress.mdc` для вказаного робочого каталогу й повертає exit-код (`0` — OK, `1` — є помилки). |
22
-
23
- Модуль використовує ES Modules (`.mjs`), іменований експорт `check`. Default-експорту немає.
24
-
25
- ## Функції
26
-
27
- ### `readGitignoreLines(cwd)`
28
-
29
- Приватна допоміжна функція для читання змістовних рядків `.gitignore`.
30
-
31
- - **Сигнатура:** `async function readGitignoreLines(cwd: string): Promise<string[] | null>`
32
- - **Параметри:**
33
- - `cwd` — абсолютний шлях до кореня репозиторію, де очікується `.gitignore`.
34
- - **Повертає:**
35
- - `null`, якщо файл `.gitignore` відсутній;
36
- - масив рядків (`string[]`), кожен з яких уже `trim`-нутий, не порожній і не починається з `#`.
37
- - **Side effects:** один синхронний `existsSync` і один асинхронний `readFile` (UTF-8) у файловій системі. Не пише нічого.
38
- - **Поведінкові деталі:** коментарі визначаються лише за префіксом `#` на початку trim-нутого рядка; in-line коментарі (після `#` всередині рядка) не вирізаються.
39
-
40
- ### `checkHashCacheNotIgnored(pass, fail, cwd)`
41
-
42
- Перевіряє, що файл `.n-minify-image.tsv` **не** перерахований у `.gitignore`. Файл є закомічуваним source of truth для split-cache 3.2.0 (зберігає sha1 + originalSize + size для slow-path і метрики lifetime savings), тому має потрапляти в git.
43
-
44
- - **Сигнатура:** `async function checkHashCacheNotIgnored(pass: (msg: string) => void, fail: (msg: string) => void, cwd: string): Promise<void>`
45
- - **Параметри:**
46
- - `pass` — callback, що викликається при успіху з людиночитаним повідомленням;
47
- - `fail` — callback, що викликається при провалі з повідомленням і вказівкою на дію;
48
- - `cwd` — корінь репозиторію.
49
- - **Повертає:** `Promise<void>`. Реєстрація результату здійснюється через `pass`/`fail` (зовнішній reporter).
50
- - **Side effects:** одне читання `.gitignore` через `readGitignoreLines`.
51
- - **Логіка:**
52
- - якщо `.gitignore` є й містить точний рядок `.n-minify-image.tsv` → `fail` з вимогою прибрати рядок;
53
- - інакше (файл відсутній або рядка немає) → `pass`.
54
- - **Важливо:** сам факт існування `.n-minify-image.tsv` не вимагається. На новому проєкті без обробки зображень файла ще немає — і це нормально.
55
-
56
- ### `checkLegacyCacheRemoved(pass, fail, cwd)`
57
-
58
- Перевіряє, що застарілий 4-колонковий кеш `.minify-image-cache.tsv` (з `@nitra/minify-image` < 3.2) повністю видалений з проєкту.
59
-
60
- - **Сигнатура:** `async function checkLegacyCacheRemoved(pass: (msg: string) => void, fail: (msg: string) => void, cwd: string): Promise<void>`
61
- - **Параметри:**
62
- - `pass` — callback для успішного звіту;
63
- - `fail` — callback для помилки;
64
- - `cwd` — корінь репозиторію.
65
- - **Повертає:** `Promise<void>`.
66
- - **Side effects:** один `existsSync` на файл у корені; за умови, що файла нема, додатково читає `.gitignore`.
67
- - **Логіка (виконується послідовно з `early return`):**
68
- 1. Якщо `<cwd>/.minify-image-cache.tsv` **існує на диску** → `fail` з готовим bash-snippet для повного видалення (`git rm --cached … && rm -f …`) і нагадуванням прибрати рядок з `.gitignore`. Подальші перевірки в цій функції пропускаються.
69
- 2. Інакше читає `.gitignore`; якщо там є точний рядок `.minify-image-cache.tsv` → `fail` з вимогою прибрати застарілий ігнор.
70
- 3. Інакше → `pass` («міграція на split-cache завершена»).
71
-
72
- ### `check(cwd?)`
8
+ # package_setup.mjs
73
9
 
74
- Експортована публічна функція — точка входу для агрегатора правил `@nitra/cursor`.
75
-
76
- - **Сигнатура:** `export async function check(cwd: string = process.cwd()): Promise<number>`
77
- - **Параметри:**
78
- - `cwd` — необов’язковий шлях до кореня репозиторію; за замовчуванням `process.cwd()`.
79
- - **Повертає:** exit-код як `number` (`0` — все ок; `1` — є хоча б один `fail`). Значення формує `reporter.getExitCode()` з `createCheckReporter`.
80
- - **Side effects:**
81
- - друк звіту в stdout/stderr через reporter (формат залежить від `createCheckReporter`);
82
- - читання файлів `package.json`, `.gitignore`, `.minify-image-cache.tsv` у `cwd`. Жодного запису на диск.
83
- - **Поведінкові деталі:**
84
- 1. Створює локальний `reporter` через `createCheckReporter()` і дістає з нього `pass`/`fail`.
85
- 2. **Guard:** якщо в корені нема `package.json` — друкує `fail` із підказкою додати файл і **негайно повертає** `reporter.getExitCode()` (≈ `1`). Інші перевірки в цій ітерації не виконуються.
86
- 3. Якщо `package.json` є — `pass` з нагадуванням, що структуру `scripts` перевіряє Rego через `npx @nitra/cursor fix → image_compress.package_json`.
87
- 4. Виконує `checkHashCacheNotIgnored` (await).
88
- 5. Виконує `checkLegacyCacheRemoved` (await).
89
- 6. Повертає `reporter.getExitCode()`.
90
-
91
- ## Залежності
92
-
93
- ### Зовнішні (Node.js core)
94
-
95
- - `node:fs`
96
- - `existsSync` — синхронна перевірка існування `package.json`, `.gitignore`, застарілого кешу;
97
- - `node:fs/promises`
98
- - `readFile` — асинхронне читання `.gitignore` у кодуванні UTF-8;
99
- - `node:path`
100
- - `join` — кросплатформена побудова шляхів від кореня репозиторію.
101
-
102
- ### Внутрішні
103
-
104
- - `../../../scripts/lib/check-reporter.mjs`
105
- - `createCheckReporter()` — створює об’єкт із методами `pass(msg)`, `fail(msg)` і `getExitCode()`. Інкапсулює формат друку результатів і агрегацію статусу.
106
-
107
- ### Файли проєкту, з якими взаємодіє
108
-
109
- - `<cwd>/package.json` — лише перевірка існування;
110
- - `<cwd>/.gitignore` — читання й пошук рядків `.n-minify-image.tsv`, `.minify-image-cache.tsv`;
111
- - `<cwd>/.minify-image-cache.tsv` — лише перевірка існування (legacy-файл, який має бути відсутній);
112
- - `<cwd>/.n-minify-image.tsv` — **не** перевіряється напряму на диску, лише на присутність у `.gitignore`.
113
-
114
- ### Зовнішня політика
115
-
116
- - `npm/rules/image-compress/policy/package_json/` — Rego-правила, які перевіряють і автофіксять структуру `package.json` (script `lint-image`, агрегований `lint`, відсутність залежності `@nitra/minify-image`).
117
-
118
- ## Потік виконання / Використання
119
-
120
- ### Як викликається
121
-
122
- `check(cwd)` запускається оркестратором `@nitra/cursor` як одна з перевірок правила `image-compress.mdc`. У типовому сценарії команда `npx @nitra/cursor check` або `npx @nitra/cursor fix` обходить активні правила, для кожного імпортує його `check` і збирає звіт.
123
-
124
- Можливий також прямий ESM-імпорт:
125
-
126
- ```js
127
- import { check } from '@nitra/cursor/npm/rules/image-compress/js/package_setup.mjs'
128
-
129
- const exitCode = await check(process.cwd())
130
- process.exit(exitCode)
131
- ```
132
-
133
- ### Послідовність кроків усередині `check`
134
-
135
- 1. Створюється `reporter`, з нього дістаються `pass`/`fail`.
136
- 2. Перевірка наявності `package.json` (guard з early return при відсутності).
137
- 3. `await checkHashCacheNotIgnored(pass, fail, cwd)` — гарантує, що split-cache не виключений із git.
138
- 4. `await checkLegacyCacheRemoved(pass, fail, cwd)` — гарантує, що legacy-кеш не висить ні на диску, ні в `.gitignore`.
139
- 5. Повертається `reporter.getExitCode()`.
10
+ ## Огляд
140
11
 
141
- ### Типові сценарії результату
12
+ Файл виконує перевірку наявності та видалення кешу. Він зчитує рядки з `.gitignore`, перевіряє наявність кешу `HASH_CACHE_FILENAME` та видаляє застарілий кеш `LEGACY_CACHE_FILENAME`. Код перевіряє відповідність правилу, визначеного в (image-compress.mdc).
142
13
 
143
- - **Свіжий проєкт без зображень.** `package.json` є, `.gitignore` не містить ні `.n-minify-image.tsv`, ні `.minify-image-cache.tsv`, файлів на диску немає → три `pass`, exit-код `0`.
144
- - **Проєкт з обробленими зображеннями (3.2+).** На диску є закомічений `.n-minify-image.tsv`, у `.gitignore` його немає, legacy-файла немає → exit-код `0`.
145
- - **Незавершена міграція з 3.1 → 3.2.** На диску ще лежить `.minify-image-cache.tsv` → `fail` з готовим bash-snippet для очищення; exit-код `1`.
146
- - **Помилково додано split-cache в `.gitignore`.** `.gitignore` містить `.n-minify-image.tsv` → `fail` з вимогою прибрати рядок; exit-код `1`.
147
- - **Немає `package.json`.** Перша ж перевірка повертає `fail` і виконання обривається на guard-у; жодних інших перевірок не запускається; exit-код `1`.
14
+ ## Поведінка
148
15
 
149
- ### Розподіл відповідальності з Rego
16
+ 1. Зчитування рядків з `.gitignore`
17
+ 2. Перевірка наявності кешу `HASH_CACHE_FILENAME` у `.gitignore`
18
+ 3. Перевірка видалення застарілого кешу `LEGACY_CACHE_FILENAME`
19
+ 4. Перевірка відповідності правилу `image-compress.mdc`
150
20
 
151
- | Перевірка | Де реалізована |
152
- | ----------------------------------------------------------- | ----------------------------- |
153
- | Наявність `package.json` | `package_setup.mjs` |
154
- | `.n-minify-image.tsv` не в `.gitignore` | `package_setup.mjs` |
155
- | `.minify-image-cache.tsv` відсутній (диск + `.gitignore`) | `package_setup.mjs` |
156
- | `scripts.lint-image` коректний (без `--avif`) | Rego (`policy/package_json/`) |
157
- | `bun run lint-image` в агрегованому `lint` | Rego (`policy/package_json/`) |
158
- | `@nitra/minify-image` не в `dependencies`/`devDependencies` | Rego (`policy/package_json/`) |
21
+ ## Публічний API
159
22
 
160
- ## Rebuild Test
23
+ check Перевіряє, чи відсутній у `.gitignore` файл `.n-minify-image.tsv` та чи видалено `.minify-image-cache.tsv`. Вказує, що CI-workflow для image не потрібен, оскільки лінтування зображень відбувається лише локально. (image-compress.mdc)
161
24
 
162
- Якщо файл `package_setup.mjs` втрачено, відтворіть його за такою специфікацією:
25
+ ## Гарантії поведінки
163
26
 
164
- 1. **Розташування:** `npm/rules/image-compress/js/package_setup.mjs` (ESM, розширення `.mjs`).
165
- 2. **Імпорти:**
166
- - `existsSync` з `node:fs`;
167
- - `readFile` з `node:fs/promises`;
168
- - `join` з `node:path`;
169
- - `createCheckReporter` з `../../../scripts/lib/check-reporter.mjs`.
170
- 3. **Константи модульного рівня:**
171
- - `HASH_CACHE_FILENAME = '.n-minify-image.tsv'`;
172
- - `LEGACY_CACHE_FILENAME = '.minify-image-cache.tsv'`.
173
- 4. **Приватна `readGitignoreLines(cwd)`:** будує шлях `<cwd>/.gitignore`; якщо файла нема — `return null`; інакше читає UTF-8, розбиває по `\n`, `trim` кожного рядка, фільтрує порожні й ті, що починаються з `#`; повертає масив.
174
- 5. **Приватна `checkHashCacheNotIgnored(pass, fail, cwd)`:** читає рядки `.gitignore`; якщо вони є й містять `HASH_CACHE_FILENAME` — `fail` (з підказкою прибрати рядок), інакше `pass` («не в .gitignore — має бути в git»).
175
- 6. **Приватна `checkLegacyCacheRemoved(pass, fail, cwd)`:**
176
- - якщо `<cwd>/<LEGACY_CACHE_FILENAME>` існує на диску — `fail` з готовим bash-snippet (`git rm --cached … 2>/dev/null || true && rm -f …`) і нагадуванням про `.gitignore`, потім `return`;
177
- - інакше читає `.gitignore`; якщо містить `LEGACY_CACHE_FILENAME` — `fail` (прибрати застарілий ігнор), потім `return`;
178
- - інакше `pass` («міграція на split-cache завершена»).
179
- 7. **Експортована `check(cwd = process.cwd())`:**
180
- - `const reporter = createCheckReporter()`; деструктурує `{ pass, fail }`;
181
- - якщо `<cwd>/package.json` не існує — `fail` («додай — image-compress.mdc») і одразу `return reporter.getExitCode()`;
182
- - інакше `pass` («package.json є; структуру перевіряє npx @nitra/cursor fix → image_compress.package_json»);
183
- - `await checkHashCacheNotIgnored(pass, fail, cwd)`;
184
- - `await checkLegacyCacheRemoved(pass, fail, cwd)`;
185
- - `return reporter.getExitCode()`.
186
- 8. **Інваріанти:**
187
- - модуль не пише на диск нічого;
188
- - `pass`/`fail` приймають лише `string` і викликаються рівно один раз на гілку логіки;
189
- - функція `check` завжди повертає `number`, навіть на guard-шляху;
190
- - усі шляхи будуються через `join(cwd, ...)`, ніяких рядкових конкатенацій.
191
- 9. **Текст повідомлень** містить посилання на правило `image-compress.mdc` і термін `split-cache 3.2.0`, щоб користувач у звіті бачив джерело вимоги.
27
+ - Read-only: файл не виконує операцій запису у файлову систему.
28
+ - За невдачі повертає значення помилки (`false`/`null`/`Err`) замість генерування винятку чи паніки.
29
+ - Кешує результати в межах одного прогону.
30
+ - Свідомо пропускає шляхи: `.git`.
31
+ - Не звертається до мережі.