@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,137 +1,35 @@
1
+ ---
2
+ docgen:
3
+ source: npm/rules/npm-module/js/rule_meta.mjs
4
+ crc: 8262678c
5
+ score: 100
6
+ ---
7
+
1
8
  # rule_meta.mjs
2
9
 
3
10
  ## Огляд
4
11
 
5
- Модуль `rule_meta.mjs` реалізує перевірку метаданих правил пакета `@nitra/cursor`. Він є частиною концерну правила `npm-module` й обслуговує валідацію файлів `npm/rules/<id>/meta.json` у репозиторії пакета.
6
-
7
- Логіка перевірки покриває такі інваріанти для кожного підкаталогу `npm/rules/<id>/`:
8
-
9
- - наявність валідного `meta.json`;
10
- - коректність поля `auto`, якщо воно присутнє (розпізнаваність специфікації через `parseRuleAutoSpec`: значення `"завжди"`, масив, `{glob}` або `{predicate}`);
11
- - для специфікації `{predicate}` — наявність відповідного імені у реєстрі `RULE_PREDICATES`;
12
- - коректність поля `lint`, якщо воно присутнє (`"quick"` чи `"ci"`), з обовʼязковою наявністю файлу `js/lint.mjs` у каталозі правила;
13
- - відсутність застарілого `auto.md` поряд із `meta.json` (міграція метаданих у `meta.json` вже завершена).
14
-
15
- Перевірка застосовна виключно у репо самого пакета `@nitra/cursor`, де існує каталог `npm/rules/`. У споживацьких репо такого каталогу немає, тож модуль м’яко рапортує `pass` і завершується кодом виходу `0`.
16
-
17
- Модуль експортує єдину функцію `check`, яка повертає `Promise<number>` із POSIX-кодом виходу: `0` — порушень немає, `1` — є хоча б одне порушення. Звітування реалізоване через інстанс репортера, отриманий від `createCheckReporter`.
18
-
19
- ## Експорти / API
20
-
21
- | Експорт | Тип | Призначення |
22
- | -------------------------------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------- |
23
- | `check(cwd?: string): Promise<number>` | іменований експорт (функція) | Валідує всі `npm/rules/<id>/meta.json` у переданому корені репозиторію та повертає підсумковий код виходу. |
24
-
25
- Інших експортів (default, типи, константи) модуль не має.
26
-
27
- ## Функції
28
-
29
- ### `check(cwd = process.cwd())`
30
-
31
- Валідує всі `meta.json` у `<cwd>/npm/rules/<id>/`.
32
-
33
- - **Сигнатура:** `export function check(cwd?: string): Promise<number>`
34
- - **Параметри:**
35
- - `cwd` — рядок із абсолютним або відносним шляхом до кореня репозиторію. Необовʼязковий. Якщо не вказано, використовується `process.cwd()` (поточний робочий каталог процесу Node).
36
- - **Повертає:** `Promise<number>`, що резолвиться у код виходу від репортера (`reporter.getExitCode()`). Конвенція:
37
- - `0` — усі знайдені правила пройшли валідацію, або каталог `npm/rules/` відсутній (у такому випадку додатково логиться `pass`-повідомлення `"npm/rules/ відсутній — немає правил для валідації"`);
38
- - `1` — зафіксовано принаймні одне порушення (зокрема: залишковий `auto.md`, відсутній/невалідний `meta.json`, нерозпізнаний `auto`, невідомий `predicate`, нерозпізнаний `lint`, або `lint` без `js/lint.mjs`).
39
- - **Side effects:**
40
- - Виконує синхронне читання файлової системи: `existsSync` для перевірки наявності `npm/rules/`, `npm/rules/<id>/auto.md`, `npm/rules/<id>/js/lint.mjs`; `readdirSync` зі списком підкаталогів `npm/rules/`.
41
- - Делегує читання та парсинг `meta.json` у `readRuleMetaRaw` (також синхронне читання файла).
42
- - Викликає методи репортера (`reporter.pass`, `reporter.fail`), які за домовленістю виводять статусні повідомлення (зазвичай у stdout/stderr — залежно від реалізації `createCheckReporter`).
43
- - Не змінює файли на диску, не запускає дочірніх процесів, не звертається до мережі.
44
- - **Алгоритм:**
45
- 1. Створює репортер: `reporter = createCheckReporter()`.
46
- 2. Обчислює `rulesDir = join(cwd, 'npm', 'rules')`.
47
- 3. Якщо `rulesDir` не існує — рапортує `pass` і резолвить `Promise.resolve(reporter.getExitCode())` (зазвичай `0`).
48
- 4. Інакше перебирає вміст `rulesDir` через `readdirSync(rulesDir, { withFileTypes: true })` і для кожного запису:
49
- - пропускає, якщо це не каталог (`!entry.isDirectory()`) або імʼя починається з крапки (`entry.name.startsWith('.')`);
50
- - встановлює локальний прапор `ruleOk = true`;
51
- - якщо знайдено залишковий `auto.md` у каталозі правила — `reporter.fail(...)`, `ruleOk = false`;
52
- - читає сирий обʼєкт метаданих через `readRuleMetaRaw(ruleDir)`. Якщо повернуто falsy — `reporter.fail("rules/<id>: відсутній або невалідний meta.json")` і `continue` (наступне правило);
53
- - якщо `raw.auto !== undefined` — парсить через `parseRuleAutoSpec(raw.auto)`:
54
- - якщо повернуто `null` — `reporter.fail(...)`, `ruleOk = false`;
55
- - інакше якщо в `spec` є ключ `'predicate'` і його значення немає у `RULE_PREDICATES` — `reporter.fail(...)`, `ruleOk = false`;
56
- - якщо `raw.lint !== undefined` — валідує через `parseRuleLintPhase(raw.lint)`:
57
- - якщо повернуто `null` — `reporter.fail(...)`, `ruleOk = false`;
58
- - інакше якщо немає файла `<ruleDir>/js/lint.mjs` — `reporter.fail(...)`, `ruleOk = false`;
59
- - наприкінці ітерації, якщо `ruleOk` усе ще `true` — `reporter.pass("rules/<id>: meta.json валідний")`.
60
- 5. Резолвить `Promise.resolve(reporter.getExitCode())` із підсумковим кодом виходу.
61
- - **Особливості реалізації:**
62
- - Усі гілки порушень для одного правила фіксуються незалежно одна від одної (наприклад, у тому ж проході може бути зафіксовано і нерозпізнаний `auto`, і нерозпізнаний `lint`). Виняток — повністю відсутній/невалідний `meta.json`: тоді решта перевірок для цього правила пропускається через `continue`.
63
- - Функція синхронно виконує всю роботу, але повертає `Promise<number>` через `Promise.resolve(...)` — для уніфікованої сигнатури з іншими `check`-модулями.
64
- - Перевірка `'predicate' in spec` дозволяє валідувати лише гілку `{predicate}`-специфікації; інші форми (`"завжди"`, масив, `{glob}`) уже визнані валідними самим `parseRuleAutoSpec`.
65
-
66
- ## Залежності
67
-
68
- ### Зовнішні (Node.js standard library)
69
-
70
- - `node:fs` — `existsSync` (перевірка існування файлів і каталогів), `readdirSync` (читання вмісту каталогу `npm/rules/`).
71
- - `node:path` — `join` (формування шляхів до каталогів і файлів).
72
-
73
- ### Внутрішні (репо-локальні)
74
-
75
- - `../../../scripts/lib/check-reporter.mjs` — `createCheckReporter()`. Створює репортер з методами `pass(msg)`, `fail(msg)`, `getExitCode()`; останній використовується для отримання підсумкового коду виходу.
76
- - `../../../scripts/lib/rule-meta.mjs`:
77
- - `readRuleMetaRaw(ruleDir)` — читає та парсить сирий `meta.json` із каталогу правила; повертає обʼєкт або falsy (за відсутності/невалідності файла).
78
- - `parseRuleAutoSpec(value)` — парсить значення поля `auto`; повертає валідовану специфікацію або `null` за нерозпізнаним вводом.
79
- - `parseRuleLintPhase(value)` — парсить значення поля `lint`; повертає валідовану фазу (`"quick"`/`"ci"`) або `null`.
80
- - `../../../scripts/lib/rule-predicates.mjs` — `RULE_PREDICATES`: обʼєкт-реєстр відомих імен предикатів; ключі використовуються для перевірки наявності предиката через `Object.hasOwn`.
81
-
82
- ### Глобальні
83
-
84
- - `process.cwd()` — використовується як дефолтний `cwd`.
85
-
86
- ## Потік виконання / Використання
87
-
88
- Модуль є check-функцією конкретного правила і підпорядкований конвенції `check-{id}` (тут — `rule_meta`). Очікуваний сценарій використання:
89
-
90
- 1. Виклик з вищерівневого скрипта (наприклад, агрегованої перевірки правил пакета):
91
-
92
- ```js
93
- import { check } from './npm/rules/npm-module/js/rule_meta.mjs'
94
-
95
- const exit = await check(process.cwd())
96
- process.exit(exit)
97
- ```
98
-
99
- У такому сценарії функцію викликають із кореня репозиторію пакета `@nitra/cursor`.
100
-
101
- 2. Запуск у репо-споживачі (де `npm/rules/` відсутній) — функція тихо рапортує `pass` і повертає `0`, не блокуючи pipeline.
102
- 3. Сценарій порушення: будь-який із описаних інваріантів спричиняє `fail`-звіт і код виходу `1`, що сигналізує CI зупинку.
12
+ Перевіряє наявність директорії npm/rules у вказаному шляху. Ітерує по всіх директоріях у директорії npm/rules. Для кожної директорії виконує перевірку наявності файлу auto.md та валідність полів auto та lint у конфігурації meta.json. Перевіряє наявність файлу js/lint.mjs у каталозі правила. Збирає результати валідації та повертає код виходу репортера.
103
13
 
