@nitra/cursor 12.6.0 → 12.7.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 (269) hide show
  1. package/.claude-template/settings.template.json +1 -1
  2. package/CHANGELOG.md +16 -0
  3. package/bin/docs/n-cursor.md +4 -20
  4. package/bin/n-cursor.js +7 -53
  5. package/docs/stryker.config.md +20 -28
  6. package/package.json +1 -1
  7. package/rules/abie/docs/index.md +1 -0
  8. package/rules/abie/docs/main.md +29 -0
  9. package/rules/abie/{fix.mjs → main.mjs} +5 -3
  10. package/rules/adr/docs/index.md +1 -0
  11. package/rules/adr/docs/main.md +29 -0
  12. package/rules/adr/{fix.mjs → main.mjs} +5 -3
  13. package/rules/bun/docs/index.md +1 -0
  14. package/rules/bun/docs/main.md +30 -0
  15. package/rules/bun/js/docs/layout.md +11 -36
  16. package/rules/bun/{fix.mjs → main.mjs} +5 -3
  17. package/rules/capacitor/docs/index.md +1 -0
  18. package/rules/capacitor/docs/main.md +29 -0
  19. package/rules/capacitor/{fix.mjs → main.mjs} +5 -3
  20. package/rules/changelog/docs/index.md +1 -0
  21. package/rules/changelog/docs/main.md +27 -0
  22. package/rules/changelog/main.mjs +20 -0
  23. package/rules/ci4/docs/index.md +1 -0
  24. package/rules/ci4/docs/main.md +30 -0
  25. package/rules/ci4/main.mjs +20 -0
  26. package/rules/doc-files/docs/index.md +1 -0
  27. package/rules/doc-files/docs/main.md +31 -0
  28. package/rules/doc-files/js/docgen-files-batch.mjs +47 -3
  29. package/rules/doc-files/js/docgen-scan.mjs +89 -9
  30. package/rules/doc-files/js/docs/docgen-files-batch.md +15 -15
  31. package/rules/doc-files/js/docs/docgen-scan.md +34 -34
  32. package/rules/doc-files/js/docs/index.md +1 -0
  33. package/rules/doc-files/js/docs/run-lint.md +27 -0
  34. package/rules/doc-files/{lint/lint.mjs → js/run-lint.mjs} +23 -9
  35. package/rules/doc-files/{js/lint.mjs → main.mjs} +60 -10
  36. package/rules/docker/docs/index.md +1 -0
  37. package/rules/docker/docs/main.md +28 -0
  38. package/rules/docker/js/docs/lint.md +26 -54
  39. package/rules/docker/js/lint.mjs +11 -0
  40. package/rules/docker/lib/docker-hadolint.mjs +1 -1
  41. package/rules/docker/lib/docs/docker-hadolint.md +16 -173
  42. package/rules/docker/main.mjs +20 -0
  43. package/rules/efes/docs/index.md +1 -0
  44. package/rules/efes/docs/main.md +29 -0
  45. package/rules/efes/main.mjs +20 -0
  46. package/rules/feedback/docs/index.md +1 -0
  47. package/rules/feedback/docs/main.md +30 -0
  48. package/rules/feedback/main.mjs +20 -0
  49. package/rules/ga/docs/index.md +1 -0
  50. package/rules/ga/docs/main.md +29 -0
  51. package/rules/ga/{lint/lint.mjs → main.mjs} +36 -10
  52. package/rules/graphql/docs/index.md +1 -0
  53. package/rules/graphql/docs/main.md +36 -0
  54. package/rules/graphql/main.mjs +20 -0
  55. package/rules/hasura/docs/index.md +1 -0
  56. package/rules/hasura/docs/main.md +30 -0
  57. package/rules/hasura/main.mjs +20 -0
  58. package/rules/image-avif/docs/index.md +1 -0
  59. package/rules/image-avif/docs/main.md +30 -0
  60. package/rules/image-avif/js/docs/avif_generation.md +20 -233
  61. package/rules/image-avif/main.mjs +20 -0
  62. package/rules/image-compress/docs/index.md +1 -0
  63. package/rules/image-compress/docs/main.md +29 -0
  64. package/rules/image-compress/js/docs/package_setup.md +12 -11
  65. package/rules/image-compress/{js/lint.mjs → main.mjs} +21 -5
  66. package/rules/js-bun-db/docs/index.md +1 -0
  67. package/rules/js-bun-db/docs/main.md +30 -0
  68. package/rules/js-bun-db/main.mjs +20 -0
  69. package/rules/js-bun-redis/docs/index.md +1 -0
  70. package/rules/js-bun-redis/docs/main.md +29 -0
  71. package/rules/js-bun-redis/main.mjs +20 -0
  72. package/rules/js-lint/docs/index.md +1 -0
  73. package/rules/js-lint/docs/main.md +29 -0
  74. package/rules/js-lint/js/check.mjs +268 -0
  75. package/rules/js-lint/js/docs/check.md +39 -0
  76. package/rules/js-lint/js/docs/index.md +1 -1
  77. package/rules/js-lint/js/docs/tooling.md +12 -32
  78. package/rules/js-lint/js/tooling.mjs +1 -265
  79. package/rules/js-lint/{js/lint.mjs → main.mjs} +19 -2
  80. package/rules/js-lint-ci/docs/index.md +1 -0
  81. package/rules/js-lint-ci/docs/main.md +27 -0
  82. package/rules/js-lint-ci/main.mjs +33 -0
  83. package/rules/js-mssql/docs/index.md +1 -0
  84. package/rules/js-mssql/docs/main.md +30 -0
  85. package/rules/js-mssql/main.mjs +20 -0
  86. package/rules/js-run/docs/index.md +1 -0
  87. package/rules/js-run/docs/main.md +30 -0
  88. package/rules/js-run/main.mjs +20 -0
  89. package/rules/k8s/docs/index.md +1 -0
  90. package/rules/k8s/docs/main.md +40 -0
  91. package/rules/k8s/js/docs/index.md +12 -0
  92. package/rules/k8s/{lint/lint.mjs → main.mjs} +32 -10
  93. package/rules/nginx-default-tpl/docs/index.md +1 -0
  94. package/rules/nginx-default-tpl/docs/main.md +30 -0
  95. package/rules/nginx-default-tpl/main.mjs +20 -0
  96. package/rules/npm-module/docs/index.md +1 -0
  97. package/rules/npm-module/docs/main.md +29 -0
  98. package/rules/npm-module/js/docs/rule_meta.md +17 -16
  99. package/rules/npm-module/js/rule_meta.mjs +13 -3
  100. package/rules/npm-module/main.mjs +20 -0
  101. package/rules/php/docs/index.md +1 -0
  102. package/rules/php/docs/main.md +33 -0
  103. package/rules/php/js/docs/tooling.md +10 -10
  104. package/rules/php/{lint/lint.mjs → main.mjs} +32 -6
  105. package/rules/python/docs/index.md +1 -0
  106. package/rules/python/docs/main.md +31 -0
  107. package/rules/python/js/docs/tooling.md +17 -17
  108. package/rules/python/{lint/lint.mjs → main.mjs} +29 -5
  109. package/rules/rego/docs/index.md +1 -0
  110. package/rules/rego/docs/main.md +37 -0
  111. package/rules/rego/{lint/lint.mjs → main.mjs} +27 -5
  112. package/rules/release/docs/index.md +1 -0
  113. package/rules/release/docs/main.md +29 -0
  114. package/rules/release/docs/release.md +0 -3
  115. package/rules/release/release.mdc +10 -0
  116. package/rules/rust/docs/index.md +1 -0
  117. package/rules/rust/docs/main.md +27 -0
  118. package/rules/rust/{js/lint.mjs → main.mjs} +20 -3
  119. package/rules/security/docs/index.md +1 -0
  120. package/rules/security/docs/main.md +28 -0
  121. package/rules/security/main.mjs +45 -0
  122. package/rules/style-lint/docs/index.md +1 -0
  123. package/rules/style-lint/docs/main.md +29 -0
  124. package/rules/style-lint/{js/lint.mjs → main.mjs} +19 -1
  125. package/rules/tauri/docs/index.md +1 -0
  126. package/rules/tauri/docs/main.md +29 -0
  127. package/rules/tauri/main.mjs +20 -0
  128. package/rules/test/docs/index.md +1 -0
  129. package/rules/test/docs/main.md +30 -0
  130. package/rules/test/main.mjs +20 -0
  131. package/rules/text/docs/index.md +1 -0
  132. package/rules/text/docs/main.md +29 -0
  133. package/rules/text/js/docs/cspell-fix.md +30 -0
  134. package/rules/text/js/docs/formatting.md +12 -45
  135. package/rules/text/js/docs/index.md +4 -0
  136. package/rules/text/js/docs/run-dotenv-linter.md +31 -0
  137. package/rules/text/js/docs/run-shellcheck.md +28 -0
  138. package/rules/text/js/docs/run-v8r.md +29 -0
  139. package/rules/text/{lint/lint.mjs → main.mjs} +38 -9
  140. package/rules/text/text.mdc +5 -14
  141. package/rules/tool-surface/docs/index.md +1 -0
  142. package/rules/tool-surface/docs/main.md +29 -0
  143. package/rules/tool-surface/main.mjs +20 -0
  144. package/rules/vue/docs/index.md +1 -0
  145. package/rules/vue/docs/main.md +29 -0
  146. package/rules/vue/main.mjs +20 -0
  147. package/rules/worktree/docs/index.md +1 -0
  148. package/rules/worktree/docs/main.md +28 -0
  149. package/rules/worktree/main.mjs +20 -0
  150. package/scripts/docs/index.md +1 -0
  151. package/scripts/docs/post-tool-use-check.md +29 -0
  152. package/scripts/docs/sync-claude-config.md +64 -92
  153. package/scripts/lib/adr/docs/normalize-cli.md +0 -3
  154. package/scripts/lib/adr/docs/normalize-pipeline.md +0 -3
  155. package/scripts/lib/docs/gha-workflow.md +25 -317
  156. package/scripts/lib/docs/index.md +1 -0
  157. package/scripts/lib/docs/list-project-rules-mdc.md +5 -4
  158. package/scripts/lib/docs/list-rule-ids.md +15 -148
  159. package/scripts/lib/docs/read-n-cursor-config-lite.md +12 -16
  160. package/scripts/lib/docs/run-lint-step.md +13 -13
  161. package/scripts/lib/docs/run-lint.md +30 -0
  162. package/scripts/lib/docs/run-rule-cli.md +14 -10
  163. package/scripts/lib/docs/run-standard-lint.md +27 -10
  164. package/scripts/lib/docs/run-standard-rule.md +12 -11
  165. package/scripts/lib/docs/timing-summary.md +11 -12
  166. package/scripts/lib/docs/worktree-notice.md +0 -3
  167. package/scripts/lib/fix/docs/index.md +1 -0
  168. package/scripts/lib/fix/docs/orchestrator.md +23 -18
  169. package/scripts/lib/fix/docs/run-conformance-check.md +32 -0
  170. package/scripts/lib/fix/docs/t0.md +10 -9
  171. package/scripts/lib/fix/orchestrator.mjs +5 -5
  172. package/scripts/lib/fix/{run-fix-check.mjs → run-conformance-check.mjs} +13 -13
  173. package/scripts/lib/fix/t0.mjs +3 -3
  174. package/scripts/lib/gha-workflow.mjs +1 -1
  175. package/scripts/lib/list-project-rules-mdc.mjs +1 -1
  176. package/scripts/lib/list-rule-ids.mjs +12 -3
  177. package/scripts/lib/read-n-cursor-config-lite.mjs +2 -2
  178. package/scripts/lib/run-lint-step.mjs +1 -1
  179. package/{rules/lint/js/orchestrate.mjs → scripts/lib/run-lint.mjs} +42 -20
  180. package/scripts/lib/run-rule-cli.mjs +4 -4
  181. package/scripts/lib/run-standard-lint.mjs +19 -6
  182. package/scripts/lib/run-standard-rule.mjs +4 -4
  183. package/scripts/lib/timing-summary.mjs +1 -1
  184. package/scripts/{post-tool-use-fix.mjs → post-tool-use-check.mjs} +9 -9
  185. package/scripts/sync-claude-config.mjs +2 -2
  186. package/rules/changelog/fix.mjs +0 -18
  187. package/rules/ci4/fix.mjs +0 -18
  188. package/rules/doc-files/fix.mjs +0 -19
  189. package/rules/doc-files/js/docs/lint.md +0 -34
  190. package/rules/doc-files/lint/docs/index.md +0 -11
  191. package/rules/doc-files/lint/docs/lint.md +0 -35
  192. package/rules/docker/fix.mjs +0 -18
  193. package/rules/docker/lint/docs/index.md +0 -11
  194. package/rules/docker/lint/docs/lint.md +0 -200
  195. package/rules/docker/lint/lint.mjs +0 -95
  196. package/rules/efes/fix.mjs +0 -18
  197. package/rules/feedback/fix.mjs +0 -18
  198. package/rules/ga/fix.mjs +0 -18
  199. package/rules/ga/js/docs/lint.md +0 -20
  200. package/rules/ga/js/lint.mjs +0 -12
  201. package/rules/ga/lint/docs/index.md +0 -11
  202. package/rules/ga/lint/docs/lint.md +0 -31
  203. package/rules/graphql/fix.mjs +0 -18
  204. package/rules/hasura/fix.mjs +0 -18
  205. package/rules/image-avif/fix.mjs +0 -18
  206. package/rules/image-compress/fix.mjs +0 -18
  207. package/rules/image-compress/js/docs/lint.md +0 -24
  208. package/rules/js-bun-db/fix.mjs +0 -18
  209. package/rules/js-bun-redis/fix.mjs +0 -18
  210. package/rules/js-lint/fix.mjs +0 -18
  211. package/rules/js-lint/js/docs/lint.md +0 -32
  212. package/rules/js-lint-ci/fix.mjs +0 -18
  213. package/rules/js-lint-ci/js/docs/lint.md +0 -22
  214. package/rules/js-lint-ci/js/lint.mjs +0 -15
  215. package/rules/js-mssql/fix.mjs +0 -18
  216. package/rules/js-run/fix.mjs +0 -18
  217. package/rules/k8s/fix.mjs +0 -18
  218. package/rules/k8s/js/lint.mjs +0 -14
  219. package/rules/k8s/lint/docs/index.md +0 -11
  220. package/rules/k8s/lint/docs/lint.md +0 -413
  221. package/rules/lint/docs/fix.md +0 -25
  222. package/rules/lint/docs/index.md +0 -11
  223. package/rules/lint/fix.mjs +0 -18
  224. package/rules/lint/js/docs/index.md +0 -11
  225. package/rules/lint/js/docs/orchestrate.md +0 -31
  226. package/rules/lint/meta.json +0 -1
  227. package/rules/nginx-default-tpl/fix.mjs +0 -18
  228. package/rules/npm-module/fix.mjs +0 -18
  229. package/rules/php/fix.mjs +0 -18
  230. package/rules/php/js/docs/lint.md +0 -20
  231. package/rules/php/js/lint.mjs +0 -15
  232. package/rules/php/lint/docs/index.md +0 -11
  233. package/rules/php/lint/docs/lint.md +0 -219
  234. package/rules/python/fix.mjs +0 -18
  235. package/rules/python/js/docs/lint.md +0 -21
  236. package/rules/python/js/lint.mjs +0 -14
  237. package/rules/python/lint/docs/index.md +0 -11
  238. package/rules/python/lint/docs/lint.md +0 -29
  239. package/rules/rego/fix.mjs +0 -18
  240. package/rules/rego/js/docs/lint.md +0 -21
  241. package/rules/rego/js/lint.mjs +0 -12
  242. package/rules/rego/lint/docs/index.md +0 -11
  243. package/rules/rego/lint/docs/lint.md +0 -208
  244. package/rules/rust/fix.mjs +0 -18
  245. package/rules/rust/js/docs/lint.md +0 -21
  246. package/rules/security/fix.mjs +0 -18
  247. package/rules/security/js/docs/lint.md +0 -175
  248. package/rules/security/js/lint.mjs +0 -26
  249. package/rules/style-lint/fix.mjs +0 -18
  250. package/rules/style-lint/js/docs/lint.md +0 -31
  251. package/rules/tauri/fix.mjs +0 -18
  252. package/rules/test/fix.mjs +0 -18
  253. package/rules/text/fix.mjs +0 -18
  254. package/rules/text/js/docs/lint.md +0 -23
  255. package/rules/text/js/lint.mjs +0 -15
  256. package/rules/text/lint/docs/cspell-fix.md +0 -32
  257. package/rules/text/lint/docs/index.md +0 -15
  258. package/rules/text/lint/docs/lint.md +0 -36
  259. package/rules/text/lint/docs/run-dotenv-linter.md +0 -161
  260. package/rules/text/lint/docs/run-shellcheck.md +0 -216
  261. package/rules/text/lint/docs/run-v8r.md +0 -201
  262. package/rules/tool-surface/fix.mjs +0 -18
  263. package/rules/vue/fix.mjs +0 -18
  264. package/rules/worktree/fix.mjs +0 -18
  265. /package/rules/release/{fix.mjs → main.mjs} +0 -0
  266. /package/rules/text/{lint → js}/cspell-fix.mjs +0 -0
  267. /package/rules/text/{lint → js}/run-dotenv-linter.mjs +0 -0
  268. /package/rules/text/{lint → js}/run-shellcheck.mjs +0 -0
  269. /package/rules/text/{lint → js}/run-v8r.mjs +0 -0
