@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,98 +1,36 @@
1
- # fix.mjs — точка входу правила `npm-module`
1
+ ---
2
+ docgen:
3
+ source: npm/rules/npm-module/fix.mjs
4
+ crc: 38cf876b
5
+ score: 100
6
+ ---
2
7
 
3
- ## Огляд
4
-
5
- `fix.mjs` — мінімалістична точка входу (entry-point) для правила з ідентифікатором, що відповідає назві теки, у якій файл розташований (`npm/rules/npm-module/`). Файл виконує дві ролі одночасно:
6
-
7
- 1. **Library mode** — експортує функцію `run(ctx)`, яку викликає оркестратор `npm/scripts/lib/run-standard-rule.mjs` через стандартний імпорт. Це дозволяє іншому коду (наприклад, агрегатору правил `@nitra/cursor`) виконувати правило у складі загального прогону.
8
- 2. **Standalone mode** — якщо файл стартує напряму (наприклад, `bun npm/rules/npm-module/fix.mjs`), він прогорає еквівалент команди `npx @nitra/cursor fix npm-module` через `runRuleCli` із завантаженням конфігу, whitelist та фінальним summary; повертає у процес коректний exit-code для CI/IDE.
9
-
10
- Логіки самого правила тут немає — файл лише делегує виконання у стандартний раннер `runStandardRule`, який послідовно проганяє чотири фази правила: `applies` → `JS-concerns` → `policy` → `mdc-refs`.
11
-
12
- ## Експорти / API
13
-
14
- | Назва | Тип | Призначення |
15
- | ----- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
16
- | `run` | `function (ctx?) => Promise<number>` | Іменований експорт для library-mode. Викликає `runStandardRule` зі шляхом до теки правила та опційним контекстом. Повертає Promise з exit-кодом: `0` — правило не зафіксувало порушень, `1` — є порушення. |
17
-
18
- Дефолтних експортів немає. Side-effect верхнього рівня: за умови запуску як CLI, наприкінці модуля викликається `process.exit(...)` з кодом, який повернув `runRuleCli`.
19
-
20
- ## Функції (сигнатура / параметри / повертає / side effects)
21
-
22
- ### `run(ctx)`
23
-
24
- ```js
25
- export function run(ctx)
26
- ```
27
-
28
- - **Параметри**
29
- - `ctx` _(опційний)_ — об'єкт типу `RuleContext`, імпортований з `../../scripts/lib/run-standard-rule.mjs`. Може містити, зокрема, `walkCache` (закешований обхід дерева файлів), щоб уникнути повторного walk при паралельному прогоні кількох правил.
30
- - **Повертає** `Promise<number>`:
31
- - `0` — правило не виявило порушень або не застосовується до поточного workspace.
32
- - `1` — зафіксовано принаймні одне порушення.
33
- - **Side effects**
34
- - Жодних прямих побічних ефектів у самій `run`. Усі побічні ефекти (читання файлів, друк summary, мутація `walkCache`) — у `runStandardRule` та підлеглих фазах правила.
35
- - **Реалізація**
36
-
37
- ```js
38
- return runStandardRule(import.meta.dirname, ctx)
39
- ```
8
+ # fix.mjs
40
9
 
41
- `import.meta.dirname` дає абсолютний шлях до теки правила (`.../npm/rules/npm-module/`); цей шлях `runStandardRule` використовує як корінь для пошуку фаз правила (`applies.mjs`, `js/`, `policy.mjs`, `mdc-refs.mjs` тощо).
42
-
43
- ### Standalone-блок (без іменованої функції)
44
-
45
- ```js
46
- if (isRunAsCli(import.meta.url)) {
47
- process.exit(await runRuleCli(import.meta.dirname))
48
- }
49
- ```
50
-
51
- - **Умова** — `isRunAsCli(import.meta.url)` повертає `true`, якщо модуль є точкою входу процесу (а не імпортується іншим модулем).
52
- - **Дія** — `await runRuleCli(import.meta.dirname)` виконує повний CLI-цикл (config-loading, whitelist, прогін правила, summary) і повертає exit-код. Цей код передається у `process.exit`.
53
- - **Коментар у коді** свідомо вимикає правила лінтера `n/no-process-exit` та `unicorn/no-process-exit`, оскільки standalone-entry-point має повертати exit-код для CI/IDE.
54
-
55
- ## Залежності
56
-
57
- Прямі (внутрішні) залежності — два модулі зі спільної бібліотеки скриптів проєкту:
58
-
59
- | Шлях імпорту | Що бере | Призначення |
60
- | ----------------------------------------- | -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
61
- | `../../scripts/lib/run-rule-cli.mjs` | `isRunAsCli`, `runRuleCli` | Допоміжна логіка для роботи у standalone-режимі: визначення, чи модуль є entry-point процесу, і запуск повного CLI-циклу правила, який є еквівалентом `npx @nitra/cursor fix <id>`. |
62
- | `../../scripts/lib/run-standard-rule.mjs` | `runStandardRule`, тип `RuleContext` (через JSDoc) | Уніфікований раннер чотирифазного правила (`applies → JS-concerns → policy → mdc-refs`). Через нього прогрівається walk-cache і виконуються фази у фіксованому порядку. |
63
-
64
- Зовнішніх (npm) залежностей файл не має. Він спирається на Node.js / Bun рантайм-можливості:
65
-
66
- - `import.meta.url` — для визначення, чи модуль запущений як CLI.
67
- - `import.meta.dirname` — для отримання абсолютного шляху до теки правила.
68
- - `process.exit` — для повернення exit-коду у standalone-режимі.
69
-
70
- ## Потік виконання / Використання
71
-
72
- ### Сценарій A: Library mode (через оркестратор `@nitra/cursor`)
10
+ ## Огляд
73
11
 