104
- Типові точки інтеграції:
14
+ ## Поведінка
105
15
 
106
- - CI lint-фаза пакета `@nitra/cursor` (виклик в одному з кореневих скриптів `bun run lint` / спеціалізованої перевірки правил).
107
- - Локальний запуск через CLI з кореня репозиторію.
16
+ 1. Перевірка наявності директорії npm/rules у вказаному шляху.
17
+ 2. Ітерація по всіх директоріях у директорії npm/rules.
18
+ 3. Для кожної директорії виконується перевірка правила.
19
+ 4. Перевірка наявності файлу auto.md у директорії правила.
20
+ 5. Перевірка валідності поля auto у meta.json правила.
21
+ 6. Перевірка наявності поля lint у meta.json правила.
22
+ 7. Перевірка валідності поля lint у meta.json правила.
23
+ 8. Перевірка наявності файлу js/lint.mjs у каталозі правила.
24
+ 9. Збір результатів валідації.
25
+ 10. Повернення коду виходу репортера.
108
26
 
109
- Файл не має побічних ефектів під час імпорту: експортована функція не виконується самовільно — її викликає консьюмер.
27
+ ## Публічний API
110
28
 
111
- ## Rebuild Test
29
+ check Валідує всі `npm/rules/<id>/meta.json`.
112
30
 
