@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,310 +0,0 @@
1
- /** @see ./docs/tooling.md */
2
- import { existsSync } from 'node:fs'
3
- import { copyFile, readFile } from 'node:fs/promises'
4
- import { join } from 'node:path'
5
-
6
- import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
7
-
8
- import {
9
- KNIP_CANONICAL_JSON_PATH,
10
- OXLINT_CANONICAL_JSON_PATH,
11
- OXLINTRC_DRIFT,
12
- OXLINTRC_MISSING,
13
- verifyOxlintRcAgainstCanonical
14
- } from '../tooling/main.mjs'
15
-
16
- import {
17
- AUTO_IMPORTS_IGNORE,
18
- ESLINT_CONFIG_IGNORES,
19
- ESLINT_CONFIG_MISSING,
20
- ESLINT_CONFIG_VUE_WORKSPACE,
21
- detectWorkspaceTypes,
22
- parseVueList
23
- } from './eslint-config.mjs'
24
-
25
- const NON_DIGITS_RE = /\D+/u
26
-
27
- /**
28
- * Перевіряє ESLint flat config файл.
29
- * @param {(msg: string) => void} passFn callback при успішній перевірці
30
- * @param {(msg: string) => void} failFn callback при помилці
31
- * @param {string} cwd корінь репозиторію
32
- */
33
- async function checkEslintConfig(passFn, failFn, cwd) {
34
- let eslintPath
35
- if (existsSync(join(cwd, 'eslint.config.js'))) {
36
- eslintPath = 'eslint.config.js'
37
- passFn('eslint.config.js існує')
38
- } else if (existsSync(join(cwd, 'eslint.config.mjs'))) {
39
- eslintPath = 'eslint.config.mjs'
40
- passFn('eslint.config.mjs існує')
41
- } else {
42
- failFn('Відсутній eslint.config.js або eslint.config.mjs — flat config з getConfig (js.mdc)', ESLINT_CONFIG_MISSING)
43
- return
44
- }
45
- const eslintRaw = await readFile(join(cwd, eslintPath), 'utf8')
46
- const checks = [
47
- {
48
- needle: 'getConfig',
49
- ok: `${eslintPath}: містить getConfig`,
50
- err: `${eslintPath}: потрібен виклик getConfig (js.mdc)`
51
- },
52
- {
53
- needle: '@nitra/eslint-config',
54
- ok: `${eslintPath}: імпорт @nitra/eslint-config`,
55
- err: `${eslintPath}: імпортуй getConfig з @nitra/eslint-config`
56
- },
57
- {
58
- needle: AUTO_IMPORTS_IGNORE,
59
- ok: `${eslintPath}: ignores містить ${AUTO_IMPORTS_IGNORE}`,
60
- err: `${eslintPath}: додай у ignores запис ${AUTO_IMPORTS_IGNORE} (js.mdc)`,
61
- reason: ESLINT_CONFIG_IGNORES
62
- }
63
- ]
64
- for (const { needle, ok, err, reason } of checks) {
65
- if (eslintRaw.includes(needle)) {
66
- passFn(ok)
67
- } else {
68
- failFn(err, reason)
69
- }
70
- }
71
- await checkEslintWorkspaceTypes(eslintRaw, eslintPath, passFn, failFn, cwd)
72
- }
73
-
74
- /**
75
- * Кожен vue-воркспейс (детекція: `workspaces` root package.json + vue-залежність
76
- * або `.vue` файли) має бути у `vue: [...]` аргументах getConfig — інакше eslint
77
- * не підключає vue-parser і всі `.vue` файли воркспейсу не парсяться. Ловить
78
- * хибний scaffold типу `getConfig({ node: ['npm'] })` у vue-монорепо.
79
- * @param {string} eslintRaw вміст eslint.config
80
- * @param {string} eslintPath ім'я файлу конфігу для повідомлень
81
- * @param {(msg: string) => void} passFn callback при успішній перевірці
82
- * @param {(msg: string, reason?: string) => void} failFn callback при помилці
83
- * @param {string} cwd корінь репозиторію
84
- */
85
- async function checkEslintWorkspaceTypes(eslintRaw, eslintPath, passFn, failFn, cwd) {
86
- const types = await detectWorkspaceTypes(cwd)
87
- if (types.vue.length === 0) return
88
- const vueEntries = parseVueList(eslintRaw)
89
- for (const ws of types.vue) {
90
- if (vueEntries.includes(ws)) {
91
- passFn(`${eslintPath}: vue-воркспейс '${ws}' у vue: [...]`)
92
- } else {
93
- failFn(
94
- `${eslintPath}: воркспейс '${ws}' містить Vue-код, але відсутній у vue: [...] getConfig — ` +
95
- '.vue файли не парсяться (js.mdc)',
96
- ESLINT_CONFIG_VUE_WORKSPACE
97
- )
98
- }
99
- }
100
- }
101
-
102
- // Перевірки `prettier` / `@nitra/prettier-config` у залежностях (text.mdc) і
103
- // `@nitra/eslint-config ≥ 3.10.0` тепер у Rego: відповідно
104
- // `npm/policy/text/package_json/` і `npm/policy/js_lint/package_json/`. Тут
105
- // лишилася лише workspace-ітерація для `type: "module"` і engines, бо js_lint
106
- // Rego запускається лише на кореневому `package.json`.
107
-
108
- /**
109
- * Перевіряє, що package.json має `"type": "module"`.
110
- * @param {string} label шлях або назва пакета для повідомлень
111
- * @param {{ type?: string }} pkg parsed package.json
112
- * @param {(msg: string) => void} passFn callback при успішній перевірці
113
- * @param {(msg: string) => void} failFn callback при помилці
114
- */
115
- function checkPackageJsonTypeModule(label, pkg, passFn, failFn) {
116
- if (pkg.type === 'module') {
117
- passFn(`${label}: "type": "module"`)
118
- } else {
119
- failFn(`${label}: має містити "type": "module" (js.mdc)`)
120
- }
121
- }
122
-
123
- /**
124
- * `"type": "module"`, `engines.node >= 24` і `engines.bun >= 1.3` у кожному workspace `package.json`.
125
- * @param {unknown[]} workspaces поле workspaces з package.json
126
- * @param {(msg: string) => void} passFn callback при успішній перевірці
127
- * @param {(msg: string) => void} failFn callback при помилці
128
- * @param {string} cwd корінь репозиторію
129
- */
130
- async function checkWorkspacePackages(workspaces, passFn, failFn, cwd) {
131
- for (const ws of workspaces) {
132
- const wsPkgRel = `${ws}/package.json`
133
- const wsPkgAbs = join(cwd, wsPkgRel)
134
- if (existsSync(wsPkgAbs)) {
135
- const wsPkg = JSON.parse(await readFile(wsPkgAbs, 'utf8'))
136
- checkPackageJsonTypeModule(wsPkgRel, wsPkg, passFn, failFn)
137
- checkEnginesNode(wsPkgRel, wsPkg, passFn, failFn)
138
- checkEnginesBun(wsPkgRel, wsPkg, passFn, failFn)
139
- }
140
- }
141
- }
142
-
143
- /**
144
- * engines.node >= 24.
145
- * @param {string} label шлях або назва пакета для повідомлень
146
- * @param {{ engines?: { node?: string } }} pkg розпарсений package.json
147
- * @param {(msg: string) => void} passFn callback при успішній перевірці
148
- * @param {(msg: string) => void} failFn callback при помилці
149
- */
150
- function checkEnginesNode(label, pkg, passFn, failFn) {
151
- const nodeEngine = pkg.engines?.node
152
- if (nodeEngine) {
153
- const firstNumeric = String(nodeEngine).split(NON_DIGITS_RE).find(Boolean)
154
- if (firstNumeric && Number(firstNumeric) >= 24) {
155
- passFn(`${label}: engines.node "${nodeEngine}"`)
156
- } else {
157
- failFn(`${label}: engines.node "${nodeEngine}" — має бути >=24`)
158
- }
159
- } else {
160
- failFn(`${label} не містить engines.node — додай: "engines": { "node": ">=24" }`)
161
- }
162
- }
163
-
164
- /**
165
- * engines.bun >= 1.3.
166
- * @param {string} label шлях або назва пакета для повідомлень
167
- * @param {{ engines?: { bun?: string } }} pkg розпарсений package.json
168
- * @param {(msg: string) => void} passFn callback при успішній перевірці
169
- * @param {(msg: string) => void} failFn callback при помилці
170
- */
171
- function checkEnginesBun(label, pkg, passFn, failFn) {
172
- const bunEngine = pkg.engines?.bun
173
- if (bunEngine) {
174
- const [major, minor] = String(bunEngine).split(NON_DIGITS_RE).filter(Boolean).map(Number)
175
- if (Number.isFinite(major) && Number.isFinite(minor) && (major > 1 || (major === 1 && minor >= 3))) {
176
- passFn(`${label}: engines.bun "${bunEngine}"`)
177
- } else {
178
- failFn(`${label}: engines.bun "${bunEngine}" — має бути >=1.3`)
179
- }
180
- } else {
181
- failFn(`${label} не містить engines.bun — додай: "engines": { "bun": ">=1.3" }`)
182
- }
183
- }
184
-
185
- /**
186
- * Workspace-ітерація: для кожного workspace `package.json` перевіряємо
187
- * `type: "module"` і `engines.{node,bun}`. Кореневий `package.json` ці поля
188
- * валідує `npm/policy/js_lint/package_json/`; lint-js скрипт і `@nitra/eslint-config`
189
- * — теж у Rego.
190
- * @param {(msg: string) => void} passFn callback при успішній перевірці
191
- * @param {(msg: string) => void} failFn callback при помилці
192
- * @param {string} cwd корінь репозиторію
193
- */
194
- async function checkPackageJsonJsLint(passFn, failFn, cwd) {
195
- const pkgPath = join(cwd, 'package.json')
196
- if (!existsSync(pkgPath)) return
197
- const pkg = JSON.parse(await readFile(pkgPath, 'utf8'))
198
- const workspaces = Array.isArray(pkg.workspaces) ? pkg.workspaces : []
199
- await checkWorkspacePackages(workspaces, passFn, failFn, cwd)
200
- }
201
-
202
- /**
203
- * Перевіряє .oxlintrc.json.
204
- * @param {(msg: string) => void} passFn callback при успішній перевірці
205
- * @param {(msg: string) => void} failFn callback при помилці
206
- * @param {string} cwd корінь репозиторію
207
- */
208
- async function checkOxlintRc(passFn, failFn, cwd) {
209
- const oxPath = join(cwd, '.oxlintrc.json')
210
- if (!existsSync(oxPath)) {
211
- failFn('.oxlintrc.json не існує — додай конфіг oxlint (js.mdc)', OXLINTRC_MISSING)
212
- return
213
- }
214
- let oxCfg
215
- try {
216
- oxCfg = JSON.parse(await readFile(oxPath, 'utf8'))
217
- } catch {
218
- failFn('.oxlintrc.json не є валідним JSON')
219
- return
220
- }
221
- passFn('.oxlintrc.json існує')
222
- let canonical
223
- try {
224
- canonical = JSON.parse(await readFile(OXLINT_CANONICAL_JSON_PATH, 'utf8'))
225
- } catch {
226
- failFn('внутрішня помилка: не вдалося прочитати канон oxlint з пакета @7n/rules')
227
- return
228
- }
229
- const oxV = verifyOxlintRcAgainstCanonical(oxCfg, canonical)
230
- if (oxV.ok) {
231
- passFn('.oxlintrc.json збігається з каноном oxlint (@7n/rules)')
232
- } else {
233
- for (const msg of oxV.failures) {
234
- failFn(msg, OXLINTRC_DRIFT)
235
- }
236
- }
237
- }
238
-
239
- /**
240
- * Cross-file перевірка: `lint.yml` (якщо існує) не дублює лінт JS-кроки з `lint-js.yml`.
241
- * Existence і структуру `lint-js.yml` валідує mixin-концерн `js/lint_js_yml`
242
- * плагіна `@7n/rules-ci-github` (провайдер-специфіка — поза ядром).
243
- * @param {(msg: string) => void} passFn callback при успішній перевірці
244
- * @param {(msg: string) => void} failFn callback при помилці
245
- * @param {string} cwd корінь репозиторію
246
- */
247
- async function checkLintJsWorkflows(passFn, failFn, cwd) {
248
- // Existence/структуру lint-js.yml вимагає провайдер-плагін @7n/rules-ci-github
249
- // (mixin js/lint_js_yml, policy required) — ядро провайдер-агностичне і тут
250
- // перевіряє лише крос-файловий дубляж, коли GitHub-workflow уже існують.
251
- const lintYmlPath = join(cwd, '.github/workflows/lint.yml')
252
- if (existsSync(lintYmlPath)) {
253
- const lintYml = await readFile(lintYmlPath, 'utf8')
254
- if (lintYml.includes('bunx oxlint') && lintYml.includes('bunx eslint') && lintYml.includes('jscpd')) {
255
- failFn('.github/workflows/lint.yml дублює кроки lint-js.yml — залиш один workflow на лінт JS (js.mdc)')
256
- } else {
257
- passFn('.github/workflows/lint.yml не дублює oxlint/eslint/jscpd з lint-js.yml')
258
- }
259
- }
260
- }
261
-
262
- /**
263
- * Перевіряє наявність `knip.json` у корені проєкту. Якщо файл відсутній —
264
- * копіює канонічний `knip-canonical.json` з пакета `@7n/rules` як стартовий
265
- * baseline; зміст подальших модифікацій локально не валідується (`entry` /
266
- * `project` / `ignore` / `ignoreDependencies` / `ignoreBinaries` дозволені
267
- * будь-які; це side effect — описано у js.mdc).
268
- * @param {(msg: string) => void} passFn callback при успішній перевірці
269
- * @param {(msg: string) => void} failFn callback при помилці
270
- * @param {string} cwd корінь репозиторію
271
- */
272
- async function checkKnipConfig(passFn, failFn, cwd) {
273
- const knipPath = join(cwd, 'knip.json')
274
- if (existsSync(knipPath)) {
275
- passFn('knip.json існує')
276
- return
277
- }
278
- if (!existsSync(KNIP_CANONICAL_JSON_PATH)) {
279
- failFn(
280
- `knip.json відсутній, і канонічний шаблон у пакеті не знайдено (${KNIP_CANONICAL_JSON_PATH}) — ` +
281
- 'перевстанови @7n/rules'
282
- )
283
- return
284
- }
285
- await copyFile(KNIP_CANONICAL_JSON_PATH, knipPath)
286
- passFn('knip.json створено з канонічного npm/rules/js/tooling/data/tooling/knip-canonical.json (js.mdc)')
287
- }
288
-
289
- /**
290
- * Перевіряє відповідність проєкту правилам js.mdc
291
- * @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту
292
- * @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} перелік порушень
293
- */
294
- export async function lint(ctx) {
295
- const cwd = ctx.cwd
296
- const reporter = createViolationReporter(ctx)
297
- const { pass, fail } = reporter
298
-
299
- await checkEslintConfig(pass, fail, cwd)
300
- await checkPackageJsonJsLint(pass, fail, cwd)
301
- await checkOxlintRc(pass, fail, cwd)
302
- await checkLintJsWorkflows(pass, fail, cwd)
303
- await checkKnipConfig(pass, fail, cwd)
304
-
305
- for (const dup of ['.eslintrc', '.eslintrc.js', '.eslintrc.json', '.eslintrc.yml']) {
306
- if (existsSync(join(cwd, dup))) fail(`Знайдено застарілий конфіг ESLint: ${dup} — видали, використовуй flat config`)
307
- }
308
-
309
- return reporter.result()
310
- }
@@ -1,4 +0,0 @@
1
- {
2
- "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
3
- "lint": { "scope": "full", "glob": ["**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}"] }
4
- }
@@ -1,36 +0,0 @@
1
- ## Залежнісна політика (що не додавати)
2
-
3
- `@e18e/eslint-plugin` окремо не додавай — він уже в залежностях `@nitra/eslint-config` (з **3.8.0**), oxlint підвантажує його з `node_modules`. Пакети `oxlint`/`eslint`/`jscpd`/`knip` теж не додавай у `devDependencies` без потреби монорепо — `bunx` тягне їх ad-hoc.
4
-
5
- ### Заборона `ua-parser-js`
6
-
7
- Пакет **`ua-parser-js`** заборонений починаючи з версії **2.x**, де ліцензія змінилась з MIT на **AGPL-3.0** — несумісну з комерційним використанням у закритому SaaS. Замінити на **`bowser`** (MIT, ~6 KB gzip):
8
-
9
- ```javascript title="❌ до"
10
- import { UAParser } from 'ua-parser-js'
11
- const parser = new UAParser(userAgent)
12
- const result = parser.getResult()
13
- const browserName = result.browser.name
14
- ```
15
-
16
- ```javascript title="✅ після"
17
- import Bowser from 'bowser'
18
- const browser = Bowser.getParser(userAgent)
19
- const browserName = browser.getBrowserName()
20
- ```
21
-
22
- Bowser надає ті самі поля: `getBrowserName()`, `getOSName()`, `getPlatform().vendor`. Міграція займає кілька рядків; логіка не змінюється.
23
-
24
- ### Заборона `@nitra/as-integrations-fastify`
25
-
26
- Пакет **`@nitra/as-integrations-fastify`** заборонений у **`dependencies`**, **`peerDependencies`** та в import-specifier-ах. Це чистий републіш upstream, застряглий на peer `@apollo/server: "^4.0.0"`, тож на Apollo 5 `bun install` дає `warn: incorrect peer dependency`. Заміна — upstream **`@as-integrations/fastify`** (**`^3.1.0`**): peer `@apollo/server: "^4.0.0 || ^5.0.0"` + `fastify: "^5.3.0"`.
27
-
28
- Міграція — лише specifier у трьох місцях: залежність у `package.json`, `import`, та `vi.mock(...)` / `await import(...)` у тестах. **Код не міняється**, експорти ті самі: `default` → `fastifyApollo`, named → `fastifyApolloDrainPlugin`.
29
-
30
- ```javascript title="❌ до"
31
- import fastifyApollo, { fastifyApolloDrainPlugin } from '@nitra/as-integrations-fastify'
32
- ```
33
-
34
- ```javascript title="✅ після"
35
- import fastifyApollo, { fastifyApolloDrainPlugin } from '@as-integrations/fastify'
36
- ```
@@ -1,35 +0,0 @@
1
- ---
2
- type: JS Module
3
- title: main.mjs
4
- resource: npm/rules/js/dep-policy/main.mjs
5
- docgen:
6
- crc: 12ae4636
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
- Файл сканує всі JS/TS-файли у поточному робочому каталозі, виключаючи конфігураційно визначені шляхи. Завдяки публічній функції main, він перевіряє відповідність усіх імпортів у коді політиці залежностей, визначеній у dep-policy.mdc. Ця **read-only** операція виявляє та фіксує будь-які імпорти, заборонені в dep-policy.mdc, надаючи підказки заміни з js.mdc. Механізм працює з fail-safe принципом, перехоплюючи помилки та не дозволяючи виняткам виходити назовні.
16
-
17
- ## Поведінка
18
-
19
- Поведінка:
20
-
21
- 1. Виконується функція main.
22
- 2. Аналізуються всі JS/TS-файли у поточному робочому каталозі, виключаючи шляхи, визначені конфігурацією.
23
- 3. Для кожного файлу витягуються всі імпорти (статичні, динамічні та виклики require).
24
- 4. Знаходяться імпорти, які знаходяться у списку заборонених especifiers (dep-policy.mdc).
25
- 5. Якщо знайдений імпорт заборонений, реєструється помилка, яка вказує на шлях до файлу, заборонений імпорт та підказку про його заміну (js.mdc).
26
- 6. Після перевірки всіх файлів, якщо заборонених імпортів не знайдено, реєструється повідомлення про успішне завершення перевірки.
27
-
28
- ## Публічний API
29
-
30
- main — перевіряє імпорти у файлах JavaScript та TypeScript на відповідність політиці залежностей.
31
-
32
- ## Гарантії поведінки
33
-
34
- - Read-only: не виконує операцій запису (ФС/БД).
35
- - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
@@ -1,99 +0,0 @@
1
- /** @see ./docs/dep-policy.md */
2
- import { readFile } from 'node:fs/promises'
3
- import { relative } from 'node:path'
4
-
5
- import { parseSync } from 'oxc-parser'
6
-
7
- import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
8
- import { loadCursorIgnorePaths } from '../../../scripts/lib/load-cursor-config.mjs'
9
- import { walkDir } from '../../../scripts/utils/walkDir.mjs'
10
- import {
11
- dynamicImportModule,
12
- langFromPath,
13
- requireCallModule,
14
- walkAstWithAncestors
15
- } from '../../../scripts/utils/ast-scan-utils.mjs'
16
-
17
- const JS_SOURCE_RE = /\.(?:[cm]?[jt]sx?)$/u
18
-
19
- /**
20
- * Пакети, заборонені як import-specifier у будь-якому JS/TS-файлі.
21
- * Ключ — specifier, значення — підказка про заміну.
22
- */
23
- const BANNED_SPECIFIERS = new Map([
24
- ['@nitra/as-integrations-fastify', 'використовуй @as-integrations/fastify'],
25
- [
26
- 'ua-parser-js',
27
- 'замінити на bowser (MIT, ~6 KB) — npm i bowser. ua-parser-js v2 змінив ліцензію на AGPL-3.0, несумісну з комерційним використанням'
28
- ]
29
- ])
30
-
31
- /**
32
- * Витягає з джерела всі import-specifier'и (static + dynamic + require).
33
- * @param {string} source текст файлу
34
- * @param {string} filePath шлях до файлу (для вибору мови OXC-парсера)
35
- * @returns {string[]} список specifier'ів
36
- */
37
- function extractImportSpecifiers(source, filePath) {
38
- /** @type {string[]} */
39
- const result = []
40
- let parsed
41
- try {
42
- parsed = parseSync(filePath, source, { lang: langFromPath(filePath) })
43
- } catch {
44
- return result
45
- }
46
- for (const imp of parsed?.module?.staticImports ?? []) {
47
- if (typeof imp?.moduleRequest?.value === 'string') result.push(imp.moduleRequest.value)
48
- }
49
- const program = parsed?.program
50
- if (program && typeof program === 'object') {
51
- walkAstWithAncestors(program, [], node => {
52
- const dyn = dynamicImportModule(node)
53
- if (dyn !== null) result.push(dyn)
54
- const req = requireCallModule(node)
55
- if (req !== null) result.push(req)
56
- })
57
- }
58
- return result
59
- }
60
-
61
- /**
62
- * Сканує всі JS/TS-файли проєкту на заборонені import-specifier'и (dep-policy.mdc).
63
- * @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту
64
- * @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} Результат лінту з переліком порушень.
65
- */
66
- export async function lint(ctx) {
67
- const reporter = createViolationReporter(ctx)
68
- const cwd = ctx.cwd
69
- const ignorePaths = await loadCursorIgnorePaths(cwd)
70
-
71
- const files = []
72
- await walkDir(
73
- cwd,
74
- p => {
75
- if (JS_SOURCE_RE.test(p)) files.push(p)
76
- },
77
- ignorePaths
78
- )
79
-
80
- let violations = 0
81
- for (const absPath of files) {
82
- const source = await readFile(absPath, 'utf8')
83
- const specifiers = extractImportSpecifiers(source, absPath)
84
- for (const spec of specifiers) {
85
- const hint = BANNED_SPECIFIERS.get(spec)
86
- if (hint !== undefined) {
87
- const rel = relative(cwd, absPath)
88
- reporter.fail(`${rel}: заборонений import '${spec}' — ${hint} (js.mdc dep-policy)`)
89
- violations += 1
90
- }
91
- }
92
- }
93
-
94
- if (violations === 0) {
95
- reporter.pass(`dep-policy: перевірено ${files.length} файлів — заборонених import-specifier'ів немає (js.mdc)`)
96
- }
97
-
98
- return reporter.result()
99
- }
@@ -1,11 +0,0 @@
1
- ---
2
- type: Directory Index
3
- title: npm/rules/js
4
- resource: npm/rules/js/
5
- ---
6
-
7
- # npm/rules/js
8
-
9
- | Файл | Тип |
10
- | ------------------- | --------- |
11
- | [main.mjs](main.md) | JS Module |
@@ -1,8 +0,0 @@
1
- {
2
- "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
3
- "skipLocalTier": true,
4
- "lint": {
5
- "scope": "per-file",
6
- "glob": ["**/*.{js,mjs,cjs,jsx,ts,tsx,vue}"]
7
- }
8
- }
@@ -1,50 +0,0 @@
1
- ---
2
- type: JS Module
3
- title: fix-eslint.mjs
4
- resource: npm/rules/js/eslint/fix-eslint.mjs
5
- docgen:
6
- crc: 31afb96e
7
- model: manual
8
- ---
9
-
10
- ## Огляд
11
-
12
- T0-autofix для `js/eslint`, два патерни в порядку застосування. `js-eslint-autofix`:
13
- детермінований прогін лінтерів у fix-режимі (`oxlint --fix` + `eslint --fix`) по файлах, де
14
- детектор знайшов порушення — виправляє лише авто-fixable правила. `js-eslint-mechanical-text-fix`:
15
- для правил, які `--fix` НЕ покриває (suggestion-only у власній реалізації інструментів, перевірено
16
- емпірично на реальних lint-прогонах), але заміна на позначеному `data.line` текстуально однозначна
17
- й безпечна без AST-парсингу. Усе, що лишається непокритим — детектору на повторну перевірку, а
18
- далі LLM-ладдеру. Запис незворотний (поза rollback).
19
-
20
- ## Поведінка
21
-
22
- `js-eslint-autofix`:
23
- - Збирає унікальні файли з порушень концерну, лишає лише js-сімейство (`.mjs/.cjs/.js/.jsx/.ts/.tsx/.vue`).
24
- - Послідовно застосовує `oxlint --fix` (CLI) і `eslint --fix` (через API з `outputFixes`).
25
- - До списку змінених потрапляють лише файли, чий вміст фактично змінився (порівняння до/після).
26
-
27
- `js-eslint-mechanical-text-fix`:
28
- - `MECHANICAL_TEXT_FIXES` — реєстр `{ reasons, replace }`: `reasons` покриває обидва формати
29
- `violation.reason` (eslint `"plugin/rule"`, oxlint `"plugin(rule)"` — той самий rule різні тули
30
- віддають по-різному); `replace(line)` — чиста функція рядка, `null` якщо шаблон не знайдено.
31
- - Групує порушення за файлом, для кожного цільового `data.line` (1-indexed) застосовує
32
- відповідну `replace`; рядок без очікуваного шаблону (файл змінився з моменту detect-у) —
33
- пропускається без гадання.
34
- - Наразі покриває `unicorn/prefer-number-is-safe-integer` (`Number.isInteger` → `Number.isSafeInteger`).
35
-
36
- ## Публічний API
37
-
38
- - `patterns` — масив T0-патернів (`id` / `test` / `apply`), що його споживає центральний fix-pipeline:
39
- `js-eslint-autofix` (лінтери в fix-режимі), `js-eslint-mechanical-text-fix` (текстові заміни для
40
- suggestion-only правил).
41
-
42
- ## Гарантії поведінки
43
-
44
- - `js-eslint-autofix`: якщо серед порушень немає js-файлів — лінтери не запускаються, змін немає.
45
- - `js-eslint-mechanical-text-fix`: пише лише файли з реальною зміною рядка (шаблон збігся); не
46
- чіпає рядки поза `MECHANICAL_TEXT_FIXES`-реєстром.
47
- - Обидва патерни повертають лише фактично змінені файли; перед записом кожен реєструється через
48
- `recordWrite`.
49
- - Межа CI: модуль належить fix-фазі; у `--no-fix` (CI) не запускається — узгоджено із
50
- забороною `oxlint --fix`/`eslint --fix` у CI.
@@ -1,31 +0,0 @@
1
- ---
2
- type: JS Module
3
- title: fix-worker.mjs
4
- resource: npm/rules/js/eslint/fix-worker.mjs
5
- docgen:
6
- crc: 802ef1f3
7
- model: manual
8
- ---
9
-
10
- ## Огляд
11
-
12
- Custom fix-worker `js/eslint` (перекриває дефолтний `default-worker.mjs`): замість одного `runAgentFix`-виклику з усіма порушеннями з усіх файлів concern-а — окрема агентна сесія на кожен файл, ПАРАЛЕЛЬНО (обмежений пул, не більше `MAX_PARALLEL_FILES`). Мотивація й еволюція дизайну — `docs/adr/260718-0754-js-eslint-fix-worker-per-session-overhead.md`: послідовна версія стабільно впиралась у timeout на всіх 4 rung-ах драбини (local-min→cloud-avg); профайлінг реального прогону показав, що домінує кількість/довжина раундів моделі на файл, а не фіксовані bootstrap-витрати сесії — тож паралелізм (кілька файлів одночасно замість черги) дає пряме пришвидшення незалежно від причини.
13
-
14
- ## Поведінка
15
-
16
- 1. Групує вхідні `violations` за `file`; порушення без `file` ігноруються.
17
- 2. Дедлайн — `DEADLINE_FRACTION` (0.8) від `ctx.timeoutMs`; гейтить лише СТАРТ нового файлу з черги (не скасовує вже запущені).
18
- 3. `runPooled` — обмежений пул воркерів (`MAX_PARALLEL_FILES=4`): при `files.length ≤ MAX_PARALLEL_FILES` усі файли стартують майже одночасно й отримують практично весь бюджет незалежно один від одного; при більшій кількості черга природно звужує бюджет пізніших хвиль (`callTimeoutMs` рахується в момент старту файлу з черги, не наперед).
19
- 4. На кожен файл — окремий `runAgentFix` із `targetFiles: [file]` і власним `verify` (`verifyFile`): item-scoped canonical re-detect лише цього файлу, не всього concern-а — інакше evidence-гейт хибно вважав би файл незакритим через порушення в ІНШИХ файлах.
20
- 5. Один файл, що завершився з `error` АБО кинув виняток (try/catch у тілі воркера), не обриває пул — пропускається, решта файлів обробляються незалежно.
21
- 6. Повертає лише `touchedFiles` з успішних (`!error`) викликів; success rung-а все одно визначає whole-concern canonical re-detect runner-а (`runRung`), не цей worker.
22
-
23
- ## Публічний API
24
-
25
- - `fixWorker(violations, ctx)` — контракт `FixWorkerFn`; резолвиться автоматично замість `default-worker.mjs`, бо лежить як `fix-worker.mjs` поруч із `main.mjs` concern-а.
26
-
27
- ## Гарантії поведінки
28
-
29
- - Пише лише у файли з переданих `violations` (`targetFiles: [file]` на кожен виклик) — той самий semantic-collateral guard, що й у дефолтного worker-а.
30
- - `recordWrite` (не durable) на кожен файл: rollback-контракт незмінний — якщо після worker-а в concern-і лишилось хоч одне порушення будь-де, `runRung` відкочує ВСІ правки цього rung-а, включно з уже полагодженими файлами.
31
- - Конкурентні виклики `recordWrite` безпечні: central snapshot — синхронні Map-операції без `await` усередині, event loop не перериває їх посеред виконання.
@@ -1,11 +0,0 @@
1
- ---
2
- type: Directory Index
3
- title: npm/rules/js/eslint
4
- resource: npm/rules/js/eslint/
5
- ---
6
-
7
- | Файл | Тип |
8
- | ------------------------------- | --------- |
9
- | [fix-eslint.mjs](fix-eslint.md) | JS Module |
10
- | [fix-worker.mjs](fix-worker.md) | JS Module |
11
- | [main.mjs](main.md) | JS Module |
@@ -1,35 +0,0 @@
1
- ---
2
- type: JS Module
3
- title: main.mjs
4
- resource: npm/rules/js/eslint/main.mjs
5
- docgen:
6
- crc: e831a6e8
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
- Цей файл надає публічний інтерфейс для валідації коду, використовуючи інструменти Oxlint та ESLint. Він дозволяє визначати набір JavaScript-файлів для аналізу через функцію `filterJsFiles` та виконувати сам процес лінтингу за допомогою функції `lint`. Компонент є read-only, оскільки не здійснює змін до файлової системи чи баз даних. У разі виявлення помилок, механізм забезпечує fail-safe режим, перехоплюючи їх та не викликаючи винятків назовні.
16
-
17
- ## Поведінка
18
-
19
- Поведінка:
20
- filterJsFiles фільтрує список вказаних файлів, залишаючи лише ті, що відповідають розширенням JavaScript.
21
- lint запускає лінтинг для файлів. Якщо передаються файли, він аналізує їх на наявність порушень; якщо не передані, він виконує повний аналіз проекту.
22
-
23
- ## Публічний API
24
-
25
- filterJsFiles — відбирає файли для подальшої обробки.
26
- lint — проводить статичний аналіз коду (пофайлово або по всьому проєкту).
27
-
28
- ## Гарантії поведінки
29
-
30
- - Read-only: не виконує операцій запису (ФС/БД).
31
- - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
32
-
33
- **warnIgnored: false.** ESLint конструюється з `warnIgnored: false` — файли з delta-списку, що матчать ignore-патерни `eslint.config.js` (наприклад, синковані `.pi/extensions/**` чи згенеровані `npm/types/**`), не рахуються порушеннями.
34
-
35
- **Worktree-чекаути ігноруються.** Обидва інструменти виключають `.worktrees/**` і `.claude/worktrees/**` (копії репо від сесійних git-worktree, яких споживацький конфіг зазвичай не виключає): ESLint — через global ignores у `overrideConfig`, oxlint — через `--ignore-pattern`. Діє і у full-режимі, і для явно переданих файлів.