74
- 1. Оркестратор імпортує модуль: `const mod = await import('npm/rules/npm-module/fix.mjs')`.
75
- 2. `isRunAsCli(import.meta.url)` повертає `false` (модуль не є entry-point) — standalone-блок ігнорується.
76
- 3. Оркестратор викликає `await mod.run(ctx)`, передаючи спільний `RuleContext` (наприклад, з заздалегідь побудованим `walkCache`).
77
- 4. `run` делегує виконання `runStandardRule(import.meta.dirname, ctx)`, який проганяє чотири фази правила і повертає `0` або `1`.
78
- 5. Оркестратор агрегує exit-коди всіх правил у фінальний код процесу.
12
+ Виконує обробку JS-занепокоєних на наданому контексті прогону, застосовує політику [Політика_X] та генерує посилання MDC.
79
13
 
80
- ### Сценарій B: Standalone mode
14
+ ## Поведінка
81
15
 
82
- 1. Користувач запускає `bun npm/rules/npm-module/fix.mjs` (еквівалент `npx @nitra/cursor fix npm-module`).
83
- 2. Модуль завантажується як entry-point — `isRunAsCli(import.meta.url)` повертає `true`.
84
- 3. Виконується `await runRuleCli(import.meta.dirname)`:
85
- - завантажується конфіг (`.cursor`/проектні налаштування),
86
- - застосовується whitelist (якщо є),
87
- - запускається чотирифазне правило,
88
- - друкується summary з кількістю порушень.
89
- 4. Повернутий exit-код передається у `process.exit(...)`, що завершує процес. CI/IDE отримує `0` (успіх) або `1` (порушення).
16
+ 1. Запуск правила.
17
+ * Приймає контекст прогону.
18
+ * Виконує застосування JS-занепокоєних.
19
+ * Застосовує політику.
20
+ * Генерує посилання MDC.
21
+ * Повертає результат прогону.
22
+ 2. Виконання у режимі CLI.
23
+ * Виконується як автономний скрипт.
24
+ * Виконує повний еквівалент команди `npx @nitra/cursor fix <id>`.
25
+ * Повертає код виходу з процесу.
90
26
 
91
- ### Контракт двох ролей
27
+ ## Публічний API
92
28
 
93
- Дизайн «library + standalone в одному файлі» є типовим для правил `@nitra/cursor`:
29
+ run запускає правило: applies JS-concerns policy mdc-refs (через runStandardRule).
30
+ Library mode — викликається CLI orchestration через `import + run`.
94
31
 
95
- - Функція `run` — публічний API для оркестратора; вона **не** викликає `process.exit` і не друкує summary, лише повертає код.
96
- - Standalone-блок навпаки відповідає за повноцінний CLI-UX: завантаження конфігу, whitelist, summary, exit-code — усе, що очікується від `fix.mjs` правила, який запускається окремо.
32
+ ## Гарантії поведінки
97
33
 
98
- Завдяки цьому контракту той самий файл інтегрується і у пакетний прогін правил, і в локальне налагодження одного правила без дублювання логіки.
34
+ - Read-only: файл не виконує операцій запису у файлову систему.
35
+ - Кешує результати в межах одного прогону.
36
+ - Не звертається до мережі.
@@ -1,32 +1,32 @@
1
1
  ---
2
2
  docgen:
3
3
  source: npm/rules/npm-module/js/header_doc_pointer.mjs
4
- crc: 9058c4ea
4
+ crc: d96a2957
5
+ score: 100
5
6
  ---
6
7
 
7
8
  # header_doc_pointer.mjs
8
9
 
9
10
  ## Огляд
10
11
 