113
- Контрольні питання, чиї відповіді достатні, щоб реконструювати модуль без перегляду коду:
31
+ ## Гарантії поведінки
114
32
 
115
- 1. Який каталог сканує функція `check`?
116
- - `<cwd>/npm/rules/`, де `cwd` необовʼязковий параметр (дефолт `process.cwd()`).
117
- 2. Як обробляється відсутність цього каталогу?
118
- - Рапортується `pass("npm/rules/ відсутній — немає правил для валідації")`, повертається `0`.
119
- 3. Які записи в `npm/rules/` пропускаються?
120
- - Не-каталоги та елементи, чиє імʼя починається з `.`.
121
- 4. За наявності якого файла поряд із `meta.json` фіксується порушення?
122
- - `auto.md` (повідомлення `"rules/<id>: залишковий auto.md — видали (метадані тепер у meta.json)"`).
123
- 5. Що відбувається, якщо `meta.json` відсутній або невалідний?
124
- - `reporter.fail("rules/<id>: відсутній або невалідний meta.json")` і `continue` до наступного правила.
125
- 6. Які гілки валідації поля `auto`?
126
- - Якщо `parseRuleAutoSpec` повертає `null` — fail (нерозпізнане).
127
- - Якщо специфікація містить ключ `predicate`, але його значення відсутнє в `RULE_PREDICATES` — fail (`невідомий predicate`).
128
- 7. Які гілки валідації поля `lint`?
129
- - Якщо `parseRuleLintPhase` повертає `null` — fail (`нерозпізнане, очікується "quick"|"ci"`).
130
- - Якщо валідне, але немає `js/lint.mjs` — fail (`lint:"..." але немає js/lint.mjs`).
131
- 8. Як формується підсумковий код виходу?
132
- - Через `reporter.getExitCode()`, обгорнутий у `Promise.resolve(...)`.
133
- 9. Чи синхронна реалізація?
134
- - Так: усі IO операції — синхронні (`existsSync`, `readdirSync`, `readRuleMetaRaw`); проміс використано лише для уніфікації сигнатури.
135
- 10. Які `pass`-повідомлення можливі?
136
- - `"npm/rules/ відсутній — немає правил для валідації"` (за відсутності каталогу).
137
- - `"rules/<id>: meta.json валідний"` (за успішної валідації окремого правила).
33
+ - Read-only: файл не виконує операцій запису у файлову систему.
34
+ - За невдачі повертає значення помилки (`false`/`null`/`Err`) замість генерування винятку чи паніки.
35
+ - Не звертається до мережі.
@@ -1,190 +1,28 @@
1
+ ---
2
+ docgen:
3
+ source: npm/rules/npm-module/js/skill_meta.mjs
4
+ crc: a069397b
5
+ score: 100
6
+ ---
7
+
1
8
  # skill_meta.mjs
2
9
 
3
10
  ## Огляд
4
11
 
