@7n/rules-lang-js 0.3.1 → 0.4.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 (258) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/package.json +14 -4
  3. package/rules/bun/bunfig/bunfig.mdc +17 -0
  4. package/rules/bun/bunfig/bunfig.rego +29 -0
  5. package/rules/bun/bunfig/concern.json +9 -0
  6. package/rules/bun/bunfig/template/bunfig.toml.snippet.toml +2 -0
  7. package/rules/bun/docs/index.md +11 -0
  8. package/rules/bun/layout/concern.json +16 -0
  9. package/rules/bun/layout/docs/fix-layout.md +29 -0
  10. package/rules/bun/layout/docs/main.md +34 -0
  11. package/rules/bun/layout/fix-layout.mjs +63 -0
  12. package/rules/bun/layout/layout.mdc +60 -0
  13. package/rules/bun/layout/main.mjs +53 -0
  14. package/rules/bun/licensee/concern.json +7 -0
  15. package/rules/bun/licensee/docs/fix-licensee.md +27 -0
  16. package/rules/bun/licensee/docs/index.md +12 -0
  17. package/rules/bun/licensee/docs/main.md +30 -0
  18. package/rules/bun/licensee/fix-licensee.mjs +31 -0
  19. package/rules/bun/licensee/main.mjs +68 -0
  20. package/rules/bun/lint-surface/concern.json +3 -0
  21. package/rules/bun/lint-surface/lint-surface.mdc +13 -0
  22. package/rules/bun/main.json +1 -0
  23. package/rules/bun/main.mdc +11 -0
  24. package/rules/bun/package_json/concern.json +9 -0
  25. package/rules/bun/package_json/docs/fix-package_json.md +28 -0
  26. package/rules/bun/package_json/docs/index.md +9 -0
  27. package/rules/bun/package_json/fix-package_json.mjs +311 -0
  28. package/rules/bun/package_json/package_json.mdc +14 -0
  29. package/rules/bun/package_json/package_json.rego +64 -0
  30. package/rules/bun/package_json/template/package.json.deny.json +4 -0
  31. package/rules/js/check/check.mdc +26 -0
  32. package/rules/js/check/concern.json +19 -0
  33. package/rules/js/check/docs/eslint-config.md +56 -0
  34. package/rules/js/check/docs/fix-check.md +48 -0
  35. package/rules/js/check/docs/index.md +13 -0
  36. package/rules/js/check/docs/main.md +48 -0
  37. package/rules/js/check/eslint-config.mjs +262 -0
  38. package/rules/js/check/fix-check.mjs +82 -0
  39. package/rules/js/check/main.mjs +310 -0
  40. package/rules/js/dep-policy/concern.json +4 -0
  41. package/rules/js/dep-policy/dep-policy.mdc +36 -0
  42. package/rules/js/dep-policy/docs/main.md +35 -0
  43. package/rules/js/dep-policy/main.mjs +99 -0
  44. package/rules/js/docs/index.md +11 -0
  45. package/rules/js/eslint/concern.json +8 -0
  46. package/rules/js/eslint/docs/fix-eslint.md +50 -0
  47. package/rules/js/eslint/docs/fix-worker.md +31 -0
  48. package/rules/js/eslint/docs/index.md +11 -0
  49. package/rules/js/eslint/docs/main.md +35 -0
  50. package/rules/js/eslint/fix-eslint.mjs +160 -0
  51. package/rules/js/eslint/fix-worker.mjs +139 -0
  52. package/rules/js/eslint/main.mjs +115 -0
  53. package/rules/js/file-extensions/concern.json +3 -0
  54. package/rules/js/file-extensions/file-extensions.mdc +12 -0
  55. package/rules/js/jscpd_config/concern.json +11 -0
  56. package/rules/js/jscpd_config/docs/fix-jscpd_config.md +25 -0
  57. package/rules/js/jscpd_config/docs/index.md +9 -0
  58. package/rules/js/jscpd_config/fix-jscpd_config.mjs +3 -0
  59. package/rules/js/jscpd_config/jscpd_config.mdc +42 -0
  60. package/rules/js/jscpd_config/jscpd_config.rego +44 -0
  61. package/rules/js/jscpd_config/template/.jscpd.json.snippet.json +7 -0
  62. package/rules/js/jscpd_duplicates/concern.json +7 -0
  63. package/rules/js/jscpd_duplicates/docs/main.md +29 -0
  64. package/rules/js/jscpd_duplicates/main.mjs +69 -0
  65. package/rules/js/knip/concern.json +7 -0
  66. package/rules/js/knip/docs/main.md +32 -0
  67. package/rules/js/knip/knip.mdc +15 -0
  68. package/rules/js/knip/main.mjs +68 -0
  69. package/rules/js/lint-findings/concern.json +3 -0
  70. package/rules/js/lint-findings/docs/main.md +40 -0
  71. package/rules/js/lint-findings/main.mjs +125 -0
  72. package/rules/js/main.json +1 -0
  73. package/rules/js/main.mdc +18 -0
  74. package/rules/js/package_json/concern.json +9 -0
  75. package/rules/js/package_json/docs/fix-package_json.md +25 -0
  76. package/rules/js/package_json/docs/index.md +9 -0
  77. package/rules/js/package_json/fix-package_json.mjs +3 -0
  78. package/rules/js/package_json/package_json.mdc +15 -0
  79. package/rules/js/package_json/package_json.rego +142 -0
  80. package/rules/js/package_json/template/package.json.snippet.json +6 -0
  81. package/rules/js/tooling/concern.json +3 -0
  82. package/rules/js/tooling/data/tooling/knip-canonical.json +30 -0
  83. package/rules/js/tooling/data/tooling/oxlint-canonical.json +400 -0
  84. package/rules/js/tooling/docs/main.md +53 -0
  85. package/rules/js/tooling/main.mjs +183 -0
  86. package/rules/js/utils_imports/concern.json +4 -0
  87. package/rules/js/utils_imports/docs/main.md +50 -0
  88. package/rules/js/utils_imports/main.mjs +185 -0
  89. package/rules/js/utils_imports/utils_imports.mdc +15 -0
  90. package/rules/js/vscode_extensions/concern.json +11 -0
  91. package/rules/js/vscode_extensions/docs/fix-vscode_extensions.md +24 -0
  92. package/rules/js/vscode_extensions/docs/index.md +11 -0
  93. package/rules/js/vscode_extensions/fix-vscode_extensions.mjs +1 -0
  94. package/rules/js/vscode_extensions/template/extensions.json.snippet.json +6 -0
  95. package/rules/js/vscode_extensions/vscode_extensions.mdc +11 -0
  96. package/rules/js/vscode_extensions/vscode_extensions.rego +12 -0
  97. package/rules/js-bun-db/connection/concern.json +3 -0
  98. package/rules/js-bun-db/connection/connection.mdc +42 -0
  99. package/rules/js-bun-db/docs/index.md +11 -0
  100. package/rules/js-bun-db/lib/bun-sql-scan.mjs +1047 -0
  101. package/rules/js-bun-db/lib/docs/bun-sql-scan.md +63 -0
  102. package/rules/js-bun-db/lib/docs/index.md +11 -0
  103. package/rules/js-bun-db/main.json +1 -0
  104. package/rules/js-bun-db/main.mdc +8 -0
  105. package/rules/js-bun-db/package_json/concern.json +9 -0
  106. package/rules/js-bun-db/package_json/package_json.mdc +31 -0
  107. package/rules/js-bun-db/package_json/package_json.rego +15 -0
  108. package/rules/js-bun-db/package_json/template/package.json.deny.json +6 -0
  109. package/rules/js-bun-db/pg_format_identifiers/concern.json +3 -0
  110. package/rules/js-bun-db/pg_format_identifiers/pg_format_identifiers.mdc +104 -0
  111. package/rules/js-bun-db/safety/concern.json +4 -0
  112. package/rules/js-bun-db/safety/docs/main.md +34 -0
  113. package/rules/js-bun-db/safety/main.mjs +430 -0
  114. package/rules/js-bun-db/safety/safety.mdc +458 -0
  115. package/rules/js-bun-redis/docs/index.md +11 -0
  116. package/rules/js-bun-redis/imports/concern.json +4 -0
  117. package/rules/js-bun-redis/imports/docs/main.md +36 -0
  118. package/rules/js-bun-redis/imports/imports.mdc +47 -0
  119. package/rules/js-bun-redis/imports/main.mjs +88 -0
  120. package/rules/js-bun-redis/lib/docs/index.md +11 -0
  121. package/rules/js-bun-redis/lib/docs/redis-imports.md +227 -0
  122. package/rules/js-bun-redis/lib/redis-imports.mjs +130 -0
  123. package/rules/js-bun-redis/main.json +1 -0
  124. package/rules/js-bun-redis/main.mdc +8 -0
  125. package/rules/js-bun-redis/package_json/concern.json +9 -0
  126. package/rules/js-bun-redis/package_json/package_json.mdc +11 -0
  127. package/rules/js-bun-redis/package_json/package_json.rego +15 -0
  128. package/rules/js-bun-redis/package_json/template/package.json.deny.json +12 -0
  129. package/rules/js-mssql/deps/concern.json +4 -0
  130. package/rules/js-mssql/deps/docs/main.md +33 -0
  131. package/rules/js-mssql/deps/main.mjs +297 -0
  132. package/rules/js-mssql/docs/index.md +11 -0
  133. package/rules/js-mssql/lib/docs/index.md +11 -0
  134. package/rules/js-mssql/lib/docs/mssql-pool-scan.md +380 -0
  135. package/rules/js-mssql/lib/mssql-pool-scan.mjs +610 -0
  136. package/rules/js-mssql/main.json +1 -0
  137. package/rules/js-mssql/main.mdc +144 -0
  138. package/rules/js-mssql/mssql-tvp/concern.json +3 -0
  139. package/rules/js-mssql/mssql-tvp/mssql-tvp.mdc +77 -0
  140. package/rules/js-mssql/package_json/concern.json +9 -0
  141. package/rules/js-mssql/package_json/package_json.mdc +9 -0
  142. package/rules/js-mssql/package_json/package_json.rego +57 -0
  143. package/rules/js-run/configmap/concern.json +9 -0
  144. package/rules/js-run/configmap/configmap.mdc +37 -0
  145. package/rules/js-run/configmap/configmap.rego +21 -0
  146. package/rules/js-run/configmap/template/configmap.yaml.contains.yml +4 -0
  147. package/rules/js-run/docs/index.md +11 -0
  148. package/rules/js-run/jsconfig/concern.json +9 -0
  149. package/rules/js-run/jsconfig/docs/fix-jsconfig.md +28 -0
  150. package/rules/js-run/jsconfig/docs/index.md +9 -0
  151. package/rules/js-run/jsconfig/fix-jsconfig.mjs +119 -0
  152. package/rules/js-run/jsconfig/jsconfig.mdc +48 -0
  153. package/rules/js-run/jsconfig/jsconfig.rego +59 -0
  154. package/rules/js-run/jsconfig/template/jsconfig.json.snippet.json +10 -0
  155. package/rules/js-run/lib/bunyan-imports.mjs +98 -0
  156. package/rules/js-run/lib/check-env-scan.mjs +338 -0
  157. package/rules/js-run/lib/conn-file-rules.mjs +214 -0
  158. package/rules/js-run/lib/conn-imports-scan.mjs +154 -0
  159. package/rules/js-run/lib/docs/bunyan-imports.md +121 -0
  160. package/rules/js-run/lib/docs/check-env-scan.md +438 -0
  161. package/rules/js-run/lib/docs/conn-file-rules.md +304 -0
  162. package/rules/js-run/lib/docs/conn-imports-scan.md +208 -0
  163. package/rules/js-run/lib/docs/index.md +16 -0
  164. package/rules/js-run/lib/docs/promise-settimeout-scan.md +334 -0
  165. package/rules/js-run/lib/docs/temporal-scan.md +29 -0
  166. package/rules/js-run/lib/promise-settimeout-scan.mjs +128 -0
  167. package/rules/js-run/lib/temporal-scan.mjs +52 -0
  168. package/rules/js-run/main.json +1 -0
  169. package/rules/js-run/main.mdc +16 -0
  170. package/rules/js-run/package_json/concern.json +9 -0
  171. package/rules/js-run/package_json/package_json.mdc +44 -0
  172. package/rules/js-run/package_json/package_json.rego +37 -0
  173. package/rules/js-run/package_json/template/package.json.deny.json +22 -0
  174. package/rules/js-run/project-structure/concern.json +3 -0
  175. package/rules/js-run/project-structure/project-structure.mdc +11 -0
  176. package/rules/js-run/runtime/concern.json +12 -0
  177. package/rules/js-run/runtime/docs/fix-runtime.md +27 -0
  178. package/rules/js-run/runtime/docs/main.md +35 -0
  179. package/rules/js-run/runtime/fix-runtime.mjs +46 -0
  180. package/rules/js-run/runtime/main.mjs +496 -0
  181. package/rules/js-run/runtime/runtime.mdc +184 -0
  182. package/rules/js-run/scope/concern.json +3 -0
  183. package/rules/js-run/scope/scope.mdc +11 -0
  184. package/rules/npm-module/docs/index.md +11 -0
  185. package/rules/npm-module/emit_types_config/concern.json +9 -0
  186. package/rules/npm-module/emit_types_config/docs/fix-emit_types_config.md +25 -0
  187. package/rules/npm-module/emit_types_config/docs/index.md +9 -0
  188. package/rules/npm-module/emit_types_config/emit_types_config.mdc +43 -0
  189. package/rules/npm-module/emit_types_config/emit_types_config.rego +28 -0
  190. package/rules/npm-module/emit_types_config/fix-emit_types_config.mjs +5 -0
  191. package/rules/npm-module/emit_types_config/template/tsconfig.emit-types.json.snippet.json +9 -0
  192. package/rules/npm-module/header_doc_pointer/concern.json +5 -0
  193. package/rules/npm-module/header_doc_pointer/docs/main.md +40 -0
  194. package/rules/npm-module/header_doc_pointer/header_doc_pointer.mdc +18 -0
  195. package/rules/npm-module/header_doc_pointer/main.mjs +131 -0
  196. package/rules/npm-module/main.json +1 -0
  197. package/rules/npm-module/main.mdc +36 -0
  198. package/rules/npm-module/npm_package_json/concern.json +9 -0
  199. package/rules/npm-module/npm_package_json/docs/fix-npm_package_json.md +26 -0
  200. package/rules/npm-module/npm_package_json/docs/index.md +9 -0
  201. package/rules/npm-module/npm_package_json/fix-npm_package_json.mjs +5 -0
  202. package/rules/npm-module/npm_package_json/npm_package_json.mdc +57 -0
  203. package/rules/npm-module/npm_package_json/npm_package_json.rego +73 -0
  204. package/rules/npm-module/npm_package_json/template/package.json.snippet.json +1 -0
  205. package/rules/npm-module/package_structure/concern.json +5 -0
  206. package/rules/npm-module/package_structure/docs/main.md +37 -0
  207. package/rules/npm-module/package_structure/main.mjs +448 -0
  208. package/rules/npm-module/package_structure/package_structure.mdc +63 -0
  209. package/rules/npm-module/root_package_json/concern.json +9 -0
  210. package/rules/npm-module/root_package_json/docs/fix-root_package_json.md +25 -0
  211. package/rules/npm-module/root_package_json/docs/index.md +9 -0
  212. package/rules/npm-module/root_package_json/fix-root_package_json.mjs +5 -0
  213. package/rules/npm-module/root_package_json/root_package_json.mdc +41 -0
  214. package/rules/npm-module/root_package_json/root_package_json.rego +28 -0
  215. package/rules/npm-module/root_package_json/template/package.json.snippet.json +1 -0
  216. package/rules/npm-module/rule_meta/concern.json +8 -0
  217. package/rules/npm-module/rule_meta/docs/main.md +35 -0
  218. package/rules/npm-module/rule_meta/main.mjs +119 -0
  219. package/rules/npm-module/rule_meta/rule_meta.mdc +11 -0
  220. package/rules/npm-module/skill_meta/concern.json +5 -0
  221. package/rules/npm-module/skill_meta/docs/main.md +149 -0
  222. package/rules/npm-module/skill_meta/main.mjs +91 -0
  223. package/rules/npm-module/skill_meta/skill_meta.mdc +11 -0
  224. package/rules/tool-surface/docs/index.md +11 -0
  225. package/rules/tool-surface/main.json +6 -0
  226. package/rules/tool-surface/main.mdc +72 -0
  227. package/rules/vue/composition-api/composition-api.mdc +82 -0
  228. package/rules/vue/composition-api/concern.json +3 -0
  229. package/rules/vue/docs/index.md +11 -0
  230. package/rules/vue/lib/docs/index.md +11 -0
  231. package/rules/vue/lib/docs/vue-forbidden-imports.md +265 -0
  232. package/rules/vue/lib/vue-forbidden-imports.mjs +240 -0
  233. package/rules/vue/main.json +1 -0
  234. package/rules/vue/main.mdc +18 -0
  235. package/rules/vue/nheader-layout/concern.json +3 -0
  236. package/rules/vue/nheader-layout/nheader-layout.mdc +171 -0
  237. package/rules/vue/package_json/concern.json +9 -0
  238. package/rules/vue/package_json/package_json.mdc +30 -0
  239. package/rules/vue/package_json/package_json.rego +140 -0
  240. package/rules/vue/packages/concern.json +6 -0
  241. package/rules/vue/packages/docs/index.md +11 -0
  242. package/rules/vue/packages/docs/main.md +35 -0
  243. package/rules/vue/packages/main.mjs +575 -0
  244. package/rules/vue/packages/packages.mdc +56 -0
  245. package/rules/vue/quasar-ui/concern.json +3 -0
  246. package/rules/vue/quasar-ui/quasar-ui.mdc +32 -0
  247. package/rules/vue/structure/concern.json +3 -0
  248. package/rules/vue/structure/structure.mdc +101 -0
  249. package/rules/vue/testing/concern.json +3 -0
  250. package/rules/vue/testing/testing.mdc +40 -0
  251. package/rules/vue/tfm-translations/concern.json +7 -0
  252. package/rules/vue/tfm-translations/docs/main.md +29 -0
  253. package/rules/vue/tfm-translations/main.mjs +55 -0
  254. package/rules/vue/tfm-translations/tfm-translations.mdc +32 -0
  255. package/rules/vue/vite-config/concern.json +3 -0
  256. package/rules/vue/vite-config/vite-config.mdc +153 -0
  257. package/rules/vue/vite-env/concern.json +3 -0
  258. package/rules/vue/vite-env/vite-env.mdc +61 -0
