@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,53 +0,0 @@
1
- /** @see ./docs/layout.md */
2
- import { existsSync } from 'node:fs'
3
- import { join } from 'node:path'
4
-
5
- import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
6
-
7
- // Перевірка `devDependencies` кореневого `package.json` (дозволено лише `@nitra/*`)
8
- // — у rego (`npm/policy/bun/package_json/`). JS-копії `isAllowedRootDevDependency`
9
- // видалено, щоб не було двох джерел істини.
10
-
11
- /**
12
- * Перевіряє відповідність проєкту правилам bun.mdc
13
- * @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст lint-прогону
14
- * @returns {import('../../../scripts/lib/lint-surface/types.mjs').LintResult} результат перевірки
15
- */
16
- export function lint(ctx) {
17
- const cwd = ctx.cwd
18
- const reporter = createViolationReporter(ctx)
19
- const { pass, fail } = reporter
20
-
21
- for (const f of ['package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', '.yarnrc.yml']) {
22
- if (existsSync(join(cwd, f))) {
23
- fail(`Знайдено заборонений файл: ${f} — видали його`)
24
- } else {
25
- pass(`Немає ${f}`)
26
- }
27
- }
28
-
29
- if (existsSync(join(cwd, '.yarn'))) {
30
- fail('Знайдено директорію .yarn — видали її')
31
- } else {
32
- pass('Немає .yarn/')
33
- }
34
- if (existsSync(join(cwd, 'bun.lock'))) {
35
- pass('bun.lock є')
36
- } else {
37
- fail('Відсутній bun.lock — запусти bun i')
38
- }
39
-
40
- if (existsSync(join(cwd, 'bunfig.toml'))) {
41
- pass('bunfig.toml є (структуру перевіряє npx @7n/rules fix → bun.bunfig)')
42
- } else {
43
- fail('Відсутній bunfig.toml — створи з [install] linker = "hoisted" (bun.mdc)')
44
- }
45
-
46
- const pkgPath = join(cwd, 'package.json')
47
- if (!existsSync(pkgPath)) {
48
- fail('Відсутній package.json у корені')
49
- return reporter.result()
50
- }
51
-
52
- return reporter.result()
53
- }
@@ -1,7 +0,0 @@
1
- {
2
- "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
3
- "fixability": "config",
4
- "lint": {
5
- "scope": "full"
6
- }
7
- }
@@ -1,27 +0,0 @@
1
- ---
2
- type: JS Module
3
- title: fix-licensee.mjs
4
- resource: npm/rules/bun/licensee/fix-licensee.mjs
5
- docgen:
6
- crc: 5c27ef32
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
- Цей модуль виконує детерміновану генерацію конфігураційного файлу `.licensee.json` у корені проекту. Генерація відбувається через виконання канонічної команди `licensee --init`, що ініціалізує файл `.licensee.json` для забезпечення метаданих ліцензування проекту. Це механізм для встановлення початкової конфігурації.
16
-
17
- ## Поведінка
18
-
19
- Поведінка:
20
- 1. Перевіряється, чи існують порушення, пов'язані з відсутністю конфігурації `licensee` у контексті.
21
- 2. Якщо порушення виявлено, викликається команда `bun x licensee --init --production --quiet` у поточному робочому каталозі для створення або ініціалізації файлу `.licensee.json`.
22
- 3. Результат виконання команди фіксується, а файл `.licensee.json` позначається як змінений.
23
- 4. Якщо порушень немає, жодних дій не виконується.
24
-
25
- ## Гарантії поведінки
26
-
27
- - Пише лише `.licensee.json`; за відсутності `bun` у PATH — no-op.
@@ -1,12 +0,0 @@
1
- ---
2
- type: Directory Index
3
- title: npm/rules/bun/licensee
4
- resource: npm/rules/bun/licensee/
5
- ---
6
-
7
- # npm/rules/bun/licensee
8
-
9
- | Файл | Тип |
10
- | ----------------------------------- | --------- |
11
- | [fix-licensee.mjs](fix-licensee.md) | JS Module |
12
- | [main.mjs](main.md) | JS Module |
@@ -1,30 +0,0 @@
1
- ---
2
- type: JS Module
3
- title: main.mjs
4
- resource: npm/rules/bun/licensee/main.mjs
5
- docgen:
6
- crc: 787e39cc
7
- model: manual
8
- ---
9
-
10
- ## Огляд
11
-
12
- Read-only detector `bun/licensee`: перевіряє ліцензії npm-залежностей проєкту через зовнішній інструмент `licensee` (`bun x licensee`), звіряючи їх з allowlist у `.licensee.json`. Розрізняє два принципово різні провали: `licensee` знайшов реально заборонену ліцензію (`license-violation`) — і `licensee` сам впав з помилкою (fail-open діагностика, не порушення), наприклад через несумісність `@npmcli/arborist` (яким він читає `node_modules`) з деревом, зібраним `bun install`.
13
-
14
- ## Поведінка
15
-
16
- 1. Якщо `.licensee.json` відсутній — `licensee-config-missing`; генерація конфігу — окремий T0-фікс (`fix-licensee.mjs`), не тут.
17
- 2. Якщо `bun` не знайдено в PATH — `bun-missing`.
18
- 3. Запускає `bun x licensee --production --errors-only` (без `--quiet` — реальне порушення потребує деталі: ім'я/версія/ліцензія пакета, які `licensee` пише в stdout через `print()`).
19
- 4. Статус 0 — без порушень.
20
- 5. Статус ≠ 0 і є вивід у **stderr** — трактується як crash/`die()` самого `licensee` (invalid config або необроблений виняток усередині тула), НЕ як ліцензійне порушення: **fail-open** — warn-діагностика (видима у `--verbose`, не блокує exit code) зі stderr і підказкою перевірити вручну `bunx licensee --production`; fail-closed тут перманентно червонив би CI bun-монорепо.
21
- 6. Статус ≠ 0 і stderr порожній, є вивід у **stdout** — це справжній `NOT APPROVED`-звіт від `licensee` (`--errors-only` друкує лише невідповідні пакети): `license-violation` з деталлю пакета/ліцензії у повідомленні.
22
-
23
- ## Публічний API
24
-
25
- - `lint(ctx)` — detector-контракт unified lint surface; повертає `{ violations }` (при crash тула — `{ violations: [], diagnostics }`).
26
-
27
- ## Гарантії поведінки
28
-
29
- - Read-only: не пише `.licensee.json` і не змінює `node_modules`/lockfile сам (побічний ефект `bun x` — авто-встановлення пакета `licensee`, якщо відсутній у bunx-кеші, — керується bun, не цим модулем).
30
- - Канал stdout/stderr — єдиний сигнал розрізнення crash vs реальне порушення; текстові евристики за вмістом повідомлення не використовуються.
@@ -1,31 +0,0 @@
1
- /**
2
- * T0-autofix для `bun/licensee` — детермінована генерація `.licensee.json` через
3
- * `licensee --init` (canon-команда самого тула, та сама, що detector радить запустити
4
- * вручну). Реальні `license-violation` (файл є, але залежності не проходять) — НЕ
5
- * T0-фікс: потребують людського рішення про ліцензійну політику, не regen.
6
- */
7
- import { join } from 'node:path'
8
-
9
- import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
10
- import { spawnAsync } from '../../../scripts/utils/spawn-async.mjs'
11
-
12
- /** @type {import('../../../scripts/lib/lint-surface/types.mjs').T0Pattern[]} */
13
- export const patterns = [
14
- {
15
- id: 'bun-licensee-config-init',
16
- test: violations => violations.some(v => v.reason === 'licensee-config-missing'),
17
- apply: async (violations, ctx) => {
18
- const bun = resolveCmd('bun')
19
- if (!bun) return { touchedFiles: [] }
20
-
21
- await spawnAsync(bun, ['x', 'licensee', '--init', '--production', '--quiet'], {
22
- cwd: ctx.cwd,
23
- shell: false
24
- })
25
-
26
- const configPath = join(ctx.cwd, '.licensee.json')
27
- ctx.recordWrite?.(configPath)
28
- return { touchedFiles: [configPath], message: 'licensee --init: .licensee.json' }
29
- }
30
- }
31
- ]
@@ -1,68 +0,0 @@
1
- /**
2
- * lint-поверхня bun/licensee: read-only detector ліцензій npm-залежностей (`licensee`).
3
- * Генерація дефолтного `.licensee.json` — окремий T0-fix (`fix-licensee.mjs`), не в detector-і.
4
- */
5
- import { existsSync } from 'node:fs'
6
- import { join } from 'node:path'
7
-
8
- import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
9
- import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
10
- import { spawnAsync } from '../../../scripts/utils/spawn-async.mjs'
11
-
12
- /**
13
- * Detector bun/licensee: ліцензії npm-залежностей через `licensee` (read-only).
14
- * @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст lint-прогону
15
- * @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат detector-а
16
- */
17
- export async function lint(ctx) {
18
- const reporter = createViolationReporter(ctx)
19
- const { fail } = reporter
20
- const cwd = ctx.cwd
21
-
22
- const configPath = join(cwd, '.licensee.json')
23
- if (!existsSync(configPath)) {
24
- fail(
25
- 'lint-bun: licensee — немає .licensee.json; запустіть `npx @7n/rules lint bun` локально для генерації (bun.mdc)',
26
- 'licensee-config-missing'
27
- )
28
- return reporter.result()
29
- }
30
-
31
- const bun = resolveCmd('bun')
32
- if (!bun) {
33
- fail('lint-bun: `bun` не знайдено в PATH (bun.mdc)', 'bun-missing')
34
- return reporter.result()
35
- }
36
-
37
- // Без --quiet: `licensee` пише реальні NOT APPROVED записи (name/version/license) у
38
- // stdout через print() — деталь замість голого "код 1". Crash/die() усередині
39
- // самого тула (invalid config, внутрішній виняток на кшталт "Cannot read properties
40
- // of undefined (reading 'localeCompare')" — спостережено з @npmcli/arborist на
41
- // bun-based node_modules) завжди йде у stderr через die(); легітимний звіт про
42
- // порушення — лише у stdout. Канал розрізняє crash від реального порушення.
43
- const r = await spawnAsync(bun, ['x', 'licensee', '--production', '--errors-only'], { cwd, shell: false })
44
- if (r.exitCode !== 0) {
45
- const stderr = (r.stderr ?? '').trim().slice(0, 2000)
46
- if (stderr) {
47
- // Crash самого тула — НЕ підтверджене ліцензійне порушення: fail-open
48
- // діагностикою (не блокує CI-гейт). Fail-closed тут перманентно червонив би
49
- // bun-монорепо: @npmcli/arborist (яким licensee читає node_modules)
50
- // несумісний із деревом bun install.
51
- const result = reporter.result()
52
- result.diagnostics = [
53
- {
54
- level: 'warn',
55
- message:
56
- `lint-bun: licensee — інструмент завершився з помилкою, це НЕ підтверджене ліцензійне порушення ` +
57
- `(код ${r.exitCode}, bun.mdc). Ймовірна причина — несумісність @npmcli/arborist з деревом bun install. ` +
58
- `Перевір вручну: \`bunx licensee --production\`.\n${stderr}`
59
- }
60
- ]
61
- return result
62
- }
63
- const stdout = (r.stdout ?? '').trim().slice(0, 2000)
64
- const detail = stdout ? `\n${stdout}` : ''
65
- fail(`lint-bun: licensee — порушення ліцензій (код ${r.exitCode}, bun.mdc)${detail}`, 'license-violation')
66
- }
67
- return reporter.result()
68
- }
@@ -1,3 +0,0 @@
1
- {
2
- "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json"
3
- }
@@ -1,13 +0,0 @@
1
- ## Лінт через n-rules, не package.json-скрипти
2
-
3
- Лінт запускається через CLI **`n-rules`** (локально) / **`npx @7n/rules`** (без локальної інсталяції),
4
- **не** через `package.json`-скрипти:
5
-
6
- - **`npx @7n/rules lint --full`** — весь репо (CI-режим);
7
- - **`npx @7n/rules lint`** — дельта vs origin (лише змінені файли, типовий задачний прогін);
8
- - **`n-rules lint <rule…>`** — конкретні правила, напр. **`n-rules lint ga`**.
9
-
10
- У кореневому `package.json` **не повинно бути** `lint`/`lint-*` скриптів — єдина точка лінту — CLI
11
- `n-rules` (пакет `@7n/rules`). Цей запис механічно перевіряється Rego-gate'ом
12
- [`bun.package_json`](../package_json/package_json.mdc) (deny на `scripts.lint` / `scripts.lint-*`) —
13
- тут лишається лише пояснення *чому* так (єдина точка входу для лінту), без дублювання самого чеку.
@@ -1 +0,0 @@
1
- { "auto": { "glob": ["package.json", ".licensee.json"] } }
@@ -1,11 +0,0 @@
1
- ---
2
- description: Bun як єдиний package manager у монорепо
3
- globs: "**/package.json,**/bunfig.toml,**/bun.lock,**/bun.lockb"
4
- alwaysApply: false
5
- version: '2.1'
6
- ---
7
-
8
- Проект використовує тільки Bun для керування залежностями та запуску скриптів.
9
-
10
- - [package.json.deny.json](./package_json/template/package.json.deny.json)
11
- - [bunfig.toml.snippet.toml](./bunfig/template/bunfig.toml.snippet.toml)
@@ -1,9 +0,0 @@
1
- {
2
- "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
3
- "fixability": "config",
4
- "policy": {
5
- "files": {
6
- "single": "package.json"
7
- }
8
- }
9
- }
@@ -1,28 +0,0 @@
1
- ---
2
- type: JS Module
3
- title: fix-package_json.mjs
4
- resource: npm/rules/bun/package_json/fix-package_json.mjs
5
- docgen:
6
- crc: f55b3994
7
- model: openai-codex/gpt-5.4-mini
8
- score: 100
9
- issues: judge:inaccurate:0.97
10
- judgeModel: openai-codex/gpt-5.4-mini
11
- ---
12
-
13
- ## Огляд
14
-
15
- Файл знаходить `package.json` із порушеннями policy `bun/package_json` серед заборонених top-level полів і `scripts.lint` / `scripts.lint-*` та запускає T0-autofix для цих випадків. Він видаляє top-level поля за каноном `template/package.json.deny.json` і `package.json.deny.json`, а lint-скрипти переписує на канонічний `bunx n-rules lint ...` лише після репо-wide пошуку всіх їхніх викликів; нерозпізнані виклики лишаються без змін, і в такому разі скрипт не видаляється. Помилки обробляє fail-safe і не кидає назовні.
16
-
17
- ## Поведінка
18
-
19
- 1. `patterns` знаходить package.json, у яких є порушення policy для `bun/package_json`, і запускає T0-autofix лише для них.
20
- 2. Для кожного такого package.json вона орієнтується на канон deny-списку з `template/package.json.deny.json` і прибирає заборонені top-level поля.
21
- 3. Якщо в `package.json` є `scripts.lint` або `scripts.lint-*`, вона спершу шукає їхні виклики в репозиторії та переписує їх на канонічний `bunx n-rules lint ...`, щоб не зламати споживачів цих скриптів.
22
- 4. Власні скрипти цього ж `package.json` теж оновлюються до канонічного запуску, якщо вони посилаються на lint-скрипти, що плануються до видалення.
23
- 5. Скрипт видаляє `scripts.lint*` лише тоді, коли для них не лишається нерозпізнаних викликів; якщо десь є незрозумілий спосіб запуску, він лишає скрипт на місці й лише повідомляє про це.
24
- 6. Після змін вона записує оновлений `package.json` і повертає перелік зачеплених файлів та короткий підсумок змін; назовні помилки не пробиваються.
25
-
26
- ## Гарантії поведінки
27
-
28
- - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
@@ -1,9 +0,0 @@
1
- ---
2
- type: Directory Index
3
- title: npm/rules/bun/package_json
4
- resource: npm/rules/bun/package_json/
5
- ---
6
-
7
- | Файл | Тип |
8
- | ------------------------------------------- | --------- |
9
- | [fix-package_json.mjs](fix-package_json.md) | JS Module |
@@ -1,311 +0,0 @@
1
- /**
2
- * T0-autofix для policy-concern-а `bun/package_json`: видаляє заборонені top-level поля
3
- * (канон — `template/package.json.deny.json`, той самий `data.template.deny`, що бачить rego)
4
- * і `scripts.lint` / `scripts.lint-*` (bun.mdc — лінт лише через `n-rules lint`, не npm-скрипти).
5
- *
6
- * Просте видалення `scripts.lint*` небезпечне: якщо десь у репо (workflow yml, інший
7
- * npm-скрипт) є виклик `bun run lint-js` тощо, видалення ключа зламає цей виклик.
8
- * Тому перед видаленням шукаємо всі виклики кожного lint-скрипта репо-вайд і переписуємо
9
- * їх на прямий `bunx n-rules lint <surface>` (canonical — той самий, що вимагають
10
- * lint_js_yml/lint_style_yml). Скрипт видаляється лише якщо ВСІ його виклики вдалось
11
- * переписати (файли, де виклик не розпізнано — залишаємо як є, скрипт теж лишається,
12
- * щоб не зламати консьюмера мовчки).
13
- */
14
- import { existsSync, readFileSync, writeFileSync } from 'node:fs'
15
- import { join } from 'node:path'
16
-
17
- import { walkDir } from '../../../scripts/utils/walkDir.mjs'
18
- import { loadCursorIgnorePaths } from '../../../scripts/lib/load-cursor-config.mjs'
19
-
20
- const LINT_SCRIPT_RE = /^lint(-.*)?$/u
21
- const WORKFLOW_YML_RE = /^\.github\/workflows\/.*\.ya?ml$/u
22
- const LOCKFILE_RE = /(^|\/)(bun\.lockb?|package-lock\.json|yarn\.lock|pnpm-lock\.yaml)$/u
23
- const PACKAGE_MANAGER_SCRIPT_PREFIX_RE = /\b(?:(?:bun|yarn|pnpm)(?:\s+run)?|npm\s+run)\s+/gu
24
- const SCRIPT_NAME_CONTINUATION_RE = /[\w-]/u
25
-
26
- // `lint-<suffix>` → rule-id канонічного `n-rules lint <rule-id>`; bare `lint` → без rule-id.
27
- const SURFACE_MAP = { image: 'image-compress' }
28
-
29
- /**
30
- * @param {string} scriptName напр. `lint-js`, `lint`
31
- * @returns {string} суфікс аргументу для `n-rules lint` (порожній рядок для bare `lint`)
32
- */
33
- function surfaceArgFor(scriptName) {
34
- const suffix = scriptName.slice('lint'.length)
35
- if (suffix.length === 0) return ''
36
- const normalized = suffix.startsWith('-') ? suffix.slice(1) : suffix
37
- return ` ${SURFACE_MAP[normalized] ?? normalized}`
38
- }
39
-
40
- /**
41
- * Знаходить діапазони виклику package-manager-ом заданого npm-скрипта: `bun[ run] X`,
42
- * `yarn[ run] X`, `pnpm[ run] X`, `npm run X` (голий `npm X` — не валідний npm-синтаксис,
43
- * окрім start/test). Right-boundary — НЕ `\b` (hyphen — non-word char, тож `lint\b`
44
- * матчить всередині `lint-js`), а перевірка проти `[\w-]`, щоб `lint` не «зжирав»
45
- * префікс `lint-js`.
46
- * @param {string} content вміст для пошуку
47
- * @param {string} scriptName ім'я npm-скрипта
48
- * @returns {Array<[number, number]>} діапазони повного виклику в content
49
- */
50
- function invocationRanges(content, scriptName) {
51
- /** @type {Array<[number, number]>} */
52
- const ranges = []
53
- PACKAGE_MANAGER_SCRIPT_PREFIX_RE.lastIndex = 0
54
- let match
55
- while ((match = PACKAGE_MANAGER_SCRIPT_PREFIX_RE.exec(content))) {
56
- const scriptStart = PACKAGE_MANAGER_SCRIPT_PREFIX_RE.lastIndex
57
- if (!content.startsWith(scriptName, scriptStart)) continue
58
- const scriptEnd = scriptStart + scriptName.length
59
- if (SCRIPT_NAME_CONTINUATION_RE.test(content[scriptEnd] ?? '')) continue
60
- ranges.push([match.index, scriptEnd])
61
- }
62
- return ranges
63
- }
64
-
65
- /**
66
- * Читає JSON-файл template-а з deny-полями концерну; відсутній/невалідний → {}.
67
- * @param {string} path абсолютний шлях
68
- * @returns {Record<string, string>} мапа `field -> reason`
69
- */
70
- function readDenyTemplate(path) {
71
- if (!existsSync(path)) return {}
72
- try {
73
- return JSON.parse(readFileSync(path, 'utf8'))
74
- } catch {
75
- return {}
76
- }
77
- }
78
-
79
- /**
80
- * `workflow`/`package-json` — відомий, безпечно переписуваний формат; `other` — будь-який
81
- * інший текстовий файл (Makefile, README, shell-скрипт…), де ми ЛИШЕ детектуємо виклик,
82
- * але не переписуємо (немає надійного canonical-заміщення для довільного формату).
83
- * @typedef {'workflow'|'package-json'|'other'} FileKind
84
- */
85
-
86
- /**
87
- * @param {string} rel posix-відносний шлях від кореня репо
88
- * @param {string} abs абсолютний шлях
89
- * @param {string} rootPkgAbs абсолютний шлях кореневого package.json (сам він — не кандидат)
90
- * @returns {FileKind|null} категорія файлу, або null якщо файл взагалі не кандидат (лок-файли)
91
- */
92
- function classifyCandidate(rel, abs, rootPkgAbs) {
93
- if (LOCKFILE_RE.test(rel)) return null
94
- if (WORKFLOW_YML_RE.test(rel)) return 'workflow'
95
- if (rel.endsWith('package.json')) return abs === rootPkgAbs ? null : 'package-json'
96
- return 'other'
97
- }
98
-
99
- /**
100
- * Знаходить УСІ файли репозиторію (крім кореневого package.json і лок-файлів) як кандидатів
101
- * на пошук викликів npm-скриптів — виклик може бути де завгодно (Makefile, README, CI,
102
- * інший package.json), не лише у відомих форматах.
103
- * @param {string} cwd абсолютний корінь репозиторію
104
- * @param {string} rootPkgAbs абсолютний шлях кореневого package.json (виключити)
105
- * @returns {Promise<Array<{ abs: string, kind: FileKind }>>} кандидати з категорією
106
- */
107
- async function findUsageCandidateFiles(cwd, rootPkgAbs) {
108
- const ignorePaths = await loadCursorIgnorePaths(cwd)
109
- /** @type {Array<{ abs: string, kind: FileKind }>} */
110
- const out = []
111
- await walkDir(
112
- cwd,
113
- abs => {
114
- const rel = abs
115
- .slice(cwd.length + 1)
116
- .split('\\')
117
- .join('/')
118
- const kind = classifyCandidate(rel, abs, rootPkgAbs)
119
- if (kind) out.push({ abs, kind })
120
- },
121
- ignorePaths
122
- )
123
- return out
124
- }
125
-
126
- /**
127
- * Переписує один файл-кандидат: кожен знайдений виклик `scriptName` замінюється на
128
- * канонічний `bunx n-rules lint<surface>` (workflow yml — з `--no-fix`, package.json
129
- * scripts-чейни — без, дев-контекст хоче autofix).
130
- * @param {string} content вміст файлу
131
- * @param {string} scriptName ім'я lint-скрипта
132
- * @param {boolean} isWorkflow чи це workflow yml (інакше — package.json)
133
- * @returns {{ content: string, matched: boolean }} новий вміст і чи був матч
134
- */
135
- function rewriteUsages(content, scriptName, isWorkflow) {
136
- const ranges = invocationRanges(content, scriptName)
137
- if (ranges.length === 0) return { content, matched: false }
138
- const canonical = `bunx n-rules lint${surfaceArgFor(scriptName)}${isWorkflow ? ' --no-fix' : ''}`
139
- let next = ''
140
- let lastIndex = 0
141
- for (const [start, end] of ranges) {
142
- next += content.slice(lastIndex, start) + canonical
143
- lastIndex = end
144
- }
145
- next += content.slice(lastIndex)
146
- return { content: next, matched: true }
147
- }
148
-
149
- /**
150
- * Для кожного lint-скрипта шукає й переписує його виклики по всіх кандидатах.
151
- * `workflow`/`package-json` — переписуємо на канонічний `bunx n-rules lint`; `other`
152
- * (Makefile, README, довільний shell) — лише детектуємо, без canonical-заміщення для
153
- * довільного формату скрипт НЕ видаляємо (блокуючий, а не мовчки проігнорований, збіг).
154
- * @param {string[]} scriptNames кандидати на видалення (`lint`, `lint-js`, …)
155
- * @param {Array<{ abs: string, kind: FileKind }>} candidateFiles файли-кандидати з категорією
156
- * @param {(absPath: string) => void} recordWrite реєстрація запису для rollback
157
- * @returns {{ safeToRemove: Set<string>, touchedFiles: string[] }} скрипти без залишкових
158
- * викликів (безпечно видалити) і список фактично змінених файлів
159
- */
160
- function adaptUsages(scriptNames, candidateFiles, recordWrite) {
161
- const unresolved = new Set()
162
- const touchedFiles = []
163
- const sortedNames = scriptNames.toSorted((a, b) => b.length - a.length)
164
-
165
- for (const { abs, kind } of candidateFiles) {
166
- if (kind === 'other') continue
167
- const isWorkflow = kind === 'workflow'
168
- let content
169
- try {
170
- content = readFileSync(abs, 'utf8')
171
- } catch {
172
- continue
173
- }
174
- let next = content
175
- // Найдовші імена першими (defense-in-depth поряд із right-boundary lookahead) —
176
- // `lint-js` перепишеться до того, як коротший `lint` встигне зачепити його префікс.
177
- for (const name of sortedNames) next = rewriteUsages(next, name, isWorkflow).content
178
- if (next === content) continue
179
- recordWrite?.(abs)
180
- writeFileSync(abs, next)
181
- touchedFiles.push(abs)
182
- }
183
-
184
- // Другий прохід (після переписів) — чи лишився десь виклик, який ми не розпізнали
185
- // (`other`-формат або невідомий package-manager-синтаксис); такий скрипт НЕ видаляємо.
186
- for (const { abs } of candidateFiles) {
187
- let content
188
- try {
189
- content = readFileSync(abs, 'utf8')
190
- } catch {
191
- continue
192
- }
193
- for (const name of scriptNames) {
194
- if (invocationRanges(content, name).length > 0) unresolved.add(name)
195
- }
196
- }
197
-
198
- return { safeToRemove: new Set(scriptNames.filter(n => !unresolved.has(n))), touchedFiles }
199
- }
200
-
201
- /**
202
- * Адаптує виклики lint-скриптів в ІНШИХ скриптах ТОГО Ж package.json (напр. `precommit`:
203
- * `bun run lint-js && bun test`) — цей файл не потрапляє у зовнішній `findUsageCandidateFiles`,
204
- * бо він же ціль видалення. Мутує `pkg.scripts` на місці.
205
- * @param {object} pkg розпарсений package.json (мутується)
206
- * @param {string[]} scriptNames кандидати на видалення
207
- * @returns {Set<string>} імена, для яких лишився нерозпізнаний виклик у власних скриптах
208
- */
209
- function adaptOwnScripts(pkg, scriptNames) {
210
- const unresolved = new Set()
211
- if (!pkg.scripts || typeof pkg.scripts !== 'object') return unresolved
212
-
213
- const sorted = scriptNames.toSorted((a, b) => b.length - a.length)
214
- const otherEntries = Object.entries(pkg.scripts).filter(
215
- ([key, value]) => !scriptNames.includes(key) && typeof value === 'string'
216
- )
217
-
218
- for (const [key, value] of otherEntries) {
219
- let next = value
220
- for (const name of sorted) next = rewriteUsages(next, name, false).content
221
- if (next !== value) pkg.scripts[key] = next
222
- }
223
- // Пере-перевірка після мутації: чи лишився десь нерозпізнаний виклик.
224
- for (const [key] of otherEntries) {
225
- const current = pkg.scripts[key]
226
- if (typeof current !== 'string') continue
227
- for (const name of scriptNames) {
228
- if (invocationRanges(current, name).length > 0) unresolved.add(name)
229
- }
230
- }
231
- return unresolved
232
- }
233
-
234
- /**
235
- * Видаляє заборонені top-level поля й `scripts.lint*` (лише ті, чиї виклики вже адаптовано)
236
- * з `package.json`.
237
- * @param {object} pkg розпарсений package.json
238
- * @param {Record<string, string>} denyFields канон заборонених top-level полів
239
- * @param {Set<string>} safeToRemove скрипти без залишкових зовнішніх викликів
240
- * @returns {string[]} список видалених ключів (для message)
241
- */
242
- function stripDenied(pkg, denyFields, safeToRemove) {
243
- const removed = []
244
- for (const field of Object.keys(denyFields)) {
245
- if (!Object.hasOwn(pkg, field)) continue
246
- delete pkg[field]
247
- removed.push(field)
248
- }
249
- if (pkg.scripts && typeof pkg.scripts === 'object') {
250
- for (const name of Object.keys(pkg.scripts)) {
251
- if (!LINT_SCRIPT_RE.test(name) || !safeToRemove.has(name)) continue
252
- delete pkg.scripts[name]
253
- removed.push(`scripts.${name}`)
254
- }
255
- }
256
- return removed
257
- }
258
-
259
- /** @type {import('../../../scripts/lib/lint-surface/types.mjs').T0Pattern[]} */
260
- export const patterns = [
261
- {
262
- id: 'bun-package_json-strip-denied',
263
- test: violations => violations.some(v => v.reason === 'policy-deny' && v.file),
264
- apply: async (violations, ctx) => {
265
- const denyFields = readDenyTemplate(join(ctx.concernDir ?? '', 'template', 'package.json.deny.json'))
266
- const files = [...new Set(violations.filter(v => v.file).map(v => v.file))]
267
- const touchedFiles = []
268
- const messages = []
269
-
270
- for (const rel of files) {
271
- const abs = join(ctx.cwd, rel)
272
- let pkg
273
- try {
274
- pkg = JSON.parse(readFileSync(abs, 'utf8'))
275
- } catch {
276
- continue
277
- }
278
-
279
- const lintScriptNames =
280
- pkg.scripts && typeof pkg.scripts === 'object'
281
- ? Object.keys(pkg.scripts).filter(n => LINT_SCRIPT_RE.test(n))
282
- : []
283
-
284
- let safeToRemove = new Set(lintScriptNames)
285
- if (lintScriptNames.length > 0) {
286
- const ownUnresolved = adaptOwnScripts(pkg, lintScriptNames)
287
- const candidateFiles = await findUsageCandidateFiles(ctx.cwd, abs)
288
- const adapted = adaptUsages(lintScriptNames, candidateFiles, ctx.recordWrite)
289
- safeToRemove = new Set([...adapted.safeToRemove].filter(n => !ownUnresolved.has(n)))
290
- touchedFiles.push(...adapted.touchedFiles)
291
- const skipped = lintScriptNames.filter(n => !safeToRemove.has(n))
292
- if (skipped.length > 0) {
293
- messages.push(
294
- `${rel}: не видаляю scripts.${skipped.join(', scripts.')} — знайдено нерозпізнаний виклик деінде`
295
- )
296
- }
297
- }
298
-
299
- const removed = stripDenied(pkg, denyFields, safeToRemove)
300
- if (removed.length === 0) continue
301
-
302
- ctx.recordWrite?.(abs)
303
- writeFileSync(abs, `${JSON.stringify(pkg, null, 2)}\n`)
304
- touchedFiles.push(abs)
305
- messages.push(`${rel}: -${removed.join(', -')}`)
306
- }
307
-
308
- return touchedFiles.length > 0 ? { touchedFiles, message: messages.join('; ') } : { touchedFiles: [] }
309
- }
310
- }
311
- ]
@@ -1,14 +0,0 @@
1
- ## Rego-gate: заборонені поля та devDependencies у кореневому package.json
2
-
3
- Rego-пакет: `bun.package_json`
4
-
5
- Цільовий файл: кореневий `package.json`.
6
-
7
- Список заборонених top-level полів (template-driven): [package.json.deny.json](./template/package.json.deny.json)
8
-
9
- Gate виносить два класи deny:
10
-
11
- 1. **Заборонені top-level поля** — будь-яке поле з `package.json.deny.json` присутнє у файлі (навіть із порожнім значенням `{}`).
12
- 2. **devDependencies не з білого списку** — дозволені лише `@nitra/*`/`@7n/*` та root-only тестові peer/tools (`vitest`, `@vitest/coverage-v8`, `@stryker-mutator/vitest-runner`, `@playwright/test`). Будь-який інший пакет → deny. CLI-тули, які `n-rules lint` спавнить через `bunx` (oxlint, jscpd, v8r, github-actionlint тощо), у root не пінуються — вони приїжджають як `dependencies` пакета `@7n/rules` (npm-module.mdc).
13
-
14
- Перевірки, що потребують FS або cross-file контексту (наприклад наявність `yarn.lock`), лишаються у JS-шарі.