5
- Модуль `skill_meta.mjs` перевірка валідності метаданих скілів (`meta.json`) пакета `@nitra/cursor`. Належить до концерну правила `npm-module` (тека `npm/rules/npm-module/js/`).
6
-
7
- Перевірка застосовується **виключно в репозиторії пакета**, де є каталог `npm/skills/`. Якщо каталог відсутній (наприклад, у проєктах-споживачах залежності), перевірка пропускається без помилки (повертає `pass`).
8
-
9
- Для кожного підкаталогу `npm/skills/<id>/` модуль виконує контракт:
10
-
11
- - забороняється залишковий файл `auto.md` (метадані мігровані на `meta.json`);
12
- - файл `meta.json` має бути присутнім і валідним JSON-об'єктом з очікуваною структурою;
13
- - поле `worktree` обов'язкове і має бути `boolean`;
14
- - поле `auto` опціональне, але якщо є — має бути або рядком `"завжди"`, або непорожнім масивом рядків.
15
-
16
- Результат акумулюється через `check-reporter` і повертається кодом виходу `0` (OK) або `1` (порушення).
17
-
18
- ## Експорти / API
19
-
20
- | Експорт | Тип | Призначення |
21
- | ------- | ---------- | -------------------------------------------------------------------------- |
22
- | `check` | `function` | Іменований експорт; функція-перевірка метаданих скілів у вказаному корені. |
23
-
24
- Модуль є ESM (`.mjs`), без `default` експорту.
25
-
26
- ## Функції
27
-
28
- ### `check(cwd?)`
29
-
30
- **Сигнатура:**
31
-
32
- ```js
33
- export function check(cwd = process.cwd()): Promise<number>
34
- ```
35
-
36
- **Параметри:**
37
-
38
- | Параметр | Тип | Обов'язковий | За замовчуванням | Опис |
39
- | -------- | -------- | ------------ | ---------------- | ---------------------------------------------------------------- |
40
- | `cwd` | `string` | ні | `process.cwd()` | Корінь репозиторію; від нього резолвиться шлях до `npm/skills/`. |
41
-
42
- **Повертає:**
43
-
44
- `Promise<number>` — код виходу від `reporter.getExitCode()`:
45
-
46
- - `0` — усі перевірені скіли валідні (або каталог `npm/skills/` відсутній);
47
- - `1` — щонайменше одне порушення зафіксовано через `reporter.fail(...)`.
48
-
49
- Хоча всередині немає `async`/`await`, функція обертає результат у `Promise.resolve(...)` для однорідного API з іншими `check`-функціями в цьому проєкті.
50
-
51
- **Алгоритм:**
52
-
53
- 1. Створюється локальний звітник: `reporter = createCheckReporter()`.
54
- 2. Будується шлях `skillsDir = join(cwd, 'npm', 'skills')`.
55
- 3. Якщо `skillsDir` не існує (`existsSync(...) === false`):
56
- - викликається `reporter.pass('npm/skills/ відсутній — немає скілів для валідації')`;
57
- - повертається `Promise.resolve(reporter.getExitCode())` (рання гілка).
58
- 4. Інакше — ітерація `readdirSync(skillsDir, { withFileTypes: true })`:
59
- - пропускаються не-директорії та назви, що починаються з крапки (`.` префікс);
60
- - для кожного скіла `id = entry.name` будується `skillDir = join(skillsDir, id)` і прапор `skillOk = true`.
61
- 5. Для кожного скіла послідовно перевіряється:
62
- - **Залишковий `auto.md`**: якщо `existsSync(join(skillDir, 'auto.md'))`, фіксується
63
- `fail("skills/<id>: залишковий auto.md — видали (метадані тепер у meta.json)")` і `skillOk = false`.
64
- - **`meta.json` присутній/валідний**: викликається `raw = readSkillMetaRaw(skillDir)`.
65
- Якщо `raw` falsy — фіксується `fail("skills/<id>: відсутній або невалідний meta.json ...")` і виконується `continue` (решта перевірок для цього скіла пропускається).
66
- - **Тип `worktree`**: якщо `typeof raw.worktree !== 'boolean'` — `fail("skills/<id>: meta.json.worktree має бути boolean")` і `skillOk = false`.
67
- - **Розпізнаваність `auto`**: якщо `raw.auto !== undefined` і `parseSkillAutoSpec(raw.auto) === null` — `fail("skills/<id>: meta.json.auto нерозпізнане — очікується \"завжди\" або непорожній масив правил")` і `skillOk = false`.
68
- 6. Якщо після всіх перевірок цього скіла `skillOk === true`, фіксується `pass("skills/<id>: meta.json валідний")`.
69
- 7. Після проходу всіх скілів повертається `Promise.resolve(reporter.getExitCode())`.
70
-
71
- **Side effects:**
72
-
73
- - читання файлової системи (`existsSync`, `readdirSync`) — синхронне;
74
- - мутація стану внутрішнього звітника (`createCheckReporter()`) через `pass(...)` / `fail(...)`;
75
- - запис у `stdout`/`stderr` залежить від реалізації `check-reporter` (зазвичай агрегує повідомлення для подальшого виводу викликачем);
76
- - **не змінює** жодних файлів і **не** створює директорій.
77
-
78
- **Поведінкові інваріанти:**
79
-
80
- - Відсутність `npm/skills/` — не помилка, а явний `pass` (модуль працює і в репо-споживачі).
81
- - Невалідний `meta.json` зупиняє подальші перевірки конкретного скіла (`continue`), але **не зупиняє** обхід інших скілів.
82
- - Прихований запис (назва починається з `.`) ігнорується, тож `.DS_Store` чи `.tmp` не плутають перевірку.
83
- - Перевірка детермінована: результат залежить тільки від вмісту `npm/skills/` у `cwd`.
84
-
85
- ## Залежності
86
-
87
- ### Стандартна бібліотека Node.js
88
-
89
- | Модуль | Імпортовані символи | Використання |
90
- | ----------- | --------------------------- | -------------------------------------------------------------------- |
91
- | `node:fs` | `existsSync`, `readdirSync` | перевірка наявності `npm/skills/`, `auto.md`; читання списку скілів. |
92
- | `node:path` | `join` | побудова крос-платформних шляхів до каталогів і файлів. |
93
-
94
- ### Внутрішні модулі проєкту
95
-
96
- | Модуль | Імпортовані символи | Використання |
97
- | ----------------------------------------- | ---------------------------------------- | --------------------------------------------------------------------------- |
98
- | `../../../scripts/lib/check-reporter.mjs` | `createCheckReporter` | створення звітника з API `pass(msg)` / `fail(msg)` / `getExitCode()`. |
99
- | `../../../scripts/lib/skill-meta.mjs` | `readSkillMetaRaw`, `parseSkillAutoSpec` | читання сирого `meta.json` зі скіла; парсинг/валідація специфікації `auto`. |
100
-
101
- ### Контракти зовнішніх модулів (як використовуються в коді)
102
-
103
- - `createCheckReporter()` → об'єкт із методами `pass(message: string)`, `fail(message: string)`, `getExitCode(): number` (`0` якщо не було `fail`, `1` якщо хоч раз був).
104
- - `readSkillMetaRaw(skillDir: string)` → розпарсений об'єкт `meta.json` або falsy (наприклад, `null`) якщо файл відсутній/невалідний.
105
- - `parseSkillAutoSpec(value)` → нормалізована специфікація `auto` або `null`, якщо значення нерозпізнане. Прийнятні форми: рядок `"завжди"` або непорожній масив рядків.
106
-
107
- ## Потік виконання / Використання
108
-
109
- ### Контекст
110
-
111
- Модуль викликається з раннера правил концерну `npm-module` (точка входу `npm/rules/npm-module/js/index.mjs` або аналог). У типовому пайплайні `bun run lint` / `n-cursor check` всі `check`-функції правил зібрані в реєстр і виконуються послідовно; результат об'єднується в загальний код виходу процесу.
112
-
113
- ### Типовий виклик
114
-
115
- ```js
116
- import { check } from './skill_meta.mjs'
117
-
118
- const exitCode = await check() // використає process.cwd()
119
- process.exit(exitCode)
120
- ```
121
-
122
- Або з явним коренем (тести/інтеграція):
123
-
124
- ```js
125
- const exitCode = await check('/abs/path/to/repo-root')
126
- ```
127
-
128
- ### Сценарій 1: репо самого пакета `@nitra/cursor`
129
-
130
- - `npm/skills/` існує, містить кілька скілів (наприклад, `n-docgen/`, `n-fix/`, `mdc-check/`).
131
- - Для кожного скіла читається `meta.json`, перевіряються `worktree` (boolean) і `auto` (опціонально).
132
- - Якщо хоч один скіл має `auto.md`, або відсутній/невалідний `meta.json`, або `worktree` не boolean, або `auto` нерозпізнане — функція повертає `1`.
133
- - Інакше — `0`.
134
-
135
- ### Сценарій 2: проєкт-споживач `@nitra/cursor`
136
-
137
- - `npm/skills/` відсутній (інша файлова структура).
138
- - Функція фіксує `pass(...)`, повертає `0` і не виконує жодної ітерації.
139
- - Це дозволяє правилам пакета транзитивно застосовуватися в чужих проєктах без false-negative.
140
-
141
- ### Сценарій 3: переходова міграція на `meta.json`
142
-
143
- - У скілі лишилася стара пам'ятка-метадані `auto.md` поряд з новим `meta.json`.
144
- - Перевірка явно фейлить такий скіл повідомленням `залишковий auto.md — видали (метадані тепер у meta.json)`.
145
- - Це примушує закрити технічний борг міграції.
146
-
147
- ### Очікуваний формат `meta.json`
148
-
149
- ```json
150
- {
151
- "worktree": true,
152
- "auto": "завжди"
153
- }
154
- ```
155
-
156
- або
157
-
158
- ```json
159
- {
160
- "worktree": false,
161
- "auto": ["n-bun", "n-flow"]
162
- }
163
- ```
164
-
165
- або (мінімально):
12
+ Перевірка стану конфігурації. Файл перевіряє відповідність між полями worktree та requireRoot. Перевірка спирається на конфіги meta.json.
166
13
 
