@nielspeter/eess-ts 0.1.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 (371) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +364 -0
  3. package/dist/builders/call-rule-builder.d.ts +199 -0
  4. package/dist/builders/call-rule-builder.d.ts.map +1 -0
  5. package/dist/builders/call-rule-builder.js +254 -0
  6. package/dist/builders/call-rule-builder.js.map +1 -0
  7. package/dist/builders/class-rule-builder.d.ts +136 -0
  8. package/dist/builders/class-rule-builder.d.ts.map +1 -0
  9. package/dist/builders/class-rule-builder.js +253 -0
  10. package/dist/builders/class-rule-builder.js.map +1 -0
  11. package/dist/builders/cross-layer-builder.d.ts +96 -0
  12. package/dist/builders/cross-layer-builder.d.ts.map +1 -0
  13. package/dist/builders/cross-layer-builder.js +172 -0
  14. package/dist/builders/cross-layer-builder.js.map +1 -0
  15. package/dist/builders/function-rule-builder.d.ts +198 -0
  16. package/dist/builders/function-rule-builder.d.ts.map +1 -0
  17. package/dist/builders/function-rule-builder.js +287 -0
  18. package/dist/builders/function-rule-builder.js.map +1 -0
  19. package/dist/builders/jsx-rule-builder.d.ts +113 -0
  20. package/dist/builders/jsx-rule-builder.d.ts.map +1 -0
  21. package/dist/builders/jsx-rule-builder.js +150 -0
  22. package/dist/builders/jsx-rule-builder.js.map +1 -0
  23. package/dist/builders/module-rule-builder.d.ts +159 -0
  24. package/dist/builders/module-rule-builder.d.ts.map +1 -0
  25. package/dist/builders/module-rule-builder.js +237 -0
  26. package/dist/builders/module-rule-builder.js.map +1 -0
  27. package/dist/builders/scoped-function-rule-builder.d.ts +21 -0
  28. package/dist/builders/scoped-function-rule-builder.d.ts.map +1 -0
  29. package/dist/builders/scoped-function-rule-builder.js +26 -0
  30. package/dist/builders/scoped-function-rule-builder.js.map +1 -0
  31. package/dist/builders/slice-rule-builder.d.ts +85 -0
  32. package/dist/builders/slice-rule-builder.d.ts.map +1 -0
  33. package/dist/builders/slice-rule-builder.js +134 -0
  34. package/dist/builders/slice-rule-builder.js.map +1 -0
  35. package/dist/builders/type-rule-builder.d.ts +103 -0
  36. package/dist/builders/type-rule-builder.d.ts.map +1 -0
  37. package/dist/builders/type-rule-builder.js +170 -0
  38. package/dist/builders/type-rule-builder.js.map +1 -0
  39. package/dist/cli/bin.d.ts +3 -0
  40. package/dist/cli/bin.d.ts.map +1 -0
  41. package/dist/cli/bin.js +4 -0
  42. package/dist/cli/bin.js.map +1 -0
  43. package/dist/cli/commands/baseline.d.ts +11 -0
  44. package/dist/cli/commands/baseline.d.ts.map +1 -0
  45. package/dist/cli/commands/baseline.js +16 -0
  46. package/dist/cli/commands/baseline.js.map +1 -0
  47. package/dist/cli/commands/check.d.ts +21 -0
  48. package/dist/cli/commands/check.d.ts.map +1 -0
  49. package/dist/cli/commands/check.js +94 -0
  50. package/dist/cli/commands/check.js.map +1 -0
  51. package/dist/cli/commands/explain.d.ts +9 -0
  52. package/dist/cli/commands/explain.d.ts.map +1 -0
  53. package/dist/cli/commands/explain.js +49 -0
  54. package/dist/cli/commands/explain.js.map +1 -0
  55. package/dist/cli/config.d.ts +31 -0
  56. package/dist/cli/config.d.ts.map +1 -0
  57. package/dist/cli/config.js +20 -0
  58. package/dist/cli/config.js.map +1 -0
  59. package/dist/cli/index.d.ts +21 -0
  60. package/dist/cli/index.d.ts.map +1 -0
  61. package/dist/cli/index.js +168 -0
  62. package/dist/cli/index.js.map +1 -0
  63. package/dist/cli/load-rules.d.ts +20 -0
  64. package/dist/cli/load-rules.d.ts.map +1 -0
  65. package/dist/cli/load-rules.js +97 -0
  66. package/dist/cli/load-rules.js.map +1 -0
  67. package/dist/cli/resolve-config.d.ts +11 -0
  68. package/dist/cli/resolve-config.d.ts.map +1 -0
  69. package/dist/cli/resolve-config.js +61 -0
  70. package/dist/cli/resolve-config.js.map +1 -0
  71. package/dist/cli/watch.d.ts +49 -0
  72. package/dist/cli/watch.d.ts.map +1 -0
  73. package/dist/cli/watch.js +138 -0
  74. package/dist/cli/watch.js.map +1 -0
  75. package/dist/conditions/body-analysis-function.d.ts +23 -0
  76. package/dist/conditions/body-analysis-function.d.ts.map +1 -0
  77. package/dist/conditions/body-analysis-function.js +103 -0
  78. package/dist/conditions/body-analysis-function.js.map +1 -0
  79. package/dist/conditions/body-analysis-module.d.ts +27 -0
  80. package/dist/conditions/body-analysis-module.d.ts.map +1 -0
  81. package/dist/conditions/body-analysis-module.js +99 -0
  82. package/dist/conditions/body-analysis-module.js.map +1 -0
  83. package/dist/conditions/body-analysis.d.ts +34 -0
  84. package/dist/conditions/body-analysis.d.ts.map +1 -0
  85. package/dist/conditions/body-analysis.js +95 -0
  86. package/dist/conditions/body-analysis.js.map +1 -0
  87. package/dist/conditions/call.d.ts +62 -0
  88. package/dist/conditions/call.d.ts.map +1 -0
  89. package/dist/conditions/call.js +267 -0
  90. package/dist/conditions/call.js.map +1 -0
  91. package/dist/conditions/catch-analysis.d.ts +31 -0
  92. package/dist/conditions/catch-analysis.d.ts.map +1 -0
  93. package/dist/conditions/catch-analysis.js +78 -0
  94. package/dist/conditions/catch-analysis.js.map +1 -0
  95. package/dist/conditions/class.d.ts +33 -0
  96. package/dist/conditions/class.d.ts.map +1 -0
  97. package/dist/conditions/class.js +110 -0
  98. package/dist/conditions/class.js.map +1 -0
  99. package/dist/conditions/cross-layer.d.ts +28 -0
  100. package/dist/conditions/cross-layer.d.ts.map +1 -0
  101. package/dist/conditions/cross-layer.js +105 -0
  102. package/dist/conditions/cross-layer.js.map +1 -0
  103. package/dist/conditions/dependency.d.ts +73 -0
  104. package/dist/conditions/dependency.d.ts.map +1 -0
  105. package/dist/conditions/dependency.js +177 -0
  106. package/dist/conditions/dependency.js.map +1 -0
  107. package/dist/conditions/exports.d.ts +33 -0
  108. package/dist/conditions/exports.d.ts.map +1 -0
  109. package/dist/conditions/exports.js +101 -0
  110. package/dist/conditions/exports.js.map +1 -0
  111. package/dist/conditions/function.d.ts +79 -0
  112. package/dist/conditions/function.d.ts.map +1 -0
  113. package/dist/conditions/function.js +167 -0
  114. package/dist/conditions/function.js.map +1 -0
  115. package/dist/conditions/helpers.d.ts +14 -0
  116. package/dist/conditions/helpers.d.ts.map +1 -0
  117. package/dist/conditions/helpers.js +26 -0
  118. package/dist/conditions/helpers.js.map +1 -0
  119. package/dist/conditions/jsx.d.ts +40 -0
  120. package/dist/conditions/jsx.d.ts.map +1 -0
  121. package/dist/conditions/jsx.js +133 -0
  122. package/dist/conditions/jsx.js.map +1 -0
  123. package/dist/conditions/members.d.ts +74 -0
  124. package/dist/conditions/members.d.ts.map +1 -0
  125. package/dist/conditions/members.js +224 -0
  126. package/dist/conditions/members.js.map +1 -0
  127. package/dist/conditions/pattern.d.ts +20 -0
  128. package/dist/conditions/pattern.d.ts.map +1 -0
  129. package/dist/conditions/pattern.js +108 -0
  130. package/dist/conditions/pattern.js.map +1 -0
  131. package/dist/conditions/reverse-dependency.d.ts +28 -0
  132. package/dist/conditions/reverse-dependency.d.ts.map +1 -0
  133. package/dist/conditions/reverse-dependency.js +275 -0
  134. package/dist/conditions/reverse-dependency.js.map +1 -0
  135. package/dist/conditions/slice.d.ts +49 -0
  136. package/dist/conditions/slice.d.ts.map +1 -0
  137. package/dist/conditions/slice.js +153 -0
  138. package/dist/conditions/slice.js.map +1 -0
  139. package/dist/conditions/structural.d.ts +58 -0
  140. package/dist/conditions/structural.d.ts.map +1 -0
  141. package/dist/conditions/structural.js +102 -0
  142. package/dist/conditions/structural.js.map +1 -0
  143. package/dist/conditions/type-level.d.ts +29 -0
  144. package/dist/conditions/type-level.d.ts.map +1 -0
  145. package/dist/conditions/type-level.js +48 -0
  146. package/dist/conditions/type-level.js.map +1 -0
  147. package/dist/core/import-options.d.ts +32 -0
  148. package/dist/core/import-options.d.ts.map +1 -0
  149. package/dist/core/import-options.js +29 -0
  150. package/dist/core/import-options.js.map +1 -0
  151. package/dist/core/module-dependencies.d.ts +28 -0
  152. package/dist/core/module-dependencies.d.ts.map +1 -0
  153. package/dist/core/module-dependencies.js +35 -0
  154. package/dist/core/module-dependencies.js.map +1 -0
  155. package/dist/core/pair-condition.d.ts +10 -0
  156. package/dist/core/pair-condition.d.ts.map +1 -0
  157. package/dist/core/pair-condition.js +2 -0
  158. package/dist/core/pair-condition.js.map +1 -0
  159. package/dist/core/project.d.ts +68 -0
  160. package/dist/core/project.d.ts.map +1 -0
  161. package/dist/core/project.js +127 -0
  162. package/dist/core/project.js.map +1 -0
  163. package/dist/core/type-matcher.d.ts +10 -0
  164. package/dist/core/type-matcher.d.ts.map +1 -0
  165. package/dist/core/type-matcher.js +2 -0
  166. package/dist/core/type-matcher.js.map +1 -0
  167. package/dist/core/violation.d.ts +38 -0
  168. package/dist/core/violation.d.ts.map +1 -0
  169. package/dist/core/violation.js +130 -0
  170. package/dist/core/violation.js.map +1 -0
  171. package/dist/graphql/index.d.ts +76 -0
  172. package/dist/graphql/index.d.ts.map +1 -0
  173. package/dist/graphql/index.js +108 -0
  174. package/dist/graphql/index.js.map +1 -0
  175. package/dist/graphql/resolver-rule-builder.d.ts +75 -0
  176. package/dist/graphql/resolver-rule-builder.d.ts.map +1 -0
  177. package/dist/graphql/resolver-rule-builder.js +146 -0
  178. package/dist/graphql/resolver-rule-builder.js.map +1 -0
  179. package/dist/graphql/schema-conditions.d.ts +31 -0
  180. package/dist/graphql/schema-conditions.d.ts.map +1 -0
  181. package/dist/graphql/schema-conditions.js +119 -0
  182. package/dist/graphql/schema-conditions.js.map +1 -0
  183. package/dist/graphql/schema-loader.d.ts +75 -0
  184. package/dist/graphql/schema-loader.d.ts.map +1 -0
  185. package/dist/graphql/schema-loader.js +113 -0
  186. package/dist/graphql/schema-loader.js.map +1 -0
  187. package/dist/graphql/schema-predicates.d.ts +42 -0
  188. package/dist/graphql/schema-predicates.d.ts.map +1 -0
  189. package/dist/graphql/schema-predicates.js +74 -0
  190. package/dist/graphql/schema-predicates.js.map +1 -0
  191. package/dist/graphql/schema-rule-builder.d.ts +74 -0
  192. package/dist/graphql/schema-rule-builder.d.ts.map +1 -0
  193. package/dist/graphql/schema-rule-builder.js +188 -0
  194. package/dist/graphql/schema-rule-builder.js.map +1 -0
  195. package/dist/helpers/body-traversal.d.ts +58 -0
  196. package/dist/helpers/body-traversal.d.ts.map +1 -0
  197. package/dist/helpers/body-traversal.js +180 -0
  198. package/dist/helpers/body-traversal.js.map +1 -0
  199. package/dist/helpers/callback-extractor.d.ts +28 -0
  200. package/dist/helpers/callback-extractor.d.ts.map +1 -0
  201. package/dist/helpers/callback-extractor.js +159 -0
  202. package/dist/helpers/callback-extractor.js.map +1 -0
  203. package/dist/helpers/complexity.d.ts +26 -0
  204. package/dist/helpers/complexity.d.ts.map +1 -0
  205. package/dist/helpers/complexity.js +64 -0
  206. package/dist/helpers/complexity.js.map +1 -0
  207. package/dist/helpers/matchers.d.ts +206 -0
  208. package/dist/helpers/matchers.d.ts.map +1 -0
  209. package/dist/helpers/matchers.js +470 -0
  210. package/dist/helpers/matchers.js.map +1 -0
  211. package/dist/helpers/pattern.d.ts +37 -0
  212. package/dist/helpers/pattern.d.ts.map +1 -0
  213. package/dist/helpers/pattern.js +22 -0
  214. package/dist/helpers/pattern.js.map +1 -0
  215. package/dist/helpers/slice-graph.d.ts +32 -0
  216. package/dist/helpers/slice-graph.d.ts.map +1 -0
  217. package/dist/helpers/slice-graph.js +89 -0
  218. package/dist/helpers/slice-graph.js.map +1 -0
  219. package/dist/helpers/tarjan.d.ts +21 -0
  220. package/dist/helpers/tarjan.d.ts.map +1 -0
  221. package/dist/helpers/tarjan.js +71 -0
  222. package/dist/helpers/tarjan.js.map +1 -0
  223. package/dist/helpers/type-matchers.d.ts +67 -0
  224. package/dist/helpers/type-matchers.d.ts.map +1 -0
  225. package/dist/helpers/type-matchers.js +108 -0
  226. package/dist/helpers/type-matchers.js.map +1 -0
  227. package/dist/helpers/within.d.ts +41 -0
  228. package/dist/helpers/within.d.ts.map +1 -0
  229. package/dist/helpers/within.js +32 -0
  230. package/dist/helpers/within.js.map +1 -0
  231. package/dist/index.d.ts +101 -0
  232. package/dist/index.d.ts.map +1 -0
  233. package/dist/index.js +116 -0
  234. package/dist/index.js.map +1 -0
  235. package/dist/models/arch-call.d.ts +83 -0
  236. package/dist/models/arch-call.d.ts.map +1 -0
  237. package/dist/models/arch-call.js +90 -0
  238. package/dist/models/arch-call.js.map +1 -0
  239. package/dist/models/arch-function.d.ts +76 -0
  240. package/dist/models/arch-function.d.ts.map +1 -0
  241. package/dist/models/arch-function.js +122 -0
  242. package/dist/models/arch-function.js.map +1 -0
  243. package/dist/models/arch-jsx-element.d.ts +75 -0
  244. package/dist/models/arch-jsx-element.d.ts.map +1 -0
  245. package/dist/models/arch-jsx-element.js +231 -0
  246. package/dist/models/arch-jsx-element.js.map +1 -0
  247. package/dist/models/cross-layer.d.ts +15 -0
  248. package/dist/models/cross-layer.d.ts.map +1 -0
  249. package/dist/models/cross-layer.js +2 -0
  250. package/dist/models/cross-layer.js.map +1 -0
  251. package/dist/models/slice.d.ts +60 -0
  252. package/dist/models/slice.d.ts.map +1 -0
  253. package/dist/models/slice.js +89 -0
  254. package/dist/models/slice.js.map +1 -0
  255. package/dist/predicates/call.d.ts +49 -0
  256. package/dist/predicates/call.d.ts.map +1 -0
  257. package/dist/predicates/call.js +115 -0
  258. package/dist/predicates/call.js.map +1 -0
  259. package/dist/predicates/class.d.ts +42 -0
  260. package/dist/predicates/class.d.ts.map +1 -0
  261. package/dist/predicates/class.js +83 -0
  262. package/dist/predicates/class.js.map +1 -0
  263. package/dist/predicates/function.d.ts +81 -0
  264. package/dist/predicates/function.d.ts.map +1 -0
  265. package/dist/predicates/function.js +157 -0
  266. package/dist/predicates/function.js.map +1 -0
  267. package/dist/predicates/identity.d.ts +55 -0
  268. package/dist/predicates/identity.d.ts.map +1 -0
  269. package/dist/predicates/identity.js +96 -0
  270. package/dist/predicates/identity.js.map +1 -0
  271. package/dist/predicates/index.d.ts +4 -0
  272. package/dist/predicates/index.d.ts.map +1 -0
  273. package/dist/predicates/index.js +3 -0
  274. package/dist/predicates/index.js.map +1 -0
  275. package/dist/predicates/jsx.d.ts +41 -0
  276. package/dist/predicates/jsx.d.ts.map +1 -0
  277. package/dist/predicates/jsx.js +84 -0
  278. package/dist/predicates/jsx.js.map +1 -0
  279. package/dist/predicates/metrics.d.ts +30 -0
  280. package/dist/predicates/metrics.d.ts.map +1 -0
  281. package/dist/predicates/metrics.js +65 -0
  282. package/dist/predicates/metrics.js.map +1 -0
  283. package/dist/predicates/module.d.ts +44 -0
  284. package/dist/predicates/module.d.ts.map +1 -0
  285. package/dist/predicates/module.js +70 -0
  286. package/dist/predicates/module.js.map +1 -0
  287. package/dist/predicates/type.d.ts +48 -0
  288. package/dist/predicates/type.d.ts.map +1 -0
  289. package/dist/predicates/type.js +107 -0
  290. package/dist/predicates/type.js.map +1 -0
  291. package/dist/presets/boundaries.d.ts +19 -0
  292. package/dist/presets/boundaries.d.ts.map +1 -0
  293. package/dist/presets/boundaries.js +93 -0
  294. package/dist/presets/boundaries.js.map +1 -0
  295. package/dist/presets/data-layer.d.ts +20 -0
  296. package/dist/presets/data-layer.d.ts.map +1 -0
  297. package/dist/presets/data-layer.js +30 -0
  298. package/dist/presets/data-layer.js.map +1 -0
  299. package/dist/presets/index.d.ts +9 -0
  300. package/dist/presets/index.d.ts.map +1 -0
  301. package/dist/presets/index.js +5 -0
  302. package/dist/presets/index.js.map +1 -0
  303. package/dist/presets/layered.d.ts +21 -0
  304. package/dist/presets/layered.d.ts.map +1 -0
  305. package/dist/presets/layered.js +103 -0
  306. package/dist/presets/layered.js.map +1 -0
  307. package/dist/presets/shared.d.ts +3 -0
  308. package/dist/presets/shared.d.ts.map +1 -0
  309. package/dist/presets/shared.js +5 -0
  310. package/dist/presets/shared.js.map +1 -0
  311. package/dist/rules/architecture.d.ts +10 -0
  312. package/dist/rules/architecture.d.ts.map +1 -0
  313. package/dist/rules/architecture.js +14 -0
  314. package/dist/rules/architecture.js.map +1 -0
  315. package/dist/rules/code-quality.d.ts +55 -0
  316. package/dist/rules/code-quality.d.ts.map +1 -0
  317. package/dist/rules/code-quality.js +116 -0
  318. package/dist/rules/code-quality.js.map +1 -0
  319. package/dist/rules/dependencies.d.ts +32 -0
  320. package/dist/rules/dependencies.d.ts.map +1 -0
  321. package/dist/rules/dependencies.js +37 -0
  322. package/dist/rules/dependencies.js.map +1 -0
  323. package/dist/rules/errors.d.ts +31 -0
  324. package/dist/rules/errors.d.ts.map +1 -0
  325. package/dist/rules/errors.js +97 -0
  326. package/dist/rules/errors.js.map +1 -0
  327. package/dist/rules/hygiene.d.ts +54 -0
  328. package/dist/rules/hygiene.d.ts.map +1 -0
  329. package/dist/rules/hygiene.js +62 -0
  330. package/dist/rules/hygiene.js.map +1 -0
  331. package/dist/rules/metrics-function.d.ts +45 -0
  332. package/dist/rules/metrics-function.d.ts.map +1 -0
  333. package/dist/rules/metrics-function.js +87 -0
  334. package/dist/rules/metrics-function.js.map +1 -0
  335. package/dist/rules/metrics.d.ts +64 -0
  336. package/dist/rules/metrics.d.ts.map +1 -0
  337. package/dist/rules/metrics.js +157 -0
  338. package/dist/rules/metrics.js.map +1 -0
  339. package/dist/rules/naming.d.ts +24 -0
  340. package/dist/rules/naming.d.ts.map +1 -0
  341. package/dist/rules/naming.js +51 -0
  342. package/dist/rules/naming.js.map +1 -0
  343. package/dist/rules/security.d.ts +59 -0
  344. package/dist/rules/security.d.ts.map +1 -0
  345. package/dist/rules/security.js +92 -0
  346. package/dist/rules/security.js.map +1 -0
  347. package/dist/rules/typescript.d.ts +73 -0
  348. package/dist/rules/typescript.d.ts.map +1 -0
  349. package/dist/rules/typescript.js +105 -0
  350. package/dist/rules/typescript.js.map +1 -0
  351. package/dist/smells/duplicate-bodies.d.ts +24 -0
  352. package/dist/smells/duplicate-bodies.d.ts.map +1 -0
  353. package/dist/smells/duplicate-bodies.js +131 -0
  354. package/dist/smells/duplicate-bodies.js.map +1 -0
  355. package/dist/smells/fingerprint.d.ts +27 -0
  356. package/dist/smells/fingerprint.d.ts.map +1 -0
  357. package/dist/smells/fingerprint.js +50 -0
  358. package/dist/smells/fingerprint.js.map +1 -0
  359. package/dist/smells/inconsistent-siblings.d.ts +21 -0
  360. package/dist/smells/inconsistent-siblings.d.ts.map +1 -0
  361. package/dist/smells/inconsistent-siblings.js +135 -0
  362. package/dist/smells/inconsistent-siblings.js.map +1 -0
  363. package/dist/smells/index.d.ts +12 -0
  364. package/dist/smells/index.d.ts.map +1 -0
  365. package/dist/smells/index.js +15 -0
  366. package/dist/smells/index.js.map +1 -0
  367. package/dist/smells/smell-builder.d.ts +37 -0
  368. package/dist/smells/smell-builder.d.ts.map +1 -0
  369. package/dist/smells/smell-builder.js +51 -0
  370. package/dist/smells/smell-builder.js.map +1 -0
  371. package/package.json +121 -0
