@7n/rules-lang-js 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/package.json +14 -4
  3. package/rules/bun/bunfig/bunfig.mdc +17 -0
  4. package/rules/bun/bunfig/bunfig.rego +29 -0
  5. package/rules/bun/bunfig/concern.json +9 -0
  6. package/rules/bun/bunfig/template/bunfig.toml.snippet.toml +2 -0
  7. package/rules/bun/docs/index.md +11 -0
  8. package/rules/bun/layout/concern.json +16 -0
  9. package/rules/bun/layout/docs/fix-layout.md +29 -0
  10. package/rules/bun/layout/docs/main.md +34 -0
  11. package/rules/bun/layout/fix-layout.mjs +63 -0
  12. package/rules/bun/layout/layout.mdc +60 -0
  13. package/rules/bun/layout/main.mjs +53 -0
  14. package/rules/bun/licensee/concern.json +7 -0
  15. package/rules/bun/licensee/docs/fix-licensee.md +27 -0
  16. package/rules/bun/licensee/docs/index.md +12 -0
  17. package/rules/bun/licensee/docs/main.md +30 -0
  18. package/rules/bun/licensee/fix-licensee.mjs +31 -0
  19. package/rules/bun/licensee/main.mjs +68 -0
  20. package/rules/bun/lint-surface/concern.json +3 -0
  21. package/rules/bun/lint-surface/lint-surface.mdc +13 -0
  22. package/rules/bun/main.json +1 -0
  23. package/rules/bun/main.mdc +11 -0
  24. package/rules/bun/package_json/concern.json +9 -0
  25. package/rules/bun/package_json/docs/fix-package_json.md +28 -0
  26. package/rules/bun/package_json/docs/index.md +9 -0
  27. package/rules/bun/package_json/fix-package_json.mjs +311 -0
  28. package/rules/bun/package_json/package_json.mdc +14 -0
  29. package/rules/bun/package_json/package_json.rego +64 -0
  30. package/rules/bun/package_json/template/package.json.deny.json +4 -0
  31. package/rules/js/check/check.mdc +26 -0
  32. package/rules/js/check/concern.json +19 -0
  33. package/rules/js/check/docs/eslint-config.md +56 -0
  34. package/rules/js/check/docs/fix-check.md +48 -0
  35. package/rules/js/check/docs/index.md +13 -0
  36. package/rules/js/check/docs/main.md +48 -0
  37. package/rules/js/check/eslint-config.mjs +262 -0
  38. package/rules/js/check/fix-check.mjs +82 -0
  39. package/rules/js/check/main.mjs +310 -0
  40. package/rules/js/dep-policy/concern.json +4 -0
  41. package/rules/js/dep-policy/dep-policy.mdc +36 -0
  42. package/rules/js/dep-policy/docs/main.md +35 -0
  43. package/rules/js/dep-policy/main.mjs +99 -0
  44. package/rules/js/docs/index.md +11 -0
  45. package/rules/js/eslint/concern.json +8 -0
  46. package/rules/js/eslint/docs/fix-eslint.md +50 -0
  47. package/rules/js/eslint/docs/fix-worker.md +31 -0
  48. package/rules/js/eslint/docs/index.md +11 -0
  49. package/rules/js/eslint/docs/main.md +35 -0
  50. package/rules/js/eslint/fix-eslint.mjs +160 -0
  51. package/rules/js/eslint/fix-worker.mjs +139 -0
  52. package/rules/js/eslint/main.mjs +115 -0
  53. package/rules/js/file-extensions/concern.json +3 -0
  54. package/rules/js/file-extensions/file-extensions.mdc +12 -0
  55. package/rules/js/jscpd_config/concern.json +11 -0
  56. package/rules/js/jscpd_config/docs/fix-jscpd_config.md +25 -0
  57. package/rules/js/jscpd_config/docs/index.md +9 -0
  58. package/rules/js/jscpd_config/fix-jscpd_config.mjs +3 -0
  59. package/rules/js/jscpd_config/jscpd_config.mdc +42 -0
  60. package/rules/js/jscpd_config/jscpd_config.rego +44 -0
  61. package/rules/js/jscpd_config/template/.jscpd.json.snippet.json +7 -0
  62. package/rules/js/jscpd_duplicates/concern.json +7 -0
  63. package/rules/js/jscpd_duplicates/docs/main.md +29 -0
  64. package/rules/js/jscpd_duplicates/main.mjs +69 -0
  65. package/rules/js/knip/concern.json +7 -0
  66. package/rules/js/knip/docs/main.md +32 -0
  67. package/rules/js/knip/knip.mdc +15 -0
  68. package/rules/js/knip/main.mjs +68 -0
  69. package/rules/js/lint-findings/concern.json +3 -0
  70. package/rules/js/lint-findings/docs/main.md +40 -0
  71. package/rules/js/lint-findings/main.mjs +125 -0
  72. package/rules/js/main.json +1 -0
  73. package/rules/js/main.mdc +18 -0
  74. package/rules/js/package_json/concern.json +9 -0
  75. package/rules/js/package_json/docs/fix-package_json.md +25 -0
  76. package/rules/js/package_json/docs/index.md +9 -0
  77. package/rules/js/package_json/fix-package_json.mjs +3 -0
  78. package/rules/js/package_json/package_json.mdc +15 -0
  79. package/rules/js/package_json/package_json.rego +142 -0
  80. package/rules/js/package_json/template/package.json.snippet.json +6 -0
  81. package/rules/js/tooling/concern.json +3 -0
  82. package/rules/js/tooling/data/tooling/knip-canonical.json +30 -0
  83. package/rules/js/tooling/data/tooling/oxlint-canonical.json +400 -0
  84. package/rules/js/tooling/docs/main.md +53 -0
  85. package/rules/js/tooling/main.mjs +183 -0
  86. package/rules/js/utils_imports/concern.json +4 -0
  87. package/rules/js/utils_imports/docs/main.md +50 -0
  88. package/rules/js/utils_imports/main.mjs +185 -0
  89. package/rules/js/utils_imports/utils_imports.mdc +15 -0
  90. package/rules/js/vscode_extensions/concern.json +11 -0
  91. package/rules/js/vscode_extensions/docs/fix-vscode_extensions.md +24 -0
  92. package/rules/js/vscode_extensions/docs/index.md +11 -0
  93. package/rules/js/vscode_extensions/fix-vscode_extensions.mjs +1 -0
  94. package/rules/js/vscode_extensions/template/extensions.json.snippet.json +6 -0
  95. package/rules/js/vscode_extensions/vscode_extensions.mdc +11 -0
  96. package/rules/js/vscode_extensions/vscode_extensions.rego +12 -0
  97. package/rules/js-bun-db/connection/concern.json +3 -0
  98. package/rules/js-bun-db/connection/connection.mdc +42 -0
  99. package/rules/js-bun-db/docs/index.md +11 -0
  100. package/rules/js-bun-db/lib/bun-sql-scan.mjs +1047 -0
  101. package/rules/js-bun-db/lib/docs/bun-sql-scan.md +63 -0
  102. package/rules/js-bun-db/lib/docs/index.md +11 -0
  103. package/rules/js-bun-db/main.json +1 -0
  104. package/rules/js-bun-db/main.mdc +8 -0
  105. package/rules/js-bun-db/package_json/concern.json +9 -0
  106. package/rules/js-bun-db/package_json/package_json.mdc +31 -0
  107. package/rules/js-bun-db/package_json/package_json.rego +15 -0
  108. package/rules/js-bun-db/package_json/template/package.json.deny.json +6 -0
  109. package/rules/js-bun-db/pg_format_identifiers/concern.json +3 -0
  110. package/rules/js-bun-db/pg_format_identifiers/pg_format_identifiers.mdc +104 -0
  111. package/rules/js-bun-db/safety/concern.json +4 -0
  112. package/rules/js-bun-db/safety/docs/main.md +34 -0
  113. package/rules/js-bun-db/safety/main.mjs +430 -0
  114. package/rules/js-bun-db/safety/safety.mdc +458 -0
  115. package/rules/js-bun-redis/docs/index.md +11 -0
  116. package/rules/js-bun-redis/imports/concern.json +4 -0
  117. package/rules/js-bun-redis/imports/docs/main.md +36 -0
  118. package/rules/js-bun-redis/imports/imports.mdc +47 -0
  119. package/rules/js-bun-redis/imports/main.mjs +88 -0
  120. package/rules/js-bun-redis/lib/docs/index.md +11 -0
  121. package/rules/js-bun-redis/lib/docs/redis-imports.md +227 -0
  122. package/rules/js-bun-redis/lib/redis-imports.mjs +130 -0
  123. package/rules/js-bun-redis/main.json +1 -0
  124. package/rules/js-bun-redis/main.mdc +8 -0
  125. package/rules/js-bun-redis/package_json/concern.json +9 -0
  126. package/rules/js-bun-redis/package_json/package_json.mdc +11 -0
  127. package/rules/js-bun-redis/package_json/package_json.rego +15 -0
  128. package/rules/js-bun-redis/package_json/template/package.json.deny.json +12 -0
  129. package/rules/js-mssql/deps/concern.json +4 -0
  130. package/rules/js-mssql/deps/docs/main.md +33 -0
  131. package/rules/js-mssql/deps/main.mjs +297 -0
  132. package/rules/js-mssql/docs/index.md +11 -0
  133. package/rules/js-mssql/lib/docs/index.md +11 -0
  134. package/rules/js-mssql/lib/docs/mssql-pool-scan.md +380 -0
  135. package/rules/js-mssql/lib/mssql-pool-scan.mjs +610 -0
  136. package/rules/js-mssql/main.json +1 -0
  137. package/rules/js-mssql/main.mdc +144 -0
  138. package/rules/js-mssql/mssql-tvp/concern.json +3 -0
  139. package/rules/js-mssql/mssql-tvp/mssql-tvp.mdc +77 -0
  140. package/rules/js-mssql/package_json/concern.json +9 -0
  141. package/rules/js-mssql/package_json/package_json.mdc +9 -0
  142. package/rules/js-mssql/package_json/package_json.rego +57 -0
  143. package/rules/js-run/configmap/concern.json +9 -0
  144. package/rules/js-run/configmap/configmap.mdc +37 -0
  145. package/rules/js-run/configmap/configmap.rego +21 -0
  146. package/rules/js-run/configmap/template/configmap.yaml.contains.yml +4 -0
  147. package/rules/js-run/docs/index.md +11 -0
  148. package/rules/js-run/jsconfig/concern.json +9 -0
  149. package/rules/js-run/jsconfig/docs/fix-jsconfig.md +28 -0
  150. package/rules/js-run/jsconfig/docs/index.md +9 -0
  151. package/rules/js-run/jsconfig/fix-jsconfig.mjs +119 -0
  152. package/rules/js-run/jsconfig/jsconfig.mdc +48 -0
  153. package/rules/js-run/jsconfig/jsconfig.rego +59 -0
  154. package/rules/js-run/jsconfig/template/jsconfig.json.snippet.json +10 -0
  155. package/rules/js-run/lib/bunyan-imports.mjs +98 -0
  156. package/rules/js-run/lib/check-env-scan.mjs +338 -0
  157. package/rules/js-run/lib/conn-file-rules.mjs +214 -0
  158. package/rules/js-run/lib/conn-imports-scan.mjs +154 -0
  159. package/rules/js-run/lib/docs/bunyan-imports.md +121 -0
  160. package/rules/js-run/lib/docs/check-env-scan.md +438 -0
  161. package/rules/js-run/lib/docs/conn-file-rules.md +304 -0
  162. package/rules/js-run/lib/docs/conn-imports-scan.md +208 -0
  163. package/rules/js-run/lib/docs/index.md +16 -0
  164. package/rules/js-run/lib/docs/promise-settimeout-scan.md +334 -0
  165. package/rules/js-run/lib/docs/temporal-scan.md +29 -0
  166. package/rules/js-run/lib/promise-settimeout-scan.mjs +128 -0
  167. package/rules/js-run/lib/temporal-scan.mjs +52 -0
  168. package/rules/js-run/main.json +1 -0
  169. package/rules/js-run/main.mdc +16 -0
  170. package/rules/js-run/package_json/concern.json +9 -0
  171. package/rules/js-run/package_json/package_json.mdc +44 -0
  172. package/rules/js-run/package_json/package_json.rego +37 -0
  173. package/rules/js-run/package_json/template/package.json.deny.json +22 -0
  174. package/rules/js-run/project-structure/concern.json +3 -0
  175. package/rules/js-run/project-structure/project-structure.mdc +11 -0
  176. package/rules/js-run/runtime/concern.json +12 -0
  177. package/rules/js-run/runtime/docs/fix-runtime.md +27 -0
  178. package/rules/js-run/runtime/docs/main.md +35 -0
  179. package/rules/js-run/runtime/fix-runtime.mjs +46 -0
  180. package/rules/js-run/runtime/main.mjs +496 -0
  181. package/rules/js-run/runtime/runtime.mdc +184 -0
  182. package/rules/js-run/scope/concern.json +3 -0
  183. package/rules/js-run/scope/scope.mdc +11 -0
  184. package/rules/npm-module/docs/index.md +11 -0
  185. package/rules/npm-module/emit_types_config/concern.json +9 -0
  186. package/rules/npm-module/emit_types_config/docs/fix-emit_types_config.md +25 -0
  187. package/rules/npm-module/emit_types_config/docs/index.md +9 -0
  188. package/rules/npm-module/emit_types_config/emit_types_config.mdc +43 -0
  189. package/rules/npm-module/emit_types_config/emit_types_config.rego +28 -0
  190. package/rules/npm-module/emit_types_config/fix-emit_types_config.mjs +5 -0
  191. package/rules/npm-module/emit_types_config/template/tsconfig.emit-types.json.snippet.json +9 -0
  192. package/rules/npm-module/header_doc_pointer/concern.json +5 -0
  193. package/rules/npm-module/header_doc_pointer/docs/main.md +40 -0
  194. package/rules/npm-module/header_doc_pointer/header_doc_pointer.mdc +18 -0
  195. package/rules/npm-module/header_doc_pointer/main.mjs +131 -0
  196. package/rules/npm-module/main.json +1 -0
  197. package/rules/npm-module/main.mdc +36 -0
  198. package/rules/npm-module/npm_package_json/concern.json +9 -0
  199. package/rules/npm-module/npm_package_json/docs/fix-npm_package_json.md +26 -0
  200. package/rules/npm-module/npm_package_json/docs/index.md +9 -0
  201. package/rules/npm-module/npm_package_json/fix-npm_package_json.mjs +5 -0
  202. package/rules/npm-module/npm_package_json/npm_package_json.mdc +57 -0
  203. package/rules/npm-module/npm_package_json/npm_package_json.rego +73 -0
  204. package/rules/npm-module/npm_package_json/template/package.json.snippet.json +1 -0
  205. package/rules/npm-module/package_structure/concern.json +5 -0
  206. package/rules/npm-module/package_structure/docs/main.md +37 -0
  207. package/rules/npm-module/package_structure/main.mjs +448 -0
  208. package/rules/npm-module/package_structure/package_structure.mdc +63 -0
  209. package/rules/npm-module/root_package_json/concern.json +9 -0
  210. package/rules/npm-module/root_package_json/docs/fix-root_package_json.md +25 -0
  211. package/rules/npm-module/root_package_json/docs/index.md +9 -0
  212. package/rules/npm-module/root_package_json/fix-root_package_json.mjs +5 -0
  213. package/rules/npm-module/root_package_json/root_package_json.mdc +41 -0
  214. package/rules/npm-module/root_package_json/root_package_json.rego +28 -0
  215. package/rules/npm-module/root_package_json/template/package.json.snippet.json +1 -0
  216. package/rules/npm-module/rule_meta/concern.json +8 -0
  217. package/rules/npm-module/rule_meta/docs/main.md +35 -0
  218. package/rules/npm-module/rule_meta/main.mjs +119 -0
  219. package/rules/npm-module/rule_meta/rule_meta.mdc +11 -0
  220. package/rules/npm-module/skill_meta/concern.json +5 -0
  221. package/rules/npm-module/skill_meta/docs/main.md +149 -0
  222. package/rules/npm-module/skill_meta/main.mjs +91 -0
  223. package/rules/npm-module/skill_meta/skill_meta.mdc +11 -0
  224. package/rules/tool-surface/docs/index.md +11 -0
  225. package/rules/tool-surface/main.json +6 -0
  226. package/rules/tool-surface/main.mdc +72 -0
  227. package/rules/vue/composition-api/composition-api.mdc +82 -0
  228. package/rules/vue/composition-api/concern.json +3 -0
  229. package/rules/vue/docs/index.md +11 -0
  230. package/rules/vue/lib/docs/index.md +11 -0
  231. package/rules/vue/lib/docs/vue-forbidden-imports.md +265 -0
  232. package/rules/vue/lib/vue-forbidden-imports.mjs +240 -0
  233. package/rules/vue/main.json +1 -0
  234. package/rules/vue/main.mdc +18 -0
  235. package/rules/vue/nheader-layout/concern.json +3 -0
  236. package/rules/vue/nheader-layout/nheader-layout.mdc +171 -0
  237. package/rules/vue/package_json/concern.json +9 -0
  238. package/rules/vue/package_json/package_json.mdc +30 -0
  239. package/rules/vue/package_json/package_json.rego +140 -0
  240. package/rules/vue/packages/concern.json +6 -0
  241. package/rules/vue/packages/docs/index.md +11 -0
  242. package/rules/vue/packages/docs/main.md +35 -0
  243. package/rules/vue/packages/main.mjs +575 -0
  244. package/rules/vue/packages/packages.mdc +56 -0
  245. package/rules/vue/quasar-ui/concern.json +3 -0
  246. package/rules/vue/quasar-ui/quasar-ui.mdc +32 -0
  247. package/rules/vue/structure/concern.json +3 -0
  248. package/rules/vue/structure/structure.mdc +101 -0
  249. package/rules/vue/testing/concern.json +3 -0
  250. package/rules/vue/testing/testing.mdc +40 -0
  251. package/rules/vue/tfm-translations/concern.json +7 -0
  252. package/rules/vue/tfm-translations/docs/main.md +29 -0
  253. package/rules/vue/tfm-translations/main.mjs +55 -0
  254. package/rules/vue/tfm-translations/tfm-translations.mdc +32 -0
  255. package/rules/vue/vite-config/concern.json +3 -0
  256. package/rules/vue/vite-config/vite-config.mdc +153 -0
  257. package/rules/vue/vite-env/concern.json +3 -0
  258. package/rules/vue/vite-env/vite-env.mdc +61 -0
