@7n/rules 1.27.0 → 1.28.1

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 (268) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +1 -5
  3. package/schemas/v8r-catalog.json +10 -1
  4. package/scripts/auto-rules.mjs +2 -3
  5. package/scripts/docs/auto-rules.md +1 -1
  6. package/scripts/lib/docs/glob-to-regex.md +31 -0
  7. package/scripts/lib/docs/index.md +2 -0
  8. package/scripts/lib/docs/js-source-signals.md +32 -0
  9. package/scripts/lib/glob-to-regex.mjs +79 -0
  10. package/scripts/lib/js-source-signals.mjs +50 -0
  11. package/scripts/utils/ast-scan-utils.mjs +2 -2
  12. package/scripts/utils/docs/ast-scan-utils.md +1 -1
  13. package/rules/bun/bunfig/bunfig.mdc +0 -17
  14. package/rules/bun/bunfig/bunfig.rego +0 -29
  15. package/rules/bun/bunfig/concern.json +0 -9
  16. package/rules/bun/bunfig/template/bunfig.toml.snippet.toml +0 -2
  17. package/rules/bun/docs/index.md +0 -11
  18. package/rules/bun/layout/concern.json +0 -16
  19. package/rules/bun/layout/docs/fix-layout.md +0 -29
  20. package/rules/bun/layout/docs/main.md +0 -34
  21. package/rules/bun/layout/fix-layout.mjs +0 -63
  22. package/rules/bun/layout/layout.mdc +0 -60
  23. package/rules/bun/layout/main.mjs +0 -53
  24. package/rules/bun/licensee/concern.json +0 -7
  25. package/rules/bun/licensee/docs/fix-licensee.md +0 -27
  26. package/rules/bun/licensee/docs/index.md +0 -12
  27. package/rules/bun/licensee/docs/main.md +0 -30
  28. package/rules/bun/licensee/fix-licensee.mjs +0 -31
  29. package/rules/bun/licensee/main.mjs +0 -68
  30. package/rules/bun/lint-surface/concern.json +0 -3
  31. package/rules/bun/lint-surface/lint-surface.mdc +0 -13
  32. package/rules/bun/main.json +0 -1
  33. package/rules/bun/main.mdc +0 -11
  34. package/rules/bun/package_json/concern.json +0 -9
  35. package/rules/bun/package_json/docs/fix-package_json.md +0 -28
  36. package/rules/bun/package_json/docs/index.md +0 -9
  37. package/rules/bun/package_json/fix-package_json.mjs +0 -311
  38. package/rules/bun/package_json/package_json.mdc +0 -14
  39. package/rules/bun/package_json/package_json.rego +0 -64
  40. package/rules/bun/package_json/template/package.json.deny.json +0 -4
  41. package/rules/js/check/check.mdc +0 -26
  42. package/rules/js/check/concern.json +0 -19
  43. package/rules/js/check/docs/eslint-config.md +0 -56
  44. package/rules/js/check/docs/fix-check.md +0 -48
  45. package/rules/js/check/docs/index.md +0 -13
  46. package/rules/js/check/docs/main.md +0 -48
  47. package/rules/js/check/eslint-config.mjs +0 -262
  48. package/rules/js/check/fix-check.mjs +0 -82
  49. package/rules/js/check/main.mjs +0 -310
  50. package/rules/js/dep-policy/concern.json +0 -4
  51. package/rules/js/dep-policy/dep-policy.mdc +0 -36
  52. package/rules/js/dep-policy/docs/main.md +0 -35
  53. package/rules/js/dep-policy/main.mjs +0 -99
  54. package/rules/js/docs/index.md +0 -11
  55. package/rules/js/eslint/concern.json +0 -8
  56. package/rules/js/eslint/docs/fix-eslint.md +0 -50
  57. package/rules/js/eslint/docs/fix-worker.md +0 -31
  58. package/rules/js/eslint/docs/index.md +0 -11
  59. package/rules/js/eslint/docs/main.md +0 -35
  60. package/rules/js/eslint/fix-eslint.mjs +0 -160
  61. package/rules/js/eslint/fix-worker.mjs +0 -139
  62. package/rules/js/eslint/main.mjs +0 -115
  63. package/rules/js/file-extensions/concern.json +0 -3
  64. package/rules/js/file-extensions/file-extensions.mdc +0 -12
  65. package/rules/js/jscpd_config/concern.json +0 -11
  66. package/rules/js/jscpd_config/docs/fix-jscpd_config.md +0 -26
  67. package/rules/js/jscpd_config/docs/index.md +0 -9
  68. package/rules/js/jscpd_config/fix-jscpd_config.mjs +0 -3
  69. package/rules/js/jscpd_config/jscpd_config.mdc +0 -42
  70. package/rules/js/jscpd_config/jscpd_config.rego +0 -44
  71. package/rules/js/jscpd_config/template/.jscpd.json.snippet.json +0 -7
  72. package/rules/js/jscpd_duplicates/concern.json +0 -7
  73. package/rules/js/jscpd_duplicates/docs/main.md +0 -29
  74. package/rules/js/jscpd_duplicates/main.mjs +0 -69
  75. package/rules/js/knip/concern.json +0 -7
  76. package/rules/js/knip/docs/main.md +0 -32
  77. package/rules/js/knip/knip.mdc +0 -15
  78. package/rules/js/knip/main.mjs +0 -68
  79. package/rules/js/lint-findings/concern.json +0 -3
  80. package/rules/js/lint-findings/docs/main.md +0 -41
  81. package/rules/js/lint-findings/main.mjs +0 -125
  82. package/rules/js/main.json +0 -1
  83. package/rules/js/main.mdc +0 -18
  84. package/rules/js/package_json/concern.json +0 -9
  85. package/rules/js/package_json/docs/fix-package_json.md +0 -26
  86. package/rules/js/package_json/docs/index.md +0 -9
  87. package/rules/js/package_json/fix-package_json.mjs +0 -3
  88. package/rules/js/package_json/package_json.mdc +0 -15
  89. package/rules/js/package_json/package_json.rego +0 -142
  90. package/rules/js/package_json/template/package.json.snippet.json +0 -6
  91. package/rules/js/tooling/concern.json +0 -3
  92. package/rules/js/tooling/data/tooling/knip-canonical.json +0 -30
  93. package/rules/js/tooling/data/tooling/oxlint-canonical.json +0 -400
  94. package/rules/js/tooling/docs/main.md +0 -53
  95. package/rules/js/tooling/main.mjs +0 -183
  96. package/rules/js/utils_imports/concern.json +0 -4
  97. package/rules/js/utils_imports/docs/main.md +0 -50
  98. package/rules/js/utils_imports/main.mjs +0 -185
  99. package/rules/js/utils_imports/utils_imports.mdc +0 -15
  100. package/rules/js/vscode_extensions/concern.json +0 -11
  101. package/rules/js/vscode_extensions/docs/fix-vscode_extensions.md +0 -25
  102. package/rules/js/vscode_extensions/docs/index.md +0 -11
  103. package/rules/js/vscode_extensions/fix-vscode_extensions.mjs +0 -1
  104. package/rules/js/vscode_extensions/template/extensions.json.snippet.json +0 -6
  105. package/rules/js/vscode_extensions/vscode_extensions.mdc +0 -11
  106. package/rules/js/vscode_extensions/vscode_extensions.rego +0 -12
  107. package/rules/js-bun-db/connection/concern.json +0 -3
  108. package/rules/js-bun-db/connection/connection.mdc +0 -42
  109. package/rules/js-bun-db/docs/index.md +0 -11
  110. package/rules/js-bun-db/lib/bun-sql-scan.mjs +0 -1055
  111. package/rules/js-bun-db/lib/docs/bun-sql-scan.md +0 -63
  112. package/rules/js-bun-db/lib/docs/index.md +0 -11
  113. package/rules/js-bun-db/main.json +0 -1
  114. package/rules/js-bun-db/main.mdc +0 -8
  115. package/rules/js-bun-db/package_json/concern.json +0 -9
  116. package/rules/js-bun-db/package_json/package_json.mdc +0 -31
  117. package/rules/js-bun-db/package_json/package_json.rego +0 -15
  118. package/rules/js-bun-db/package_json/template/package.json.deny.json +0 -6
  119. package/rules/js-bun-db/pg_format_identifiers/concern.json +0 -3
  120. package/rules/js-bun-db/pg_format_identifiers/pg_format_identifiers.mdc +0 -104
  121. package/rules/js-bun-db/safety/concern.json +0 -4
  122. package/rules/js-bun-db/safety/docs/main.md +0 -34
  123. package/rules/js-bun-db/safety/main.mjs +0 -430
  124. package/rules/js-bun-db/safety/safety.mdc +0 -458
  125. package/rules/js-bun-redis/docs/index.md +0 -11
  126. package/rules/js-bun-redis/imports/concern.json +0 -4
  127. package/rules/js-bun-redis/imports/docs/main.md +0 -36
  128. package/rules/js-bun-redis/imports/imports.mdc +0 -47
  129. package/rules/js-bun-redis/imports/main.mjs +0 -88
  130. package/rules/js-bun-redis/lib/docs/index.md +0 -11
  131. package/rules/js-bun-redis/lib/docs/redis-imports.md +0 -227
  132. package/rules/js-bun-redis/lib/redis-imports.mjs +0 -130
  133. package/rules/js-bun-redis/main.json +0 -1
  134. package/rules/js-bun-redis/main.mdc +0 -8
  135. package/rules/js-bun-redis/package_json/concern.json +0 -9
  136. package/rules/js-bun-redis/package_json/package_json.mdc +0 -11
  137. package/rules/js-bun-redis/package_json/package_json.rego +0 -15
  138. package/rules/js-bun-redis/package_json/template/package.json.deny.json +0 -12
  139. package/rules/js-mssql/deps/concern.json +0 -4
  140. package/rules/js-mssql/deps/docs/main.md +0 -33
  141. package/rules/js-mssql/deps/main.mjs +0 -297
  142. package/rules/js-mssql/docs/index.md +0 -11
  143. package/rules/js-mssql/lib/docs/index.md +0 -11
  144. package/rules/js-mssql/lib/docs/mssql-pool-scan.md +0 -380
  145. package/rules/js-mssql/lib/mssql-pool-scan.mjs +0 -610
  146. package/rules/js-mssql/main.json +0 -1
  147. package/rules/js-mssql/main.mdc +0 -144
  148. package/rules/js-mssql/mssql-tvp/concern.json +0 -3
  149. package/rules/js-mssql/mssql-tvp/mssql-tvp.mdc +0 -77
  150. package/rules/js-mssql/package_json/concern.json +0 -9
  151. package/rules/js-mssql/package_json/package_json.mdc +0 -9
  152. package/rules/js-mssql/package_json/package_json.rego +0 -57
  153. package/rules/js-run/configmap/concern.json +0 -9
  154. package/rules/js-run/configmap/configmap.mdc +0 -37
  155. package/rules/js-run/configmap/configmap.rego +0 -21
  156. package/rules/js-run/configmap/template/configmap.yaml.contains.yml +0 -4
  157. package/rules/js-run/docs/index.md +0 -11
  158. package/rules/js-run/jsconfig/concern.json +0 -9
  159. package/rules/js-run/jsconfig/docs/fix-jsconfig.md +0 -29
  160. package/rules/js-run/jsconfig/docs/index.md +0 -9
  161. package/rules/js-run/jsconfig/fix-jsconfig.mjs +0 -119
  162. package/rules/js-run/jsconfig/jsconfig.mdc +0 -48
  163. package/rules/js-run/jsconfig/jsconfig.rego +0 -59
  164. package/rules/js-run/jsconfig/template/jsconfig.json.snippet.json +0 -10
  165. package/rules/js-run/lib/bunyan-imports.mjs +0 -98
  166. package/rules/js-run/lib/check-env-scan.mjs +0 -338
  167. package/rules/js-run/lib/conn-file-rules.mjs +0 -214
  168. package/rules/js-run/lib/conn-imports-scan.mjs +0 -154
  169. package/rules/js-run/lib/docs/bunyan-imports.md +0 -121
  170. package/rules/js-run/lib/docs/check-env-scan.md +0 -438
  171. package/rules/js-run/lib/docs/conn-file-rules.md +0 -304
  172. package/rules/js-run/lib/docs/conn-imports-scan.md +0 -208
  173. package/rules/js-run/lib/docs/index.md +0 -16
  174. package/rules/js-run/lib/docs/promise-settimeout-scan.md +0 -334
  175. package/rules/js-run/lib/docs/temporal-scan.md +0 -29
  176. package/rules/js-run/lib/promise-settimeout-scan.mjs +0 -128
  177. package/rules/js-run/lib/temporal-scan.mjs +0 -52
  178. package/rules/js-run/main.json +0 -1
  179. package/rules/js-run/main.mdc +0 -16
  180. package/rules/js-run/package_json/concern.json +0 -9
  181. package/rules/js-run/package_json/package_json.mdc +0 -44
  182. package/rules/js-run/package_json/package_json.rego +0 -37
  183. package/rules/js-run/package_json/template/package.json.deny.json +0 -22
  184. package/rules/js-run/project-structure/concern.json +0 -3
  185. package/rules/js-run/project-structure/project-structure.mdc +0 -11
  186. package/rules/js-run/runtime/concern.json +0 -12
  187. package/rules/js-run/runtime/docs/fix-runtime.md +0 -27
  188. package/rules/js-run/runtime/docs/main.md +0 -35
  189. package/rules/js-run/runtime/fix-runtime.mjs +0 -46
  190. package/rules/js-run/runtime/main.mjs +0 -494
  191. package/rules/js-run/runtime/runtime.mdc +0 -184
  192. package/rules/js-run/scope/concern.json +0 -3
  193. package/rules/js-run/scope/scope.mdc +0 -11
  194. package/rules/npm-module/docs/index.md +0 -11
  195. package/rules/npm-module/emit_types_config/concern.json +0 -9
  196. package/rules/npm-module/emit_types_config/docs/fix-emit_types_config.md +0 -25
  197. package/rules/npm-module/emit_types_config/docs/index.md +0 -9
  198. package/rules/npm-module/emit_types_config/emit_types_config.mdc +0 -43
  199. package/rules/npm-module/emit_types_config/emit_types_config.rego +0 -28
  200. package/rules/npm-module/emit_types_config/fix-emit_types_config.mjs +0 -5
  201. package/rules/npm-module/emit_types_config/template/tsconfig.emit-types.json.snippet.json +0 -9
  202. package/rules/npm-module/header_doc_pointer/concern.json +0 -5
  203. package/rules/npm-module/header_doc_pointer/docs/main.md +0 -40
  204. package/rules/npm-module/header_doc_pointer/header_doc_pointer.mdc +0 -18
  205. package/rules/npm-module/header_doc_pointer/main.mjs +0 -131
  206. package/rules/npm-module/main.json +0 -1
  207. package/rules/npm-module/main.mdc +0 -36
  208. package/rules/npm-module/npm_package_json/concern.json +0 -9
  209. package/rules/npm-module/npm_package_json/docs/fix-npm_package_json.md +0 -27
  210. package/rules/npm-module/npm_package_json/docs/index.md +0 -9
  211. package/rules/npm-module/npm_package_json/fix-npm_package_json.mjs +0 -5
  212. package/rules/npm-module/npm_package_json/npm_package_json.mdc +0 -57
  213. package/rules/npm-module/npm_package_json/npm_package_json.rego +0 -73
  214. package/rules/npm-module/npm_package_json/template/package.json.snippet.json +0 -1
  215. package/rules/npm-module/package_structure/concern.json +0 -5
  216. package/rules/npm-module/package_structure/docs/main.md +0 -37
  217. package/rules/npm-module/package_structure/main.mjs +0 -515
  218. package/rules/npm-module/package_structure/package_structure.mdc +0 -63
  219. package/rules/npm-module/root_package_json/concern.json +0 -9
  220. package/rules/npm-module/root_package_json/docs/fix-root_package_json.md +0 -26
  221. package/rules/npm-module/root_package_json/docs/index.md +0 -9
  222. package/rules/npm-module/root_package_json/fix-root_package_json.mjs +0 -5
  223. package/rules/npm-module/root_package_json/root_package_json.mdc +0 -41
  224. package/rules/npm-module/root_package_json/root_package_json.rego +0 -28
  225. package/rules/npm-module/root_package_json/template/package.json.snippet.json +0 -1
  226. package/rules/npm-module/rule_meta/concern.json +0 -8
  227. package/rules/npm-module/rule_meta/docs/main.md +0 -35
  228. package/rules/npm-module/rule_meta/main.mjs +0 -119
  229. package/rules/npm-module/rule_meta/rule_meta.mdc +0 -11
  230. package/rules/npm-module/skill_meta/concern.json +0 -5
  231. package/rules/npm-module/skill_meta/docs/main.md +0 -149
  232. package/rules/npm-module/skill_meta/main.mjs +0 -91
  233. package/rules/npm-module/skill_meta/skill_meta.mdc +0 -11
  234. package/rules/tool-surface/docs/index.md +0 -11
  235. package/rules/tool-surface/main.json +0 -6
  236. package/rules/tool-surface/main.mdc +0 -72
  237. package/rules/vue/composition-api/composition-api.mdc +0 -82
  238. package/rules/vue/composition-api/concern.json +0 -3
  239. package/rules/vue/docs/index.md +0 -11
  240. package/rules/vue/lib/docs/index.md +0 -11
  241. package/rules/vue/lib/docs/vue-forbidden-imports.md +0 -265
  242. package/rules/vue/lib/vue-forbidden-imports.mjs +0 -264
  243. package/rules/vue/main.json +0 -1
  244. package/rules/vue/main.mdc +0 -18
  245. package/rules/vue/nheader-layout/concern.json +0 -3
  246. package/rules/vue/nheader-layout/nheader-layout.mdc +0 -171
  247. package/rules/vue/package_json/concern.json +0 -9
  248. package/rules/vue/package_json/package_json.mdc +0 -30
  249. package/rules/vue/package_json/package_json.rego +0 -140
  250. package/rules/vue/packages/concern.json +0 -6
  251. package/rules/vue/packages/docs/index.md +0 -11
  252. package/rules/vue/packages/docs/main.md +0 -35
  253. package/rules/vue/packages/main.mjs +0 -575
  254. package/rules/vue/packages/packages.mdc +0 -56
  255. package/rules/vue/quasar-ui/concern.json +0 -3
  256. package/rules/vue/quasar-ui/quasar-ui.mdc +0 -32
  257. package/rules/vue/structure/concern.json +0 -3
  258. package/rules/vue/structure/structure.mdc +0 -101
  259. package/rules/vue/testing/concern.json +0 -3
  260. package/rules/vue/testing/testing.mdc +0 -40
  261. package/rules/vue/tfm-translations/concern.json +0 -7
  262. package/rules/vue/tfm-translations/docs/main.md +0 -29
  263. package/rules/vue/tfm-translations/main.mjs +0 -55
  264. package/rules/vue/tfm-translations/tfm-translations.mdc +0 -32
  265. package/rules/vue/vite-config/concern.json +0 -3
  266. package/rules/vue/vite-config/vite-config.mdc +0 -153
  267. package/rules/vue/vite-env/concern.json +0 -3
  268. package/rules/vue/vite-env/vite-env.mdc +0 -61