@@ -3,328 +3,36 @@ type: JS Module
3
3
  title: gha-workflow.mjs
4
4
  resource: npm/scripts/lib/gha-workflow.mjs
5
5
  docgen:
6
- crc: 266986bf
6
+ crc: d73b42f2
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
7
9
  ---
8
10
 
9
- Модуль `gha-workflow.mjs` — це набір допоміжних чистих функцій для **структурного аналізу GitHub Actions workflow-файлів** (`.yml`) після їх розбору як YAML.
11
+ Надає функції для структурного аналізу конфігурацій GitHub Actions workflow (`.yml`). Дозволяє парсити YAML, витягувати значення з кроків, зокрема `uses:` та `run:`, а також перевіряти відповідність структури workflow певним вимогам. Це забезпечує цілеспрямований аналіз конфігурацій, замінюючи пошук підрядків у сирому тексті.
10
12
 
11
- Призначення модуля — замінити крихкий пошук підрядків у сирому тексті workflow-файла на **типобезпечну** перевірку значень `uses:` та `run:` у кроках (`steps`) робіт (`jobs`). Модуль використовується сценаріями перевірки (checkers) проєктних правил:
13
+ ## Поведінка
12
14
 
13
- - `check-ga` загальна перевірка GitHub Actions workflows;
14
- - `check-js-lint` перевірка структури `lint-js.yml`;
15
- - `check-text` перевірка наявності викликів `bun run lint-text` у CI;
16
- - `check-style-lint` перевірка викликів стайл-лінту в CI;
17
- - `check-npm-module` перевірка workflow npm-модуля.
15
+ parseWorkflowYaml парсить вміст workflow YAML у об'єкт, повертаючи `null` у разі синтаксичної помилки.
16
+ flattenWorkflowSteps збирає плоский список усіх кроків з усіх job'ів workflow, додаючи метадані про job та індекс кроку.
17
+ getStepUses отримує значення `uses` для заданого кроку.
18
+ getStepRun отримує текст команди з поля `run` заданого кроку, об'єднуючи багаторядкові значення.
19
+ eventPathsIncludeExact перевіряє, чи містить `on.push.paths` або `on.pull_request.paths` точне значення шляху.
20
+ verifyLintJsWorkflowStructure перевіряє структуру workflow для відповідності вимогам, зокрема наявність `actions/checkout@v6` з `persist-credentials: false`, використання `setup-bun-deps` та наявність команд `bunx oxlint`, `bunx eslint .`, `bunx jscpd .` у кроках `run`.
21
+ anyRunStepIncludes перевіряє, чи містить хоча б один `run` будь-якого кроку підрядок, який вказує на певний інструмент.
18
22
 