11
- Концерн правила `npm-module`, що закріплює контракт між `docs/<stem>.md` і module-level JSDoc у скриптах правил і скілів. Якщо файл вже описано у `docs/<stem>.md` — наратив у заголовному коментарі файлу є дублюванням і заборонений. Якщо `docs` немає header залишається єдиним джерелом опису поведінки і жодних обмежень немає.
12
+ Файл виконує перевірку документації для модулів. Сканує директорії npm/rules та npm/skills. Перевіряє наявність файлів docs/<stem>.md у піддиректоріях правил/скілів. Перевіряє, чи містить відповідні js-файли не більше одного рядка JSDoc. У разі перевищення ліміту, генерує звіт про порушення.
12
13
 
13
14
  ## Поведінка
14
15
 
15
- 1. Сканує всі `.mjs`-файли (крім `.test.mjs`) у `npm/rules/*/js/` та `npm/skills/*/js/`.
16
- 2. Для кожного файлу перевіряє наявність `docs/<stem>.md` поруч із `js/`.
17
- 3. Якщо `docs/<stem>.md` **відсутній** пропускає файл: перевірка не застосовується.
18
- 4. Якщо `docs/<stem>.md` **присутній** знаходить module-level JSDoc (перший `/** ... */` до першого `import`/`export` на початку рядка).
19
- 5. Рахує непорожні змістовні рядки блоку (після зрізання відступу `*`). Більше одного → порушення.
16
+ 1. Сканувати директорії npm/rules та npm/skills.
17
+ 2. Для кожної директорії перевіряти піддиректорії правил/скілів.
18
+ 3. Для кожного знайденого js-файлу перевіряти наявність файлу docs/<stem>.md.
19
+ 4. Якщо файл docs/<stem>.md існує, перевіряти, чи містить module-level JSDoc не більше одного непорожного рядка.
20
+ 5. У разі перевищення ліміту, зарепортувати порушення.
21
+ 6. Повертати код виходу репортера.
20
22
 
21
- Допустимі форми при наявних docs:
23
+ ## Публічний API
22
24
 
23
- - відсутній module-level JSDoc (0 рядків)
24
- - `/** @see ./docs/<stem>.md */` (1 рядок)
25
- - `/** Контракт: ./docs/<stem>.md */` (1 рядок)
25
+ - check сканує файли `npm/rules/*/js/*.mjs` та `npm/skills/*/js/*.mjs`.
26
+ - Якщо існує `docs/<stem>.md`, модуль повинен мати посилання на JSDoc (не наратив).
27
+ - Якщо `docs` відсутній, обмеження не застосовуються.
26
28
 
27
29
  ## Гарантії поведінки
28
30
 
29
- - Файли без `docs/`-відповідника повністю ігноруються — перевірка не створює обмежень до того, як docgen запишеться.
30
- - Якщо у файлі немає жодного module-level JSDoc — перевірка проходить.
31
- - Тестові файли (`*.test.mjs`) не скануються.
32
- - Підкаталоги `tests/`, `data/`, `templates/` у `js/` не скануються (discovery бере лише `*.mjs` безпосередньо в `js/`, не рекурсивно).
31
+ - Read-only: файл не виконує операцій запису у файлову систему.
32
+ - Не звертається до мережі.
@@ -1,274 +1,52 @@
1
+ ---
2
+ docgen:
3
+ source: npm/rules/npm-module/js/package_structure.mjs
4
+ crc: 943e3b76
5
+ score: 85
6
+ ---
7
+
1
8
  # package_structure.mjs
2
9
 
3
10
  ## Огляд
4
11
 