@@ -0,0 +1,297 @@
1
+ /** @see ./docs/deps.md */
2
+ import { existsSync } from 'node:fs'
3
+ import { readFile } from 'node:fs/promises'
4
+ import { join, relative } from 'node:path'
5
+
6
+ import { createViolationReporter } from '@7n/rules/scripts/lib/lint-surface/violation-reporter.mjs'
7
+ import { findAllPackageJsonPaths } from '@7n/rules/scripts/utils/find-package-json-paths.mjs'
8
+ import {
9
+ findMssqlPerRequestConnectionInText,
10
+ findSharedMssqlRequestInText,
11
+ findUnsafeMssqlQueryTemplateCallInText,
12
+ findUnsafeMssqlDynamicSqlListInText,
13
+ findUnsafeMssqlInListUnparsedInText,
14
+ findUnsafeMssqlInListMissingEmptyGuardInText,
15
+ isMssqlScanSourceFile
16
+ } from '../lib/mssql-pool-scan.mjs'
17
+ import { loadCursorIgnorePaths } from '@7n/rules/scripts/lib/load-cursor-config.mjs'
18
+ import { walkDir } from '@7n/rules/scripts/utils/walkDir.mjs'
19
+
20
+ const VERSION_PREFIX_RE = /^[\^~>=<]+\s*/u
21
+ const SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)/u
22
+
23
+ /** Мінімальна дозволена версія mssql (js-mssql.mdc). */
24
+ const MIN_MSSQL_VERSION = { major: 12, minor: 5, patch: 0 }
25
+
26
+ /**
27
+ * Збирає абсолютні шляхи JS/TS джерел у репозиторії для скану mssql.
28
+ * @param {string} repoRoot абсолютний шлях до кореня репозиторію
29
+ * @param {string[]} ignorePaths абсолютні шляхи каталогів, повністю виключених з обходу
30
+ * @returns {Promise<string[]>} абсолютні шляхи, відсортовані за відносним шляхом
31
+ */
32
+ async function findAllSourcePathsForMssqlScan(repoRoot, ignorePaths) {
33
+ /** @type {string[]} */
34
+ const paths = []
35
+ await walkDir(
36
+ repoRoot,
37
+ absPath => {
38
+ const rel = relative(repoRoot, absPath).split('\\').join('/')
39
+ if (isMssqlScanSourceFile(rel)) {
40
+ paths.push(absPath)
41
+ }
42
+ },
43
+ ignorePaths
44
+ )
45
+ paths.sort((a, b) => relative(repoRoot, a).localeCompare(relative(repoRoot, b)))
46
+ return paths
47
+ }
48
+
49
+ /**
50
+ * @param {unknown} v parsed JSON
51
+ * @returns {Record<string, unknown>} object або {}
52
+ */
53
+ function asObject(v) {
54
+ if (!v || typeof v !== 'object' || Array.isArray(v)) return {}
55
+ return /** @type {Record<string, unknown>} */ (v)
56
+ }
57
+
58
+ /**
59
+ * Витягає рядок версії `dependencies.mssql`, якщо він існує.
60
+ * @param {unknown} deps deps з package.json
61
+ * @returns {string | null} версія або null
62
+ */
63
+ function getMssqlDependencyRange(deps) {
64
+ const o = asObject(deps)
65
+ const v = o.mssql
66
+ return typeof v === 'string' && v.trim() ? v.trim() : null
67
+ }
68
+
69
+ /**
70
+ * Парсить першу semver з діапазону виду "^12.5.0", ">=12.5.0", "12.5.0".
71
+ * @param {string} range версійний діапазон
72
+ * @returns {{ major: number, minor: number, patch: number } | null} semver або null
73
+ */
74
+ function parseLeadingSemver(range) {
75
+ const cleaned = String(range).trim().replace(VERSION_PREFIX_RE, '')
76
+ const m = cleaned.match(SEMVER_RE)
77
+ if (!m) return null
78
+ const major = Number(m[1])
79
+ const minor = Number(m[2])
80
+ const patch = Number(m[3])
81
+ if ([major, minor, patch].some(n => Number.isNaN(n))) return null
82
+ return { major, minor, patch }
83
+ }
84
+
85
+ /**
86
+ * @param {{ major: number, minor: number, patch: number }} a перша semver
87
+ * @param {{ major: number, minor: number, patch: number }} b друга semver
88
+ * @returns {boolean} true, якщо a >= b
89
+ */
90
+ function semverGte(a, b) {
91
+ if (a.major !== b.major) return a.major > b.major
92
+ if (a.minor !== b.minor) return a.minor > b.minor
93
+ return a.patch >= b.patch
94
+ }
95
+
96
+ /**
97
+ * Аудит одного package.json на dependencies.mssql: версія має бути >=12.5.0.
98
+ * Повертає інкремент для лічильників `{ found, bad }`.
99
+ * @param {string} rel шлях у людино-читабельному вигляді
100
+ * @param {unknown} parsed розпарений package.json
101
+ * @param {(msg: string) => void} pass pass callback
102
+ * @param {(msg: string) => void} fail fail callback
103
+ * @returns {{ found: 0 | 1, bad: 0 | 1 }} прирости лічильників
104
+ */
105
+ function auditMssqlVersionInPackageJson(rel, parsed, pass, fail) {
106
+ const range = getMssqlDependencyRange(asObject(parsed).dependencies)
107
+ if (!range) return { found: 0, bad: 0 }
108
+
109
+ const parsedVer = parseLeadingSemver(range)
110
+ if (!parsedVer) {
111
+ fail(`js-mssql: ${rel}: dependencies.mssql має нечитабельну версію: ${JSON.stringify(range)} (js-mssql.mdc)`)
112
+ return { found: 1, bad: 1 }
113
+ }
114
+ if (semverGte(parsedVer, MIN_MSSQL_VERSION)) {
115
+ pass(`js-mssql: ${rel}: dependencies.mssql ${JSON.stringify(range)} (>=12.5.0)`)
116
+ return { found: 1, bad: 0 }
117
+ }
118
+ fail(`js-mssql: ${rel}: dependencies.mssql ${JSON.stringify(range)} — має бути >=12.5.0 (js-mssql.mdc)`)
119
+ return { found: 1, bad: 1 }
120
+ }
121
+
122
+ /**
123
+ * Прогін усіх package.json: рахує знайдені mssql і ті, що не задовольняють мінімум.
124
+ * @param {string} repoRoot корінь репозиторію
125
+ * @param {string[]} pkgJsonPaths абсолютні шляхи до package.json
126
+ * @param {(msg: string) => void} pass pass callback
127
+ * @param {(msg: string) => void} fail fail callback
128
+ * @returns {Promise<{ found: number, bad: number }>} підсумкові лічильники
129
+ */
130
+ async function aggregateMssqlVersionsAcrossPackages(repoRoot, pkgJsonPaths, pass, fail) {
131
+ let found = 0
132
+ let bad = 0
133
+ for (const absPath of pkgJsonPaths) {
134
+ const rel = relative(repoRoot, absPath).split('\\').join('/')
135
+ let parsed
136
+ try {
137
+ parsed = JSON.parse(await readFile(absPath, 'utf8'))
138
+ } catch {
139
+ fail(`js-mssql: ${rel} — невалідний JSON`)
140
+ continue
141
+ }
142
+ const inc = auditMssqlVersionInPackageJson(rel, parsed, pass, fail)
143
+ found += inc.found
144
+ bad += inc.bad
145
+ }
146
+ return { found, bad }
147
+ }
148
+
149
+ /**
150
+ * Підрахунок порушень у одному файлі джерела mssql.
151
+ * Кожен лічильник інкрементується відповідним сканером, повідомлення йдуть у `fail`.
152
+ * @param {string} rel relative-шлях файлу
153
+ * @param {string} content вихідний код
154
+ * @param {Record<string, number>} counters агрегатор лічильників
155
+ * @param {(msg: string) => void} fail fail callback
156
+ */
157
+ function scanMssqlOneSourceFile(rel, content, counters, fail) {
158
+ for (const v of findMssqlPerRequestConnectionInText(content, rel)) {
159
+ counters.violations++
160
+ fail(
161
+ `js-mssql: ${rel}:${v.line} — не створюй new sql.ConnectionPool(...) на кожен запит; використовуй singleton sql.ConnectionPool: ${v.snippet}`
162
+ )
163
+ }
164
+ for (const v of findSharedMssqlRequestInText(content, rel)) {
165
+ counters.sharedRequestViolations++
166
+ fail(
167
+ `js-mssql: ${rel}:${v.line} — заборонено шарити Request (наприклад export const request = pool.request()); створюй pool.request() щоразу заново (js-mssql.mdc): ${v.snippet}`
168
+ )
169
+ }
170
+ for (const v of findUnsafeMssqlQueryTemplateCallInText(content, rel)) {
171
+ counters.unsafeQueryCalls++
172
+ fail(
173
+ `js-mssql: ${rel}:${v.line} — заборонено query(\`...\`): це не tagged template; використовуй pool.request().query\`...\` (js-mssql.mdc): ${v.snippet}`
174
+ )
175
+ }
176
+ for (const v of findUnsafeMssqlDynamicSqlListInText(content, rel)) {
177
+ counters.unsafeDynamicSqlLists++
178
+ fail(
179
+ `js-mssql: ${rel}:${v.line} — заборонено підставляти у SQL динамічні списки через .join(',') (типово IN (...) / VALUES (...)); використовуй TVP (sql.Table) + JOIN/INSERT (js-mssql.mdc): ${v.snippet}`
180
+ )
181
+ }
182
+ for (const v of findUnsafeMssqlInListUnparsedInText(content, rel)) {
183
+ counters.unparsedInLists++
184
+ fail(
185
+ `js-mssql: ${rel}:${v.line} — у SQL IN (\${...}) значення мають бути попередньо приведені числовим парсером (parseInt/Number/BigInt/parseFloat) і відфільтровані від NaN, інакше можливий SQL injection (js-mssql.mdc): ${v.snippet}`
186
+ )
187
+ }
188
+ for (const v of findUnsafeMssqlInListMissingEmptyGuardInText(content, rel)) {
189
+ counters.inListGuardViolations++
190
+ if (v.reason === 'missing_guard') {
191
+ fail(
192
+ `js-mssql: ${rel}:${v.line} — перед IN-списком ${JSON.stringify(v.name)} потрібна перевірка на пустоту з throw ` +
193
+ `(наприклад if (!${v.name}.length) throw ...), інакше можливі некоректні запити (js-mssql.mdc): ${v.snippet}`
194
+ )
195
+ } else {
196
+ fail(
197
+ `js-mssql: ${rel}:${v.line} — значення для IN (\${...}) у template literal треба винести в окрему змінну ` +
198
+ `і перевірити на пустоту (throw), не підставляти вираз напряму (js-mssql.mdc): ${v.snippet}`
199
+ )
200
+ }
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Звіт про відсутність порушень у джерелах mssql: кожен лічильник із 0 → один pass-рядок.
206
+ * @param {Record<string, number>} counters лічильники після проходу всіх файлів
207
+ * @param {(msg: string) => void} pass pass callback
208
+ */
209
+ function reportZeroMssqlSourceViolations(counters, pass) {
210
+ if (counters.violations === 0) {
211
+ pass('js-mssql: немає створення new sql.ConnectionPool(...) всередині функцій (singleton pool)')
212
+ }
213
+ if (counters.sharedRequestViolations === 0) {
214
+ pass('js-mssql: немає shared Request (export const request = pool.request())')
215
+ }
216
+ if (counters.unsafeQueryCalls === 0) {
217
+ pass('js-mssql: немає небезпечних викликів query(`...`) (потрібно query`...`)')
218
+ }
219
+ if (counters.unsafeDynamicSqlLists === 0) {
220
+ pass("js-mssql: немає небезпечних динамічних SQL-списків через .join(',') у IN/VALUES")
221
+ }
222
+ if (counters.unparsedInLists === 0) {
223
+ pass(`js-mssql: немає підстановок IN (\${...}) без числового парсера значень`)
224
+ }
225
+ if (counters.inListGuardViolations === 0) {
226
+ pass('js-mssql: усі IN-списки винесені у змінні та мають перевірку на пустоту з throw')
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Аудит усіх JS/TS-джерел репо щодо безпечного використання mssql.
232
+ * @param {string} repoRoot корінь репозиторію
233
+ * @param {string[]} ignorePaths абсолютні шляхи каталогів, повністю виключених з обходу
234
+ * @param {(msg: string) => void} pass pass callback
235
+ * @param {(msg: string) => void} fail fail callback
236
+ * @returns {Promise<void>} визначається по завершенню аудиту всіх знайдених джерел
237
+ */
238
+ async function auditMssqlSources(repoRoot, ignorePaths, pass, fail) {
239
+ const sourcePaths = await findAllSourcePathsForMssqlScan(repoRoot, ignorePaths)
240
+ if (sourcePaths.length === 0) {
241
+ pass('js-mssql: немає JS/TS файлів для скану singleton ConnectionPool')
242
+ return
243
+ }
244
+
245
+ const counters = {
246
+ violations: 0,
247
+ sharedRequestViolations: 0,
248
+ unsafeQueryCalls: 0,
249
+ unsafeDynamicSqlLists: 0,
250
+ unparsedInLists: 0,
251
+ inListGuardViolations: 0
252
+ }
253
+ for (const absPath of sourcePaths) {
254
+ const rel = relative(repoRoot, absPath).split('\\').join('/')
255
+ const content = await readFile(absPath, 'utf8')
256
+ scanMssqlOneSourceFile(rel, content, counters, fail)
257
+ }
258
+
259
+ reportZeroMssqlSourceViolations(counters, pass)
260
+ }
261
+
262
+ /**
263
+ * Перевіряє відповідність проєкту правилу js-mssql.mdc
264
+ * @param {import('@7n/rules/scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту
265
+ * @returns {Promise<import('@7n/rules/scripts/lib/lint-surface/types.mjs').LintResult>} перелік порушень
266
+ */
267
+ export async function lint(ctx) {
268
+ const reporter = createViolationReporter(ctx)
269
+ const { pass, fail } = reporter
270
+
271
+ const repoRoot = ctx.cwd
272
+ if (!existsSync(join(repoRoot, 'package.json'))) {
273
+ pass('js-mssql: package.json у корені відсутній — перевірку пропущено')
274
+ return reporter.result()
275
+ }
276
+
277
+ const ignorePaths = await loadCursorIgnorePaths(repoRoot)
278
+ const pkgJsonPaths = await findAllPackageJsonPaths(repoRoot, ignorePaths)
279
+ if (pkgJsonPaths.length === 0) {
280
+ pass('js-mssql: package.json не знайдено — перевірку пропущено')
281
+ return reporter.result()
282
+ }
283
+
284
+ const { found, bad } = await aggregateMssqlVersionsAcrossPackages(repoRoot, pkgJsonPaths, pass, fail)
285
+
286
+ if (found === 0) {
287
+ pass('js-mssql: пакет mssql не знайдено в dependencies жодного package.json')
288
+ return reporter.result()
289
+ }
290
+ if (bad === 0) {
291
+ pass(`js-mssql: всі знайдені dependencies.mssql відповідають мінімальній версії 12.5.0 (${found})`)
292
+ }
293
+
294
+ await auditMssqlSources(repoRoot, ignorePaths, pass, fail)
295
+
296
+ return reporter.result()
297
+ }
@@ -0,0 +1,11 @@
1
+ ---
2
+ type: Directory Index
3
+ title: npm/rules/js-mssql
4
+ resource: plugins/lang-js/rules/js-mssql/
5
+ ---
6
+
7
+ # npm/rules/js-mssql
8
+
9
+ | Файл | Тип |
10
+ | ------------------- | --------- |
11
+ | [main.mjs](main.md) | JS Module |
@@ -0,0 +1,11 @@
1
+ ---
2
+ type: Directory Index
3
+ title: npm/rules/js-mssql/lib
4
+ resource: plugins/lang-js/rules/js-mssql/lib/
5
+ ---
6
+
7
+ # npm/rules/js-mssql/lib
8
+
9
+ | Файл | Тип |
10
+ | ----------------------------------------- | --------- |
11
+ | [mssql-pool-scan.mjs](mssql-pool-scan.md) | JS Module |