19
- Крім перевірки значень `uses:` та `run:`, модуль уміє:
23
+ ## Публічний API
20
24
 
21
- - розпізнавати локальну composite-action `./.github/actions/setup-bun-deps`;
22
- - перевіряти, що `actions/checkout@v6` викликається з `with.persist-credentials: false`;
23
- - виявляти заборонені в CI прапорці `--fix` у викликах `oxlint` та `eslint`;
24
- - перевіряти включення точного `glob` у списки `on.push.paths` / `on.pull_request.paths`.
25
+ parseWorkflowYaml перетворює YAML-файл робочого процесу у структурований об'єкт; повертає `null` при помилці синтаксису.
26
+ flattenWorkflowSteps об'єднує всі кроки, визначені у всіх завданнях.
27
+ getStepUses отримує значення, вказане у полі `uses:` для кроку.
28
+ getStepRun отримує команду, яку виконує крок (може бути одним або багатьма рядками).
29
+ eventPathsIncludeExact — визначає, чи містить список шляхів події (push або pull_request) точне збігання.
30
+ verifyLintJsWorkflowStructure — перевіряє наявність необхідних компонентів у файлі `lint-js.yml` (наприклад, `checkout@v6`, `persist-credentials`, `setup-bun-deps`, виконання команд).
31
+ anyRunStepIncludes — виявляє, чи містить будь-який рядок виконання (`run`) певний підрядок.
25
32
 