5
- Модуль `package_structure.mjs` — це checker правила `npm-module.mdc` у пакеті `@nitra/cursor`. Він валідує структуру npm-модуля в монорепо: наявність каталогу `npm/`, файлу `npm/package.json`, конфігурації hk (`hk.pkl` або `.config/hk.pkl`), workflow `npm-publish.yml`, та узгодженість TypeScript-emit (поле `types`, генерація `index.d.ts`, виклик `tsc` у pre-commit hook).
6
-
7
- Модуль підтримує два альтернативні layout-и npm-модуля:
8
-
9
- 1. **`npm/src` + `.js`-файли** — канонічний layout зі згенерованим `npm/types/index.d.ts` через `tsc` з прапорцями `--declaration --allowJs --emitDeclarationOnly --outDir types --skipLibCheck`.
10
- 2. **`npm/tsconfig.emit-types.json`** — коли `.js`-файлів під `npm/src` немає; типи виганяються через `tsc -p tsconfig.emit-types.json`.
11
-
12
- Окремо модуль контролює, щоб опублікований пакет (`npm pack`) не містив тестів і фікстур: сканує каталог `npm/` за полем `"files"` з `package.json` (з урахуванням негативних glob-патернів) і відсіює test-style каталоги, імена файлів та AST-імпорти test-фреймворків.
13
-
14
- Деякі перевірки (структура `npm/package.json`, валідація `compilerOptions` у `tsconfig.emit-types.json`, валідація полів `npm-publish.yml`) делеговані Rego-полісі у `npm/policy/npm_module/`. У цьому файлі лишається лише cross-file / FS / AST-частина: чи реально існує файл на диску, чи містить опублікований tarball тести, чи має `hk.pkl` правильні підрядки команди `tsc`.
15
-
16
- Узгодженість `version`/`CHANGELOG.md` у файлі **не** перевіряється — це робить `changelog/js/consistency.mjs` за моделлю `n-changelog.mdc`.
17
-
18
- ## Експорти / API
19
-
20
- | Експорт | Тип | Призначення |
21
- | ----------------------------------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------- |
22
- | `globToRegex(glob)` | `function` | Перетворює glob-патерн на `RegExp` із якорями `^` / `$`; підтримує `**`, `*`, `?`, `{a,b,c}`. |
23
- | `findTestFrameworkImport(content, virtualPath)` | `async function` | Парсить JS/TS через `oxc-parser` і повертає назву модуля test-фреймворку, якщо знайдено import / require / dynamic import. |
24
- | `classifyPublishedFileAsTest(relPath, cwd?)` | `async function` | Класифікує файл як test/fixture за каталогом, basename або AST-імпортом. |
25
- | `check(cwd?)` | `async function` | Головна точка входу checker-а правила `npm-module.mdc`; повертає exit-code `0` / `1`. |
26
-
27
- Решта функцій (`npmSrcTreeHasJsFile`, `readHkConfig`, `missingHkSrcLayoutFragments`, `missingHkEmitTypesConfigFragments`, `npmTypesFileFromPackageField`, `checkNpmPackageJson`, `checkEmitTypesConfig`, `checkPublishWorkflow`, `collectPublishedFiles`, `checkNoTestsInPublishedFiles`, `checkNpmModuleBasicStructure`) — приватні для модуля.
28
-
29
- ## Константи
30
-
31
- | Константа | Значення / Опис |
32
- | ------------------------ | -------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
33
- | `EMIT_TYPES_CONFIG` | `'npm/tsconfig.emit-types.json'` — шлях до TS-config для emit без `src`. |
34
- | `TEST_DIR_NAMES` | `Set` з `'tests'`, `'__tests__'`, `'fixtures'`, `'__fixtures__'`, `'spec'`, `'test'`. |
35
- | `TEST_FILE_PATTERNS` | `[/^.+\.(test | spec)\.[cm]?[jt]sx?$/iu]` — патерн test-файлів за basename. Rego-файли (`\*\_test.rego`) свідомо не входять (conftest-конвенція). |
36
- | `JS_LIKE_EXT_RE` | `/\.[cm]?[jt]sx?$/iu` — розширення, у яких сканується AST на імпорти test-фреймворків. |
37
- | `TEST_FRAMEWORK_MODULES` | `Set` з `'bun:test'`, `'node:test'`, `'vitest'`, `'@jest/globals'`, `'jest'`, `'mocha'`, `'ava'`, `'tap'`, `'tape'`. |
38
- | `REGEX_SPECIAL_IN_GLOB` | `Set` спецсимволів regex, які екрануються у glob-сегменті (без `*`/`?`). |
39
- | `GLOBSTAR_LEADING_RE` | `/^__GLOBSTAR__\//u` — маркер `**/` на початку. |
40
- | `GLOBSTAR_TRAILING_RE` | `/\/__GLOBSTAR__$/u` — маркер `/**` у кінці. |
41
-
42
- ## Функції
43
-
44
- ### `npmSrcTreeHasJsFile(cwd, ignorePaths = [])`
45
-
46
- - **Сигнатура:** `async (cwd: string, ignorePaths?: string[]) => Promise<boolean>`
47
- - **Параметри:**
48
- - `cwd` — корінь репозиторію.
49
- - `ignorePaths` — абсолютні шляхи каталогів, повністю виключених з обходу (з `loadCursorIgnorePaths`).
50
- - **Повертає:** `true`, якщо хоча б один `.js` під `npm/src` (рекурсивно); інакше `false`. Якщо `npm/src` не існує — одразу `false`.
51
- - **Side effects:** жодних (тільки FS-читання).
52
-
53
- ### `readHkConfig(cwd)`
54
-
55
- - **Сигнатура:** `async (cwd: string) => Promise<{ path: string, text: string } | null>`
56
- - **Параметри:** `cwd` — корінь репозиторію.
57
- - **Повертає:** обʼєкт із relative-шляхом (`hk.pkl` або `.config/hk.pkl`) і повним текстом файлу; `null`, якщо жоден кандидат не існує.
58
- - **Side effects:** читання файлу через `readFile`.
59
-
60
- ### `missingHkSrcLayoutFragments(hkText)`
61
-
62
- - **Сигнатура:** `(hkText: string) => string[]`
63
- - **Параметри:** `hkText` — текст hk-конфігурації.
64
- - **Повертає:** список фрагментів, яких немає в тексті. Очікувані фрагменти: `["pre-commit"]`, `bunx -p typescript tsc`, `src/**/*.js`, `--declaration`, `--allowJs`, `--emitDeclarationOnly`, `--outDir types`, `--skipLibCheck`.
65
- - **Side effects:** немає.
66
-
67
- ### `missingHkEmitTypesConfigFragments(hkText)`
68
-
69
- - **Сигнатура:** `(hkText: string) => string[]`
70
- - **Параметри:** `hkText` — текст hk-конфігурації.
71
- - **Повертає:** список відсутніх фрагментів для layout-у через `tsconfig.emit-types.json`: `["pre-commit"]`, `bunx -p typescript tsc`, `tsconfig.emit-types.json`.
72
- - **Side effects:** немає.
73
-
74
- ### `npmTypesFileFromPackageField(typesField)`
75
-
76
- - **Сигнатура:** `(typesField: unknown) => string | null`
77
- - **Параметри:** `typesField` — значення поля `types` з `npm/package.json`.
78
- - **Повертає:** posix-шлях `npm/<rel>` (наприклад, `npm/types/bin/x.d.ts`) або `null`, якщо значення не починається з `./types/` чи не є рядком.
79
- - **Side effects:** немає.
80
-
81
- ### `checkNpmPackageJson(useSrcJsLayout, passFn, failFn, cwd)`
82
-
83
- - **Сигнатура:** `async (useSrcJsLayout: boolean, passFn, failFn, cwd: string) => Promise<void>`
84
- - **Поведінка:**
85
- - Якщо `npm/package.json` відсутній — нічого не робить (вище у потоці це вже відловлено).
86
- - Для layout `src+js`: очікує існування `npm/types/index.d.ts`.
87
- - Для layout `emit-types`: бере `npm/<types-field>` і перевіряє існування.
88
- - **Викликає:** `passFn(msg)` при успіху, `failFn(msg)` при помилці.
89
- - **Side effects:** читає `npm/package.json`.
90
-
91
- ### `checkEmitTypesConfig(passFn, failFn, cwd)`
92
-
93
- - **Сигнатура:** `(passFn, failFn, cwd: string) => void`
94
- - **Поведінка:** перевіряє лише існування `npm/tsconfig.emit-types.json`. Структуру `compilerOptions` валідує Rego-полісі `npm_module/emit_types_config`.
95
-
96
- ### `checkPublishWorkflow(passFn, failFn, cwd)`
97
-
98
- - **Сигнатура:** `(passFn, failFn, cwd: string) => void`
99
- - **Поведінка:** перевіряє лише існування `.github/workflows/npm-publish.yml`. Структуру полів workflow валідує Rego-полісі `npm_module/npm_publish_yml`.
100
-
101
- ### `globToRegex(glob)` (експортована)
102
-
103
- - **Сигнатура:** `(glob: string) => RegExp`
104
- - **Параметри:** `glob` — posix-шлях у glob-нотації.
105
- - **Повертає:** `RegExp` з якорями `^` / `$` і прапорцем `u`.
106
- - **Підтримка синтаксису:**
107
- - `**` — нуль або більше сегментів (`(?:/.*/|/)` між сегментами, `(?:.*/)?` на початку, `(?:/.*)?` у кінці, `.*` як єдиний токен).
108
- - `*` — будь-які символи без `/` (`[^/]*`).
109
- - `?` — один символ без `/` (`[^/]`).
110
- - `{a,b,c}` — brace-альтернативи (`(?:a|b|c)`).
111
- - **Не підтримує:** клас `[…]` (для негативних патернів `files` цього достатньо).
112
- - **Safety:** усі спецсимволи екрануються через `REGEX_SPECIAL_IN_GLOB`; eslint правило `security/detect-non-literal-regexp` явно вимкнено, бо вхід контрольований (поле `files` з `npm/package.json`).
113
-
114
- ### `collectPublishedFiles(filesField, cwd)`
115
-
116
- - **Сигнатура:** `async (filesField: string[], cwd: string) => Promise<string[]>`
117
- - **Параметри:**
118
- - `filesField` — значення поля `files` з `npm/package.json`.
119
- - `cwd` — корінь репозиторію.
120
- - **Алгоритм:**
121
- 1. Розділяє patterns на позитивні і негативні (за префіксом `!`).
122
- 2. Для кожного позитивного pattern: якщо це файл — додає до `collected`; якщо директорія — рекурсивно через `walkDir` додає всі знайдені файли (posix-шляхи без `npm/` префікса).
123
- 3. Фільтрує: викидає файли, які матчать будь-який негативний `globToRegex`.
124
- 4. Сортує `[].sort()` (лексикографічно) і повертає.
125
- - **Side effects:** `stat()` для кожного позитивного pattern, `walkDir` для директорій.
126
- - **Обмеження:** не дублює всю логіку `npm pack` (LICENSE / README / mandatory files); сканує лише простір імен `files`.
127
-
128
- ### `findTestFrameworkImport(content, virtualPath)` (експортована)
129
-
130
- - **Сигнатура:** `(content: string, virtualPath: string) => string | null`
131
- - **Параметри:**
132
- - `content` — повний текст файлу.
133
- - `virtualPath` — шлях файлу (для вибору `lang` через `langFromPath`).
134
- - **Повертає:** ім'я модуля test-фреймворку (з `TEST_FRAMEWORK_MODULES`), якщо знайдено; `null` інакше.
135
- - **Алгоритм:**
136
- 1. Парсить через `parseSync` із `oxc-parser`; при помилці парсингу — повертає `null` (це не AST-checker для синтаксису).
137
- 2. Якщо `result.errors.length` ≠ 0 — повертає `null`.
138
- 3. Спочатку перевіряє `result.module.staticImports`.
139
- 4. Якщо в static-import не знайдено — обходить AST через `walkAstWithAncestors` і шукає `require(...)` (через `requireCallModule`) та `import(...)` dynamic (через `dynamicImportModule`).
140
- - **Side effects:** немає.
141
-
142
- ### `classifyPublishedFileAsTest(relPath, cwd = process.cwd())` (експортована)
143
-
144
- - **Сигнатура:** `async (relPath: string, cwd?: string) => Promise<string | null>`
145
- - **Параметри:**
146
- - `relPath` — posix-шлях відносно `npm/`.
147
- - `cwd` — корінь репозиторію (за замовчуванням `process.cwd()`).
148
- - **Повертає:** рядок-причину порушення або `null`, якщо файл валідний.
149
- - **Класифікація (за пріоритетом):**
150
- 1. У path є сегмент із `TEST_DIR_NAMES` → `'test-style каталог "<seg>/"'`.
151
- 2. Basename матчить `TEST_FILE_PATTERNS` → `"test-style ім'я файлу"`.
152
- 3. Розширення JS-like і AST містить імпорт test-фреймворку → `'імпорт test-фреймворку "<mod>"'`.
153
- - **Carve-out:** для `rules/<rule-name>/...` сегмент `<rule-name>` (індекс 1) ігнорується, бо це ім'я правила (наприклад, правило з id `test` саме описує конвенцію тестів і не є fixture-каталогом). Подальші сегменти (`rules/<r>/js/<c>/tests/`) продовжують перевірятись.
154
- - **Side effects:** для JS-like розширень — `readFile(join(cwd, 'npm', relPath))`.
155
-
156
- ### `checkNoTestsInPublishedFiles(pass, fail, cwd)`
157
-
158
- - **Сигнатура:** `async (pass, fail, cwd: string) => Promise<void>`
159
- - **Поведінка:**
160
- - Якщо `npm/package.json` відсутній або поле `files` не масив — нічого не робить.
161
- - Інакше збирає файли через `collectPublishedFiles` і прогонить кожен через `classifyPublishedFileAsTest`.
162
- - На порушення викликає `fail(...)` з підказкою додати негативний glob у `files`.
163
- - На повну чистоту — `pass(...)` з кількістю перевірених файлів.
164
-
165
- ### `checkNpmModuleBasicStructure(pass, fail, cwd)`
166
-
167
- - **Сигнатура:** `async (pass, fail, cwd: string) => Promise<void>`
168
- - **Поведінка:** перевіряє наявність `package.json`, директорії `npm/` і `npm/package.json`. Поле `workspaces ∋ "npm"` у кореневому `package.json` валідує Rego.
169
-
170
- ### `check(cwd = process.cwd())` (експортована, головна)
171
-
172
- - **Сигнатура:** `async (cwd?: string) => Promise<number>`
173
- - **Повертає:** `0` — все OK, `1` — є проблеми (через `reporter.getExitCode()`).
174
- - **Алгоритм:**
175
- 1. Створює `createCheckReporter()`, дістає `pass`, `fail`.
176
- 2. `checkNpmModuleBasicStructure` — `package.json`, `npm/`, `npm/package.json`.
177
- 3. `checkNoTestsInPublishedFiles` — компактність tarball.
178
- 4. `loadCursorIgnorePaths(cwd)` для подальшого скану `npm/src`.
179
- 5. `npmSrcTreeHasJsFile` → визначає `useSrcJsLayout`.
180
- 6. `checkNpmPackageJson(useSrcJsLayout, ...)` — поле `types` і відповідний файл на диску.
181
- 7. Якщо НЕ `useSrcJsLayout` — `checkEmitTypesConfig`.
182
- 8. `readHkConfig` → знайти hk; перевірити pre-commit-фрагменти через `missingHkSrcLayoutFragments` або `missingHkEmitTypesConfigFragments` залежно від layout.
183
- 9. `.github/workflows/` існує.
184
- 10. `checkPublishWorkflow` — `npm-publish.yml`.
185
- 11. `return reporter.getExitCode()`.
186
-
187
- ## Залежності
188
-
189
- ### Node.js core
190
-
191
- - `node:fs` — `existsSync`.
192
- - `node:fs/promises` — `readFile`, `stat`.
193
- - `node:path` — `join`, `sep`.
194
-
195
- ### Зовнішні npm
196
-
197
- - `oxc-parser` — `parseSync` для AST-парсингу JS/TS у `findTestFrameworkImport`.
198
-
199
- ### Внутрішні (relative)
200
-
201
- - `../../../scripts/utils/ast-scan-utils.mjs` — `dynamicImportModule`, `langFromPath`, `requireCallModule`, `walkAstWithAncestors`.
202
- - `../../../scripts/lib/check-reporter.mjs` — `createCheckReporter` (повертає `{ pass, fail, getExitCode }`).
203
- - `../../../scripts/lib/load-cursor-config.mjs` — `loadCursorIgnorePaths` (читає `.cursorignore`-подібні шляхи).
204
- - `../../../scripts/utils/walkDir.mjs` — `walkDir(root, callback, ignorePaths?)` для рекурсивного обходу.
205
-
206
- ## Потік виконання / Використання
207
-
208
- ### Базовий потік `check(cwd)`
209
-
210
- ```text
211
- check(cwd)
212
- ├── createCheckReporter() → { pass, fail, getExitCode }
213
- ├── checkNpmModuleBasicStructure(pass, fail, cwd)
214
- │ ├── existsSync(cwd/package.json) ? pass : fail
215
- │ ├── existsSync(cwd/npm) && stat(...).isDirectory() ? pass : fail
216
- │ └── existsSync(cwd/npm/package.json) ? pass : fail
217
- ├── checkNoTestsInPublishedFiles(pass, fail, cwd)
218
- │ ├── readFile(npm/package.json) → pkg
219
- │ ├── if !Array.isArray(pkg.files) → return
220
- │ ├── files = collectPublishedFiles(pkg.files, cwd)
221
- │ └── for rel of files: classifyPublishedFileAsTest(rel, cwd)
222
- ├── ignorePaths = loadCursorIgnorePaths(cwd)
223
- ├── useSrcJsLayout = npmSrcTreeHasJsFile(cwd, ignorePaths)
224
- ├── checkNpmPackageJson(useSrcJsLayout, pass, fail, cwd)
225
- ├── if !useSrcJsLayout → checkEmitTypesConfig(pass, fail, cwd)
226
- ├── hk = readHkConfig(cwd)
227
- │ ├── hk == null → fail (потрібен hk.pkl)
228
- │ └── inakshe →
229
- │ missing = useSrcJsLayout
230
- │ ? missingHkSrcLayoutFragments(hk.text)
231
- │ : missingHkEmitTypesConfigFragments(hk.text)
232
- │ missing.length === 0 ? pass : fail
233
- ├── existsSync(.github/workflows/) ? pass : fail
234
- ├── checkPublishWorkflow(pass, fail, cwd)
235
- └── return reporter.getExitCode()
236
- ```
12
+ globToRegex
13
+ Перетворює glob-патерн у RegExp з якорями `^` та `$`.
237
14
 
