@7n/rules-lang-js 0.3.1 → 0.4.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 (258) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +14 -4
  3. package/rules/bun/bunfig/bunfig.mdc +17 -0
  4. package/rules/bun/bunfig/bunfig.rego +29 -0
  5. package/rules/bun/bunfig/concern.json +9 -0
  6. package/rules/bun/bunfig/template/bunfig.toml.snippet.toml +2 -0
  7. package/rules/bun/docs/index.md +11 -0
  8. package/rules/bun/layout/concern.json +16 -0
  9. package/rules/bun/layout/docs/fix-layout.md +29 -0
  10. package/rules/bun/layout/docs/main.md +34 -0
  11. package/rules/bun/layout/fix-layout.mjs +63 -0
  12. package/rules/bun/layout/layout.mdc +60 -0
  13. package/rules/bun/layout/main.mjs +53 -0
  14. package/rules/bun/licensee/concern.json +7 -0
  15. package/rules/bun/licensee/docs/fix-licensee.md +27 -0
  16. package/rules/bun/licensee/docs/index.md +12 -0
  17. package/rules/bun/licensee/docs/main.md +30 -0
  18. package/rules/bun/licensee/fix-licensee.mjs +31 -0
  19. package/rules/bun/licensee/main.mjs +68 -0
  20. package/rules/bun/lint-surface/concern.json +3 -0
  21. package/rules/bun/lint-surface/lint-surface.mdc +13 -0
  22. package/rules/bun/main.json +1 -0
  23. package/rules/bun/main.mdc +11 -0
  24. package/rules/bun/package_json/concern.json +9 -0
  25. package/rules/bun/package_json/docs/fix-package_json.md +28 -0
  26. package/rules/bun/package_json/docs/index.md +9 -0
  27. package/rules/bun/package_json/fix-package_json.mjs +311 -0
  28. package/rules/bun/package_json/package_json.mdc +14 -0
  29. package/rules/bun/package_json/package_json.rego +64 -0
  30. package/rules/bun/package_json/template/package.json.deny.json +4 -0
  31. package/rules/js/check/check.mdc +26 -0
  32. package/rules/js/check/concern.json +19 -0
  33. package/rules/js/check/docs/eslint-config.md +56 -0
  34. package/rules/js/check/docs/fix-check.md +48 -0
  35. package/rules/js/check/docs/index.md +13 -0
  36. package/rules/js/check/docs/main.md +48 -0
  37. package/rules/js/check/eslint-config.mjs +262 -0
  38. package/rules/js/check/fix-check.mjs +82 -0
  39. package/rules/js/check/main.mjs +310 -0
  40. package/rules/js/dep-policy/concern.json +4 -0
  41. package/rules/js/dep-policy/dep-policy.mdc +36 -0
  42. package/rules/js/dep-policy/docs/main.md +35 -0
  43. package/rules/js/dep-policy/main.mjs +99 -0
  44. package/rules/js/docs/index.md +11 -0
  45. package/rules/js/eslint/concern.json +8 -0
  46. package/rules/js/eslint/docs/fix-eslint.md +50 -0
  47. package/rules/js/eslint/docs/fix-worker.md +31 -0
  48. package/rules/js/eslint/docs/index.md +11 -0
  49. package/rules/js/eslint/docs/main.md +35 -0
  50. package/rules/js/eslint/fix-eslint.mjs +160 -0
  51. package/rules/js/eslint/fix-worker.mjs +139 -0
  52. package/rules/js/eslint/main.mjs +115 -0
  53. package/rules/js/file-extensions/concern.json +3 -0
  54. package/rules/js/file-extensions/file-extensions.mdc +12 -0
  55. package/rules/js/jscpd_config/concern.json +11 -0
  56. package/rules/js/jscpd_config/docs/fix-jscpd_config.md +25 -0
  57. package/rules/js/jscpd_config/docs/index.md +9 -0
  58. package/rules/js/jscpd_config/fix-jscpd_config.mjs +3 -0
  59. package/rules/js/jscpd_config/jscpd_config.mdc +42 -0
  60. package/rules/js/jscpd_config/jscpd_config.rego +44 -0
  61. package/rules/js/jscpd_config/template/.jscpd.json.snippet.json +7 -0
  62. package/rules/js/jscpd_duplicates/concern.json +7 -0
  63. package/rules/js/jscpd_duplicates/docs/main.md +29 -0
  64. package/rules/js/jscpd_duplicates/main.mjs +69 -0
  65. package/rules/js/knip/concern.json +7 -0
  66. package/rules/js/knip/docs/main.md +31 -0
  67. package/rules/js/knip/knip.mdc +15 -0
  68. package/rules/js/knip/main.mjs +89 -0
  69. package/rules/js/lint-findings/concern.json +3 -0
  70. package/rules/js/lint-findings/docs/main.md +40 -0
  71. package/rules/js/lint-findings/main.mjs +125 -0
  72. package/rules/js/main.json +1 -0
  73. package/rules/js/main.mdc +18 -0
  74. package/rules/js/package_json/concern.json +9 -0
  75. package/rules/js/package_json/docs/fix-package_json.md +25 -0
  76. package/rules/js/package_json/docs/index.md +9 -0
  77. package/rules/js/package_json/fix-package_json.mjs +3 -0
  78. package/rules/js/package_json/package_json.mdc +15 -0
  79. package/rules/js/package_json/package_json.rego +142 -0
  80. package/rules/js/package_json/template/package.json.snippet.json +6 -0
  81. package/rules/js/tooling/concern.json +3 -0
  82. package/rules/js/tooling/data/tooling/knip-canonical.json +30 -0
  83. package/rules/js/tooling/data/tooling/oxlint-canonical.json +400 -0
  84. package/rules/js/tooling/docs/main.md +53 -0
  85. package/rules/js/tooling/main.mjs +183 -0
  86. package/rules/js/utils_imports/concern.json +4 -0
  87. package/rules/js/utils_imports/docs/main.md +50 -0
  88. package/rules/js/utils_imports/main.mjs +185 -0
  89. package/rules/js/utils_imports/utils_imports.mdc +15 -0
  90. package/rules/js/vscode_extensions/concern.json +11 -0
  91. package/rules/js/vscode_extensions/docs/fix-vscode_extensions.md +24 -0
  92. package/rules/js/vscode_extensions/docs/index.md +11 -0
  93. package/rules/js/vscode_extensions/fix-vscode_extensions.mjs +1 -0
  94. package/rules/js/vscode_extensions/template/extensions.json.snippet.json +6 -0
  95. package/rules/js/vscode_extensions/vscode_extensions.mdc +11 -0
  96. package/rules/js/vscode_extensions/vscode_extensions.rego +12 -0
  97. package/rules/js-bun-db/connection/concern.json +3 -0
  98. package/rules/js-bun-db/connection/connection.mdc +42 -0
  99. package/rules/js-bun-db/docs/index.md +11 -0
  100. package/rules/js-bun-db/lib/bun-sql-scan.mjs +1047 -0
  101. package/rules/js-bun-db/lib/docs/bun-sql-scan.md +63 -0
  102. package/rules/js-bun-db/lib/docs/index.md +11 -0
  103. package/rules/js-bun-db/main.json +1 -0
  104. package/rules/js-bun-db/main.mdc +8 -0
  105. package/rules/js-bun-db/package_json/concern.json +9 -0
  106. package/rules/js-bun-db/package_json/package_json.mdc +31 -0
  107. package/rules/js-bun-db/package_json/package_json.rego +15 -0
  108. package/rules/js-bun-db/package_json/template/package.json.deny.json +6 -0
  109. package/rules/js-bun-db/pg_format_identifiers/concern.json +3 -0
  110. package/rules/js-bun-db/pg_format_identifiers/pg_format_identifiers.mdc +104 -0
  111. package/rules/js-bun-db/safety/concern.json +4 -0
  112. package/rules/js-bun-db/safety/docs/main.md +34 -0
  113. package/rules/js-bun-db/safety/main.mjs +430 -0
  114. package/rules/js-bun-db/safety/safety.mdc +458 -0
  115. package/rules/js-bun-redis/docs/index.md +11 -0
  116. package/rules/js-bun-redis/imports/concern.json +4 -0
  117. package/rules/js-bun-redis/imports/docs/main.md +36 -0
  118. package/rules/js-bun-redis/imports/imports.mdc +47 -0
  119. package/rules/js-bun-redis/imports/main.mjs +88 -0
  120. package/rules/js-bun-redis/lib/docs/index.md +11 -0
  121. package/rules/js-bun-redis/lib/docs/redis-imports.md +227 -0
  122. package/rules/js-bun-redis/lib/redis-imports.mjs +130 -0
  123. package/rules/js-bun-redis/main.json +1 -0
  124. package/rules/js-bun-redis/main.mdc +8 -0
  125. package/rules/js-bun-redis/package_json/concern.json +9 -0
  126. package/rules/js-bun-redis/package_json/package_json.mdc +11 -0
  127. package/rules/js-bun-redis/package_json/package_json.rego +15 -0
  128. package/rules/js-bun-redis/package_json/template/package.json.deny.json +12 -0
  129. package/rules/js-mssql/deps/concern.json +4 -0
  130. package/rules/js-mssql/deps/docs/main.md +33 -0
  131. package/rules/js-mssql/deps/main.mjs +297 -0
  132. package/rules/js-mssql/docs/index.md +11 -0
  133. package/rules/js-mssql/lib/docs/index.md +11 -0
  134. package/rules/js-mssql/lib/docs/mssql-pool-scan.md +380 -0
  135. package/rules/js-mssql/lib/mssql-pool-scan.mjs +610 -0
  136. package/rules/js-mssql/main.json +1 -0
  137. package/rules/js-mssql/main.mdc +144 -0
  138. package/rules/js-mssql/mssql-tvp/concern.json +3 -0
  139. package/rules/js-mssql/mssql-tvp/mssql-tvp.mdc +77 -0
  140. package/rules/js-mssql/package_json/concern.json +9 -0
  141. package/rules/js-mssql/package_json/package_json.mdc +9 -0
  142. package/rules/js-mssql/package_json/package_json.rego +57 -0
  143. package/rules/js-run/configmap/concern.json +9 -0
  144. package/rules/js-run/configmap/configmap.mdc +37 -0
  145. package/rules/js-run/configmap/configmap.rego +21 -0
  146. package/rules/js-run/configmap/template/configmap.yaml.contains.yml +4 -0
  147. package/rules/js-run/docs/index.md +11 -0
  148. package/rules/js-run/jsconfig/concern.json +9 -0
  149. package/rules/js-run/jsconfig/docs/fix-jsconfig.md +28 -0
  150. package/rules/js-run/jsconfig/docs/index.md +9 -0
  151. package/rules/js-run/jsconfig/fix-jsconfig.mjs +119 -0
  152. package/rules/js-run/jsconfig/jsconfig.mdc +48 -0
  153. package/rules/js-run/jsconfig/jsconfig.rego +59 -0
  154. package/rules/js-run/jsconfig/template/jsconfig.json.snippet.json +10 -0
  155. package/rules/js-run/lib/bunyan-imports.mjs +98 -0
  156. package/rules/js-run/lib/check-env-scan.mjs +338 -0
  157. package/rules/js-run/lib/conn-file-rules.mjs +214 -0
  158. package/rules/js-run/lib/conn-imports-scan.mjs +154 -0
  159. package/rules/js-run/lib/docs/bunyan-imports.md +121 -0
  160. package/rules/js-run/lib/docs/check-env-scan.md +438 -0
  161. package/rules/js-run/lib/docs/conn-file-rules.md +304 -0
  162. package/rules/js-run/lib/docs/conn-imports-scan.md +208 -0
  163. package/rules/js-run/lib/docs/index.md +16 -0
  164. package/rules/js-run/lib/docs/promise-settimeout-scan.md +334 -0
  165. package/rules/js-run/lib/docs/temporal-scan.md +29 -0
  166. package/rules/js-run/lib/promise-settimeout-scan.mjs +128 -0
  167. package/rules/js-run/lib/temporal-scan.mjs +52 -0
  168. package/rules/js-run/main.json +1 -0
  169. package/rules/js-run/main.mdc +16 -0
  170. package/rules/js-run/package_json/concern.json +9 -0
  171. package/rules/js-run/package_json/package_json.mdc +44 -0
  172. package/rules/js-run/package_json/package_json.rego +37 -0
  173. package/rules/js-run/package_json/template/package.json.deny.json +22 -0
  174. package/rules/js-run/project-structure/concern.json +3 -0
  175. package/rules/js-run/project-structure/project-structure.mdc +11 -0
  176. package/rules/js-run/runtime/concern.json +12 -0
  177. package/rules/js-run/runtime/docs/fix-runtime.md +27 -0
  178. package/rules/js-run/runtime/docs/main.md +35 -0
  179. package/rules/js-run/runtime/fix-runtime.mjs +46 -0
  180. package/rules/js-run/runtime/main.mjs +496 -0
  181. package/rules/js-run/runtime/runtime.mdc +184 -0
  182. package/rules/js-run/scope/concern.json +3 -0
  183. package/rules/js-run/scope/scope.mdc +11 -0
  184. package/rules/npm-module/docs/index.md +11 -0
  185. package/rules/npm-module/emit_types_config/concern.json +9 -0
  186. package/rules/npm-module/emit_types_config/docs/fix-emit_types_config.md +25 -0
  187. package/rules/npm-module/emit_types_config/docs/index.md +9 -0
  188. package/rules/npm-module/emit_types_config/emit_types_config.mdc +43 -0
  189. package/rules/npm-module/emit_types_config/emit_types_config.rego +28 -0
  190. package/rules/npm-module/emit_types_config/fix-emit_types_config.mjs +5 -0
  191. package/rules/npm-module/emit_types_config/template/tsconfig.emit-types.json.snippet.json +9 -0
  192. package/rules/npm-module/header_doc_pointer/concern.json +5 -0
  193. package/rules/npm-module/header_doc_pointer/docs/main.md +40 -0
  194. package/rules/npm-module/header_doc_pointer/header_doc_pointer.mdc +18 -0
  195. package/rules/npm-module/header_doc_pointer/main.mjs +131 -0
  196. package/rules/npm-module/main.json +1 -0
  197. package/rules/npm-module/main.mdc +36 -0
  198. package/rules/npm-module/npm_package_json/concern.json +9 -0
  199. package/rules/npm-module/npm_package_json/docs/fix-npm_package_json.md +26 -0
  200. package/rules/npm-module/npm_package_json/docs/index.md +9 -0
  201. package/rules/npm-module/npm_package_json/fix-npm_package_json.mjs +5 -0
  202. package/rules/npm-module/npm_package_json/npm_package_json.mdc +57 -0
  203. package/rules/npm-module/npm_package_json/npm_package_json.rego +73 -0
  204. package/rules/npm-module/npm_package_json/template/package.json.snippet.json +1 -0
  205. package/rules/npm-module/package_structure/concern.json +5 -0
  206. package/rules/npm-module/package_structure/docs/main.md +37 -0
  207. package/rules/npm-module/package_structure/main.mjs +448 -0
  208. package/rules/npm-module/package_structure/package_structure.mdc +63 -0
  209. package/rules/npm-module/root_package_json/concern.json +9 -0
  210. package/rules/npm-module/root_package_json/docs/fix-root_package_json.md +25 -0
  211. package/rules/npm-module/root_package_json/docs/index.md +9 -0
  212. package/rules/npm-module/root_package_json/fix-root_package_json.mjs +5 -0
  213. package/rules/npm-module/root_package_json/root_package_json.mdc +41 -0
  214. package/rules/npm-module/root_package_json/root_package_json.rego +28 -0
  215. package/rules/npm-module/root_package_json/template/package.json.snippet.json +1 -0
  216. package/rules/npm-module/rule_meta/concern.json +8 -0
  217. package/rules/npm-module/rule_meta/docs/main.md +35 -0
  218. package/rules/npm-module/rule_meta/main.mjs +119 -0
  219. package/rules/npm-module/rule_meta/rule_meta.mdc +11 -0
  220. package/rules/npm-module/skill_meta/concern.json +5 -0
  221. package/rules/npm-module/skill_meta/docs/main.md +149 -0
  222. package/rules/npm-module/skill_meta/main.mjs +91 -0
  223. package/rules/npm-module/skill_meta/skill_meta.mdc +11 -0
  224. package/rules/tool-surface/docs/index.md +11 -0
  225. package/rules/tool-surface/main.json +6 -0
  226. package/rules/tool-surface/main.mdc +72 -0
  227. package/rules/vue/composition-api/composition-api.mdc +82 -0
  228. package/rules/vue/composition-api/concern.json +3 -0
  229. package/rules/vue/docs/index.md +11 -0
  230. package/rules/vue/lib/docs/index.md +11 -0
  231. package/rules/vue/lib/docs/vue-forbidden-imports.md +265 -0
  232. package/rules/vue/lib/vue-forbidden-imports.mjs +240 -0
  233. package/rules/vue/main.json +1 -0
  234. package/rules/vue/main.mdc +18 -0
  235. package/rules/vue/nheader-layout/concern.json +3 -0
  236. package/rules/vue/nheader-layout/nheader-layout.mdc +171 -0
  237. package/rules/vue/package_json/concern.json +9 -0
  238. package/rules/vue/package_json/package_json.mdc +30 -0
  239. package/rules/vue/package_json/package_json.rego +140 -0
  240. package/rules/vue/packages/concern.json +6 -0
  241. package/rules/vue/packages/docs/index.md +11 -0
  242. package/rules/vue/packages/docs/main.md +35 -0
  243. package/rules/vue/packages/main.mjs +575 -0
  244. package/rules/vue/packages/packages.mdc +56 -0
  245. package/rules/vue/quasar-ui/concern.json +3 -0
  246. package/rules/vue/quasar-ui/quasar-ui.mdc +32 -0
  247. package/rules/vue/structure/concern.json +3 -0
  248. package/rules/vue/structure/structure.mdc +101 -0
  249. package/rules/vue/testing/concern.json +3 -0
  250. package/rules/vue/testing/testing.mdc +40 -0
  251. package/rules/vue/tfm-translations/concern.json +7 -0
  252. package/rules/vue/tfm-translations/docs/main.md +29 -0
  253. package/rules/vue/tfm-translations/main.mjs +55 -0
  254. package/rules/vue/tfm-translations/tfm-translations.mdc +32 -0
  255. package/rules/vue/vite-config/concern.json +3 -0
  256. package/rules/vue/vite-config/vite-config.mdc +153 -0
  257. package/rules/vue/vite-env/concern.json +3 -0
  258. package/rules/vue/vite-env/vite-env.mdc +61 -0