167
- ```json
168
- {
169
- "worktree": false
170
- }
171
- ```
14
+ ## Поведінка
172
15
 
173
- ### Невалідні приклади (будуть зафейлені)
16
+ 1. Перевірка поля worktree
17
+ 2. Перевірка поля auto
18
+ 3. Перевірка поля requireRoot
19
+ 4. Перевірка суперечності between worktree та requireRoot
174
20
 
175
- - відсутній файл `meta.json` → `відсутній або невалідний meta.json`;
176
- - `{"worktree": "yes"}` → `meta.json.worktree має бути boolean`;
177
- - `{"worktree": true, "auto": []}` або `{"worktree": true, "auto": "always"}` → `meta.json.auto нерозпізнане ...`;
178
- - наявний `auto.md` поряд → `залишковий auto.md — видали`.
21
+ ## Публічний API
179
22
 
180
- ### Rebuild Test
23
+ check Валідує всі `npm/skills/<id>/meta.json`.
181
24
 
182
- Перевірка інваріантів модуля (можна виконати вручну для регресії):
25
+ ## Гарантії поведінки
183
26
 
184
- 1. У тимчасовому корені створити порожню директорію без `npm/skills/` → `check(tmp)` має повернути `0` і зафіксувати `pass` про відсутність каталогу.
185
- 2. Створити `npm/skills/foo/meta.json` з валідним вмістом `{"worktree": true}` → `check(tmp)` має повернути `0`.
186
- 3. Замінити `worktree` на рядок (`"true"`) → `check(tmp)` має повернути `1` з повідомленням про boolean.
187
- 4. Додати `npm/skills/foo/auto.md` → `check(tmp)` має повернути `1` з повідомленням про залишковий `auto.md`.
188
- 5. Видалити `meta.json` → `check(tmp)` має повернути `1` з повідомленням про відсутній/невалідний `meta.json`.
189
- 6. Створити `npm/skills/.hidden/` — перевірка має ігнорувати її (повернути `0`, якщо інших скілів немає).
190
- 7. Додати `npm/skills/bar/meta.json` з `{"worktree": false, "auto": "завжди"}` → `pass`; замінити `auto` на `"always"` → `fail` про нерозпізнане `auto`.
27
+ - Read-only: файл не виконує операцій запису у файлову систему.
28
+ - Не звертається до мережі.
@@ -3,7 +3,7 @@ import { existsSync, readdirSync } from 'node:fs'
3
3
  import { join } from 'node:path'