238
- ### Точка інтеграції
15
+ findTestFrameworkImport
16
+ Знаходить імпорт модуля тест-фреймворку з контенту файлу.
239
17
 
240
- Цей файл — частина пакету `@nitra/cursor` (`npm/rules/npm-module/js/`). Він викликається CLI `npx @nitra/cursor fix` (або `n-cursor`) у режимі checker правила `npm-module`. Експортована функція `check(cwd?)` — стандартний контракт для checker-ів правил у каталозі `npm/rules/<rule>/js/`.
18
+ classifyPublishedFileAsTest
19
+ Класифікує опублікований файл як test/fixture за ознаками.
241
20
 
242
- ### Розподіл відповідальностей із Rego
21
+ check
22
+ Перевіряє відповідність проєкту правилам (npm-module.mdc).
243
23
 
244
- - **Цей JS:** FS-existence (чи є файл / директорія), AST-сканування (test-imports), glob-обчислення для `files`, cross-file (`package.json` ↔ файли на диску).
245
- - **Rego (`npm/policy/npm_module/`):**
246
- - `npm_package_json` — структура `npm/package.json` (whitelist `files`, заборона `devDependencies`, тощо).
247
- - `emit_types_config` — `compilerOptions` у `npm/tsconfig.emit-types.json`.
248
- - `npm_publish_yml` — поля workflow (`on.push.paths`, `branches`, `id-token: write`, кроки JS-DevTools/npm-publish), парсяться після YAML-parse.
249
- - `root_package_json` — `workspaces ∋ "npm"` у кореневому `package.json`.
24
+ ## Поведінка
250
25
 