@@ -1,22 +0,0 @@
1
- {
2
- "dependencies": {
3
- "bunyan": "використовуй стандартні логери (js-run.mdc)",
4
- "@nitra/bunyan": "використовуй стандартні логери (js-run.mdc)"
5
- },
6
- "devDependencies": {
7
- "bunyan": "використовуй стандартні логери (js-run.mdc)",
8
- "@nitra/bunyan": "використовуй стандартні логери (js-run.mdc)"
9
- },
10
- "scriptsForbidden": [
11
- {
12
- "id": "node-runner",
13
- "pattern": "\\bnode(\\s|$)",
14
- "message": "заміни `node` на `bun` у scripts — один runtime у dev і prod (js-run.mdc)"
15
- },
16
- {
17
- "id": "env-cat-bun",
18
- "pattern": "\\benv\\s+\\$\\(cat\\s+[^)]+\\)\\s+bun\\b",
19
- "message": "заміни `env $(cat A B) bun` на `bun --env-file=A --env-file=B` (нативний Bun, js-run.mdc)"
20
- }
21
- ]
22
- }
@@ -1,3 +0,0 @@
1
- {
2
- "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json"
3
- }
@@ -1,11 +0,0 @@
1
- ## Структура проекту
2
-
3
- Рекомендується використовувати таку структуру проекту:
4
-
5
- ```
6
- k8s/ # тут всі файли для деплойменту в Kubernetes, включаючи kustomize
7
- src/ # тут всі файли необхідні для роботи проекту
8
- Dockerfile
9
- package.json
10
- readme.md
11
- ```
@@ -1,12 +0,0 @@
1
- {
2
- "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
3
- "lint": {
4
- "scope": "full",
5
- "glob": [
6
- "**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}",
7
- "**/package.json",
8
- "**/jsconfig.json",
9
- "**/k8s/base/configmap.yaml"
10
- ]
11
- }
12
- }
@@ -1,27 +0,0 @@
1
- ---
2
- type: JS Module
3
- title: fix-runtime.mjs
4
- resource: npm/rules/js-run/runtime/fix-runtime.mjs
5
- docgen:
6
- crc: e7f2ea89
7
- model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
- score: 100
9
- judgeModel: openai-codex/gpt-5.4-mini
10
- ---
11
-
12
- Процес T0-autofix автоматично створює стандартизований `jsconfig.json` у backend-пакетах, що знаходяться в каталозі `src/`, якщо такий конфігураційний файл відсутній. Для визначення канонічного вигляду цього файлу використовується шаблон, визначений у `policy/jsconfig/template/jsconfig.json.snippet.json`.
13
-
14
- Конфіги, на які спирається код: jsconfig.json, jsconfig.json.snippet.json
15
-
16
- ## Поведінка
17
-
18
- 1. Ініціалізується контент канонічного файлу `jsconfig.json` шляхом читання з `jsconfig.json.snippet.json`.
19
- 2. Протягується масив `patterns` для ідентифікації робочих простірців, яким бракує файлу `jsconfig.json`.
20
- 3. Для кожного шаблону в `patterns` перевіряється наявність підходящого вихідного стану.
21
- 4. Якщо шаблон спрацьовує, здійснюється пошук усіх відповідних робочих простірців у контексті.
22
- 5. Для кожного знайденого робочого простірця, який містить каталог `src/` та не має `jsconfig.json`, відбувається запис канонічного контенту у файл `jsconfig.json`.
23
- 6. У результаті, що створюються файли `jsconfig.json` у потрібних пакетах фіксується та повертається відповідний статус.
24
-
25
- ## Гарантії поведінки
26
-
27
- - (специфічних машинно-виведених гарантій немає)
@@ -1,35 +0,0 @@
1
- ---
2
- type: JS Module
3
- title: main.mjs
4
- resource: npm/rules/js-run/runtime/main.mjs
5
- docgen:
6
- crc: 9f11393b
7
- model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
- score: 100
9
- issues: judge:inaccurate:0.99
10
- judgeModel: openai-codex/gpt-5.4-mini
11
- ---
12
-
13
- ## Огляд
14
-
15
- Цей файл забезпечує відповідність проєкту затвердженим правилам `js-run.mdc`, спираючись на конфігурації `jsconfig.json` та `package.json`. Він перевіряє конфігурації, імпорти, неймінг, змінні середовища та таймери для кожного пакета, ігноруючи перевірку для frontend-пакетів, що використовують `vite`.
16
-
17
- ## Поведінка
18
-
19
- Поведінка:
20
- pgWriteContract: Не є публічною функцією.
21
- main: Перевіряє відповідність проєкту правилам `js-run.mdc` для кожного workspace-пакета, пропускаючи перевірку для frontend-пакетів, що використовують `vite`. Для пакетів відбувається валідація конфігурацій, імпортів, неймінгу файлів, використання змінних середовища та таймерів.
22
-
23
- ## Публічний API
24
-
25
- _Конфігураційні файли, на які спирається код: jsconfig.json, package.json_
26
-
27
- - pgWriteContract — Формує та впроваджує контракт до бази даних, використовуючи специфічний інструментарій.\*
28
- - main — Аудитує відповідність правил виконання JavaScript для окремих пакетів у структурі workspace, ігноруючи корінь репозиторію.
29
-
30
- ## Гарантії поведінки
31
-
32
- - Read-only: не виконує операцій запису (ФС/БД).
33
- - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
34
- - За певних помилок повертає порожнє значення (напр. `null`) замість винятку.
35
- - Свідомо пропускає шляхи: `base/`.
@@ -1,46 +0,0 @@
1
- /**
2
- * T0-autofix для `js-run/runtime` — детерміноване створення канонічного
3
- * `jsconfig.json` у backend-пакетах із `src/` де він відсутній. Канон читається
4
- * з `jsconfig/template/jsconfig.json.snippet.json` (єдине джерело істини).
5
- *
6
- * Unified lint surface: structured violations (test(violations)/apply(violations,ctx)).
7
- * Workspace-и читаються з `v.message` ("[<ws>] є каталог src/, але немає jsconfig.json").
8
- */
9
- import { existsSync, readFileSync, writeFileSync } from 'node:fs'
10
- import { join } from 'node:path'
11
- import { fileURLToPath } from 'node:url'
12
-
13
- const JSCONFIG_MISSING_RE = /є каталог src\/, але немає jsconfig\.json/u
14
- /** Витягує workspace із message-а одного violation (`[<ws>] є каталог src/…`). */
15
- const JSCONFIG_MISSING_WS_RE = /^\[([^\]]*)\] є каталог src\/, але немає jsconfig\.json/u
16
-
17
- const JSCONFIG_CONTENT =
18
- readFileSync(
19
- fileURLToPath(new URL('../jsconfig/template/jsconfig.json.snippet.json', import.meta.url)),
20
- 'utf8'
21
- ).trimEnd() + '\n'
22
-
23
- /** @type {import('../../../scripts/lib/lint-surface/types.mjs').T0Pattern[]} */
24
- export const patterns = [
25
- {
26
- id: 'js-run-jsconfig-create',
27
- test: violations => violations.some(v => JSCONFIG_MISSING_RE.test(v.message)),
28
- apply: (violations, ctx) => {
29
- const cwd = ctx.cwd
30
- const touchedFiles = []
31
- for (const v of violations) {
32
- const m = JSCONFIG_MISSING_WS_RE.exec(v.message)
33
- if (!m) continue
34
- const ws = m[1]
35
- const target = join(cwd, ws, 'jsconfig.json')
36
- if (!existsSync(target)) {
37
- ctx.recordWrite?.(target)
38
- writeFileSync(target, JSCONFIG_CONTENT, 'utf8')
39
- touchedFiles.push(target)
40
- }
41
- }
42
- if (touchedFiles.length === 0) return { touchedFiles: [] }
43
- return { touchedFiles, message: `створено jsconfig.json: ${touchedFiles.join(', ')}` }
44
- }
45
- }
46
- ]
@@ -1,494 +0,0 @@
1
- /** @see ./docs/runtime.md */
2
- import { existsSync, statSync } from 'node:fs'
3
- import { readFile } from 'node:fs/promises'
4
- import { join, relative } from 'node:path'
5
-
6
- import { findBunyanImportsInText, isBunyanScanSourceFile, shouldSkipFileForBunyanScan } from '../lib/bunyan-imports.mjs'
7
- import { findUncheckedProcessEnvInText, isCheckEnvScanSourceFile } from '../lib/check-env-scan.mjs'
8
- import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
9
- import { runConftestBatch } from '../../../scripts/lib/run-conftest-batch.mjs'
10
- import { findConnFileRuleViolations, isConnFileRulesSourceFile } from '../lib/conn-file-rules.mjs'
11
- import {
12
- findConnFactoryImportsInText,
13
- isConnImportsScanSourceFile,
14
- isInsideConnDir,
15
- resolveConnDirFromPackageJson
16
- } from '../lib/conn-imports-scan.mjs'
17
- import { loadCursorIgnorePaths } from '../../../scripts/lib/load-cursor-config.mjs'
18
- import { findPromiseSetTimeoutInText, isPromiseSetTimeoutScanSourceFile } from '../lib/promise-settimeout-scan.mjs'
19
- import { findTemporalUsageInText, isTemporalScanSourceFile } from '../lib/temporal-scan.mjs'
20
- import { walkDir } from '../../../scripts/utils/walkDir.mjs'
21
- import { getMonorepoPackageRootDirs } from '../../../scripts/lib/workspaces.mjs'
22
-
23
- /**
24
- * Чи існує непорожній за змістом маркер каталогу `src/` (рекомендована структура js-run).
25
- * @param {string} absPackageRoot абсолютний корінь пакета
26
- * @returns {boolean} true, якщо `src/` існує і є каталогом
27
- */
28
- function backendPackageHasSrcDir(absPackageRoot) {
29
- const srcPath = join(absPackageRoot, 'src')
30
- try {
31
- return statSync(srcPath).isDirectory()
32
- } catch {
33
- return false
34
- }
35
- }
36
-
37
- /**
38
- * FS-existence + структурна валідація `jsconfig.json` у backend-пакеті з
39
- * каталогом `src/`. Структуру (canonical `compilerOptions` і `include`)
40
- * делегуємо у rego-пакет `js_run.jsconfig` через `runConftestBatch` — Plan B:
41
- * Rego-authoritative, JS оркеструє per-package gate (frontend з `vite` сюди
42
- * взагалі не доходить, бо викликається лише з backend-гілки).
43
- * @param {string} rootDir відносний шлях workspace
44
- * @param {string} absPackageRoot абсолютний корінь пакета
45
- * @param {string} label префікс `[pkg] `
46
- * @param {(msg: string) => void} fail callback для повідомлень про порушення
47
- * @param {(msg: string) => void} passFn callback для повідомлень про успішну перевірку
48
- * @returns {Promise<void>} результат
49
- * @param {string} cwd корінь репозиторію
50
- */
51
- async function checkBackendJsconfigWhenSrcPresent(rootDir, absPackageRoot, label, fail, passFn, cwd) {
52
- if (!backendPackageHasSrcDir(absPackageRoot)) return
53
-
54
- const jcPath = join(cwd, rootDir, 'jsconfig.json')
55
- if (!existsSync(jcPath)) {
56
- fail(
57
- `${label}є каталог src/, але немає jsconfig.json — додай канонічний файл з js-run.mdc ` +
58
- `(NodeNext, include: src/**/*).`
59
- )
60
- return
61
- }
62
- const violations = await runConftestBatch({
63
- policyDirRel: 'js-run/jsconfig',
64
- namespace: 'js_run.jsconfig',
65
- files: [jcPath]
66
- })
67
- if (violations.length === 0) {
68
- passFn(`${label}jsconfig.json відповідає js_run.jsconfig (rego)`)
69
- return
70
- }
71
- for (const v of violations) fail(`${label}${v.message}`)
72
- }
73
-
74
- /**
75
- * Перетворює абсолютний шлях у posix-формі відносно кореня пакета.
76
- * @param {string} absPackageRoot абсолютний корінь пакета
77
- * @param {string} absPath абсолютний шлях до файлу
78
- * @returns {string} відносний posix-шлях
79
- */
80
- function relPosix(absPackageRoot, absPath) {
81
- return relative(absPackageRoot, absPath).split('\\').join('/')
82
- }
83
-
84
- /**
85
- * Сканує джерела пакета на заборонені імпорти `@nitra/bunyan` / `bunyan`.
86
- * @param {string} absPackageRoot абсолютний шлях до кореня пакета
87
- * @param {string[]} ignorePaths абсолютні шляхи каталогів, повністю виключених з обходу
88
- * @param {string} label префікс повідомлення `[<pkg>] `
89
- * @param {(msg: string) => void} fail callback при помилці
90
- * @returns {Promise<number>} кількість знайдених порушень
91
- */
92
- async function checkBunyanImports(absPackageRoot, ignorePaths, label, fail) {
93
- /** @type {string[]} */
94
- const sourcePaths = []
95
- await walkDir(
96
- absPackageRoot,
97
- absPath => {
98
- const rel = relPosix(absPackageRoot, absPath)
99
- if (!shouldSkipFileForBunyanScan(rel) && isBunyanScanSourceFile(rel)) {
100
- sourcePaths.push(absPath)
101
- }
102
- },
103
- ignorePaths
104
- )
105
-
106
- let violations = 0
107
- for (const absPath of sourcePaths) {
108
- const rel = relPosix(absPackageRoot, absPath)
109
- const content = await readFile(absPath, 'utf8')
110
- for (const v of findBunyanImportsInText(content, rel)) {
111
- violations++
112
- fail(`${label}${rel}:${v.line} — заміни '${v.module}' на '@nitra/pino': ${v.snippet}`)
113
- }
114
- }
115
- return violations
116
- }
117
-
118
- /**
119
- * Збирає всі JS/TS-файли пакета (без node_modules, dist тощо).
120
- * @param {string} absPackageRoot абсолютний шлях до кореня пакета
121
- * @param {string[]} ignorePaths абсолютні шляхи каталогів, повністю виключених з обходу
122
- * @returns {Promise<string[]>} абсолютні шляхи до файлів
123
- */
124
- async function collectSourceFiles(absPackageRoot, ignorePaths) {
125
- /** @type {string[]} */
126
- const out = []
127
- await walkDir(
128
- absPackageRoot,
129
- absPath => {
130
- const rel = relPosix(absPackageRoot, absPath)
131
- if (isCheckEnvScanSourceFile(rel)) out.push(absPath)
132
- },
133
- ignorePaths
134
- )
135
- return out
136
- }
137
-
138
- /**
139
- * Перевіряє правило «Внутрішні аліаси» для пакета.
140
- * @param {string} absPackageRoot абсолютний корінь пакета
141
- * @param {string[]} sourcePaths абсолютні шляхи до файлів
142
- * @param {unknown} pkgJson розпарсений `package.json` пакета (або null)
143
- * @param {string} label префікс повідомлення `[<pkg>] `
144
- * @param {(msg: string) => void} fail callback при помилці
145
- * @returns {Promise<number>} кількість порушень
146
- */
147
- async function checkConnImports(absPackageRoot, sourcePaths, pkgJson, label, fail) {
148
- const connDir = resolveConnDirFromPackageJson(pkgJson)
149
- let violations = 0
150
- for (const absPath of sourcePaths) {
151
- const rel = relPosix(absPackageRoot, absPath)
152
- if (!isConnImportsScanSourceFile(rel)) continue
153
- if (isInsideConnDir(rel, connDir)) continue
154
- const content = await readFile(absPath, 'utf8')
155
- for (const v of findConnFactoryImportsInText(content, rel)) {
156
- violations++
157
- const target = v.specifier === '*' ? `'${v.module}'` : `{ ${v.specifier} } from '${v.module}'`
158
- fail(
159
- `${label}${rel}:${v.line} — імпорт ${target} має бути в '${connDir}/' і реекспортуватися через '#conn/*': ${v.snippet}`
160
- )
161
- }
162
- }
163
- return violations
164
- }
165
-
166
- /**
167
- * Перевіряє правила нейминга та експортів для файлів усередині `#conn/`.
168
- *
169
- * Канон імені: `ql-<id>` для GraphQL, `(pg|mysql|mssql)-(read|write)[-<id>]` для БД (js-run.mdc,
170
- * розділ «Нейминг файлів у `src/conn/`»). Експорт у файлі — лише іменований, з імʼям, що
171
- * дорівнює camelCase від basename файла (`pg-write-contract.js` → `export const pgWriteContract`).
172
- * @param {string} absPackageRoot абсолютний корінь пакета
173
- * @param {string[]} sourcePaths абсолютні шляхи до файлів пакета
174
- * @param {unknown} pkgJson розпарсений package.json пакета (або null)
175
- * @param {string} label префікс повідомлення `[<pkg>] `
176
- * @param {(msg: string) => void} fail callback при помилці
177
- * @returns {Promise<number>} кількість порушень
178
- */
179
- async function checkConnFileNamingAndExports(absPackageRoot, sourcePaths, pkgJson, label, fail) {
180
- const connDir = resolveConnDirFromPackageJson(pkgJson)
181
- let violations = 0
182
- for (const absPath of sourcePaths) {
183
- const rel = relPosix(absPackageRoot, absPath)
184
- if (!isConnFileToCheck(rel, connDir)) continue
185
- const content = await readFile(absPath, 'utf8')
186
- for (const v of findConnFileRuleViolations(content, rel)) {
187
- violations++
188
- fail(formatConnFileViolation(v, label, rel, connDir))
189
- }
190
- }
191
- return violations
192
- }
193
-
194
- /**
195
- * Чи `rel` — це conn-файл, який треба валідувати: під `connDir/`, з JS/TS-розширенням,
196
- * не `index.*` (який є реекспортним барелем).
197
- * @param {string} rel відносний шлях у posix-форматі
198
- * @param {string} connDir каталог conn-файлів (наприклад `src/conn`)
199
- * @returns {boolean} true, якщо файл потрібно перевірити
200
- */
201
- function isConnFileToCheck(rel, connDir) {
202
- if (!isInsideConnDir(rel, connDir)) return false
203
- if (!isConnFileRulesSourceFile(rel)) return false
204
- const base = rel.slice(rel.lastIndexOf('/') + 1)
205
- return !base.startsWith('index.')
206
- }
207
-
208
- /**
209
- * Будує повідомлення про конкретне порушення canon-у файла з `connDir/`.
210
- * @param {{ kind: 'name' | 'default-export' | 'export-name', expectedName?: string, foundNames?: string[] }} v опис порушення
211
- * @param {string} label префікс повідомлення `[<pkg>] `
212
- * @param {string} rel відносний шлях файла
213
- * @param {string} connDir каталог conn-файлів
214
- * @returns {string} повний текст повідомлення для `fail(...)`
215
- */
216
- function formatConnFileViolation(v, label, rel, connDir) {
217
- if (v.kind === 'name') {
218
- return (
219
- `${label}${rel} — назва файла в '${connDir}/' не відповідає канону js-run: ` +
220
- `'ql-<id>', 'pg-{read|write}[-<id>]', 'mysql-{read|write}[-<id>]' або 'mssql-{read|write}[-<id>]' ` +
221
- `(kebab-case, [a-z0-9-])`
222
- )
223
- }
224
- if (v.kind === 'default-export') {
225
- return `${label}${rel} — 'export default' заборонений у '${connDir}/'; зроби іменований експорт`
226
- }
227
- const found = v.foundNames?.length ? v.foundNames.join(', ') : '—'
228
- return (
229
- `${label}${rel} — очікується іменований експорт 'export const ${v.expectedName} = …' ` +
230
- `(camelCase від назви файла); знайдено: ${found}`
231
- )
232
- }
233
-
234
- /**
235
- * Перевіряє правило «CheckEnv» для пакета.
236
- * @param {string} absPackageRoot абсолютний корінь пакета
237
- * @param {string[]} sourcePaths абсолютні шляхи до файлів
238
- * @param {string} label префікс повідомлення `[<pkg>] `
239
- * @param {(msg: string) => void} fail callback при помилці
240
- * @returns {Promise<number>} кількість порушень
241
- */
242
- async function checkProcessEnvUsage(absPackageRoot, sourcePaths, label, fail) {
243
- let violations = 0
244
- for (const absPath of sourcePaths) {
245
- const rel = relPosix(absPackageRoot, absPath)
246
- const content = await readFile(absPath, 'utf8')
247
- for (const v of findUncheckedProcessEnvInText(content, rel)) {
248
- violations++
249
- const message =
250
- v.kind === 'process-env'
251
- ? `${label}${rel}:${v.line} — process.env.${v.name}: заміни на env з '@nitra/check-env' (обов'язкова змінна + checkEnv(['${v.name}'])) або з 'node:process' (опційна)`
252
- : `${label}${rel}:${v.line} — env.${v.name} (з '@nitra/check-env') без checkEnv(['${v.name}']) (або '// @7n/rules ignore-next-line checkEnv' попереду)`
253
- fail(message)
254
- }
255
- }
256
- return violations
257
- }
258
-
259
- /**
260
- * Сканує джерела пакета на паттерн `new Promise(resolve => setTimeout(resolve, ms))`.
261
- * @param {string} absPackageRoot абсолютний корінь пакета
262
- * @param {string[]} sourcePaths абсолютні шляхи до файлів
263
- * @param {string} label префікс повідомлення `[<pkg>] `
264
- * @param {(msg: string) => void} fail callback при помилці
265
- * @returns {Promise<number>} кількість порушень
266
- */
267
- async function checkPromiseSetTimeoutPause(absPackageRoot, sourcePaths, label, fail) {
268
- let violations = 0
269
- for (const absPath of sourcePaths) {
270
- const rel = relPosix(absPackageRoot, absPath)
271
- if (!isPromiseSetTimeoutScanSourceFile(rel)) continue
272
- const content = await readFile(absPath, 'utf8')
273
- for (const v of findPromiseSetTimeoutInText(content, rel)) {
274
- violations++
275
- fail(
276
- `${label}${rel}:${v.line} — заміни 'new Promise(r => setTimeout(r, ms))' на 'await setTimeout(ms)' з 'node:timers/promises': ${v.snippet}`
277
- )
278
- }
279
- }
280
- return violations
281
- }
282
-
283
- /**
284
- * Сканує джерела пакета на `Temporal`, який у Bun runtime ще недоступний.
285
- * @param {string} absPackageRoot абсолютний корінь пакета
286
- * @param {string[]} sourcePaths абсолютні шляхи до файлів
287
- * @param {string} label префікс повідомлення `[<pkg>] `
288
- * @param {(msg: string) => void} fail callback при помилці
289
- * @returns {Promise<number>} кількість порушень
290
- */
291
- async function checkTemporalUsage(absPackageRoot, sourcePaths, label, fail) {
292
- let violations = 0
293
- for (const absPath of sourcePaths) {
294
- const rel = relPosix(absPackageRoot, absPath)
295
- if (!isTemporalScanSourceFile(rel)) continue
296
- const content = await readFile(absPath, 'utf8')
297
- for (const v of findTemporalUsageInText(content, rel)) {
298
- violations++
299
- fail(
300
- `${label}${rel}:${v.line} — Temporal API заборонений у Bun runtime; використовуй Date або інʼєктований timestamp`
301
- )
302
- }
303
- }
304
- return violations
305
- }
306
-
307
- /**
308
- * Перевіряє відповідність правилам js-run.mdc для одного workspace-пакета.
309
- * @param {string} rootDir відносний шлях workspace (не `'.'`)
310
- * @param {string[]} ignorePaths абсолютні шляхи каталогів, повністю виключених з обходу
311
- * @param {(msg: string) => void} fail функція зворотного виклику для реєстрації помилки перевірки
312
- * @param {(msg: string) => void} passFn успішне повідомлення (як у check-reporter)
313
- * @returns {Promise<void>} завершується після перевірок цього пакета
314
- * @param {string} cwd корінь репозиторію
315
- */
316
- async function checkWorkspacePackage(rootDir, ignorePaths, fail, passFn, cwd) {
317
- const label = `[${rootDir}] `
318
- const absPackageRoot = join(cwd, rootDir)
319
- const pkgJson = await loadPackageJson(rootDir, cwd)
320
-
321
- // Frontend-пакети (vite у devDependencies) виходять за межі js-run:
322
- // браузерний бандл не має `node:process`, а `process.env.*` бандлер
323
- // обробляє самостійно. Перевірку process.env / conn-аліасів пропускаємо;
324
- // bunyan-залежність валідується в Rego (`npx @7n/rules fix`).
325
- if (packageJsonHasViteDevDependency(pkgJson)) {
326
- passFn(`${label}vite-пакет (frontend) — js-run пропущено (process.env / conn-aliases / OTEL configmap)`)
327
- return
328
- }
329
-
330
- await checkBackendJsconfigWhenSrcPresent(rootDir, absPackageRoot, label, fail, passFn, cwd)
331
-
332
- const importViolations = await checkBunyanImports(absPackageRoot, ignorePaths, label, fail)
333
- if (importViolations === 0) {
334
- passFn(`${label}немає імпортів '@nitra/bunyan' / 'bunyan' у джерелах`)
335
- }
336
-
337
- const sourcePaths = await collectSourceFiles(absPackageRoot, ignorePaths)
338
-
339
- const connViolations = await checkConnImports(absPackageRoot, sourcePaths, pkgJson, label, fail)
340
- if (connViolations === 0) {
341
- const connDir = resolveConnDirFromPackageJson(pkgJson)
342
- passFn(`${label}імпорти підключень (bun#SQL / mssql / @nitra/graphql-request#GraphQLClient) лише в '${connDir}/'`)
343
- }
344
-
345
- const connFileViolations = await checkConnFileNamingAndExports(absPackageRoot, sourcePaths, pkgJson, label, fail)
346
- if (connFileViolations === 0) {
347
- const connDir = resolveConnDirFromPackageJson(pkgJson)
348
- passFn(
349
- `${label}файли в '${connDir}/' дотримують канону js-run: нейминг (ql-/pg-/mysql-/mssql-…) і іменований експорт у camelCase від basename`
350
- )
351
- }
352
-
353
- const envViolations = await checkProcessEnvUsage(absPackageRoot, sourcePaths, label, fail)
354
- if (envViolations === 0) {
355
- passFn(
356
- `${label}немає прямого process.env.*; усі env.* з '@nitra/check-env' закриті checkEnv(['…']) (або '// @7n/rules ignore-next-line checkEnv')`
357
- )
358
- }
359
-
360
- const pauseViolations = await checkPromiseSetTimeoutPause(absPackageRoot, sourcePaths, label, fail)
361
- if (pauseViolations === 0) {
362
- passFn(`${label}немає 'new Promise(r => setTimeout(r, ms))' — паузи через 'node:timers/promises'`)
363
- }
364
-
365
- const temporalViolations = await checkTemporalUsage(absPackageRoot, sourcePaths, label, fail)
366
- if (temporalViolations === 0) {
367
- passFn(`${label}немає Temporal API у Bun runtime-коді`)
368
- }
369
-
370
- checkOtelConfigmap(rootDir, passFn, fail, cwd)
371
-
372
- const connAliasViolations = checkConnAliasDeclaration(absPackageRoot, sourcePaths, pkgJson, label, fail)
373
- if (connAliasViolations === 0) {
374
- const connDir = resolveConnDirFromPackageJson(pkgJson)
375
- passFn(`${label}package.json.imports["#conn/*"] оголошений (або файлів у '${connDir}/' немає)`)
376
- }
377
- }
378
-
379
- /**
380
- * Чи має пакет `vite` у `devDependencies` (маркер frontend-пакета — vite/quasar/capacitor SPA).
381
- * Семантично ідентично `packageJsonLacksViteDevDependency` з `auto-rules.mjs`, але
382
- * приймає вже розпарсений pkgJson.
383
- * @param {unknown} pkgJson розпарсений `package.json` пакета (або null)
384
- * @returns {boolean} true, якщо `vite` присутній у `devDependencies`
385
- */
386
- function packageJsonHasViteDevDependency(pkgJson) {
387
- if (!pkgJson || typeof pkgJson !== 'object' || Array.isArray(pkgJson)) return false
388
- const devDeps = /** @type {Record<string, unknown>} */ (pkgJson).devDependencies
389
- if (!devDeps || typeof devDeps !== 'object' || Array.isArray(devDeps)) return false
390
- return Object.hasOwn(devDeps, 'vite')
391
- }
392
-
393
- /**
394
- * Завантажує `package.json` пакета (якщо є). Заборону `@nitra/bunyan` / `bunyan`
395
- * у dependencies/devDependencies перенесено в Rego (`npm/policy/js_run/package_json/`);
396
- * `npx \@7n/rules check` запускає її по всіх workspace `package.json`. Тут лишилася
397
- * лише AST-перевірка імпортів.
398
- * @param {string} rootDir відносний шлях workspace
399
- * @returns {Promise<unknown>} розпарсений package.json або null
400
- * @param {string} cwd корінь репозиторію
401
- */
402
- async function loadPackageJson(rootDir, cwd) {
403
- const pkgPath = join(cwd, rootDir, 'package.json')
404
- if (!existsSync(pkgPath)) return null
405
- return JSON.parse(await readFile(pkgPath, 'utf8'))
406
- }
407
-
408
- /**
409
- * Перевіряє наявність `k8s/base/configmap.yaml` пакета. Структуру (наявність
410
- * `OTEL_RESOURCE_ATTRIBUTES` з обов'язковими `service.name=` / `service.namespace=`)
411
- * перенесено в Rego (`npm/policy/js_run/configmap/`); `npx \@7n/rules check`
412
- * запускає її на всіх `k8s/base/configmap.yaml`.
413
- * @param {string} rootDir відносний шлях workspace
414
- * @param {(msg: string) => void} passFn успішне повідомлення
415
- * @returns {void}
416
- * @param {string} cwd корінь репозиторію
417
- */
418
- /**
419
- * Перевіряє наявність `package.json#imports["#conn/*"]` коли у `connDir` є файли.
420
- * @param {string} absPackageRoot абсолютний корінь пакета
421
- * @param {string[]} sourcePaths абсолютні шляхи до файлів пакета
422
- * @param {unknown} pkgJson розпарсений package.json пакета (або null)
423
- * @param {string} label префікс повідомлення
424
- * @param {(msg: string) => void} fail callback при помилці
425
- * @returns {number} 0 — ок, 1 — порушення
426
- */
427
- function checkConnAliasDeclaration(absPackageRoot, sourcePaths, pkgJson, label, fail) {
428
- const connDir = resolveConnDirFromPackageJson(pkgJson)
429
- const hasConnFiles = sourcePaths.some(absPath => isInsideConnDir(relPosix(absPackageRoot, absPath), connDir))
430
- if (!hasConnFiles) return 0
431
-
432
- const imports =
433
- pkgJson && typeof pkgJson === 'object' && !Array.isArray(pkgJson)
434
- ? /** @type {Record<string, unknown>} */ (pkgJson).imports
435
- : null
436
- if (imports && typeof imports === 'object' && !Array.isArray(imports) && imports['#conn/*']) return 0
437
-
438
- fail(
439
- `${label}є файли у '${connDir}/', але в package.json відсутній аліас "#conn/*" — ` +
440
- `додай "imports": { "#conn/*": "./${connDir}/*" } (js-run.mdc conn-aliases)`
441
- )
442
- return 1
443
- }
444
-
445
- /**
446
- * Перевіряє наявність OTEL configmap для workspace-пакета.
447
- * @param {string} rootDir корінь пакета відносно cwd
448
- * @param {(msg: string) => void} passFn репортер успішної перевірки
449
- * @param {(msg: string) => void} failFn репортер порушення
450
- * @param {string} cwd робочий каталог
451
- * @returns {void}
452
- */
453
- function checkOtelConfigmap(rootDir, passFn, failFn, cwd) {
454
- const k8sDir = join(cwd, rootDir, 'k8s')
455
- if (!existsSync(k8sDir)) {
456
- passFn(`${rootDir}: немає каталогу k8s/ — перевірку OTEL configmap пропущено`)
457
- return
458
- }
459
- const configmapPath = join(k8sDir, 'base', 'configmap.yaml')
460
- if (!existsSync(configmapPath)) {
461
- failFn(
462
- `${rootDir}/k8s/base/configmap.yaml відсутній — додай з полем OTEL_RESOURCE_ATTRIBUTES ` +
463
- `(service.name=, service.namespace=), js-run.mdc`
464
- )
465
- return
466
- }
467
- passFn(`${rootDir}/k8s/base/configmap.yaml є (OTEL — npx @7n/rules fix → js_run.configmap)`)
468
- }
469
-
470
- /**
471
- * Перевіряє відповідність проєкту правилам js-run.mdc лише для workspace-пакетів (не корінь репо).
472
- * @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту
473
- * @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} перелік порушень
474
- */
475
- export async function lint(ctx) {
476
- const cwd = ctx.cwd
477
- const reporter = createViolationReporter(ctx)
478
- const { pass, fail } = reporter
479
-
480
- const roots = await getMonorepoPackageRootDirs(cwd)
481
- const workspaceRoots = roots.filter(r => r !== '.')
482
-
483
- if (workspaceRoots.length === 0) {
484
- pass('js-run: немає workspace-пакетів у кореневому package.json — перевірку залежностей і k8s у пакетах пропущено')
485
- return reporter.result()
486
- }
487
-
488
- const ignorePaths = await loadCursorIgnorePaths(cwd)
489
- for (const r of workspaceRoots) {
490
- await checkWorkspacePackage(r, ignorePaths, fail, pass, cwd)
491
- }
492
-
493
- return reporter.result()
494
- }