@@ -0,0 +1,138 @@
1
+ import { watch } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { ArchRuleError } from '@nielspeter/eess';
4
+ // eess-exclude eess/no-unused-exports: consumed by the test suite (tests are outside the build project)
5
+ export const TS_FILE_RE = /\.[cm]?tsx?$/;
6
+ /**
7
+ * Scheduling logic for watch mode — extracted for testability.
8
+ *
9
+ * Debounces rapid triggers. If a trigger arrives while the callback
10
+ * is running, it queues a re-run after the current run completes.
11
+ */
12
+ // eess-exclude eess/no-unused-exports: consumed by the test suite (tests are outside the build project)
13
+ export class RunScheduler {
14
+ debounceTimer;
15
+ running = false;
16
+ _pendingRerun = false;
17
+ debounceMs;
18
+ onRun;
19
+ #runCount = 0;
20
+ constructor(onRun, debounceMs = 250) {
21
+ this.onRun = onRun;
22
+ this.debounceMs = debounceMs;
23
+ }
24
+ get runCount() {
25
+ return this.#runCount;
26
+ }
27
+ get pendingRerun() {
28
+ return this._pendingRerun;
29
+ }
30
+ get isRunning() {
31
+ return this.running;
32
+ }
33
+ /**
34
+ * Queue a run for the given trigger, resetting the debounce window.
35
+ * If a run is already in progress, marks a pending re-run instead.
36
+ */
37
+ schedule(trigger) {
38
+ if (this.debounceTimer)
39
+ clearTimeout(this.debounceTimer);
40
+ this.debounceTimer = setTimeout(() => {
41
+ if (this.running) {
42
+ this._pendingRerun = true;
43
+ return;
44
+ }
45
+ this.executeRun(trigger);
46
+ }, this.debounceMs);
47
+ }
48
+ executeRun(trigger) {
49
+ this.running = true;
50
+ this._pendingRerun = false;
51
+ this.#runCount++;
52
+ process.stdout.write('\x1B[2J\x1B[H'); // clear screen, preserve scrollback
53
+ process.stdout.write(`Change detected: ${trigger}\n\n`);
54
+ this.onRun(trigger)
55
+ .catch((err) => {
56
+ // Rule failures are expected — swallow ArchRuleError, print others
57
+ if (!(err instanceof ArchRuleError)) {
58
+ if (err instanceof Error) {
59
+ console.error(err.message);
60
+ }
61
+ }
62
+ })
63
+ .finally(() => {
64
+ this.running = false;
65
+ if (this._pendingRerun) {
66
+ this.executeRun('(queued change)');
67
+ }
68
+ else {
69
+ process.stdout.write('\nWatching for changes...\n');
70
+ }
71
+ });
72
+ }
73
+ }
74
+ /**
75
+ * Watch for file changes and re-run the callback.
76
+ *
77
+ * Uses Node.js `fs.watch` with `recursive: true` (Node 24+).
78
+ * Debounces rapid filesystem events. If a change arrives while
79
+ * a run is in progress, it is queued and executed after the
80
+ * current run completes.
81
+ *
82
+ * Known limitation: each re-run loads rule files with a fresh (cache-busting)
83
+ * jiti instance. Over long sessions, memory grows — restart the watcher
84
+ * periodically for long sessions.
85
+ */
86
+ export function watchAndRerun(options) {
87
+ const { watchDirs, watchFiles, onChangeDetected, debounceMs = 250 } = options;
88
+ const scheduler = new RunScheduler(onChangeDetected, debounceMs);
89
+ const watchers = [];
90
+ // Watch directories recursively
91
+ for (const dir of watchDirs) {
92
+ const resolved = path.resolve(dir);
93
+ const watcher = watch(resolved, { recursive: true });
94
+ watchers.push(watcher);
95
+ void (async () => {
96
+ try {
97
+ for await (const event of watcher) {
98
+ if (event.filename && TS_FILE_RE.test(event.filename)) {
99
+ scheduler.schedule(event.filename);
100
+ }
101
+ }
102
+ }
103
+ catch (err) {
104
+ if (err instanceof Error && err.message !== 'The operation was aborted') {
105
+ console.error(`Watcher error on ${dir}: ${err.message}`);
106
+ }
107
+ }
108
+ })();
109
+ }
110
+ // Watch individual rule files
111
+ for (const file of watchFiles) {
112
+ const resolved = path.resolve(file);
113
+ const watcher = watch(resolved);
114
+ watchers.push(watcher);
115
+ void (async () => {
116
+ try {
117
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- must consume async iterator
118
+ for await (const _event of watcher) {
119
+ scheduler.schedule(path.basename(file));
120
+ }
121
+ }
122
+ catch (err) {
123
+ if (err instanceof Error && err.message !== 'The operation was aborted') {
124
+ console.error(`Watcher error on ${file}: ${err.message}`);
125
+ }
126
+ }
127
+ })();
128
+ }
129
+ // Graceful shutdown — close all watchers on SIGINT
130
+ process.on('SIGINT', () => {
131
+ for (const w of watchers) {
132
+ // Ask each async iterator to release its underlying fs.watch handle.
133
+ void w[Symbol.asyncIterator]().return?.();
134
+ }
135
+ process.exit(0);
136
+ });
137
+ }
138
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/cli/watch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { Condition } from '@nielspeter/eess';
2
+ import type { ExpressionMatcher } from '../helpers/matchers.js';
3
+ import type { ArchFunction } from '../models/arch-function.js';
4
+ /**
5
+ * Function body must contain at least one node matching the matcher.
6
+ */
7
+ export declare function functionContain(matcher: ExpressionMatcher): Condition<ArchFunction>;
8
+ /**
9
+ * Function body must NOT contain any node matching the matcher.
10
+ */
11
+ export declare function functionNotContain(matcher: ExpressionMatcher): Condition<ArchFunction>;
12
+ /**
13
+ * Function body must use the 'good' pattern instead of the 'bad' pattern.
14
+ */
15
+ export declare function functionUseInsteadOf(bad: ExpressionMatcher, good: ExpressionMatcher): Condition<ArchFunction>;
16
+ /**
17
+ * Function must not have an empty body (zero statements).
18
+ *
19
+ * Expression-bodied arrows (`() => expr`) always pass — they have no block body.
20
+ * A function with only comments is still considered empty (comments are not statements).
21
+ */
22
+ export declare function functionNotHaveEmptyBody(): Condition<ArchFunction>;
23
+ //# sourceMappingURL=body-analysis-function.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body-analysis-function.d.ts","sourceRoot":"","sources":["../../src/conditions/body-analysis-function.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,kBAAkB,CAAA;AAEnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAwB9D;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,CAAC,YAAY,CAAC,CAoBnF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,CAAC,YAAY,CAAC,CAoBtF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,iBAAiB,EACtB,IAAI,EAAE,iBAAiB,GACtB,SAAS,CAAC,YAAY,CAAC,CAgCzB;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI,SAAS,CAAC,YAAY,CAAC,CAyBlE"}
@@ -0,0 +1,103 @@
1
+ import { Node } from 'ts-morph';
2
+ import { searchFunctionBody } from '../helpers/body-traversal.js';
3
+ /**
4
+ * Create an ArchViolation from an ArchFunction (not a Node).
5
+ *
6
+ * ArchFunction is not a Node, so we can't use createViolation directly.
7
+ * This helper bridges the gap.
8
+ */
9
+ function createFunctionViolation(fn, message, context) {
10
+ return {
11
+ rule: context.rule,
12
+ element: fn.getName() ?? '<anonymous>',
13
+ file: fn.getSourceFile().getFilePath(),
14
+ line: fn.getStartLineNumber(),
15
+ message,
16
+ because: context.because,
17
+ };
18
+ }
19
+ /**
20
+ * Function body must contain at least one node matching the matcher.
21
+ */
22
+ export function functionContain(matcher) {
23
+ return {
24
+ description: `contain ${matcher.description}`,
25
+ evaluate(elements, context) {
26
+ const violations = [];
27
+ for (const fn of elements) {
28
+ const result = searchFunctionBody(fn, matcher);
29
+ if (!result.found) {
30
+ violations.push(createFunctionViolation(fn, `${fn.getName() ?? '<anonymous>'} does not contain ${matcher.description}`, context));
31
+ }
32
+ }
33
+ return violations;
34
+ },
35
+ };
36
+ }
37
+ /**
38
+ * Function body must NOT contain any node matching the matcher.
39
+ */
40
+ export function functionNotContain(matcher) {
41
+ return {
42
+ description: `not contain ${matcher.description}`,
43
+ evaluate(elements, context) {
44
+ const violations = [];
45
+ for (const fn of elements) {
46
+ const result = searchFunctionBody(fn, matcher);
47
+ for (const node of result.matchingNodes) {
48
+ violations.push(createFunctionViolation(fn, `${fn.getName() ?? '<anonymous>'} contains ${matcher.description} at line ${String(node.getStartLineNumber())}`, context));
49
+ }
50
+ }
51
+ return violations;
52
+ },
53
+ };
54
+ }
55
+ /**
56
+ * Function body must use the 'good' pattern instead of the 'bad' pattern.
57
+ */
58
+ export function functionUseInsteadOf(bad, good) {
59
+ return {
60
+ description: `use ${good.description} instead of ${bad.description}`,
61
+ evaluate(elements, context) {
62
+ const violations = [];
63
+ for (const fn of elements) {
64
+ const badResult = searchFunctionBody(fn, bad);
65
+ const goodResult = searchFunctionBody(fn, good);
66
+ for (const node of badResult.matchingNodes) {
67
+ violations.push(createFunctionViolation(fn, `${fn.getName() ?? '<anonymous>'} contains ${bad.description} at line ${String(node.getStartLineNumber())} — use ${good.description} instead`, context));
68
+ }
69
+ if (!goodResult.found) {
70
+ violations.push(createFunctionViolation(fn, `${fn.getName() ?? '<anonymous>'} does not contain ${good.description}`, context));
71
+ }
72
+ }
73
+ return violations;
74
+ },
75
+ };
76
+ }
77
+ /**
78
+ * Function must not have an empty body (zero statements).
79
+ *
80
+ * Expression-bodied arrows (`() => expr`) always pass — they have no block body.
81
+ * A function with only comments is still considered empty (comments are not statements).
82
+ */
83
+ export function functionNotHaveEmptyBody() {
84
+ return {
85
+ description: 'not have an empty body',
86
+ evaluate(elements, context) {
87
+ const violations = [];
88
+ for (const fn of elements) {
89
+ const body = fn.getBody();
90
+ if (!body)
91
+ continue; // no body = declaration only, skip
92
+ // Expression-bodied arrows return the expression, not a Block
93
+ if (!Node.isBlock(body))
94
+ continue; // expression body — always has content
95
+ if (body.getStatements().length === 0) {
96
+ violations.push(createFunctionViolation(fn, `${fn.getName() ?? '<anonymous>'} has an empty body`, context));
97
+ }
98
+ }
99
+ return violations;
100
+ },
101
+ };
102
+ }
103
+ //# sourceMappingURL=body-analysis-function.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body-analysis-function.js","sourceRoot":"","sources":["../../src/conditions/body-analysis-function.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { SourceFile } from 'ts-morph';
2
+ import type { Condition } from '@nielspeter/eess';
3
+ import type { ExpressionMatcher } from '../helpers/matchers.js';
4
+ import { type ModuleBodyOptions } from '../helpers/body-traversal.js';
5
+ /**
6
+ * Module must contain at least one node matching the matcher.
7
+ *
8
+ * Default: searches the entire file. With `{ scopeToModule: true }`,
9
+ * only searches top-level statements (skips class/function bodies).
10
+ */
11
+ export declare function moduleContain(matcher: ExpressionMatcher, options?: ModuleBodyOptions): Condition<SourceFile>;
12
+ /**
13
+ * Module must NOT contain any node matching the matcher.
14
+ *
15
+ * Produces one violation per matching node found.
16
+ * Default: searches the entire file. With `{ scopeToModule: true }`,
17
+ * only searches top-level statements (skips class/function bodies).
18
+ */
19
+ export declare function moduleNotContain(matcher: ExpressionMatcher, options?: ModuleBodyOptions): Condition<SourceFile>;
20
+ /**
21
+ * Module must use the 'good' pattern instead of the 'bad' pattern.
22
+ *
23
+ * Combines notContain(bad) and contain(good) into a single condition
24
+ * with better violation messages.
25
+ */
26
+ export declare function moduleUseInsteadOf(bad: ExpressionMatcher, good: ExpressionMatcher, options?: ModuleBodyOptions): Condition<SourceFile>;
27
+ //# sourceMappingURL=body-analysis-module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body-analysis-module.d.ts","sourceRoot":"","sources":["../../src/conditions/body-analysis-module.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,kBAAkB,CAAA;AAEnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC/D,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAIvF;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,iBAAiB,EAC1B,OAAO,CAAC,EAAE,iBAAiB,GAC1B,SAAS,CAAC,UAAU,CAAC,CAqBvB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,iBAAiB,EAC1B,OAAO,CAAC,EAAE,iBAAiB,GAC1B,SAAS,CAAC,UAAU,CAAC,CAqBvB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,iBAAiB,EACtB,IAAI,EAAE,iBAAiB,EACvB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,SAAS,CAAC,UAAU,CAAC,CAkCvB"}
@@ -0,0 +1,99 @@
1
+ import { searchModuleBody } from '../helpers/body-traversal.js';
2
+ // ─── Module body conditions ────────────────────────────────────────
3
+ /**
4
+ * Module must contain at least one node matching the matcher.
5
+ *
6
+ * Default: searches the entire file. With `{ scopeToModule: true }`,
7
+ * only searches top-level statements (skips class/function bodies).
8
+ */
9
+ export function moduleContain(matcher, options) {
10
+ return {
11
+ description: `contain ${matcher.description}`,
12
+ evaluate(elements, context) {
13
+ const violations = [];
14
+ for (const sf of elements) {
15
+ const result = searchModuleBody(sf, matcher, options);
16
+ if (!result.found) {
17
+ violations.push({
18
+ rule: context.rule,
19
+ element: sf.getBaseName(),
20
+ file: sf.getFilePath(),
21
+ line: 1,
22
+ message: `${sf.getBaseName()} does not contain ${matcher.description}`,
23
+ because: context.because,
24
+ });
25
+ }
26
+ }
27
+ return violations;
28
+ },
29
+ };
30
+ }
31
+ /**
32
+ * Module must NOT contain any node matching the matcher.
33
+ *
34
+ * Produces one violation per matching node found.
35
+ * Default: searches the entire file. With `{ scopeToModule: true }`,
36
+ * only searches top-level statements (skips class/function bodies).
37
+ */
38
+ export function moduleNotContain(matcher, options) {
39
+ return {
40
+ description: `not contain ${matcher.description}`,
41
+ evaluate(elements, context) {
42
+ const violations = [];
43
+ for (const sf of elements) {
44
+ const result = searchModuleBody(sf, matcher, options);
45
+ for (const node of result.matchingNodes) {
46
+ violations.push({
47
+ rule: context.rule,
48
+ element: sf.getBaseName(),
49
+ file: sf.getFilePath(),
50
+ line: node.getStartLineNumber(),
51
+ message: `${sf.getBaseName()} contains ${matcher.description} at line ${String(node.getStartLineNumber())}`,
52
+ because: context.because,
53
+ });
54
+ }
55
+ }
56
+ return violations;
57
+ },
58
+ };
59
+ }
60
+ /**
61
+ * Module must use the 'good' pattern instead of the 'bad' pattern.
62
+ *
63
+ * Combines notContain(bad) and contain(good) into a single condition
64
+ * with better violation messages.
65
+ */
66
+ export function moduleUseInsteadOf(bad, good, options) {
67
+ return {
68
+ description: `use ${good.description} instead of ${bad.description}`,
69
+ evaluate(elements, context) {
70
+ const violations = [];
71
+ for (const sf of elements) {
72
+ const badResult = searchModuleBody(sf, bad, options);
73
+ const goodResult = searchModuleBody(sf, good, options);
74
+ for (const node of badResult.matchingNodes) {
75
+ violations.push({
76
+ rule: context.rule,
77
+ element: sf.getBaseName(),
78
+ file: sf.getFilePath(),
79
+ line: node.getStartLineNumber(),
80
+ message: `${sf.getBaseName()} contains ${bad.description} at line ${String(node.getStartLineNumber())} — use ${good.description} instead`,
81
+ because: context.because,
82
+ });
83
+ }
84
+ if (!goodResult.found) {
85
+ violations.push({
86
+ rule: context.rule,
87
+ element: sf.getBaseName(),
88
+ file: sf.getFilePath(),
89
+ line: 1,
90
+ message: `${sf.getBaseName()} does not contain ${good.description}`,
91
+ because: context.because,
92
+ });
93
+ }
94
+ }
95
+ return violations;
96
+ },
97
+ };
98
+ }
99
+ //# sourceMappingURL=body-analysis-module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body-analysis-module.js","sourceRoot":"","sources":["../../src/conditions/body-analysis-module.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { ClassDeclaration } from 'ts-morph';
2
+ import type { Condition } from '@nielspeter/eess';
3
+ import type { ExpressionMatcher } from '../helpers/matchers.js';
4
+ /**
5
+ * Class body must contain at least one node matching the matcher.
6
+ *
7
+ * Violation if NO method in the class contains a match.
8
+ */
9
+ export declare function classContain(matcher: ExpressionMatcher): Condition<ClassDeclaration>;
10
+ /**
11
+ * Class body must NOT contain any node matching the matcher.
12
+ *
13
+ * Violation for EACH matching node found in any method.
14
+ * Reports the specific line where the violation occurs.
15
+ */
16
+ export declare function classNotContain(matcher: ExpressionMatcher): Condition<ClassDeclaration>;
17
+ /**
18
+ * Class body must use the 'good' pattern instead of the 'bad' pattern.
19
+ *
20
+ * Combines notContain(bad) and contain(good) into a single condition
21
+ * with better violation messages.
22
+ *
23
+ * Two types of violations:
24
+ * 1. Class contains the 'bad' pattern — "use X instead of Y at line N"
25
+ * 2. Class does not contain the 'good' pattern — "expected X but not found"
26
+ */
27
+ export declare function classUseInsteadOf(bad: ExpressionMatcher, good: ExpressionMatcher): Condition<ClassDeclaration>;
28
+ /**
29
+ * Class must not have an empty body (zero members).
30
+ *
31
+ * A class with only comments is still considered empty.
32
+ */
33
+ export declare function classNotHaveEmptyBody(): Condition<ClassDeclaration>;
34
+ //# sourceMappingURL=body-analysis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body-analysis.d.ts","sourceRoot":"","sources":["../../src/conditions/body-analysis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAChD,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,kBAAkB,CAAA;AAGnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAK/D;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAoBpF;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAoBvF;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,iBAAiB,EACtB,IAAI,EAAE,iBAAiB,GACtB,SAAS,CAAC,gBAAgB,CAAC,CAkC7B;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,SAAS,CAAC,gBAAgB,CAAC,CAmBnE"}
@@ -0,0 +1,95 @@
1
+ import { createViolation, getElementName } from '../core/violation.js';
2
+ import { searchClassBody } from '../helpers/body-traversal.js';
3
+ // ─── Class body conditions ──────────────────────────────────────────
4
+ /**
5
+ * Class body must contain at least one node matching the matcher.
6
+ *
7
+ * Violation if NO method in the class contains a match.
8
+ */
9
+ export function classContain(matcher) {
10
+ return {
11
+ description: `contain ${matcher.description}`,
12
+ evaluate(elements, context) {
13
+ const violations = [];
14
+ for (const cls of elements) {
15
+ const result = searchClassBody(cls, matcher);
16
+ if (!result.found) {
17
+ violations.push(createViolation(cls, `${getElementName(cls)} does not contain ${matcher.description}`, context));
18
+ }
19
+ }
20
+ return violations;
21
+ },
22
+ };
23
+ }
24
+ /**
25
+ * Class body must NOT contain any node matching the matcher.
26
+ *
27
+ * Violation for EACH matching node found in any method.
28
+ * Reports the specific line where the violation occurs.
29
+ */
30
+ export function classNotContain(matcher) {
31
+ return {
32
+ description: `not contain ${matcher.description}`,
33
+ evaluate(elements, context) {
34
+ const violations = [];
35
+ for (const cls of elements) {
36
+ const result = searchClassBody(cls, matcher);
37
+ for (const node of result.matchingNodes) {
38
+ violations.push(createViolation(cls, `${getElementName(cls)} contains ${matcher.description} at line ${String(node.getStartLineNumber())}`, context));
39
+ }
40
+ }
41
+ return violations;
42
+ },
43
+ };
44
+ }
45
+ /**
46
+ * Class body must use the 'good' pattern instead of the 'bad' pattern.
47
+ *
48
+ * Combines notContain(bad) and contain(good) into a single condition
49
+ * with better violation messages.
50
+ *
51
+ * Two types of violations:
52
+ * 1. Class contains the 'bad' pattern — "use X instead of Y at line N"
53
+ * 2. Class does not contain the 'good' pattern — "expected X but not found"
54
+ */
55
+ export function classUseInsteadOf(bad, good) {
56
+ return {
57
+ description: `use ${good.description} instead of ${bad.description}`,
58
+ evaluate(elements, context) {
59
+ const violations = [];
60
+ for (const cls of elements) {
61
+ const badResult = searchClassBody(cls, bad);
62
+ const goodResult = searchClassBody(cls, good);
63
+ // Report each occurrence of the bad pattern
64
+ for (const node of badResult.matchingNodes) {
65
+ violations.push(createViolation(cls, `${getElementName(cls)} contains ${bad.description} at line ${String(node.getStartLineNumber())} — use ${good.description} instead`, context));
66
+ }
67
+ // If the good pattern is missing entirely, report that too
68
+ if (!goodResult.found) {
69
+ violations.push(createViolation(cls, `${getElementName(cls)} does not contain ${good.description}`, context));
70
+ }
71
+ }
72
+ return violations;
73
+ },
74
+ };
75
+ }
76
+ /**
77
+ * Class must not have an empty body (zero members).
78
+ *
79
+ * A class with only comments is still considered empty.
80
+ */
81
+ export function classNotHaveEmptyBody() {
82
+ return {
83
+ description: 'not have an empty body',
84
+ evaluate(elements, context) {
85
+ const violations = [];
86
+ for (const cls of elements) {
87
+ if (cls.getMembers().length === 0) {
88
+ violations.push(createViolation(cls, `${getElementName(cls)} has an empty body (zero members)`, context));
89
+ }
90
+ }
91
+ return violations;
92
+ },
93
+ };
94
+ }
95
+ //# sourceMappingURL=body-analysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body-analysis.js","sourceRoot":"","sources":["../../src/conditions/body-analysis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import type { Condition } from '@nielspeter/eess';
2
+ import type { ExpressionMatcher } from '../helpers/matchers.js';
3
+ import type { ArchCall } from '../models/arch-call.js';
4
+ /**
5
+ * The filtered call set must be empty --- no calls should match the predicates.
6
+ */
7
+ export declare function notExist(): Condition<ArchCall>;
8
+ /**
9
+ * Assert that at least one callback argument contains a match.
10
+ *
11
+ * Searches all function-like arguments (ArrowFunction, FunctionExpression)
12
+ * for a node matching the given ExpressionMatcher.
13
+ */
14
+ export declare function haveCallbackContaining(matcher: ExpressionMatcher): Condition<ArchCall>;
15
+ /**
16
+ * Assert that NO callback argument contains a match.
17
+ *
18
+ * Produces one violation per matching node found in any callback.
19
+ */
20
+ export declare function notHaveCallbackContaining(matcher: ExpressionMatcher): Condition<ArchCall>;
21
+ /**
22
+ * Assert that at least one object literal argument has ALL named properties.
23
+ *
24
+ * Scans all arguments of each call for ObjectLiteralExpression nodes.
25
+ * Passes if at least one object literal argument contains every
26
+ * specified property name.
27
+ *
28
+ * @throws {Error} if called with zero property names
29
+ */
30
+ export declare function haveArgumentWithProperty(...names: string[]): Condition<ArchCall>;
31
+ /**
32
+ * Assert that NO object literal argument has ANY of the named properties.
33
+ *
34
+ * Scans all arguments of each call for ObjectLiteralExpression nodes.
35
+ * Reports one violation per forbidden property found in any argument.
36
+ *
37
+ * @throws {Error} if called with zero property names
38
+ */
39
+ export declare function notHaveArgumentWithProperty(...names: string[]): Condition<ArchCall>;
40
+ /**
41
+ * Assert that at least one argument subtree contains a match.
42
+ *
43
+ * Searches ALL arguments of each call recursively using `findMatchesInNode`.
44
+ * This is a superset of `haveCallbackContaining` — it searches the entire
45
+ * subtree of every argument (object literals, callbacks, nested expressions),
46
+ * not just function-like arguments. Use `haveCallbackContaining` when you
47
+ * only want to search callback bodies.
48
+ */
49
+ export declare function haveArgumentContaining(matcher: ExpressionMatcher): Condition<ArchCall>;
50
+ /**
51
+ * Assert that NO argument subtree contains a match.
52
+ *
53
+ * Searches ALL arguments of each call recursively using `findMatchesInNode`.
54
+ * Produces one violation per matching node found in any argument.
55
+ *
56
+ * This is a superset of `notHaveCallbackContaining` — it searches the entire
57
+ * subtree of every argument (object literals, callbacks, nested expressions),
58
+ * not just function-like arguments. Use `notHaveCallbackContaining` when you
59
+ * only want to search callback bodies.
60
+ */
61
+ export declare function notHaveArgumentContaining(matcher: ExpressionMatcher): Condition<ArchCall>;
62
+ //# sourceMappingURL=call.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call.d.ts","sourceRoot":"","sources":["../../src/conditions/call.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,kBAAkB,CAAA;AAEnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAqCtD;;GAEG;AACH,wBAAgB,QAAQ,IAAI,SAAS,CAAC,QAAQ,CAAC,CAa9C;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,CAAC,QAAQ,CAAC,CAoBtF;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,CAAC,QAAQ,CAAC,CA6BzF;AAiCD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,QAAQ,CAAC,CAsChF;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,QAAQ,CAAC,CAqCnF;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,CAAC,QAAQ,CAAC,CA4BtF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,CAAC,QAAQ,CAAC,CA0BzF"}