251
- ### Приклад інтеграції
26
+ globToRegex
27
+ Перетворює glob-патерн у RegExp з якорями `^` / `$`.
252
28
 
253
- ```js
254
- import { check } from '@nitra/cursor/rules/npm-module/js/package_structure.mjs'
29
+ findTestFrameworkImport
30
+ Знаходить імпорт модуля тест-фреймворку з контенту файлу.
255
31
 
256
- const exitCode = await check(process.cwd())
257
- process.exit(exitCode)
258
- ```
32
+ classifyPublishedFileAsTest
33
+ Класифікує опублікований файл як test/fixture за ознаками.
259
34
 
260
- ### Що НЕ робить файл
35
+ check
36
+ Перевіряє відповідність проєкту правилам npm-module.mdc.
261
37
 
262
- - Не перевіряє узгодженість `version` ↔ `CHANGELOG.md` — це `changelog/js/consistency.mjs` (правило `n-changelog.mdc`).
263
- - Не валідує сам формат AST/синтаксис коду — за помилки парсингу `findTestFrameworkImport` мовчки повертає `null`.
264
- - Не дублює логіку `npm pack` (LICENSE / README / mandatory files) — сканує лише простір імен `files`.
265
- - Не перевіряє вміст Rego-полісі — лише дискову наявність / FS / AST.
38
+ ## Публічний API
266
39
 