26
- Модуль виконує лише читання та обчислення — він **не змінює** жодних файлів і **не виконує** жодних команд. Поведінка детермінована й залежить тільки від переданих аргументів.
33
+ ## Гарантії поведінки
27
34
 
28
- ## Експорти / API
29
-
30
- Усі експорти з модуля це **named exports** (іменовані експорти), `default export` немає.
31
-
32
- | Експорт | Тип | Короткий опис |
33
- | -------------------------------------------- | -------- | ---------------------------------------------------------------------------------------- |
34
- | `parseWorkflowYaml(content)` | function | Парсить YAML вміст у звичайний об’єкт; при помилці повертає `null`. |
35
- | `flattenWorkflowSteps(root)` | function | Збирає всі кроки з усіх jobs у плоский список з метаданими `{ jobId, stepIndex, step }`. |
36
- | `getStepUses(step)` | function | Повертає значення `uses:` кроку або порожній рядок. |
37
- | `getStepRun(step)` | function | Повертає значення `run:` кроку (підтримує рядок та масив рядків). |
38
- | `eventPathsIncludeExact(root, event, exact)` | function | Перевіряє, чи містить `on.<event>.paths` точне значення glob. |
39
- | `verifyLintJsWorkflowStructure(root)` | function | Виконує повний набір структурних перевірок для `lint-js.yml`. |
40
- | `anyRunStepIncludes(root, needle)` | function | Перевіряє, чи містить будь-який `run` кроку заданий підрядок. |
41
-
42
- Внутрішні (неекспортовані) функції-помічники:
43
-
44
- - `workflowJobsEntries(root)` — повертає `[jobId, job][]`;
45
- - `workflowJobSteps(job)` — повертає масив об’єктних кроків job;
46
- - `hasCheckoutWithPersistCredentialsFalse(steps)` — перевіряє `checkout@v6` з `persist-credentials: false`;
47
- - `appendCiFixFlagFailures(failures, steps)` — додає у `failures` рядки про заборонені `--fix` у CI.
48
-
49
- Внутрішні константи модуля:
50
-
51
- - `CHECKOUT_V6_USES = 'actions/checkout@v6'` — очікувана дія checkout та її версія.
52
- - `LOCAL_SETUP_BUN_DEPS_MARKER = './.github/actions/setup-bun-deps'` — шлях до локальної composite-action для встановлення Bun-залежностей.
53
- - `BUNX_OXLINT_FIX_RE = /bunx\s+oxlint[^\n]*--fix/u` — регулярний вираз для виявлення `bunx oxlint ... --fix` в одному рядку.
54
-
55
- ## Функції
56
-
57
- ### `parseWorkflowYaml(content)`
58
-
59
- **Сигнатура:** `parseWorkflowYaml(content: string): Record<string, unknown> | null`
60
-
61
- **Параметри:**
62
-
63
- - `content` — рядок із вмістом workflow-файла `.yml`.
64
-
65
- **Повертає:**
66
-
67
- - розібраний YAML як звичайний об’єкт (`Record<string, unknown>`), якщо вміст парситься і має тип `object` та не є `null`;
68
- - `null` — якщо `yaml.parse` кинув виняток або результат не є об’єктом.
69
-
70
- **Side effects:** немає. Помилка парсингу мовчки перехоплюється `try/catch`.
71
-
72
- **Примітки:** ця функція безпечна для викликача — навіть на некоректному YAML вона не падає, а повертає `null`, що далі обробляється у `verifyLintJsWorkflowStructure` як спеціальний випадок.
73
-
74
- ---
75
-
76
- ### `flattenWorkflowSteps(root)`
77
-
78
- **Сигнатура:** `flattenWorkflowSteps(root: Record<string, unknown>): { jobId: string, stepIndex: number, step: Record<string, unknown> }[]`
79
-
80
- **Параметри:**
81
-
82
- - `root` — корінь розібраного YAML (об’єкт із полем `jobs`).
83
-
84
- **Повертає:** плоский масив об’єктів, кожен з яких містить:
85
-
86
- - `jobId` — ім’я job (ключ у `jobs`);
87
- - `stepIndex` — порядковий номер кроку всередині `steps` цього job (починається з 0);
88
- - `step` — сам об’єкт кроку.
89
-
90
- **Side effects:** немає.
91
-
92
- **Алгоритм:** ітерує через `workflowJobsEntries(root)`, для кожного job отримує `workflowJobSteps(job)`, нумерує кроки за допомогою `Array.prototype.entries()` та пуш у акумулятор. Невалідні (необ’єктні) jobs та невалідні steps пропускаються.
93
-
94
- ---
95
-
96
- ### `getStepUses(step)`
97
-
98
- **Сигнатура:** `getStepUses(step: Record<string, unknown>): string`
99
-
100
- **Параметри:**
101
-
102
- - `step` — об’єкт одного елемента масиву `steps`.
103
-
104
- **Повертає:** значення `step.uses`, якщо це рядок; інакше — порожній рядок `''`.
105
-
106
- **Side effects:** немає.
107
-
108
- **Призначення:** уніфікований доступ до значення `uses:` без перевірок типу у викликачів.
109
-
110
- ---
111
-
112
- ### `getStepRun(step)`
113
-
114
- **Сигнатура:** `getStepRun(step: Record<string, unknown>): string`
115
-
116
- **Параметри:**
117
-
118
- - `step` — об’єкт одного елемента масиву `steps`.
119
-
120
- **Повертає:** текст команди `run:`:
121
-
122
- - якщо `step.run` — рядок, повертається як є;
123
- - якщо `step.run` — масив, кожен елемент конвертується через `String(...)` та з’єднується через `\n`;
124
- - інакше — `''`.
125
-
126
- **Side effects:** немає.
127
-
128
- **Примітки:** YAML дозволяє запис `run:` як багаторядкового скаляра (`|` / `>-`) або як масиву рядків. Функція нормалізує обидва випадки до одного `string`, який потім зручно перевіряти через `.includes(...)` або регулярним виразом.
129
-
130
- ---
131
-
132
- ### `eventPathsIncludeExact(root, event, exact)`
133
-
134
- **Сигнатура:** `eventPathsIncludeExact(root: Record<string, unknown>, event: 'push' | 'pull_request', exact: string): boolean`
135
-
136
- **Параметри:**
137
-
138
- - `root` — корінь workflow;
139
- - `event` — ім’я ключа в `on`: `'push'` або `'pull_request'`;
140
- - `exact` — очікуваний рядок (glob), який має бути присутній у `paths`.
141
-
142
- **Повертає:** `true`, якщо у `root.on[event].paths` є масив і він містить точне значення `exact`. У всіх інших випадках (відсутній `on`, відсутній `event`, `paths` не масив тощо) — `false`.
143
-
144
- **Side effects:** немає.
145
-
146
- **Гарантії безпеки:** функція захищена від відсутніх та некоректних типів проміжних об’єктів, тому її можна викликати на будь-якому `root`, повернутому з `parseWorkflowYaml`.
147
-
148
- ---
149
-
150
- ### `verifyLintJsWorkflowStructure(root)`
151
-
152
- **Сигнатура:** `verifyLintJsWorkflowStructure(root: Record<string, unknown> | null): { ok: boolean, failures: string[] }`
153
-
154
- **Параметри:**
155
-
156
- - `root` — корінь розібраного workflow або `null`, якщо парсинг не вдався.
157
-
158
- **Повертає:** об’єкт результату:
159
-
160
- - `{ ok: true, failures: [] }` — усі перевірки пройдено;
161
- - `{ ok: false, failures: [...] }` — список причин відмови у вигляді людинозрозумілих українських повідомлень.
162
-
163
- **Side effects:** немає.
164
-
165
- **Перевірки, які виконуються (у порядку додавання до `failures`):**
166
-
167
- 1. Якщо `root === null` — повертається одразу `{ ok: false, failures: ['YAML не вдалося розібрати — перевір синтаксис workflow'] }`.
168
- 2. У жодному кроці немає `uses:` з підрядком `'actions/checkout@v6'` → `'немає кроку uses: actions/checkout@v6'`.
169
- 3. Серед кроків з `actions/checkout@v6` немає такого, що містить `with.persist-credentials === false` → `'checkout@v6 без with.persist-credentials: false'`.
170
- 4. У жодному кроці немає `uses:` з підрядком `'./.github/actions/setup-bun-deps'` → `'немає uses: ./.github/actions/setup-bun-deps'`.
171
- 5. У сумарному `run`-блобі немає `'bunx oxlint'` → `'у run немає bunx oxlint'`.
172
- 6. У сумарному `run`-блобі немає `'bunx eslint .'` → `'у run немає bunx eslint .'`.
173
- 7. У сумарному `run`-блобі немає `'bunx jscpd .'` → `'у run немає bunx jscpd .'`.
174
- 8. Для кожного кроку, чий `run` матчиться `BUNX_OXLINT_FIX_RE`, додається `'у run є oxlint з --fix (у CI заборонено)'`.
175
- 9. Для кожного кроку, чий `run` містить `'eslint --fix'`, додається `'у run є eslint --fix (у CI заборонено)'`.
176
-
177
- **Примітка:** «сумарний `run`-блоб» — це `flattenWorkflowSteps(root).map(s => getStepRun(s.step)).join('\n')`. Тобто перевірки 5–7 пасять, навіть якщо `bunx oxlint`, `bunx eslint .` та `bunx jscpd .` рознесені по різних кроках.
178
-
179
- ---
180
-
181
- ### `anyRunStepIncludes(root, needle)`
182
-
183
- **Сигнатура:** `anyRunStepIncludes(root: Record<string, unknown>, needle: string): boolean`
184
-
185
- **Параметри:**
186
-
187
- - `root` — корінь workflow;
188
- - `needle` — підрядок для пошуку в текстах `run:`.
189
-
190
- **Повертає:** `true`, якщо знайдено принаймні один крок, у `run:` якого є `needle`; інакше `false`.
191
-
192
- **Side effects:** немає. Ітерація припиняється на першому збігу (рання передача).
193
-
194
- **Типовий приклад:** `anyRunStepIncludes(root, 'bun run lint-text')` для `check-text` — перевірити, що CI взагалі викликає таргет лінту текстів.
195
-
196
- ---
197
-
198
- ### `workflowJobsEntries(root)` (internal)
199
-
200
- **Сигнатура:** `workflowJobsEntries(root: Record<string, unknown>): [string, Record<string, unknown>][]`
201
-
202
- **Параметри:** `root` — корінь workflow.
203
-
204
- **Повертає:** список пар `[jobId, job]` для тих ключів `jobs`, у яких значення є непорожнім об’єктом.
205
-
206
- **Side effects:** немає.
207
-
208
- **Алгоритм:** перевіряє наявність та тип `root.jobs`, далі `Object.entries(jobs).flatMap(...)` фільтрує невалідні значення (масив порожніх або одно-елементних масивів).
209
-
210
- ---
211
-
212
- ### `workflowJobSteps(job)` (internal)
213
-
214
- **Сигнатура:** `workflowJobSteps(job: Record<string, unknown>): Record<string, unknown>[]`
215
-
216
- **Параметри:** `job` — один job-об’єкт.
217
-
218
- **Повертає:** масив об’єктних кроків з `job.steps`; невалідні (необ’єктні / `null`) елементи фільтруються.
219
-
220
- **Side effects:** немає.
221
-
222
- ---
223
-
224
- ### `hasCheckoutWithPersistCredentialsFalse(steps)` (internal)
225
-
226
- **Сигнатура:** `hasCheckoutWithPersistCredentialsFalse(steps: { step: Record<string, unknown> }[]): boolean`
227
-
228
- **Параметри:** `steps` — результат `flattenWorkflowSteps` (використовується тільки поле `step`).
229
-
230
- **Повертає:** `true`, якщо знайдено крок, у якого:
231
-
232
- - `uses` містить `'actions/checkout@v6'`;
233
- - `step.with` — об’єкт;
234
- - `step.with['persist-credentials'] === false` (саме `false`, а не «фолсі»).
235
-
236
- **Side effects:** немає.
237
-
238
- **Призначення:** перевірити, що `actions/checkout@v6` явно вимкнув збереження токена в git-конфізі — це вимога безпеки в правилі `n-ga`.
239
-
240
- ---
241
-
242
- ### `appendCiFixFlagFailures(failures, steps)` (internal)
243
-
244
- **Сигнатура:** `appendCiFixFlagFailures(failures: string[], steps: { step: Record<string, unknown> }[]): void`
245
-
246
- **Параметри:**
247
-
248
- - `failures` — акумулятор-масив, у який функція **пушить** нові рядки помилок;
249
- - `steps` — результат `flattenWorkflowSteps`.
250
-
251
- **Повертає:** `undefined` (мутує `failures`).
252
-
253
- **Side effects:** мутація переданого масиву `failures` через `Array.prototype.push`.
254
-
255
- **Логіка:** для кожного кроку:
256
-
257
- - якщо `BUNX_OXLINT_FIX_RE.test(run)` — додає повідомлення про заборонений `--fix` у `bunx oxlint`;
258
- - якщо `run.includes('eslint --fix')` — додає повідомлення про заборонений `eslint --fix`.
259
-
260
- **Примітка:** функція може додати **обидва** повідомлення для одного і того ж кроку, якщо в `run` присутні обидва патерни. Якщо в різних кроках присутній один і той самий патерн — повідомлення додасться **кілька разів** (по одному на крок).
261
-
262
- ## Залежності
263
-
264
- **Зовнішні npm-пакети:**
265
-
266
- - `yaml` — функція `parse(content)` для розбору YAML у JS-об’єкт. Імпорт іменований: `import { parse } from 'yaml'`.
267
-
268
- **Стандартна бібліотека JS:** `Object.entries`, `Array.isArray`, `Array.prototype.flatMap`, `Array.prototype.map`, `Array.prototype.entries`, `Array.prototype.some`, `Array.prototype.includes`, `Array.prototype.join`, `RegExp.prototype.test`, `String.prototype.includes`.
269
-
270
- **Внутрішні залежності проєкту:** жодних модулів проєкту не імпортує — це листовий хелпер.
271
-
272
- **Хто залежить від цього модуля (зворотні залежності):** згідно з docstring файла — скрипти `check-ga`, `check-js-lint`, `check-text`, `check-style-lint`, `check-npm-module`. Конкретні шляхи до цих скриптів живуть у `npm/scripts/` / `npm/checks/` та використовують іменовані експорти модуля.
273
-
274
- ## Потік виконання / Використання
275
-
276
- ### Типовий цикл використання сценарієм-checker
277
-
278
- 1. Сценарій читає вміст файла `.github/workflows/<name>.yml` як рядок (наприклад через `node:fs/promises`).
279
- 2. Викликає `const root = parseWorkflowYaml(content)`.
280
- 3. Якщо `root === null` — повідомляє про синтаксичну помилку YAML.
281
- 4. Інакше викликає одну зі спеціалізованих перевірок (наприклад `verifyLintJsWorkflowStructure(root)`) або серію загальних (`flattenWorkflowSteps`, `getStepUses`, `getStepRun`, `anyRunStepIncludes`, `eventPathsIncludeExact`).
282
- 5. На основі результату формує звіт перевірки.
283
-
284
- ### Приклад: перевірка `lint-js.yml`
285
-
286
- ```js
287
- import { readFile } from 'node:fs/promises'
288
- import { parseWorkflowYaml, verifyLintJsWorkflowStructure } from './gha-workflow.mjs'
289
-
290
- const content = await readFile('.github/workflows/lint-js.yml', 'utf8')
291
- const root = parseWorkflowYaml(content)
292
- const result = verifyLintJsWorkflowStructure(root)
293
-
294
- if (!result.ok) {
295
- for (const f of result.failures) {
296
- console.error('lint-js.yml:', f)
297
- }
298
- process.exit(1)
299
- }
300
- ```
301
-
302
- ### Приклад: перевірка наявності таргета `bun run lint-text`
303
-
304
- ```js
305
- import { parseWorkflowYaml, anyRunStepIncludes } from './gha-workflow.mjs'
306
-
307
- const root = parseWorkflowYaml(content)
308
- if (root && !anyRunStepIncludes(root, 'bun run lint-text')) {
309
- console.error('у CI відсутній виклик bun run lint-text')
310
- }
311
- ```
312
-
313
- ### Приклад: перевірка `on.pull_request.paths`
314
-
315
- ```js
316
- import { parseWorkflowYaml, eventPathsIncludeExact } from './gha-workflow.mjs'
317
-
318
- const root = parseWorkflowYaml(content)
319
- if (root && !eventPathsIncludeExact(root, 'pull_request', '**/*.vue')) {
320
- console.error('on.pull_request.paths не містить **/*.vue')
321
- }
322
- ```
323
-
324
- ### Властивості, корисні викликачам
325
-
326
- - **Чисті функції.** Жодних бічних ефектів (крім явної мутації `failures` в `appendCiFixFlagFailures`, яка інкапсульована всередині `verifyLintJsWorkflowStructure`).
327
- - **Безпечність до помилок типів.** Усі публічні функції захищені від некоректних або відсутніх ключів — повертають `''`, `false` або `[]` замість падіння.
328
- - **Уніфікований доступ.** `getStepUses` та `getStepRun` нормалізують форму YAML (рядок vs масив), щоб викликач завжди працював із `string`.
329
- - **Точне `paths`-зіставлення.** `eventPathsIncludeExact` вимагає **точного** елемента масиву, а не підрядка — тому glob-патерни мають бути записані як є.
330
- - **Сумарний `run`-блоб.** У `verifyLintJsWorkflowStructure` пункти 5–7 не вимагають, щоб усі команди жили в одному `run`-кроці — вони можуть бути рознесені по кроках/jobs.
35
+ - Read-only: не виконує операцій запису (ФС/БД).
36
+ - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
37
+ - За певних помилок повертає порожнє значення (напр. `null`) замість винятку.
38
+ - Свідомо пропускає шляхи: `.github`, `.git`.
@@ -31,6 +31,7 @@ resource: npm/scripts/lib/
31
31
  | [rule-predicates.mjs](rule-predicates.md) | JS Module |