4
4
 
5
5
  import { createCheckReporter } from '../../../scripts/lib/check-reporter.mjs'
6
- import { parseRuleAutoSpec, parseRuleLintPhase, readRuleMetaRaw } from '../../../scripts/lib/rule-meta.mjs'
6
+ import { parseRuleAutoSpec, parseRuleLintSpec, readRuleMetaRaw } from '../../../scripts/lib/rule-meta.mjs'
7
7
  import { RULE_PREDICATES } from '../../../scripts/lib/rule-predicates.mjs'
8
8
 
9
9
  /**
@@ -37,8 +37,8 @@ function checkAutoField(id, raw, reporter) {
37
37
  */
38
38
  function checkLintField(id, ruleDir, raw, reporter) {
39
39
  if (raw.lint === undefined) return true
40
- if (parseRuleLintPhase(raw.lint) === null) {
41
- reporter.fail(`rules/${id}: meta.json.lint нерозпізнане (очікується "quick"|"ci")`)
40
+ if (parseRuleLintSpec(raw.lint) === null) {
41
+ reporter.fail(`rules/${id}: meta.json.lint нерозпізнане (очікується "per-file"|"full")`)
42
42
  return false
43
43
  }
44
44
  if (!existsSync(join(ruleDir, 'js', 'lint.mjs'))) {
@@ -1,114 +1,37 @@
1
1
  ---
2
2
  docgen:
3
3
  source: npm/rules/php/fix.mjs
4
- crc: 12fc1644
4
+ crc: 38cf876b
5
+ score: 100
5
6
  ---
6
7
 
7
- # fix.mjs — правило `php`
8
+ # fix.mjs
8
9
 
9
10
  ## Огляд
10
11
 
11
- Файл `npm/rules/php/fix.mjs` це точка входу правила `php` у системі `@nitra/cursor`. Він виконує дві ролі одночасно:
12
+ Виконує застосування політики JS-занепокоєних до mdc-refs на вхідному контексті прогону та повертає результат.
12
13
 
13
- 1. **Library mode** експортує функцію `run(ctx)`, яку викликає CLI-оркестратор (`cursor.mjs`) під час масового прогону правил. У цьому режимі правило інтегрується у спільний pipeline і використовує загальний `walkCache` та інший контекст оркестратора.
14
- 2. **Standalone mode** — коли файл запускається напряму через `bun rules/php/fix.mjs`, він діє як самостійний CLI-скрипт, що є повним еквівалентом команди `npx @nitra/cursor fix php` (з підтягуванням конфігурації, whitelist і фінальним summary).
14
+ Виконується при запуску через командний рядок, виконуючи повний еквівалент команди `npx @nitra/cursor fix <id>` та повертає код виходу.
15
15
 
16
- Логіка правила (applies → JS-concerns → policy → mdc-refs) інкапсульована у спільному оркестраторі `runStandardRule`, тож сам файл `fix.mjs` залишається мінімальним «glue»-шаром і не містить специфічної для PHP логіки безпосередньо — конкретні чекери лежать поряд у директорії правила (`checks/`, `applies.mjs`, `policy.mjs` тощо), а їх виявлення робить `runStandardRule` за конвенцією шляху `import.meta.dirname`.
16
+ ## Поведінка
17
17
 
18
- ## Експорти / API
18
+ 1. Запуск правила.
19
+ * Приймає контекст прогону.
20
+ * Виконує застосування JS-занепокоєних до політики до mdc-refs.
21
+ * Повертає результат прогону.
19
22
 
20
- | Експорт | Тип | Призначення |
21
- | ------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
22
- | `run` | `function(ctx?: RuleContext): Promise<number>` | Іменований експорт — основний entry-point library-режиму. Запускає стандартний pipeline правила в каталозі поточного модуля. Повертає exit-code (0 — OK, 1 — порушення). |
23
+ 2. Запуск у режимі CLI.
24
+ * Виконується при запуску через CLI.
25
+ * Виконує повний еквівалент команди `npx @nitra/cursor fix <id>`.
26
+ * Повертає код виходу.
23
27
 
24
- Файл **не** має `default`-експорту. Side-effect на верхньому рівні модуля: блок `if (isRunAsCli(...))` із викликом `process.exit(...)` — спрацьовує лише при прямому запуску.
28
+ ## Публічний API
25
29
 
26
- ## Функції
30
+ run — запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
31
+ Library mode — викликається CLI orchestration через `import + run`.
27
32
 
28
- ### `run(ctx)`
33
+ ## Гарантії поведінки
29
34
 
30
- ```js
31
- export function run(ctx)
32
- ```
33
-
34
- - **Параметри:**
35
- - `ctx` _(опціональний)_ — об'єкт типу `RuleContext`, імпортований з `../../scripts/lib/run-standard-rule.mjs`. Передається оркестратором і містить кеш обходу файлової системи (`walkCache`) та інші розшаровані між правилами дані. Якщо не передано — `runStandardRule` створює власний локальний контекст.
36
- - **Повертає:** `Promise<number>` — exit-code прогону:
37
- - `0` — правило пройшло без порушень;
38
- - `1` — виявлено порушення (або правило завершилось помилкою, яку оркестратор мапить на ненульовий код).
39
- - **Side effects:**
40
- - Делегує всю реальну роботу `runStandardRule`: читання файлів, виконання чекерів, друк summary до `stdout`/`stderr`.
41
- - Сам `run` не має власних побічних ефектів — це тонкий wrapper.
42
- - **Як визначається корінь правила:** через `import.meta.dirname` — абсолютний шлях до директорії, в якій лежить `fix.mjs`. Це дозволяє `runStandardRule` знайти сусідні файли правила (`applies.mjs`, `policy.mjs`, `checks/*.mjs`, `*.mdc` тощо) без додаткових параметрів.
43
-
44
- ## Залежності
45
-
46
- Файл імпортує дві утиліти з внутрішньої бібліотеки `npm/scripts/lib/`:
47
-
48
- | Імпорт | Звідки | Призначення |
49
- | ----------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
50
- | `isRunAsCli` | `../../scripts/lib/run-rule-cli.mjs` | Детектор «чи модуль запущений напряму як CLI». Порівнює `import.meta.url` із `process.argv[1]`. Використовується для гілки standalone. |
51
- | `runRuleCli` | `../../scripts/lib/run-rule-cli.mjs` | Повноцінний CLI-runner правила: парсить аргументи, підтягує config, застосовує whitelist, друкує summary. Повертає `Promise<number>` із exit-кодом. |
52
- | `runStandardRule` | `../../scripts/lib/run-standard-rule.mjs` | Стандартний pipeline правила: послідовно виконує стадії `applies → JS-concerns → policy → mdc-refs`. Приймає шлях до директорії правила та опційний `RuleContext`. |
53
-
54
- Зовнішніх npm-залежностей файл не має — лише внутрішні модулі монорепо.
55
-
56
- ## Потік виконання / Використання
57
-
58
- ### Сценарій A — виклик з оркестратора (library mode)
59
-
60
- 1. CLI `@nitra/cursor fix` (або агрегатор) знаходить правило `php` за його директорією.
61
- 2. Динамічно імпортує `fix.mjs` і викликає `await run(ctx)`, передаючи спільний `RuleContext` (зокрема `walkCache`, щоб уникнути повторного обходу ФС між правилами).
62
- 3. `run` делегує виклик `runStandardRule(import.meta.dirname, ctx)`.
63
- 4. `runStandardRule` повертає exit-code; оркестратор агрегує коди всіх правил.
64
-
65
- ```js
66
- import { run } from '@nitra/cursor/rules/php/fix.mjs'
67
-
68
- const code = await run(sharedCtx)
69
- ```
70
-
71
- ### Сценарій B — прямий запуск файлу (standalone mode)
72
-
73
- 1. Користувач (або IDE/CI) виконує:
74
- ```bash
75
- bun npm/rules/php/fix.mjs
76
- ```
77
- 2. Top-level `if (isRunAsCli(import.meta.url))` повертає `true` (бо `import.meta.url` збігається з шляхом запущеного скрипта).
78
- 3. Викликається `await runRuleCli(import.meta.dirname)` — повноцінний CLI-режим: підвантажує конфігурацію, застосовує whitelist, друкує підсумок.
79
- 4. `process.exit(...)` завершує процес із отриманим exit-кодом, аби CI/IDE могли коректно інтерпретувати результат.
80
-
81
- ### Семантика exit-кодів
82
-
83
- - `0` — правило застосовне та порушень не виявлено (або правило незастосовне для цього проєкту — `applies` повернув `false`).
84
- - `1` — є порушення, які треба виправити.
85
-
86
- ### Коментарі та лінт-винятки
87
-
88
- У standalone-гілці явно вимкнено два правила лінтера:
89
-
90
- ```js
91
- // eslint-disable-next-line n/no-process-exit -- standalone entry-point має повертати exit-code для CI/IDE
92
- process.exit(await runRuleCli(import.meta.dirname))
93
- ```
94
-
95
- Це свідомий виняток: `process.exit` тут потрібний, щоб CLI/CI отримали ненульовий код у разі порушень — без нього процес міг би завершитись із кодом `0` навіть за наявності знайдених проблем.
96
-
97
- ## Архітектурний контекст
98
-
99
- - **Конвенція файлу `fix.mjs`** — у директорії кожного правила (`npm/rules/<id>/fix.mjs`) лежить однотипний тонкий wrapper із двома ролями (library + standalone). Це гарантує:
100
- - єдиний інтерфейс для оркестратора (`run(ctx)`);
101
- - можливість запускати окреме правило ізольовано (для дебагу/CI per-rule).
102
- - **Чому через `import.meta.dirname`** — `runStandardRule` за директорією правила автоматично знаходить усі сусідні артефакти (`applies.mjs`, `policy.mjs`, `checks/*.mjs`, `*.mdc`). Це уникає дублювання id-правила як рядка.
103
- - **Patch-free wrapper** — у самому `fix.mjs` не повинно з'являтися PHP-специфічної логіки; будь-які зміни поведінки правила робляться у сусідніх файлах правила, а не в цьому entry-point'і.
104
-
105
- ## Rebuild Test
106
-
107
- Файл можна повністю відтворити з опису вище за такими інваріантами:
108
-
109
- 1. Два імпорти: `{ isRunAsCli, runRuleCli }` з `../../scripts/lib/run-rule-cli.mjs` і `{ runStandardRule }` з `../../scripts/lib/run-standard-rule.mjs`.
110
- 2. Іменований експорт `function run(ctx)` — однорядкове тіло `return runStandardRule(import.meta.dirname, ctx)`.
111
- 3. JSDoc над `run`: опис стадій (applies → JS-concerns → policy → mdc-refs), згадка library mode, тип параметра `ctx` через `import('...').RuleContext`, тип повернення `Promise<number>` із семантикою 0/1.
112
- 4. Блок `if (isRunAsCli(import.meta.url)) { ... }` із викликом `process.exit(await runRuleCli(import.meta.dirname))` і коментарем-поясненням про дві ролі fix.mjs.
113
- 5. Лінт-disable перед `process.exit`: `n/no-process-exit, unicorn/no-process-exit` із обґрунтуванням «standalone entry-point має повертати exit-code для CI/IDE».
114
- 6. Жодних інших top-level операцій, жодного `default`-експорту.
35
+ - Read-only: файл не виконує операцій запису у файлову систему.
36
+ - Кешує результати в межах одного прогону.
37
+ - Не звертається до мережі.