@@ -0,0 +1,400 @@
1
+ {
2
+ "$schema": "./node_modules/oxlint/configuration_schema.json",
3
+ "plugins": ["unicorn", "oxc", "import", "jsdoc", "promise", "node", "vue"],
4
+ "jsPlugins": ["@e18e/eslint-plugin"],
5
+ "categories": {},
6
+ "rules": {
7
+ "e18e/prefer-includes": "error",
8
+ "e18e/prefer-array-fill": "deny",
9
+ "e18e/prefer-array-to-reversed": "deny",
10
+ "e18e/prefer-array-to-sorted": "deny",
11
+ "e18e/prefer-array-to-spliced": "deny",
12
+ "e18e/prefer-nullish-coalescing": "deny",
13
+ "e18e/prefer-spread-syntax": "deny",
14
+ "e18e/prefer-url-canparse": "deny",
15
+ "e18e/ban-dependencies": ["deny", { "allowed": ["globby"] }],
16
+ "e18e/prefer-array-from-map": "deny",
17
+ "e18e/prefer-timer-args": "deny",
18
+ "e18e/prefer-static-regex": "deny",
19
+ "e18e/prefer-date-now": "deny",
20
+ "e18e/prefer-regex-test": "deny",
21
+ "array-callback-return": "deny",
22
+ "no-new-wrappers": "deny",
23
+ "import/no-named-as-default": "deny",
24
+ "oxc/uninvoked-array-callback": "deny",
25
+ "typescript/no-non-null-assertion": "deny",
26
+ "unicorn/prefer-date-now": "deny",
27
+ "no-obj-calls": "deny",
28
+ "default-case-last": "deny",
29
+ "import/no-webpack-loader-syntax": "deny",
30
+ "promise/no-promise-in-callback": "deny",
31
+ "typescript/no-unnecessary-type-constraint": "deny",
32
+ "unicorn/prefer-dom-node-remove": "deny",
33
+ "for-direction": "deny",
34
+ "no-prototype-builtins": "deny",
35
+ "typescript/no-useless-empty-export": "deny",
36
+ "unicorn/prefer-includes": "deny",
37
+ "guard-for-in": "deny",
38
+ "no-restricted-globals": "deny",
39
+ "promise/prefer-await-to-then": "off",
40
+ "typescript/prefer-as-const": "deny",
41
+ "unicorn/prefer-math-trunc": "deny",
42
+ "no-self-assign": "deny",
43
+ "max-params": "off",
44
+ "react/button-has-type": "deny",
45
+ "typescript/prefer-function-type": "deny",
46
+ "unicorn/prefer-native-coercion-functions": "deny",
47
+ "no-extra-label": "deny",
48
+ "no-shadow-restricted-names": "deny",
49
+ "react/iframe-missing-sandbox": "deny",
50
+ "typescript/prefer-ts-expect-error": "deny",
51
+ "unicorn/prefer-number-properties": "off",
52
+ "no-labels": "deny",
53
+ "no-ternary": "off",
54
+ "react/jsx-key": "deny",
55
+ "unicorn/consistent-empty-array-spread": "deny",
56
+ "unicorn/prefer-query-selector": "deny",
57
+ "no-object-constructor": "deny",
58
+ "react/jsx-no-script-url": "deny",
59
+ "unicorn/empty-brace-spaces": "deny",
60
+ "unicorn/prefer-set-has": "deny",
61
+ "no-array-constructor": "deny",
62
+ "react/jsx-no-useless-fragment": "deny",
63
+ "unicorn/explicit-length-check": "off",
64
+ "unicorn/prefer-string-replace-all": "deny",
65
+ "no-bitwise": "deny",
66
+ "no-unsafe-optional-chaining": "deny",
67
+ "react/no-children-prop": "deny",
68
+ "unicorn/no-abusive-eslint-disable": "deny",
69
+ "unicorn/prefer-string-trim-start-end": "deny",
70
+ "no-class-assign": "deny",
71
+ "no-unused-private-class-members": "deny",
72
+ "react/no-direct-mutation-state": "deny",
73
+ "unicorn/no-array-reduce": "deny",
74
+ "unicorn/require-array-join-separator": "deny",
75
+ "no-console": "off",
76
+ "no-useless-concat": "deny",
77
+ "react/no-render-return-value": "deny",
78
+ "unicorn/no-console-spaces": "deny",
79
+ "unicorn/text-encoding-identifier-case": "deny",
80
+ "no-constant-condition": "deny",
81
+ "no-useless-rename": "deny",
82
+ "react/no-unescaped-entities": "deny",
83
+ "unicorn/no-hex-escape": "deny",
84
+ "no-control-regex": "deny",
85
+ "no-with": "deny",
86
+ "react/react-in-jsx-scope": "deny",
87
+ "unicorn/no-length-as-slice-end": "deny",
88
+ "no-div-regex": "deny",
89
+ "prefer-numeric-literals": "deny",
90
+ "react/self-closing-comp": "deny",
91
+ "unicorn/no-negation-in-equality-check": "deny",
92
+ "no-dupe-keys": "deny",
93
+ "prefer-rest-params": "deny",
94
+ "unicorn/no-new-buffer": "deny",
95
+ "no-empty-character-class": "deny",
96
+ "require-await": "deny",
97
+ "node/no-exports-assign": "deny",
98
+ "unicorn/no-process-exit": "deny",
99
+ "no-empty-static-block": "deny",
100
+ "sort-keys": "off",
101
+ "oxc/bad-array-method-on-arguments": "deny",
102
+ "unicorn/no-thenable": "deny",
103
+ "typescript/ban-ts-comment": "deny",
104
+ "no-eval": "deny",
105
+ "unicode-bom": "deny",
106
+ "jsdoc/check-access": "deny",
107
+ "oxc/bad-comparison-sequence": "deny",
108
+ "unicorn/no-unnecessary-await": "deny",
109
+ "typescript/consistent-generic-constructors": "deny",
110
+ "no-extra-boolean-cast": "deny",
111
+ "vars-on-top": "deny",
112
+ "jsdoc/empty-tags": "deny",
113
+ "oxc/bad-replace-all-arg": "deny",
114
+ "unicorn/no-useless-fallback-in-spread": "deny",
115
+ "no-global-assign": "deny",
116
+ "jsdoc/require-param": "deny",
117
+ "oxc/erasing-op": "deny",
118
+ "unicorn/no-useless-spread": "deny",
119
+ "typescript/no-confusing-non-null-assertion": "deny",
120
+ "no-invalid-regexp": "deny",
121
+ "import/no-namespace": "off",
122
+ "jsdoc/require-param-type": "deny",
123
+ "oxc/no-accumulating-spread": "deny",
124
+ "typescript/no-empty-interface": "deny",
125
+ "unicorn/no-zero-fractions": "deny",
126
+ "import/namespace": "deny",
127
+ "jsdoc/require-property-name": "deny",
128
+ "no-label-var": "deny",
129
+ "typescript/no-extra-non-null-assertion": "deny",
130
+ "oxc/no-barrel-file": "deny",
131
+ "unicorn/prefer-spread": "deny",
132
+ "no-negated-condition": "deny",
133
+ "import/no-cycle": "deny",
134
+ "jsdoc/require-returns-description": "deny",
135
+ "typescript/no-misused-new": "deny",
136
+ "oxc/no-optional-chaining": "off",
137
+ "unicorn/prefer-array-flat-map": "deny",
138
+ "no-new-native-nonconstructor": "deny",
139
+ "import/no-dynamic-require": "deny",
140
+ "oxc/only-used-in-recursion": "deny",
141
+ "typescript/no-non-null-asserted-optional-chain": "deny",
142
+ "unicorn/prefer-code-point": "deny",
143
+ "default-case": "off",
144
+ "no-nonoctal-decimal-escape": "deny",
145
+ "import/no-self-import": "deny",
146
+ "promise/catch-or-return": "deny",
147
+ "typescript/no-this-alias": "deny",
148
+ "unicorn/prefer-dom-node-dataset": "deny",
149
+ "eqeqeq": "deny",
150
+ "no-proto": "deny",
151
+ "promise/no-new-statics": "deny",
152
+ "typescript/no-unsafe-function-type": "deny",
153
+ "unicorn/prefer-event-target": "deny",
154
+ "no-regex-spaces": "deny",
155
+ "promise/prefer-await-to-callbacks": "off",
156
+ "typescript/no-wrapper-object-types": "deny",
157
+ "unicorn/prefer-math-min-max": "deny",
158
+ "max-lines": "off",
159
+ "no-script-url": "deny",
160
+ "promise/valid-params": "deny",
161
+ "typescript/prefer-for-of": "deny",
162
+ "unicorn/prefer-modern-math-apis": "deny",
163
+ "no-useless-call": "deny",
164
+ "no-setter-return": "deny",
165
+ "typescript/prefer-namespace-keyword": "deny",
166
+ "unicorn/prefer-node-protocol": "deny",
167
+ "no-nested-ternary": "off",
168
+ "no-template-curly-in-string": "deny",
169
+ "react/jsx-curly-brace-presence": "deny",
170
+ "unicorn/catch-error-name": "deny",
171
+ "unicorn/prefer-prototype-methods": "deny",
172
+ "no-throw-literal": "deny",
173
+ "react/jsx-no-duplicate-props": "deny",
174
+ "unicorn/consistent-function-scoping": "deny",
175
+ "unicorn/prefer-regexp-test": "deny",
176
+ "no-alert": "deny",
177
+ "no-unexpected-multiline": "deny",
178
+ "react/jsx-no-undef": "deny",
179
+ "unicorn/escape-case": "deny",
180
+ "unicorn/prefer-string-raw": "deny",
181
+ "no-await-in-loop": "off",
182
+ "no-unsafe-negation": "deny",
183
+ "react/no-array-index-key": "deny",
184
+ "unicorn/new-for-builtins": "deny",
185
+ "unicorn/prefer-string-starts-ends-with": "deny",
186
+ "no-case-declarations": "deny",
187
+ "no-unused-labels": "deny",
188
+ "react/no-danger": "deny",
189
+ "unicorn/no-array-for-each": "deny",
190
+ "unicorn/prefer-type-error": "deny",
191
+ "no-cond-assign": "deny",
192
+ "no-useless-catch": "deny",
193
+ "react/no-is-mounted": "deny",
194
+ "unicorn/no-await-in-promise-methods": "deny",
195
+ "unicorn/switch-case-braces": "deny",
196
+ "no-constant-binary-expression": "deny",
197
+ "no-useless-escape": "deny",
198
+ "react/no-string-refs": "deny",
199
+ "unicorn/no-empty-file": "deny",
200
+ "no-void": "deny",
201
+ "unicorn/no-invalid-remove-event-listener": "deny",
202
+ "react/prefer-es6-class": "deny",
203
+ "no-delete-var": "deny",
204
+ "prefer-exponentiation-operator": "deny",
205
+ "react/rules-of-hooks": "deny",
206
+ "unicorn/no-magic-array-flat-depth": "deny",
207
+ "no-dupe-else-if": "deny",
208
+ "prefer-object-spread": "deny",
209
+ "react/void-dom-elements-no-children": "deny",
210
+ "unicorn/no-new-array": "deny",
211
+ "no-else-return": "deny",
212
+ "radix": "off",
213
+ "unicorn/no-object-as-default-parameter": "deny",
214
+ "no-empty-pattern": "deny",
215
+ "sort-imports": "off",
216
+ "oxc/approx-constant": "deny",
217
+ "typescript/array-type": "deny",
218
+ "unicorn/no-static-only-class": "deny",
219
+ "no-eq-null": "deny",
220
+ "symbol-description": "deny",
221
+ "oxc/bad-char-at-comparison": "deny",
222
+ "typescript/ban-types": "deny",
223
+ "unicorn/no-typeof-undefined": "deny",
224
+ "no-extend-native": "deny",
225
+ "valid-typeof": "deny",
226
+ "jsdoc/check-tag-names": "deny",
227
+ "oxc/bad-object-literal-comparison": "deny",
228
+ "typescript/consistent-type-definitions": "deny",
229
+ "unicorn/no-unreadable-iife": "deny",
230
+ "no-func-assign": "deny",
231
+ "import/default": "deny",
232
+ "jsdoc/no-defaults": "deny",
233
+ "oxc/double-comparisons": "deny",
234
+ "typescript/no-inferrable-types": "deny",
235
+ "unicorn/no-useless-promise-resolve-reject": "deny",
236
+ "no-inner-declarations": "deny",
237
+ "import/no-named-default": "deny",
238
+ "oxc/missing-throw": "deny",
239
+ "jsdoc/require-param-name": "deny",
240
+ "typescript/no-dynamic-delete": "deny",
241
+ "unicorn/no-useless-undefined": "deny",
242
+ "no-iterator": "deny",
243
+ "jsdoc/require-property-description": "deny",
244
+ "oxc/no-async-endpoint-handlers": "deny",
245
+ "typescript/no-explicit-any": "deny",
246
+ "unicorn/numeric-separators-style": "off",
247
+ "no-magic-numbers": "off",
248
+ "import/no-commonjs": "off",
249
+ "jsdoc/require-returns": "deny",
250
+ "typescript/no-import-type-side-effects": "deny",
251
+ "unicorn/prefer-array-flat": "deny",
252
+ "no-new-func": "deny",
253
+ "import/no-duplicates": "deny",
254
+ "jsdoc/require-yields": "deny",
255
+ "oxc/number-arg-out-of-range": "deny",
256
+ "typescript/no-non-null-asserted-nullish-coalescing": "deny",
257
+ "unicorn/prefer-blob-reading-methods": "deny",
258
+ "no-new": "deny",
259
+ "import/no-named-as-default-member": "off",
260
+ "promise/avoid-new": "deny",
261
+ "typescript/no-require-imports": "deny",
262
+ "unicorn/prefer-dom-node-append": "deny",
263
+ "default-param-last": "deny",
264
+ "no-plusplus": "off",
265
+ "import/unambiguous": "off",
266
+ "promise/no-callback-in-promise": "deny",
267
+ "typescript/no-unsafe-declaration-merging": "deny",
268
+ "unicorn/prefer-dom-node-text-content": "deny",
269
+ "func-names": "off",
270
+ "no-redeclare": "deny",
271
+ "promise/param-names": "deny",
272
+ "typescript/no-var-requires": "deny",
273
+ "unicorn/prefer-logical-operator-over-ternary": "deny",
274
+ "max-classes-per-file": "deny",
275
+ "no-return-assign": "deny",
276
+ "promise/spec-only": "deny",
277
+ "typescript/prefer-enum-initializers": "deny",
278
+ "unicorn/prefer-modern-dom-apis": "deny",
279
+ "new-cap": "off",
280
+ "no-self-compare": "deny",
281
+ "react/checked-requires-onchange-or-readonly": "deny",
282
+ "typescript/prefer-literal-enum-member": "deny",
283
+ "unicorn/prefer-negative-index": "deny",
284
+ "no-multi-assign": "deny",
285
+ "no-sparse-arrays": "deny",
286
+ "typescript/triple-slash-reference": "deny",
287
+ "react/jsx-boolean-value": "deny",
288
+ "unicorn/prefer-optional-catch-binding": "deny",
289
+ "no-lone-blocks": "deny",
290
+ "no-this-before-super": "deny",
291
+ "react/jsx-no-comment-textnodes": "deny",
292
+ "unicorn/consistent-existence-index-check": "deny",
293
+ "unicorn/prefer-reflect-apply": "deny",
294
+ "no-duplicate-imports": "deny",
295
+ "no-undefined": "off",
296
+ "react/jsx-no-target-blank": "deny",
297
+ "unicorn/prefer-set-size": "deny",
298
+ "unicorn/error-message": "deny",
299
+ "no-async-promise-executor": "deny",
300
+ "no-unsafe-finally": "deny",
301
+ "react/jsx-props-no-spread-multi": "deny",
302
+ "unicorn/filename-case": "off",
303
+ "unicorn/prefer-string-slice": "deny",
304
+ "no-caller": "deny",
305
+ "no-unused-expressions": "deny",
306
+ "react/no-danger-with-children": "deny",
307
+ "unicorn/no-anonymous-default-export": "off",
308
+ "unicorn/prefer-structured-clone": "deny",
309
+ "no-compare-neg-zero": "deny",
310
+ "no-unused-vars": "deny",
311
+ "react/no-find-dom-node": "deny",
312
+ "unicorn/no-await-expression-member": "deny",
313
+ "unicorn/require-number-to-fixed-digits-argument": "deny",
314
+ "no-const-assign": "deny",
315
+ "no-useless-constructor": "deny",
316
+ "react/no-set-state": "deny",
317
+ "unicorn/no-document-cookie": "deny",
318
+ "unicorn/throw-new-error": "deny",
319
+ "no-constructor-return": "deny",
320
+ "no-var": "deny",
321
+ "react/no-unknown-property": "deny",
322
+ "unicorn/no-instanceof-array": "deny",
323
+ "no-debugger": "deny",
324
+ "prefer-promise-reject-errors": "deny",
325
+ "unicorn/no-lonely-if": "deny",
326
+ "no-dupe-class-members": "deny",
327
+ "prefer-object-has-own": "deny",
328
+ "react/style-prop-object": "deny",
329
+ "unicorn/no-nested-ternary": "off",
330
+ "no-duplicate-case": "deny",
331
+ "prefer-spread": "deny",
332
+ "unicorn/no-null": "off",
333
+ "no-empty-function": "deny",
334
+ "require-yield": "deny",
335
+ "node/no-new-require": "deny",
336
+ "typescript/adjacent-overload-signatures": "deny",
337
+ "unicorn/no-single-promise-in-promise-methods": "deny",
338
+ "no-empty": "deny",
339
+ "sort-vars": "deny",
340
+ "oxc/bad-bitwise-operator": "deny",
341
+ "typescript/ban-tslint-comment": "deny",
342
+ "unicorn/no-this-assignment": "deny",
343
+ "no-ex-assign": "deny",
344
+ "use-isnan": "deny",
345
+ "jsdoc/check-property-names": "deny",
346
+ "oxc/bad-min-max-func": "deny",
347
+ "typescript/consistent-indexed-object-style": "deny",
348
+ "unicorn/no-unreadable-array-destructuring": "deny",
349
+ "no-fallthrough": "deny",
350
+ "yoda": "deny",
351
+ "jsdoc/implements-on-classes": "deny",
352
+ "oxc/const-comparisons": "deny",
353
+ "unicorn/no-useless-length-check": "deny",
354
+ "typescript/explicit-function-return-type": "deny",
355
+ "no-import-assign": "deny",
356
+ "import/first": "deny",
357
+ "jsdoc/require-param-description": "deny",
358
+ "typescript/no-duplicate-enum-values": "deny",
359
+ "oxc/misrefactored-assign-op": "deny",
360
+ "unicorn/no-useless-switch-case": "deny",
361
+ "no-irregular-whitespace": "deny",
362
+ "import/max-dependencies": "off",
363
+ "jsdoc/require-property": "deny",
364
+ "oxc/no-async-await": "off",
365
+ "typescript/no-empty-object-type": "deny",
366
+ "unicorn/number-literal-case": "deny",
367
+ "no-loss-of-precision": "deny",
368
+ "import/no-amd": "deny",
369
+ "jsdoc/require-property-type": "deny",
370
+ "oxc/no-const-enum": "deny",
371
+ "typescript/no-extraneous-class": "deny",
372
+ "unicorn/prefer-add-event-listener": "deny",
373
+ "no-multi-str": "deny",
374
+ "import/no-default-export": "off",
375
+ "jsdoc/require-returns-type": "deny",
376
+ "oxc/no-rest-spread-properties": "off",
377
+ "typescript/no-namespace": "deny",
378
+ "unicorn/prefer-array-some": "deny"
379
+ },
380
+ "settings": {
381
+ "next": {
382
+ "rootDir": []
383
+ },
384
+ "jsdoc": {
385
+ "ignorePrivate": false,
386
+ "ignoreInternal": false,
387
+ "ignoreReplacesDocs": true,
388
+ "overrideReplacesDocs": true,
389
+ "augmentsExtendsReplacesDocs": false,
390
+ "implementsReplacesDocs": false,
391
+ "exemptDestructuredRootsFromChecks": false,
392
+ "tagNamePreference": {}
393
+ }
394
+ },
395
+ "env": {
396
+ "builtin": true
397
+ },
398
+ "globals": {},
399
+ "ignorePatterns": ["npm/types/**", "demo/node/rules-demo.js", "**/schema.graphql", "**/auto-imports.d.ts"]
400
+ }
@@ -0,0 +1,53 @@
1
+ ---
2
+ type: JS Module
3
+ title: main.mjs
4
+ resource: plugins/lang-js/rules/js/tooling/main.mjs
5
+ docgen:
6
+ crc: 76437b89
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
+ Шляхи до канонічних JSON-конфігурацій для `oxlint` та `knip` доступні через
16
+ `OXLINT_CANONICAL_JSON_PATH` та `KNIP_CANONICAL_JSON_PATH`. Модуль перевіряє,
17
+ чи відповідає `.oxlintrc.json` канону (`verifyOxlintRcAgainstCanonical`), і
18
+ будує детермінований merge до канону (`planOxlintrcFix`) — джерело правди для
19
+ T0-автофіксу `js/check` (`fix-check.mjs`), без LLM.
20
+
21
+ ## Поведінка
22
+
23
+ - `OXLINT_CANONICAL_JSON_PATH` / `KNIP_CANONICAL_JSON_PATH` — шляхи до
24
+ канонічних JSON-конфігів `oxlint`/`knip` у цьому пакеті.
25
+ - `OXLINTRC_MISSING` / `OXLINTRC_DRIFT` — стабільні reason-коди для
26
+ порушень `.oxlintrc.json` (відсутній файл / розходження з каноном),
27
+ які `js/check` проставляє через `createViolationReporter`, а T0-патерн
28
+ `js-check-oxlintrc` розпізнає для автофіксу.
29
+ - `verifyOxlintRcAgainstCanonical(cfg, canonical)` — звіряє `.oxlintrc.json`
30
+ проти канону: усі `rules`-ключі канону мають точний збіг значення (зайві
31
+ локальні ключі дозволені), `ignorePatterns` канону мають бути присутні
32
+ (локальні розширення дозволені), решта полів — точний глибокий збіг.
33
+ - `planOxlintrcFix(actual, canonical)` — чиста функція, що дзеркалить
34
+ правила `verifyOxlintRcAgainstCanonical` у зворотний бік: будує обʼєкт
35
+ `.oxlintrc.json`, який гарантовано проходить повторну перевірку.
36
+ Відсутній `actual` (`null`) трактується як порожній файл — результат
37
+ дорівнює канону. Наявний `actual` доповнюється до канону без втрати
38
+ project-specific розширень: зайві `rules`-ключі й `ignorePatterns`
39
+ зберігаються, а канонічні `rules`-значення й поля верхнього рівня
40
+ перезаписуються канонічними (єдине валідне значення для перевірки).
41
+
42
+ ## Публічний API
43
+
44
+ - `OXLINT_CANONICAL_JSON_PATH` — шлях до канонічного конфігу `oxlint` для перевірки/T0-фіксу.
45
+ - `KNIP_CANONICAL_JSON_PATH` — шлях до канонічного конфігу `knip`, що копіюється у корінь проєкту-споживача, якщо відсутній.
46
+ - `OXLINTRC_MISSING` / `OXLINTRC_DRIFT` — reason-коди порушень `.oxlintrc.json`.
47
+ - `verifyOxlintRcAgainstCanonical(cfg, canonical)` → `{ ok, failures }` — перевірка `.oxlintrc.json` проти канону.
48
+ - `planOxlintrcFix(actual, canonical)` → злитий обʼєкт `.oxlintrc.json` — детермінований T0-фікс без LLM.
49
+
50
+ ## Гарантії поведінки
51
+
52
+ - Read-only: не виконує операцій запису (ФС/БД); запис у `.oxlintrc.json` — відповідальність виклику (T0 `fix-check.mjs`).
53
+ - `planOxlintrcFix` — чиста функція без side effects; той самий вхід завжди дає той самий вихід.
@@ -0,0 +1,183 @@
1
+ /** @see ./docs/tooling.md */
2
+ import { dirname, join } from 'node:path'
3
+ import { fileURLToPath } from 'node:url'
4
+
5
+ /** Шлях до канонічного oxlint JSON у цьому пакеті (для перевірки та тестів). */
6
+ export const OXLINT_CANONICAL_JSON_PATH = join(
7
+ dirname(fileURLToPath(import.meta.url)),
8
+ 'data',
9
+ 'tooling',
10
+ 'oxlint-canonical.json'
11
+ )
12
+
13
+ /** Шлях до канонічного knip JSON у цьому пакеті — копіюється у корінь проєкту-споживача, якщо відсутній. */
14
+ export const KNIP_CANONICAL_JSON_PATH = join(
15
+ dirname(fileURLToPath(import.meta.url)),
16
+ 'data',
17
+ 'tooling',
18
+ 'knip-canonical.json'
19
+ )
20
+
21
+ /** `.oxlintrc.json` відсутній — T0 копіює канон (`fix-check.mjs`). */
22
+ export const OXLINTRC_MISSING = 'oxlintrc-missing'
23
+ /** `.oxlintrc.json` існує, але розходиться з каноном — T0 доводить до відповідності детермінованим merge. */
24
+ export const OXLINTRC_DRIFT = 'oxlintrc-drift'
25
+
26
+ // Канонічний рядок `lint-js`-скрипта і мінімальна версія `@nitra/eslint-config` —
27
+ // у rego (`npm/policy/js_lint/package_json/`). JS-копії (`CANONICAL_LINT_JS`,
28
+ // `isCanonicalLintJs`, `nitraEslintConfigMeetsMinVersion`) видалено, щоб не
29
+ // було двох джерел істини й ризику дрифту.
30
+
31
+ /**
32
+ * Рекурсивне порівняння фрагментів канону oxlint (масиви — порядок як у каноні; об'єкти — той самий набір ключів і вкладеність).
33
+ * @param {unknown} actual значення з `.oxlintrc.json`
34
+ * @param {unknown} expected значення з канону
35
+ * @returns {boolean} true, якщо значення збігаються за правилами канону
36
+ */
37
+ function deepEqualOxlintCanonical(actual, expected) {
38
+ if (expected === null || typeof expected !== 'object') {
39
+ return actual === expected
40
+ }
41
+ if (Array.isArray(expected)) {
42
+ return Array.isArray(actual) && JSON.stringify(actual) === JSON.stringify(expected)
43
+ }
44
+ if (typeof actual !== 'object' || actual === null || Array.isArray(actual)) {
45
+ return false
46
+ }
47
+ const exp = /** @type {Record<string, unknown>} */ (expected)
48
+ const act = /** @type {Record<string, unknown>} */ (actual)
49
+ const expKeys = Object.keys(exp)
50
+ const actKeys = Object.keys(act)
51
+ if (expKeys.length !== actKeys.length) {
52
+ return false
53
+ }
54
+ for (const k of expKeys) {
55
+ if (!(k in act) || !deepEqualOxlintCanonical(act[k], exp[k])) {
56
+ return false
57
+ }
58
+ }
59
+ return true
60
+ }
61
+
62
+ /**
63
+ * Безпечний доступ як до plain-object запису.
64
+ * @param {unknown} v будь-яке значення
65
+ * @returns {Record<string, unknown>} запис або пустий обʼєкт, якщо `v` не plain-object
66
+ */
67
+ function asRecordOrEmpty(v) {
68
+ return v && typeof v === 'object' && !Array.isArray(v) ? /** @type {Record<string, unknown>} */ (v) : {}
69
+ }
70
+
71
+ /**
72
+ * Звіряє блок `rules`: кожне правило з канону має точне збіжне значення в actual.
73
+ * @param {unknown} expected канонічне значення для `rules`
74
+ * @param {unknown} actual поточне значення для `rules`
75
+ * @param {string[]} failures буфер для помилок
76
+ */
77
+ function compareOxlintRules(expected, actual, failures) {
78
+ const er = asRecordOrEmpty(expected)
79
+ const ar = asRecordOrEmpty(actual)
80
+ for (const [ruleKey, expectedValue] of Object.entries(er)) {
81
+ if (!deepEqualOxlintCanonical(ar[ruleKey], expectedValue)) {
82
+ failures.push(
83
+ `.oxlintrc.json: rules["${ruleKey}"] очікується ${JSON.stringify(expectedValue)}, зараз ${JSON.stringify(ar[ruleKey])}`
84
+ )
85
+ }
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Звіряє блок `ignorePatterns`: кожен патерн із канону має бути присутній в actual; додаткові локальні
91
+ * патерни дозволені (канон задає мінімум, проєкт може розширити).
92
+ * @param {unknown} expected канонічний масив `ignorePatterns`
93
+ * @param {unknown} actual поточний `ignorePatterns` із `.oxlintrc.json`
94
+ * @param {string[]} failures буфер для помилок
95
+ */
96
+ function compareOxlintIgnorePatterns(expected, actual, failures) {
97
+ if (!Array.isArray(expected)) {
98
+ return
99
+ }
100
+ if (!Array.isArray(actual)) {
101
+ failures.push(
102
+ '.oxlintrc.json: поле "ignorePatterns" має бути масивом (канон задає мінімум, додаткові патерни дозволені)'
103
+ )
104
+ return
105
+ }
106
+ const set = new Set(actual)
107
+ const missing = expected.filter(p => !set.has(p))
108
+ if (missing.length > 0) {
109
+ failures.push(
110
+ `.oxlintrc.json: ignorePatterns має містити канонічні патерни — додай: ${missing.map(p => JSON.stringify(p)).join(', ')}`
111
+ )
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Перевіряє `.oxlintrc.json` проти канону пакета `@7n/rules` (усі правила з канону та інші поля з `oxlint-canonical.json`).
117
+ * Додаткові ключі лише в `rules` дозволені; інші поля мають збігатися з каноном.
118
+ * @param {unknown} cfg корінь JSON з `.oxlintrc.json`
119
+ * @param {unknown} canonical розпарений `oxlint-canonical.json`
120
+ * @returns {{ ok: boolean, failures: string[] }} статус і повідомлення для `fail`
121
+ */
122
+ export function verifyOxlintRcAgainstCanonical(cfg, canonical) {
123
+ if (!cfg || typeof cfg !== 'object' || Array.isArray(cfg)) {
124
+ return { ok: false, failures: ['.oxlintrc.json: корінь має бути значенням типу object'] }
125
+ }
126
+ if (!canonical || typeof canonical !== 'object' || Array.isArray(canonical)) {
127
+ return { ok: false, failures: ['внутрішня помилка: канон oxlint має бути object'] }
128
+ }
129
+ const failures = []
130
+ const o = /** @type {Record<string, unknown>} */ (cfg)
131
+ const c = /** @type {Record<string, unknown>} */ (canonical)
132
+
133
+ for (const [key, expected] of Object.entries(c)) {
134
+ const actual = o[key]
135
+
136
+ if (key === 'rules') {
137
+ compareOxlintRules(expected, actual, failures)
138
+ continue
139
+ }
140
+
141
+ if (key === 'ignorePatterns') {
142
+ compareOxlintIgnorePatterns(expected, actual, failures)
143
+ continue
144
+ }
145
+
146
+ if (!deepEqualOxlintCanonical(actual, expected)) {
147
+ failures.push(
148
+ `.oxlintrc.json: поле "${key}" має збігатися з каноном пакета @7n/rules (npm/rules/js/tooling/data/tooling/oxlint-canonical.json)`
149
+ )
150
+ }
151
+ }
152
+
153
+ return { ok: failures.length === 0, failures }
154
+ }
155
+
156
+ /**
157
+ * Детермінований merge `.oxlintrc.json` до відповідності канону (T0 `fix-check.mjs`) —
158
+ * дзеркалить правила `verifyOxlintRcAgainstCanonical`, тож результат завжди проходить
159
+ * повторну перевірку без LLM. Project-specific розширення зберігаються: зайві ключі в
160
+ * `rules` і зайві `ignorePatterns` не видаляються, лише доповнюються канонічними.
161
+ * @param {unknown} actual поточний вміст `.oxlintrc.json` (`null`/будь-що не-object — трактується як відсутній файл)
162
+ * @param {Record<string, unknown>} canonical розпарсений `oxlint-canonical.json`
163
+ * @returns {Record<string, unknown>} злитий обʼєкт, готовий до запису у `.oxlintrc.json`
164
+ */
165
+ export function planOxlintrcFix(actual, canonical) {
166
+ const merged = { ...asRecordOrEmpty(actual) }
167
+ for (const [key, expected] of Object.entries(canonical)) {
168
+ if (key === 'rules') {
169
+ merged.rules = { ...asRecordOrEmpty(merged.rules), ...asRecordOrEmpty(expected) }
170
+ continue
171
+ }
172
+ if (key === 'ignorePatterns') {
173
+ const existing = Array.isArray(merged.ignorePatterns) ? merged.ignorePatterns : []
174
+ const canonPatterns = Array.isArray(expected) ? expected : []
175
+ merged.ignorePatterns = [...existing, ...canonPatterns.filter(p => !existing.includes(p))]
176
+ continue
177
+ }
178
+ // Інші поля вимагають точного збігу з каноном (verifyOxlintRcAgainstCanonical) —
179
+ // єдине валідне значення й так канонічне, тож перезапис безпечний.
180
+ merged[key] = expected
181
+ }
182
+ return merged
183
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
3
+ "lint": { "scope": "full", "glob": ["**/utils/**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}"] }
4
+ }