32
32
  | [run-conftest-batch.mjs](run-conftest-batch.md) | JS Module |
33
33
  | [run-lint-step.mjs](run-lint-step.md) | JS Module |
34
+ | [run-lint.mjs](run-lint.md) | JS Module |
34
35
  | [run-rule-cli.mjs](run-rule-cli.md) | JS Module |
35
36
  | [run-rule.mjs](run-rule.md) | JS Module |
36
37
  | [run-standard-lint.mjs](run-standard-lint.md) | JS Module |
@@ -3,12 +3,14 @@ type: JS Module
3
3
  title: list-project-rules-mdc.mjs
4
4
  resource: npm/scripts/lib/list-project-rules-mdc.mjs
5
5
  docgen:
6
- crc: e17e0855
6
+ crc: 60cd4e83
7
7
  model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
8
  score: 100
9
9
  ---
10
10
 
11
- Експортує константу CURSOR_RULES_DIR, яка вказує на каталог правил у проєкті-споживачі. Надає функцію для отримання відсортованого списку всіх файлів правил `.mdc` з цього каталогу.
11
+ ## Огляд
12
+
13
+ Цей модуль визначає шлях до `.mdc`-файлів правил у проєкті-споживачі, що зберігаються у директорії, вказаній константою CURSOR_RULES_DIR. Він надає відсортований список імен цих файлів. Це винесення логіки з `bin/n-cursor.js` забезпечує розділення відповідальності між інструментом командного рядка та функцією перевірки конформності.
12
14
 