@@ -0,0 +1,184 @@
1
+ ## Runtime у `package.json#scripts`
2
+
3
+ У **backend**-пакетах (без `vite` у `devDependencies`) код запускають через **Bun**, не через бінарник **`node`** у значеннях `scripts`:
4
+
5
+ - `"start": "node src/index.js"` → `"start": "bun src/index.js"` (або `bun run …`, якщо так прийнято в репо);
6
+ - `node --watch app.js` → `bun --watch app.js`;
7
+ - `NODE_OPTIONS=… node app.js` → `NODE_OPTIONS=… bun app.js`.
8
+ - `env $(cat .env .env.local) bun src/index.js` → `bun --env-file=.env --env-file=.env.local src/index.js` (нативне завантаження env у Bun, без `env`/`cat`).
9
+
10
+ Заборонено викликати **`node`** у ланцюжках (`&&`, `;`, `|`). Заборонено обгортку **`env $(cat …) bun`** — файли з `cat` перелічуй у **`--env-file=`** (по одному прапорцю на файл, порядок як у `cat`). Допустимо: `bun`, `bunx`, `npx` (див. **bun.mdc**), інші CLI, якщо вони не підміняють рантайм на `node`.
11
+
12
+ Це **не** стосується поля `engines.node` (мінімальна версія Node для сумісності інструментів) і **не** стосується frontend-пакетів з `vite` у `devDependencies`.
13
+
14
+ Канон заборонених патернів у `scripts`: [package.json.deny.json](./policy/package_json/template/package.json.deny.json) (`scriptsForbidden`).
15
+
16
+ ## CheckEnv та заборона прямого `process.env`
17
+
18
+ ### CheckEnv
19
+
20
+ Усі змінні оточення, які використовуються в коді, повинні бути перевірені за допомогою `checkEnv` з пакету `@nitra/check-env`. Це гарантує, що всі необхідні змінні оточення встановлені перед запуском програми.
21
+
22
+ ```javascript title="Приклад підключення до PostgreSQL в /src/conn/pg.mjs"
23
+ import { checkEnv, env } from '@nitra/check-env'
24
+ import { SQL } from 'bun'
25
+
26
+ checkEnv(['PG_CONN'])
27
+
28
+ export const db = new SQL({ url: env.PG_CONN })
29
+
30
+ ```
31
+
32
+ ### process.env
33
+
34
+ Прямий доступ до `process.env.X` у коді заборонений — його треба замінити на `env`:
35
+
36
+ > Стосується лише backend-пакетів (див. **Область застосування**). У frontend-пакетах (`vite` у `devDependencies`) — **не змінюй** `process.env.*` і **не додавай** імпорт `node:process`.
37
+
38
+ - **обов'язкова змінна** — `import { checkEnv, env } from '@nitra/check-env'` плюс `checkEnv(['X'])`
39
+ у тому ж файлі (приклад див. вище в розділі **CheckEnv**);
40
+ - **опційна змінна** — `import { env } from 'node:process'`:
41
+
42
+ ```javascript title="Опційна змінна — env з node:process"
43
+ import { env } from 'node:process'
44
+
45
+ console.log(env.OPTIONAL_ENV_VAR)
46
+ ```
47
+
48
+ Тимчасово приглушити перевірку для конкретного рядка можна коментарем
49
+ `// @7n/rules ignore-next-line checkEnv` безпосередньо перед використанням
50
+ (escape-hatch для legacy-коду, не для нових файлів).
51
+
52
+ Перевірка (JS-сканер): `../lib/check-env-scan.mjs`.
53
+
54
+ ## Внутрішні аліаси для підключень до БД і GraphQL
55
+
56
+ Якщо в проекті є підключення до баз даних, зовнішніх graphql на кшталт:
57
+
58
+ ```js
59
+ import { SQL } from 'bun'
60
+
61
+ // або
62
+
63
+ import sql from 'mssql'
64
+
65
+ // або
66
+
67
+ import { GraphQLClient } from '@nitra/graphql-request'
68
+ ```
69
+
70
+ то ці підключення повинні бути винесені в окремий файл, наприклад `/src/conn/pg.mjs`, в package.json повинні бути додано аліас:
71
+
72
+ ```json
73
+ {
74
+ "imports": {
75
+ "#conn/*": "./src/conn/*"
76
+ },
77
+ }
78
+
79
+ ```
80
+
81
+ так виглядатиме підключення до PostgreSQL в коді:
82
+
83
+ ```javascript title="Приклад підключення до PostgreSQL в /src/conn/pg.mjs"
84
+ import { checkEnv, env } from '@nitra/check-env'
85
+ import { SQL } from 'bun'
86
+
87
+ checkEnv(['PG_CONN'])
88
+
89
+ export const db = new SQL({ url: env.PG_CONN })
90
+
91
+ ```
92
+
93
+ а так до GraphQL:
94
+
95
+ ```js
96
+ import { checkEnv, env } from '@nitra/check-env'
97
+ import { GraphQLClient } from '@nitra/graphql-request'
98
+
99
+ checkEnv(['QL', 'X_HASURA_ADMIN_SECRET'])
100
+
101
+ export { gql } from '@nitra/graphql-request'
102
+
103
+ export const graphQLClientSmart = new GraphQLClient(env.QL, {
104
+ headers: {
105
+ 'X-Hasura-Admin-Secret': env.X_HASURA_ADMIN_SECRET
106
+ }
107
+ })
108
+ ```
109
+
110
+ а в коді повинно бути використано:
111
+
112
+ ```js
113
+ import { pool } from '#conn/pg.mjs'
114
+
115
+ // або
116
+
117
+ import { gql, graphQLClient } from '@nitra/graphql-request'
118
+ ```
119
+
120
+ ### Нейминг файлів у `src/conn/`
121
+
122
+ Назва файла в `src/conn/` має одразу повідомляти, **до чого** підключаємось і **в якому режимі**:
123
+
124
+ - **GraphQL** — префікс `ql-`, далі ідентифікатор endpoint:
125
+ - `src/conn/ql-contract.mjs`
126
+ - `src/conn/ql-smart.mjs`
127
+ - **PostgreSQL** — префікс `pg-`, далі тип підключення (репліка vs мастер): `read` або `write`:
128
+ - `src/conn/pg-read.mjs`
129
+ - `src/conn/pg-write.mjs`
130
+ - **PostgreSQL до кількох БД** — додатково ідентифікатор підключення після типу:
131
+ - `src/conn/pg-read-smart.mjs`
132
+ - `src/conn/pg-write-contract.mjs`
133
+ - **MySQL** — префікс `mysql-` за тією ж схемою (`mysql-read.mjs`, `mysql-write-<id>.mjs` тощо).
134
+ - **MSSQL** — префікс `mssql-` за тією ж схемою (`mssql-read.mjs`, `mssql-write-<id>.mjs` тощо). Хоча npm-пакет один (`mssql`), а драйвер MS SQL Server під капотом T-SQL — у файловій назві відрізняємо MS SQL Server від MySQL, бо це різні СУБД, різні діалекти, різні рантаймні залежності. Якщо проєкт історично використовує `mysql-…` для MSSQL-підключень — він валідний і далі (для backward-compat), але новий код пишемо з префіксом `mssql-`.
135
+
136
+ Підключення до БД **обов'язково** має бути ідентифіковано як `read` (репліка) або `write` (мастер). Якщо з імені змінної оточення (наприклад, `env.PG_CONN`) це не очевидно — визнач режим за операціями в коді: якщо немає операцій зміни даних (`INSERT`/`UPDATE`/`DELETE`/DDL) — це `pg-read.mjs`, інакше `pg-write.mjs`.
137
+
138
+ ### Експорти у файлах `src/conn/`
139
+
140
+ У файлах підключень **заборонений** `export default`. Експорт має бути **іменований** і збігатися з назвою файла в camelCase.
141
+
142
+ Приклад — `src/conn/ql-smart.mjs`:
143
+
144
+ ```javascript title="❌ Так не можна"
145
+ export default new GraphQLClient(env.SMART_QL, {
146
+ headers: {
147
+ 'X-Hasura-Admin-Secret': env.SMART_X_HASURA_ADMIN_SECRET
148
+ }
149
+ })
150
+ ```
151
+
152
+ ```javascript title="✅ Канон: іменований експорт за іменем файла"
153
+ export const qlSmart = new GraphQLClient(env.SMART_QL, {
154
+ headers: {
155
+ 'X-Hasura-Admin-Secret': env.SMART_X_HASURA_ADMIN_SECRET
156
+ }
157
+ })
158
+ ```
159
+
160
+ Відповідно: `pg-read.mjs` → `export const pgRead = …`, `pg-write-contract.mjs` → `export const pgWriteContract = …`, `ql-contract.mjs` → `export const qlContract = …`.
161
+
162
+ Файли `index.*` у conn-каталозі пропускаються як можливий reexport-барель.
163
+
164
+ Перевірка (JS-сканери): `../lib/conn-file-rules.mjs` (нейминг, експорти), `../lib/conn-imports-scan.mjs` (факторні імпорти поза `src/conn/`); декларація аліаса `imports["#conn/*"]` у `package.json` — `checkConnAliasDeclaration` у `main.mjs`.
165
+
166
+ ## Паузи через setTimeout
167
+
168
+ Заборонено робити паузи через `await new Promise(resolve => setTimeout(resolve, ms))` — таку обгортку треба замінити на promise-варіант `setTimeout` з `node:timers/promises`:
169
+
170
+ ```javascript title="Замість new Promise + setTimeout"
171
+ import { setTimeout } from 'node:timers/promises'
172
+
173
+ await setTimeout(500)
174
+ ```
175
+
176
+ Імпорт `setTimeout` з `node:timers/promises` затіняє глобальний таймер у файлі — якщо в тому ж файлі потрібен callback-варіант, імпортуй його під іншим іменем (наприклад, `import { setTimeout as setTimeoutCb } from 'node:timers'`).
177
+
178
+ Перевірка (JS-сканер): `../lib/promise-settimeout-scan.mjs`.
179
+
180
+ ## Temporal API (заборона у Bun runtime)
181
+
182
+ У backend/Bun runtime-коді **не використовуй `Temporal`** (`Temporal.Now`, `Temporal.Instant`, імпорти з polyfill тощо). Bun 1.3.x (діапазон версій репозиторію — `bun >= 1.3`) ще не має глобального `Temporal` (`typeof Temporal === "undefined"`), тому агентам треба лишатися на сумісному `Date` API або передавати timestamp у чисті функції через параметр.
183
+
184
+ Перевірка `npx @7n/rules check` (AST-сканер `../lib/temporal-scan.mjs`) сканує JS/TS-код на identifier `Temporal` у backend workspace-коді.
@@ -0,0 +1,3 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json"
3
+ }
@@ -0,0 +1,11 @@
1
+ ## Область застосування
2
+
3
+ Правило стосується **виключно backend Node.js workspace-пакетів** (jobs, GraphQL/HTTP-сервери, CLI). **Не застосовується** до frontend-пакетів, які бандляться в браузер: маркер — наявність `vite` у `devDependencies` пакета (`site/`, мобільні Capacitor-пакети, будь-яка Vue/Quasar SPA).
4
+
5
+ У браузерному середовищі:
6
+
7
+ - немає `node:process` — імпорт `import { env } from 'node:process'` resolve'иться у `undefined`, і `env.X` падає з `TypeError: Cannot read properties of undefined`;
8
+ - `process.env.X` у джерелах пакета відсутнє в рантаймі — Vite або взагалі не підставляє його, або підставляє лише `process.env.NODE_ENV`;
9
+ - усі змінні оточення для frontend задаються через `VITE_*` і доступні як `import.meta.env.VITE_X` (типобезпечно через `vite-check-env`); режим — `import.meta.env.MODE` / `import.meta.env.PROD`.
10
+
11
+ Тому **у frontend-пакетах не торкайся `process.env.*`** і **не додавай** `import { env } from 'node:process'`. Якщо натрапив на `process.env.NODE_ENV` у frontend-коді — заміна, якщо взагалі потрібна, лише на `import.meta.env.MODE`.
@@ -0,0 +1,11 @@
1
+ ---
2
+ type: Directory Index
3
+ title: npm/rules/npm-module
4
+ resource: plugins/lang-js/rules/npm-module/
5
+ ---
6
+
7
+ # npm/rules/npm-module
8
+
9
+ | Файл | Тип |
10
+ | ------------------- | --------- |
11
+ | [main.mjs](main.md) | JS Module |
@@ -0,0 +1,9 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
3
+ "fixability": "config",
4
+ "policy": {
5
+ "files": {
6
+ "single": "npm/tsconfig.emit-types.json"
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,25 @@
1
+ ---
2
+ type: JS Module
3
+ title: fix-emit_types_config.mjs
4
+ resource: plugins/lang-js/rules/npm-module/emit_types_config/fix-emit_types_config.mjs
5
+ docgen:
6
+ crc: c13c69a5
7
+ model: openai-codex/gpt-5.4-mini
8
+ score: 100
9
+ issues: judge:inaccurate:0.99
10
+ judgeModel: openai-codex/gpt-5.4-mini
11
+ ---
12
+
13
+ ## Огляд
14
+
15
+ `patterns` читає `tsconfig.emit-types.json` як базовий конфіг, щоб перевіряти й підтримувати узгодженість шаблонного правила для emit-types. Це read-only джерело поведінки: воно формує очікування для контракту конфіга без записів у ФС чи БД.
16
+
17
+ ## Поведінка
18
+
19
+ 1. `patterns` визначає набір правил для синхронізації шаблонного конфіга `tsconfig.emit-types.json` у `npm/tsconfig.emit-types.json`.
20
+ 2. `patterns` слугує джерелом одного цільового виправлення для підтримки узгодженості між базовим конфігом і npm-варіантом.
21
+ 3. `patterns` не виконує запис у файлову систему чи базу даних самостійно; воно лише описує, що саме має бути виправлено.
22
+
23
+ ## Гарантії поведінки
24
+
25
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -0,0 +1,9 @@
1
+ ---
2
+ type: Directory Index
3
+ title: npm/rules/npm-module/emit_types_config
4
+ resource: plugins/lang-js/rules/npm-module/emit_types_config/
5
+ ---
6
+
7
+ | Файл | Тип |
8
+ | ----------------------------------------------------- | --------- |
9
+ | [fix-emit_types_config.mjs](fix-emit_types_config.md) | JS Module |
@@ -0,0 +1,43 @@
1
+ ## Rego-gate: конфігурація генерації типів `npm/tsconfig.emit-types.json`
2
+
3
+ Rego-пакет: `npm-module.emit_types_config`
4
+
5
+ Цільовий файл: `npm/tsconfig.emit-types.json`
6
+
7
+ ### Що перевіряється
8
+
9
+ Leaf-by-leaf порівняння з канонічним сніпетом (через `--data`): кожне поле всередині `compilerOptions` має точно відповідати очікуваному значенню. Якщо секція `compilerOptions` відсутня або не є обʼєктом — окрема deny-помилка.
10
+
11
+ Канонічний сніпет: [tsconfig.emit-types.json.snippet.json](./template/tsconfig.emit-types.json.snippet.json)
12
+
13
+ ### Допустимі відхилення
14
+
15
+ Додаткові поля у `compilerOptions` (наприклад `rootDir`, `baseUrl`) не спричиняють помилку — перевіряється лише наявність і коректність обовʼязкових ключів зі сніпету.
16
+
17
+ ### Приклади
18
+
19
+ ✓ Правильно:
20
+
21
+ ```json
22
+ {
23
+ "compilerOptions": {
24
+ "allowJs": true,
25
+ "declaration": true,
26
+ "emitDeclarationOnly": true,
27
+ "outDir": "types",
28
+ "skipLibCheck": true
29
+ }
30
+ }
31
+ ```
32
+
33
+ ✗ Неправильно — неправильний `outDir`:
34
+
35
+ ```json
36
+ { "compilerOptions": { "outDir": "dist" } }
37
+ ```
38
+
39
+ ✗ Неправильно — відсутній `compilerOptions`:
40
+
41
+ ```json
42
+ {}
43
+ ```
@@ -0,0 +1,28 @@
1
+ # Перевірка `npm/tsconfig.emit-types.json` (npm-module.mdc).
2
+ #
3
+ # Канон надходить через --data: { "template": { "snippet": ... } }
4
+ # Структура --data сформована з template/tsconfig.emit-types.json.snippet.json.
5
+ # Snippet — 2-рівнева мапа (section → key → expected). Walker такий самий,
6
+ # як для ga.vscode_settings / bun.bunfig.
7
+ package npm_module.emit_types_config
8
+
9
+ import rego.v1
10
+
11
+ # Leaf-by-leaf: коли section присутня й обʼєкт.
12
+ deny contains msg if {
13
+ some section, expected_inner in data.template.snippet
14
+ inner := object.get(input, section, {})
15
+ is_object(inner)
16
+ some leaf_key, expected_value in expected_inner
17
+ actual := object.get(inner, leaf_key, null)
18
+ actual != expected_value
19
+ msg := sprintf("npm/tsconfig.emit-types.json: %s.%s має бути %v (npm-module.mdc)", [section, leaf_key, expected_value])
20
+ }
21
+
22
+ # Section відсутня (null) або не обʼєкт.
23
+ deny contains msg if {
24
+ some section in object.keys(data.template.snippet)
25
+ raw := object.get(input, section, null)
26
+ not is_object(raw)
27
+ msg := sprintf("npm/tsconfig.emit-types.json: відсутній %s (npm-module.mdc)", [section])
28
+ }
@@ -0,0 +1,5 @@
1
+ import { createTemplateFixPattern } from '@7n/rules/scripts/lib/fix/template-deep-merge.mjs'
2
+
3
+ export const patterns = [
4
+ createTemplateFixPattern({ id: 'npm-module-emit_types_config-template', targetPath: 'npm/tsconfig.emit-types.json' })
5
+ ]
@@ -0,0 +1,9 @@
1
+ {
2
+ "compilerOptions": {
3
+ "allowJs": true,
4
+ "declaration": true,
5
+ "emitDeclarationOnly": true,
6
+ "outDir": "types",
7
+ "skipLibCheck": true
8
+ }
9
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
3
+ "fixability": "config",
4
+ "lint": { "scope": "full", "glob": ["npm/rules/**/js/**/*.mjs", "npm/skills/**/js/**/*.mjs"] }
5
+ }
@@ -0,0 +1,40 @@
1
+ ---
2
+ type: JS Module
3
+ title: main.mjs
4
+ resource: plugins/lang-js/rules/npm-module/header_doc_pointer/main.mjs
5
+ docgen:
6
+ crc: 63a40982
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
9
+ issues: judge:inaccurate:0.98
10
+ judgeModel: openai-codex/gpt-5.4-mini
11
+ ---
12
+
13
+ ## Огляд
14
+
15
+ Файл забезпечує валідацію відповідності конвенціям документації для файлів правил, розташованих у директорії `.cursor/rules/`, та файлів навичок у `.cursor/skills/`. Він сканує кодову базу у директорії `js/` для пошуку файлів документації, перевіряючи, чи не перевищує JSDoc-блок довжину одного рядка для опису поведінки кожного файлу правила або навички.
16
+
17
+ ## Поведінка
18
+
19
+ Поведінка:
20
+
21
+ 1. Викликається `main`.
22
+ 2. Створюється репортер.
23
+ 3. Для сегментів `npm/rules` та `npm/skills` сканується кожен піддиректорія правил або скілів.
24
+ 4. Для кожної піддиректорії перевіряється її каталог `js/`.
25
+ 5. У каталозі `js/` скануються всі файли з розширенням `.mjs`, окрім тестів.
26
+ 6. Для кожного знайденого файлу:
27
+ а. Визначається відповідний файл документації у `docs/`, використовуючи ім'я без розширення.
28
+ б. Якщо такий файл документації існує, аналізується перше заголовочне JSDoc-блоку у коді.
29
+ в. Якщо JSDoc-блок відсутній, перехід до наступного файлу.
30
+ г. Якщо JSDoc-блок присутній, рахується кількість непустіших рядків у його тілі, ігноруючи відступ.
31
+ д. Якщо ця кількість перевищує один, це реєструється як порушення, оскільки документ повинен лише посилатися на поведінку.
32
+ 7. Після обробки всіх файлів повертається код виходу репортера.
33
+
34
+ ## Публічний API
35
+
36
+ main — сканує файли правил у директоріях `npm/rules/*\/js/*.mjs` та `npm/skills/*\/js/*.mjs`, а також керує генерацією документації, посилаючись на існуючі файли `docs/<stem>.md`.
37
+
38
+ ## Гарантії поведінки
39
+
40
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -0,0 +1,18 @@
1
+ ## Module-level JSDoc як pointer
2
+
3
+ Якщо поряд із `js/<stem>.mjs` є файл `js/docs/<stem>.md` — module-level JSDoc у `.mjs` має бути **pointer** (не більше одного непорожнього рядка), а не повноцінний наратив.
4
+
5
+ Логіка перевірки (`header_doc_pointer.mjs`):
6
+
7
+ - Сканується перший JSDoc-блок (`/** … */`) до першого `import`/`export` у файлі.
8
+ - Підраховуються непорожні рядки тіла (після зрізання `*`-відступу).
9
+ - Якщо їх більше одного — `check` падає з повідомленням про те, що `docs/<stem>.md` вже описує поведінку і module-level JSDoc має залишатись коротким.
10
+
11
+ **Покриття:** `npm/rules/*/js/*.mjs` і `npm/skills/*/js/*.mjs` (не тестові файли `*.test.mjs`). Якщо `docs/<stem>.md` відсутня — обмежень на довжину JSDoc немає.
12
+
13
+ **Приклад правильного pointer-JSDoc:**
14
+
15
+ ```js
16
+ /** @see ./docs/package_structure.md */
17
+ import { existsSync } from 'node:fs'
18
+ ```
@@ -0,0 +1,131 @@
1
+ /** Контракт: ./docs/header_doc_pointer.md */
2
+ import { existsSync } from 'node:fs'
3
+ import { readFile, readdir } from 'node:fs/promises'
4
+ import { basename, join } from 'node:path'
5
+
6
+ import { createViolationReporter } from '@7n/rules/scripts/lib/lint-surface/violation-reporter.mjs'
7
+
8
+ /** Перший JSDoc-блок у файлі (не-жадібний). */
9
+ const MODULE_JSDOC_RE = /\/\*\*[\s\S]*?\*\//
10
+
11
+ /**
12
+ * `import` або `export` на початку рядка — межа між module-level і body.
13
+ * Regex, не AST: нас цікавить тільки текстова позиція, не семантика JS.
14
+ */
15
+ const CODE_START_RE = /^(?:import|export)\b/m
16
+
17
+ const NON_WHITESPACE_RE = /\S/
18
+ const STAR_INDENT_RE = /^\s*\*\s?/
19
+
20
+ /**
21
+ * Кількість непорожніх рядків між `/**` і `*\/` (після зрізання `*`-відступу).
22
+ * @param {string} block повний текст JSDoc-блоку з обрамленням
23
+ * @returns {number} кількість непорожніх рядків у тілі
24
+ */
25
+ function contentLineCount(block) {
26
+ return block
27
+ .split('\n')
28
+ .slice(1, -1)
29
+ .filter(l => NON_WHITESPACE_RE.test(l.replace(STAR_INDENT_RE, ''))).length
30
+ }
31
+
32
+ /**
33
+ * Повертає module-level JSDoc або `null`, якщо його немає.
34
+ * @param {string} source вміст mjs-файлу
35
+ * @returns {string|null} текст module-level JSDoc-блоку або null
36
+ */
37
+ function moduleJsDoc(source) {
38
+ const codeStart = CODE_START_RE.exec(source)
39
+ const prefix = codeStart ? source.slice(0, codeStart.index) : source
40
+ const m = MODULE_JSDOC_RE.exec(prefix)
41
+ return m ? m[0] : null
42
+ }
43
+
44
+ /**
45
+ * Чи `.mjs`-файл, що не є тестом (`*.test.mjs`).
46
+ * @param {import('node:fs').Dirent} fileEntry запис каталогу
47
+ * @returns {boolean} true для звичайних source-файлів
48
+ */
49
+ function isSourceMjs(fileEntry) {
50
+ return fileEntry.isFile() && fileEntry.name.endsWith('.mjs') && !fileEntry.name.endsWith('.test.mjs')
51
+ }
52
+
53
+ /**
54
+ * Перевіряє один source-файл: якщо поряд є `docs/<stem>.md` і module-level JSDoc
55
+ * містить >1 непорожній рядок — репортить порушення.
56
+ * @param {string} jsDir каталог `js/`
57
+ * @param {import('node:fs').Dirent} fileEntry запис файлу
58
+ * @param {string} cwd корінь репозиторію
59
+ * @param {ReturnType<typeof createViolationReporter>} reporter репортер
60
+ * @returns {Promise<void>}
61
+ */
62
+ async function checkSourceFile(jsDir, fileEntry, cwd, reporter) {
63
+ const stem = basename(fileEntry.name, '.mjs')
64
+ const docsPath = join(jsDir, 'docs', `${stem}.md`)
65
+ if (!existsSync(docsPath)) return
66
+
67
+ const filePath = join(jsDir, fileEntry.name)
68
+ const source = await readFile(filePath, 'utf8')
69
+ const block = moduleJsDoc(source)
70
+ if (!block) return
71
+
72
+ const count = contentLineCount(block)
73
+ if (count > 1) {
74
+ reporter.fail(
75
+ `${filePath.slice(cwd.length + 1)}: docs/${stem}.md вже описує поведінку — module-level JSDoc має бути pointer (≤1 рядок, зараз ${count})`
76
+ )
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Перевіряє всі source-файли в одному `js/`-каталозі правила/скіла.
82
+ * @param {string} jsDir каталог `js/`
83
+ * @param {string} cwd корінь репозиторію
84
+ * @param {ReturnType<typeof createViolationReporter>} reporter репортер
85
+ * @returns {Promise<void>}
86
+ */
87
+ async function checkJsDir(jsDir, cwd, reporter) {
88
+ for (const fileEntry of await readdir(jsDir, { withFileTypes: true })) {
89
+ if (!isSourceMjs(fileEntry)) continue
90
+ await checkSourceFile(jsDir, fileEntry, cwd, reporter)
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Перевіряє один base-сегмент (`npm/rules` чи `npm/skills`): обходить піддиректорії
96
+ * правил/скілів і їхні `js/`-каталоги.
97
+ * @param {string} absBase абсолютний шлях до base-сегмента
98
+ * @param {string} cwd корінь репозиторію
99
+ * @param {ReturnType<typeof createViolationReporter>} reporter репортер
100
+ * @returns {Promise<void>}
101
+ */
102
+ async function checkBaseSegment(absBase, cwd, reporter) {
103
+ for (const ruleEntry of await readdir(absBase, { withFileTypes: true })) {
104
+ if (!ruleEntry.isDirectory() || ruleEntry.name.startsWith('.')) continue
105
+
106
+ const jsDir = join(absBase, ruleEntry.name, 'js')
107
+ if (!existsSync(jsDir)) continue
108
+
109
+ await checkJsDir(jsDir, cwd, reporter)
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Сканує `npm/rules/*\/js/*.mjs` і `npm/skills/*\/js/*.mjs`.
115
+ * Якщо поряд існує `docs/<stem>.md` — module-level JSDoc має бути pointer (≤1 рядок),
116
+ * а не наратив; якщо docs немає — без обмежень.
117
+ * @param {import('@7n/rules/scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту (cwd, репортер).
118
+ * @returns {Promise<import('@7n/rules/scripts/lib/lint-surface/types.mjs').LintResult>} результат перевірки з pass/fail.
119
+ */
120
+ export async function lint(ctx) {
121
+ const cwd = ctx.cwd
122
+ const reporter = createViolationReporter(ctx)
123
+
124
+ for (const baseSegment of ['npm/rules', 'npm/skills']) {
125
+ const absBase = join(cwd, baseSegment)
126
+ if (!existsSync(absBase)) continue
127
+ await checkBaseSegment(absBase, cwd, reporter)
128
+ }
129
+
130
+ return reporter.result()
131
+ }
@@ -0,0 +1 @@
1
+ { "auto": { "glob": "npm/**" } }
@@ -0,0 +1,36 @@
1
+ ---
2
+ description: Оформлення репозиторію для npm модуля
3
+ globs: "npm/**,**/package.json,**/hk.pkl,.github/workflows/npm-publish.yml,**/tsconfig*.json"
4
+ alwaysApply: false
5
+ version: '1.14'
6
+ ---
7
+
8
+ Bun monorepo: workspace **`npm/`**, кореневий **`package.json`**, **`.github/workflows/`**; опційно **`demo/`**.
9
+
10
+ ## Версія та CHANGELOG
11
+
12
+ Версію (`version` у **`npm/package.json`**) і **`npm/CHANGELOG.md`** **не редагуй вручну** — навіть для hotfix. Єдиний артефакт зміни — **change-файл** (`npx @7n/n ch [--bump <major|minor|patch>] [--section <Added|Changed|Fixed|Removed>] [--message "<…>"]`); bump `version` і генерацію секції CHANGELOG робить `n-rules release` у CI на `main`. Будь-який ручний bump `version` поза CI завалює `check changelog` — навіть із change-файлом.
13
+
14
+ Повна модель (база порівняння, інверсія шляхів, формат CHANGELOG, post-release-інваріант «верхня секція CHANGELOG == `version`») — у **`n-changelog.mdc`** (джерело істини). Це правило їй підпорядковане й власних інструкцій bump/CHANGELOG не дублює.
15
+
16
+ ### Канонічний крок `npm-changelog` у hk.pkl
17
+
18
+ У v14 команду `check` прибрано (уніфікована поверхня `lint`) — виклик `npx @7n/rules check changelog` у hk.pkl **завалить** кожен коміт з `❌ Невідома команда: check`. Канонічний pre-commit-крок (hk `amends hk@1.42.0`):
19
+
20
+ ```pkl
21
+ ["npm-changelog"] {
22
+ glob = List("npm/**")
23
+ check_first = false
24
+ fix = "N_RULES_CHANGELOG_AUTOFIX=1 bun ./npm/bin/n-rules.js lint changelog"
25
+ }
26
+ ```
27
+
28
+ Лише `fix` (без `check`): env-прапорець `N_RULES_CHANGELOG_AUTOFIX=1` вмикає autofix-режим — за відсутності change-файлу правило само створює його (`patch`/`Changed`, subject останнього коміту) і одразу ставить у git-індекс (`git add`) через `writeChange`/`reportOrFixMissingChangeFile`. Тому додатковий `stage = List("npm/.changes/**")` у цьому wiring **не потрібен** — індексація вже всередині JS-кроку. `package_structure` (`npx @7n/rules lint npm-module`) валідує цей крок: fail на застарілий `check changelog` і fail, якщо кроку `npm-changelog` немає взагалі.
29
+
30
+ ## Швидкий gate через conftest
31
+
32
+ Rego-пакети (запускаються через `npx @7n/rules fix`):
33
+
34
+ - [package.json.snippet.json](./npm_package_json/template/package.json.snippet.json)
35
+ - [package.json.snippet.json](./root_package_json/template/package.json.snippet.json)
36
+ - [tsconfig.emit-types.json.snippet.json](./emit_types_config/template/tsconfig.emit-types.json.snippet.json)
@@ -0,0 +1,9 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
3
+ "fixability": "config",
4
+ "policy": {
5
+ "files": {
6
+ "single": "npm/package.json"
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,26 @@
1
+ ---
2
+ type: JS Module
3
+ title: fix-npm_package_json.mjs
4
+ resource: plugins/lang-js/rules/npm-module/npm_package_json/fix-npm_package_json.mjs
5
+ docgen:
6
+ crc: 4c61a5ff
7
+ model: openai-codex/gpt-5.4-mini
8
+ score: 100
9
+ issues: judge:inaccurate:0.96
10
+ judgeModel: openai-codex/gpt-5.4-mini
11
+ ---
12
+
13
+ ## Огляд
14
+
15
+ `patterns` формує узгоджений набір правил для `package.json`, щоб проєктні package-файли лишалися в очікуваному стані за контрактом, який спирається на конфіг з `package.json`. Read-only: не пише у ФС чи БД.
16
+
17
+ ## Поведінка
18
+
19
+ 1. `patterns` визначає набір правил для вирівнювання `npm/package.json` з еталонним шаблоном.
20
+ 2. Під час застосування кожне правило бере до уваги конфігурацію з `package.json` і використовує її як основу для корекції цільового файлу.
21
+ 3. Мета `patterns` — забезпечити однакову структуру й очікуваний вміст `npm/package.json` у межах проєкту.
22
+ 4. Значення `patterns` не виконує записів у файлову систему чи базу даних; воно лише описує, що і як має бути приведено до узгодженого стану.
23
+
24
+ ## Гарантії поведінки
25
+
26
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -0,0 +1,9 @@
1
+ ---
2
+ type: Directory Index
3
+ title: npm/rules/npm-module/npm_package_json
4
+ resource: plugins/lang-js/rules/npm-module/npm_package_json/
5
+ ---
6
+
7
+ | Файл | Тип |
8
+ | --------------------------------------------------- | --------- |
9
+ | [fix-npm_package_json.mjs](fix-npm_package_json.md) | JS Module |
@@ -0,0 +1,5 @@
1
+ import { createTemplateFixPattern } from '@7n/rules/scripts/lib/fix/template-deep-merge.mjs'
2
+
3
+ export const patterns = [
4
+ createTemplateFixPattern({ id: 'npm-module-npm_package_json-template', targetPath: 'npm/package.json' })
5
+ ]