267
- ## Rebuild Test
40
+ GlobToRegex перетворює glob-патерн у RegExp з використанням `^` та `$`. Підтримує globstar, `*`, `?` та brace-альтернативи.
41
+ FindTestFrameworkImport — визначає наявність імпорту/require/dynamic-import модуля тест-фреймворку. Парсинг через oxc-parser повертає `null` у разі помилки.
42
+ ClassifyPublishedFileAsTest — відносить опублікований файл до test/fixture, якщо присутні ознаки: каталог з `TEST_DIR_NAMES`, збіг імені файлу з `TEST_FILE_PATTERNS`, або імпорт тест-фреймворку для JS/TS розширень.
43
+ Carve-out — витягує ім'я правила з шляху `rules/<rule-name>/...` (індекс 1), що позначає ім'я правила. Правило з id `test` або `tests` описує конвенцію розміщення тестів, але не є test-fixture. Подальші сегменти продовжують перевірку.
44
+ Check — перевіряє відповідність проєкту правилам npm-module.mdc.
268
45
 
269
- Файл можна повністю відтворити з опису вище:
46
+ ## Гарантії поведінки
270
47
 
271
- - Імпорти: `node:fs` (`existsSync`), `node:fs/promises` (`readFile`, `stat`), `node:path` (`join`, `sep`), `oxc-parser` (`parseSync`), і чотири внутрішні модулі (`ast-scan-utils.mjs`, `check-reporter.mjs`, `load-cursor-config.mjs`, `walkDir.mjs`).
272
- - Константи: `EMIT_TYPES_CONFIG`, `TEST_DIR_NAMES`, `TEST_FILE_PATTERNS`, `JS_LIKE_EXT_RE`, `TEST_FRAMEWORK_MODULES`, `REGEX_SPECIAL_IN_GLOB`, `GLOBSTAR_LEADING_RE`, `GLOBSTAR_TRAILING_RE`.
273
- - Експорти: `globToRegex`, `findTestFrameworkImport`, `classifyPublishedFileAsTest`, `check`.
274
- - Алгоритми описано у секціях "Функції" і "Потік виконання".
48
+ - Read-only: файл не виконує операцій запису у файлову систему.
49
+ - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
50
+ - За невдачі повертає значення помилки (`false`/`null`/`Err`) замість генерування винятку чи паніки.
51
+ - Свідомо пропускає шляхи: `.github`, `.git`.
52
+ - Не звертається до мережі.