13
15
  ## Поведінка
14
16
 
@@ -22,5 +24,4 @@ listProjectRulesMdcFiles — Збирає список файлів MDC, що м
22
24
 
23
25
  ## Гарантії поведінки
24
26
 
25
- - Read-only: файл не виконує операцій запису у файлову систему.
26
- - Не звертається до мережі.
27
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -3,158 +3,25 @@ type: JS Module
3
3
  title: list-rule-ids.mjs
4
4
  resource: npm/scripts/lib/list-rule-ids.mjs
5
5
  docgen:
6
- crc: 5ef1ead5
6
+ crc: d8b3ea73
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
7
9
  ---
8
10
 
9
- Модуль `list-rule-ids.mjs` — невелика бібліотечна утиліта, призначена для перебору директорій-правил у каталозі `npm/rules/` та повернення відсортованого алфавітно списку ідентифікаторів правил, які реально містять виконуваний модуль `fix.mjs`.
11
+ ## Огляд
10
12
 
11
- Логіка модуля побудована навколо архітектурної інваріанти проєкту: після так званої «атомарної міграції» кожне валідне правило **зобов'язане** мати файл `fix.mjs` у власній директорії `rules/<id>/`. Будь-яка піддиректорія без `fix.mjs` вважається або «не-правилом» (службова тека), або заглушкою-чернеткою і ігнорується. Прихованих директорій (імена, що починаються з `.`) також не існує в результаті.
13
+ Перебирає директорії у `rules/` та фільтрує їх, вибираючи лише ті, що містять єдиний канонічний entrypoint (`rules/<id>/main.mjs`), згідно з ADR 2026-06-21. Функція повертає список ідентифікаторів правил, які відповідають цьому канону. Операція є лише для читання файлової системи.
12
14
 
13
- Додатково модуль підтримує опційне точкове фільтрування одним конкретним `id`, що використовується CLI-флагом `--rule abie` для прогону команд у режимі «тільки одне правило».
15
+ ## Поведінка
14
16
 
15
- Модуль повністю асинхронний (використовує `node:fs/promises`), не має зовнішніх npm-залежностей і не виконує жодних побічних ефектів окрім читання директорії та перевірки наявності файлу через `existsSync`.
17
+ 1. Зчитує список усіх каталогів у директорії, що містить правила.
18
+ 2. Фільтрує цей список, залишаючи лише каталоги, які не починаються з крапки.
19
+ 3. Для кожного каталогу перевіряє, чи існує у ньому файл `main.mjs`.
20
+ 4. Фільтрує список, залишаючи лише ті каталоги, які містять файл `main.mjs`.
21
+ 5. Якщо надано фільтр, додатково фільтрує список, залишаючи лише той ID, що збігається з фільтром.
22
+ 6. Сортує отримані ID в алфавітному порядку.
23
+ 7. Повертає відсортований список ID правил.
16
24
 
17
- ## Експорти / API
25
+ ## Гарантії поведінки
18
26
 
19
- Файл експортує одну іменовану функцію:
20
-
21
- | Експорт | Тип | Призначення |
22
- | ------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------- |
23
- | `listRuleIds` | `async function` | Повертає `Promise<string[]>` зі списком id правил, відфільтрованим за наявністю `fix.mjs` і опційним рівнянням до конкретного id. |
24
-
25
- Експорту за замовчуванням немає.
26
-
27
- ## Функції
28
-
29
- ### `listRuleIds(bundledRulesDir, filter)`
30
-
31
- #### Сигнатура
32
-
33
- ```js
34
- export async function listRuleIds(bundledRulesDir, filter)
35
- ```
36
-
37
- JSDoc-типи:
38
-
39
- ```
40
- @param {string} bundledRulesDir — абсолютний шлях до `npm/rules/`
41
- @param {string} [filter] — id одного правила (через `--rule abie`)
42
- @returns {Promise<string[]>} — відсортовані алфавітно id
43
- ```
44
-
45
- #### Параметри
46
-
47
- - **`bundledRulesDir`** (`string`, обовʼязковий) — абсолютний шлях до кореневої теки правил, найчастіше `npm/rules/` (наприклад, `/path/to/repo/npm/rules`). Передбачається, що шлях існує і є директорією; модуль не валідує його окремо — будь-яка помилка з `fs.readdir` пробрасується далі промісом.
48
- - **`filter`** (`string | undefined`, опційний) — точна назва правила, до якої потрібно звузити список. Якщо параметр не передано (`undefined`), повертаються всі знайдені id. Якщо передано, у результат потрапляють лише ті id, що _точно_ рівні `filter`. Часткові збіги, регулярні вирази або кейс-незалежність не підтримуються.
49
-
50
- #### Повертає
51
-
52
- `Promise<string[]>` — масив рядків-ідентифікаторів правил, відсортованих алфавітно за допомогою `Array.prototype.toSorted` із компаратором `a.localeCompare(b)`. Сортування _стабільне_ для оригінального методу і коректне для Unicode-локалей.
53
-
54
- Можливі сценарії результату:
55
-
56
- - Порожній масив `[]` — якщо в `bundledRulesDir` немає жодної директорії з `fix.mjs`, або якщо `filter` не збігається з жодним наявним id.
57
- - Масив з одного елемента — типово при заданому `filter`.
58
- - Повний відсортований список усіх правил — у випадку відсутності `filter`.
59
-
60
- #### Алгоритм / послідовність кроків
61
-
62
- 1. Викликається `readdir(bundledRulesDir, { withFileTypes: true })` — отримуємо масив `Dirent`-обʼєктів (а не просто рядків імен), що дає змогу одразу перевіряти тип запису без додаткових `stat`-викликів.
63
- 2. Залишаються лише записи, для яких одночасно:
64
- - `e.isDirectory()` — це саме директорія;
65
- - `!e.name.startsWith('.')` — імʼя не починається з крапки (відсікаються приховані теки на кшталт `.git`, `.cache`, тощо).
66
- 3. Записи перетворюються на голі імена (`.map(e => e.name)`).
67
- 4. Фільтрація на наявність `fix.mjs` — для кожного `id` синхронно перевіряється `existsSync(join(bundledRulesDir, id, 'fix.mjs'))`. Директорії без цього файлу відсіюються як «not-a-rule або заглушка».
68
- 5. Фільтрація за `filter` — якщо параметр визначений, залишаються лише id, рівні `filter`; інакше пропускаються всі.
69
- 6. Сортування `toSorted((a, b) => a.localeCompare(b))` — повертає новий масив без мутації проміжного.
70
-
71
- #### Side effects
72
-
73
- - **Дискові читання**: `readdir` (асинхронний обхід директорії) та `existsSync` (синхронні перевірки наявності файлу для кожного кандидата). Винятки I/O пробрасуються відхиленим промісом.
74
- - **Жодних записів, мережевих викликів, мутацій глобального стану, логування** — функція є read-only і чистою щодо побічних ефектів окрім згаданих читань ФС.
75
- - Використання `existsSync` у циклі — це _синхронні_ виклики всередині асинхронної функції; вони виконуються послідовно, але без `await`. Для типового розміру каталогу `npm/rules/` (десятки правил) це непомітна вартість.
76
-
77
- #### Гранітні випадки
78
-
79
- - Якщо `bundledRulesDir` не існує — `readdir` відхиляє проміс з `ENOENT`.
80
- - Якщо в директорії є символічні посилання — поведінка залежить від того, що повертає `Dirent.isDirectory()`; ця функція покладається на штатну семантику Node.js.
81
- - Якщо `filter` переданий як порожній рядок `''` — він _не_ є `undefined`, тому фільтр буде застосовано (`id === ''`), і результат майже напевно буде порожнім.
82
- - Файл `fix.mjs` як директорія: малоймовірний випадок, але `existsSync` поверне `true` для будь-якого існуючого запису з цим імʼям; модуль не розрізняє файл і теку.
83
-
84
- ## Залежності
85
-
86
- ### Вбудовані модулі Node.js
87
-
88
- | Модуль | Імпортований символ | Використання |
89
- | ------------------ | ------------------- | ------------------------------------------------------------ |
90
- | `node:fs` | `existsSync` | Синхронна перевірка наявності `fix.mjs` у кожному кандидаті. |
91
- | `node:fs/promises` | `readdir` | Асинхронний обхід `bundledRulesDir` з `withFileTypes: true`. |
92
- | `node:path` | `join` | Безпечне зʼєднання сегментів шляху до `fix.mjs`. |
93
-
94
- ### Зовнішні npm-залежності
95
-
96
- Немає.
97
-
98
- ### Внутрішні залежності
99
-
100
- Файл не імпортує жодних інших модулів проєкту. Сам по собі він використовується як бібліотечна функція з інших скриптів у `npm/scripts/` (CLI-обгортки, які приймають флаг `--rule`).
101
-
102
- ## Потік виконання / Використання
103
-
104
- ### Контекст у проєкті
105
-
106
- `listRuleIds` — це фундамент будь-якого скрипту, який «робить щось для кожного правила»: лінт, авто-фікс, генерація звіту, перевірка покриття, нормалізація ADR тощо. Замість того щоб кожному скрипту самостійно перелічувати теки в `npm/rules/`, всі вони викликають цю функцію та отримують однаковий, відсортований, відфільтрований список — це гарантує детермінованість порядку обробки правил.
107
-
108
- Архітектурно файл підкріплює інваріант «`fix.mjs` обовʼязковий»: будь-яка тека без нього автоматично невидима для всіх споживачів. Це дає змогу тримати у `rules/` допоміжні підтеки (наприклад, шаблони, шаред-файли) без ризику, що вони будуть оброблені як правило.
109
-
110
- ### Приклад використання
111
-
112
- ```js
113
- import { listRuleIds } from './lib/list-rule-ids.mjs'
114
- import { resolve } from 'node:path'
115
-
116
- const bundledRulesDir = resolve(import.meta.dirname, '../../rules')
117
-
118
- // 1. Всі правила.
119
- const all = await listRuleIds(bundledRulesDir)
120
- // → ['abie', 'changelog', 'feedback', ...]
121
-
122
- // 2. Тільки одне правило (з CLI-флагу --rule abie).
123
- const ruleFlag = process.argv.includes('--rule') ? process.argv[process.argv.indexOf('--rule') + 1] : undefined
124
-
125
- const subset = await listRuleIds(bundledRulesDir, ruleFlag)
126
- // → ['abie'] якщо ruleFlag === 'abie' і таке правило існує
127
- // → [] якщо ruleFlag не відповідає жодному правилу
128
- ```
129
-
130
- ### Інтеграція з CLI
131
-
132
- Типовий патерн виклику в скриптах проєкту:
133
-
134
- 1. Скрипт парсить `process.argv` (часто через `mri`/`minimist` або вручну), отримує опційний `--rule <id>`.
135
- 2. Викликає `listRuleIds(rulesDir, ruleFromArgv)` і чекає на результат.
136
- 3. Ітерується по отриманому масиву і виконує цільову дію (fix/check/коверідж) для кожного id.
137
-
138
- ### Послідовність виконання при виклику
139
-
140
- ```
141
- listRuleIds(dir, filter)
142
-
143
- ├─ readdir(dir, withFileTypes:true) ── async ──▶ [Dirent...]
144
-
145
- ├─ .filter(isDirectory && !startsWith('.'))
146
- ├─ .map(e => e.name)
147
- ├─ .filter(existsSync(<id>/fix.mjs)) ◀── sync I/O loop
148
- ├─ .filter(filter === undefined || id === filter)
149
- ├─ .toSorted(localeCompare)
150
-
151
-
152
- Promise<string[]> (відсортовані id)
153
- ```
154
-
155
- ### Очікувані помилки
156
-
157
- - `ENOENT` / `ENOTDIR` від `readdir` — якщо переданий `bundledRulesDir` неіснуючий або не є директорією. Викликач має або переконатися в коректності шляху перед викликом, або обгорнути виклик у `try/catch`.
158
- - `EACCES` — якщо немає прав на читання теки.
159
-
160
- Усі інші помилки (відсутність окремого `fix.mjs`, відсутність відповідності `filter`) семантично не є помилками — вони лише звужують повернений масив.
27
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -3,30 +3,26 @@ type: JS Module
3
3
  title: read-n-cursor-config-lite.mjs
4
4
  resource: npm/scripts/lib/read-n-cursor-config-lite.mjs
5
5
  docgen:
6
- crc: a5fb0592
6
+ crc: a38ac2f4
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
7
9
  ---
8
10
 
9
- Цей файл читає файл `.n-cursor.json`, що містить список правил для конфігурації. Він повертає цей список, щоб `fix.mjs` міг використовувати правила для визначення конфігурації. Це забезпечує базове читання конфігурації правил для запуску `fix.mjs` з командного рядка.
11
+ ## Огляд
10
12
 
11
- ## Поведінка
13
+ Модуль надає легкий, лише для читання, інтерфейс для парсингу конфігурації `.n-cursor.json`. Він призначений для ізольованих, окремих викликів `check.mjs`. Модуль визначає стан кожного правила, ґрунтуючись на вмісті `.n-cursor.json`. Якщо файл відсутній, правило вважається активним (поведінка "open by default"). Якщо файл присутній, стан правила залежить від списків `rules` та `disableRules` у конфігурації. Модуль повертає об'єкт, що містить списки активних та вимкнених правил.
12
14
 
13
- **readNCursorConfigLite**
14
- Зчитує конфігурацію з файлу `.n-cursor.json`. Повертає об'єкт з інформацією про правила та вимкнені правила. Якщо файл відсутній, повертає конфігурацію з порожнім масивом правил.
15
+ ## Поведінка
15
16
 
16
- **isRuleEnabled**
17
- Перевіряє, чи правило з активним статусом згідно з конфігурацією. Повертає `true`, якщо файл відсутній, правило вимкнено в `disable-rules` або присутнє в `rules`. Повертає `false` в іншому випадку.
17
+ Поведінка
18
+ readNCursorConfigLite читає конфігураційний файл .n-cursor.json у вказаному каталозі, повертаючи стан його існування та списки дозволених і вимкнених правил.
19
+ isRuleEnabled визначає, чи має бути виконане правило, виходячи зі стану конфігураційного файлу та ID правила.
18
20
 
19
21
  ## Публічний API
20
22
 
21
- - readNCursorConfigLite — Завантажує конфігурацію курсора.
22
- - isRuleEnabled — Перевіряє статус активності правила.
23
+ readNCursorConfigLite — зчитує базові налаштування курсора з конфігурації.
24
+ isRuleEnabled — визначає, чи діє певне правило на основі конфігурації. Якщо конфігурація відсутня, правило вважається активним за замовчуванням. Якщо правило явно вимкнено, воно не діє. Якщо правило визначено у списку правил, воно діє. В іншому випадку, правило не діє.
23
25
 
24
26
  ## Гарантії поведінки
25
27
 
26
- - Якщо файл `.n-cursor.json` відсутній, вважається, що всі правила включені.
27
- - Якщо файл `.n-cursor.json` існує, але поле `rules` порожнє, вважається, що всі правила включені.
28
- - Якщо файл `.n-cursor.json` існує і має поле `rules`, але поле `rules` порожнє, вважається, що всі правила включені.
29
- - Якщо правило вказане в полі `disable-rules`, воно вимкнено.
30
- - Повертає `false` якщо файл `.n-cursor.json` відсутній або недійсний.
31
- - Повертає `null` якщо не вдалося прочитати файл `.n-cursor.json`.
32
- - Не використовує кешування.
28
+ - Read-only: не виконує операцій запису (ФС/БД).