@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,92 @@
1
+ import { call, newExpr, access } from '../helpers/matchers.js';
2
+ import { classNotContain } from '../conditions/body-analysis.js';
3
+ import { functionNotContain } from '../conditions/body-analysis-function.js';
4
+ import { moduleNotContain } from '../conditions/body-analysis-module.js';
5
+ /**
6
+ * No eval() calls in class methods.
7
+ *
8
+ * @example
9
+ * classes(p).should().satisfy(noEval()).check()
10
+ */
11
+ export function noEval() {
12
+ return classNotContain(call('eval'));
13
+ }
14
+ /**
15
+ * No new Function() constructor (equivalent to eval).
16
+ *
17
+ * @example
18
+ * classes(p).should().satisfy(noFunctionConstructor()).check()
19
+ */
20
+ export function noFunctionConstructor() {
21
+ return classNotContain(newExpr('Function'));
22
+ }
23
+ /**
24
+ * No direct process.env access in class methods.
25
+ *
26
+ * Use dependency injection for configuration instead.
27
+ *
28
+ * @example
29
+ * classes(p).that().resideInFolder('** /domain/** ')
30
+ * .should().satisfy(noProcessEnv())
31
+ * .because('use Config injection instead')
32
+ * .check()
33
+ */
34
+ export function noProcessEnv() {
35
+ return classNotContain(access('process.env'));
36
+ }
37
+ /**
38
+ * No console.log calls in class methods.
39
+ *
40
+ * Use a logger abstraction instead.
41
+ *
42
+ * @example
43
+ * classes(p).that().resideInFolder('** /src/** ')
44
+ * .should().satisfy(noConsoleLog())
45
+ * .check()
46
+ */
47
+ export function noConsoleLog() {
48
+ return classNotContain(call('console.log'));
49
+ }
50
+ /**
51
+ * No direct console access (any method: log, warn, error, debug, info).
52
+ * Stricter than noConsoleLog — catches all console methods.
53
+ */
54
+ export function noConsole() {
55
+ return classNotContain(access(/^console\./));
56
+ }
57
+ /**
58
+ * No JSON.parse calls — centralize deserialization.
59
+ */
60
+ export function noJsonParse() {
61
+ return classNotContain(call('JSON.parse'));
62
+ }
63
+ // ─── Function variants ────────────────────────────────────────────
64
+ export function functionNoEval() {
65
+ return functionNotContain(call('eval'));
66
+ }
67
+ export function functionNoFunctionConstructor() {
68
+ return functionNotContain(newExpr('Function'));
69
+ }
70
+ export function functionNoProcessEnv() {
71
+ return functionNotContain(access('process.env'));
72
+ }
73
+ export function functionNoConsoleLog() {
74
+ return functionNotContain(call('console.log'));
75
+ }
76
+ export function functionNoConsole() {
77
+ return functionNotContain(access(/^console\./));
78
+ }
79
+ export function functionNoJsonParse() {
80
+ return functionNotContain(call('JSON.parse'));
81
+ }
82
+ // ─── Module variants ──────────────────────────────────────────────
83
+ export function moduleNoEval() {
84
+ return moduleNotContain(call('eval'));
85
+ }
86
+ export function moduleNoProcessEnv() {
87
+ return moduleNotContain(access('process.env'));
88
+ }
89
+ export function moduleNoConsoleLog() {
90
+ return moduleNotContain(call('console.log'));
91
+ }
92
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/rules/security.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAA;AAC5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAA;AAExE;;;;;GAKG;AACH,MAAM,UAAU,MAAM;IACpB,OAAO,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;AACtC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,eAAe,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAA;AAC7C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,eAAe,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAA;AAC/C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,eAAe,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAA;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO,eAAe,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAA;AAC9C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAA;AAC5C,CAAC;AAED,qEAAqE;AAErE,MAAM,UAAU,cAAc;IAC5B,OAAO,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,UAAU,6BAA6B;IAC3C,OAAO,kBAAkB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAA;AAChD,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO,kBAAkB,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAA;AAClD,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO,kBAAkB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAA;AAChD,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,kBAAkB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAA;AACjD,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,kBAAkB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAA;AAC/C,CAAC;AAED,qEAAqE;AAErE,MAAM,UAAU,YAAY;IAC1B,OAAO,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;AACvC,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,gBAAgB,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAA;AAChD,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,gBAAgB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAA;AAC9C,CAAC"}
@@ -0,0 +1,73 @@
1
+ import type { ClassDeclaration, SourceFile } from 'ts-morph';
2
+ import type { Condition } from '@nielspeter/eess';
3
+ import type { ArchFunction } from '../models/arch-function.js';
4
+ /**
5
+ * Class properties must not be typed as `any`.
6
+ *
7
+ * Detects both explicit `any` and untyped properties that resolve to `any`.
8
+ * Use `unknown` with type narrowing instead.
9
+ *
10
+ * Uses custom `evaluate()` — inspects type resolution via `getType().getText()`,
11
+ * not AST nodes. Not expressible via the `ExpressionMatcher` pattern used by
12
+ * the other rules in this file.
13
+ *
14
+ * @example
15
+ * classes(p).that().resideInFolder('** /src/** ')
16
+ * .should().satisfy(noAnyProperties())
17
+ * .because('any bypasses the type checker')
18
+ * .check()
19
+ */
20
+ export declare function noAnyProperties(): Condition<ClassDeclaration>;
21
+ /**
22
+ * Class bodies must not contain `as` type assertions.
23
+ * Allows `as const` (narrows types, doesn't widen).
24
+ * Scans methods, constructors, getters, and setters.
25
+ *
26
+ * @example
27
+ * classes(p).that().haveNameEndingWith('Service')
28
+ * .should().satisfy(noTypeAssertions())
29
+ * .check()
30
+ */
31
+ export declare function noTypeAssertions(): Condition<ClassDeclaration>;
32
+ /**
33
+ * Class bodies must not contain non-null assertions (`!`).
34
+ * Handle null/undefined explicitly instead of asserting it away.
35
+ * Scans methods, constructors, getters, and setters.
36
+ *
37
+ * @example
38
+ * classes(p).that().resideInFolder('** /domain/** ')
39
+ * .should().satisfy(noNonNullAssertions())
40
+ * .check()
41
+ */
42
+ export declare function noNonNullAssertions(): Condition<ClassDeclaration>;
43
+ /**
44
+ * Function bodies must not contain `as` type assertions (allows `as const`).
45
+ * Use type guards or explicit type annotations instead.
46
+ *
47
+ * @example
48
+ * functions(p).that().resideInFolder('** /src/** ')
49
+ * .should().satisfy(functionNoTypeAssertions())
50
+ * .check()
51
+ */
52
+ export declare function functionNoTypeAssertions(): Condition<ArchFunction>;
53
+ /**
54
+ * Function bodies must not contain non-null assertions (`!`).
55
+ * Handle null/undefined explicitly instead of asserting it away.
56
+ */
57
+ export declare function functionNoNonNullAssertions(): Condition<ArchFunction>;
58
+ /**
59
+ * Source file must not contain any `as` type assertions (allows `as const`).
60
+ * Broader than the function/class variants — catches top-level code,
61
+ * class methods, functions, arrow functions, and any other expressions.
62
+ *
63
+ * @example
64
+ * modules(p).that().resideInFolder('** /src/** ')
65
+ * .should().satisfy(moduleNoTypeAssertions())
66
+ * .check()
67
+ */
68
+ export declare function moduleNoTypeAssertions(): Condition<SourceFile>;
69
+ /**
70
+ * Source file must not contain any `!` non-null assertions.
71
+ */
72
+ export declare function moduleNoNonNullAssertions(): Condition<SourceFile>;
73
+ //# sourceMappingURL=typescript.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typescript.d.ts","sourceRoot":"","sources":["../../src/rules/typescript.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,kBAAkB,CAAA;AAGnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAM9D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,IAAI,SAAS,CAAC,gBAAgB,CAAC,CAqB7D;AAID;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,IAAI,SAAS,CAAC,gBAAgB,CAAC,CAE9D;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,IAAI,SAAS,CAAC,gBAAgB,CAAC,CAEjE;AAID;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,IAAI,SAAS,CAAC,YAAY,CAAC,CAElE;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,IAAI,SAAS,CAAC,YAAY,CAAC,CAErE;AAID;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,IAAI,SAAS,CAAC,UAAU,CAAC,CAE9D;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,SAAS,CAAC,UAAU,CAAC,CAEjE"}
@@ -0,0 +1,105 @@
1
+ import { createViolation, getElementName } from '../core/violation.js';
2
+ import { typeAssertion, nonNullAssertion } from '../helpers/matchers.js';
3
+ import { classNotContain } from '../conditions/body-analysis.js';
4
+ import { functionNotContain } from '../conditions/body-analysis-function.js';
5
+ import { moduleNotContain } from '../conditions/body-analysis-module.js';
6
+ /**
7
+ * Class properties must not be typed as `any`.
8
+ *
9
+ * Detects both explicit `any` and untyped properties that resolve to `any`.
10
+ * Use `unknown` with type narrowing instead.
11
+ *
12
+ * Uses custom `evaluate()` — inspects type resolution via `getType().getText()`,
13
+ * not AST nodes. Not expressible via the `ExpressionMatcher` pattern used by
14
+ * the other rules in this file.
15
+ *
16
+ * @example
17
+ * classes(p).that().resideInFolder('** /src/** ')
18
+ * .should().satisfy(noAnyProperties())
19
+ * .because('any bypasses the type checker')
20
+ * .check()
21
+ */
22
+ export function noAnyProperties() {
23
+ return {
24
+ description: 'have no properties typed as any',
25
+ evaluate(elements, context) {
26
+ const violations = [];
27
+ for (const cls of elements) {
28
+ for (const prop of cls.getProperties()) {
29
+ if (prop.getType().getText() === 'any') {
30
+ violations.push(createViolation(prop, `${getElementName(cls)}.${prop.getName()} is typed as 'any' — use a specific type or 'unknown'`, context));
31
+ }
32
+ }
33
+ }
34
+ return violations;
35
+ },
36
+ };
37
+ }
38
+ // ─── Class variants ──────────────────────────────────────────────
39
+ /**
40
+ * Class bodies must not contain `as` type assertions.
41
+ * Allows `as const` (narrows types, doesn't widen).
42
+ * Scans methods, constructors, getters, and setters.
43
+ *
44
+ * @example
45
+ * classes(p).that().haveNameEndingWith('Service')
46
+ * .should().satisfy(noTypeAssertions())
47
+ * .check()
48
+ */
49
+ export function noTypeAssertions() {
50
+ return classNotContain(typeAssertion());
51
+ }
52
+ /**
53
+ * Class bodies must not contain non-null assertions (`!`).
54
+ * Handle null/undefined explicitly instead of asserting it away.
55
+ * Scans methods, constructors, getters, and setters.
56
+ *
57
+ * @example
58
+ * classes(p).that().resideInFolder('** /domain/** ')
59
+ * .should().satisfy(noNonNullAssertions())
60
+ * .check()
61
+ */
62
+ export function noNonNullAssertions() {
63
+ return classNotContain(nonNullAssertion());
64
+ }
65
+ // ─── Function variants ───────────────────────────────────────────
66
+ /**
67
+ * Function bodies must not contain `as` type assertions (allows `as const`).
68
+ * Use type guards or explicit type annotations instead.
69
+ *
70
+ * @example
71
+ * functions(p).that().resideInFolder('** /src/** ')
72
+ * .should().satisfy(functionNoTypeAssertions())
73
+ * .check()
74
+ */
75
+ export function functionNoTypeAssertions() {
76
+ return functionNotContain(typeAssertion());
77
+ }
78
+ /**
79
+ * Function bodies must not contain non-null assertions (`!`).
80
+ * Handle null/undefined explicitly instead of asserting it away.
81
+ */
82
+ export function functionNoNonNullAssertions() {
83
+ return functionNotContain(nonNullAssertion());
84
+ }
85
+ // ─── Module variants ─────────────────────────────────────────────
86
+ /**
87
+ * Source file must not contain any `as` type assertions (allows `as const`).
88
+ * Broader than the function/class variants — catches top-level code,
89
+ * class methods, functions, arrow functions, and any other expressions.
90
+ *
91
+ * @example
92
+ * modules(p).that().resideInFolder('** /src/** ')
93
+ * .should().satisfy(moduleNoTypeAssertions())
94
+ * .check()
95
+ */
96
+ export function moduleNoTypeAssertions() {
97
+ return moduleNotContain(typeAssertion());
98
+ }
99
+ /**
100
+ * Source file must not contain any `!` non-null assertions.
101
+ */
102
+ export function moduleNoNonNullAssertions() {
103
+ return moduleNotContain(nonNullAssertion());
104
+ }
105
+ //# sourceMappingURL=typescript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typescript.js","sourceRoot":"","sources":["../../src/rules/typescript.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAEtE,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAA;AAC5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAA;AAExE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO;QACL,WAAW,EAAE,iCAAiC;QAC9C,QAAQ,CAAC,QAA4B,EAAE,OAAyB;YAC9D,MAAM,UAAU,GAAoB,EAAE,CAAA;YACtC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;gBAC3B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,aAAa,EAAE,EAAE,CAAC;oBACvC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,KAAK,KAAK,EAAE,CAAC;wBACvC,UAAU,CAAC,IAAI,CACb,eAAe,CACb,IAAI,EACJ,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,uDAAuD,EAC/F,OAAO,CACR,CACF,CAAA;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YACD,OAAO,UAAU,CAAA;QACnB,CAAC;KACF,CAAA;AACH,CAAC;AAED,oEAAoE;AAEpE;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,eAAe,CAAC,aAAa,EAAE,CAAC,CAAA;AACzC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,eAAe,CAAC,gBAAgB,EAAE,CAAC,CAAA;AAC5C,CAAC;AAED,oEAAoE;AAEpE;;;;;;;;GAQG;AACH,MAAM,UAAU,wBAAwB;IACtC,OAAO,kBAAkB,CAAC,aAAa,EAAE,CAAC,CAAA;AAC5C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO,kBAAkB,CAAC,gBAAgB,EAAE,CAAC,CAAA;AAC/C,CAAC;AAED,oEAAoE;AAEpE;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,gBAAgB,CAAC,aAAa,EAAE,CAAC,CAAA;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,yBAAyB;IACvC,OAAO,gBAAgB,CAAC,gBAAgB,EAAE,CAAC,CAAA;AAC7C,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { SmellBuilder } from './smell-builder.js';
2
+ import type { ArchViolation } from '../core/violation.js';
3
+ import type { ArchProject } from '../core/project.js';
4
+ export declare class DuplicateBodiesBuilder extends SmellBuilder {
5
+ private _minSimilarity;
6
+ constructor(project: ArchProject);
7
+ /** Set the AST similarity threshold. Default: 0.85. */
8
+ withMinSimilarity(threshold: number): this;
9
+ protected detect(): ArchViolation[];
10
+ protected describe(): string;
11
+ /** Check if a file path passes all glob-based filters. */
12
+ private passesFileFilters;
13
+ /** Check if a function body meets the minimum line count. */
14
+ private meetsMinLines;
15
+ /** Collect all functions matching folder/path/test filters. */
16
+ private collectFilteredFunctions;
17
+ /** Build fingerprints for all collected functions. */
18
+ private fingerprintAll;
19
+ /** Compare all pairs of fingerprints, collect those above threshold. */
20
+ private findSimilarPairs;
21
+ /** Build violations from similar pairs. */
22
+ private buildViolations;
23
+ }
24
+ //# sourceMappingURL=duplicate-bodies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duplicate-bodies.d.ts","sourceRoot":"","sources":["../../src/smells/duplicate-bodies.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAIjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAYrD,qBAAa,sBAAuB,SAAQ,YAAY;IACtD,OAAO,CAAC,cAAc,CAAO;gBAEjB,OAAO,EAAE,WAAW;IAIhC,uDAAuD;IACvD,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAK1C,SAAS,CAAC,MAAM,IAAI,aAAa,EAAE;IAOnC,SAAS,CAAC,QAAQ,IAAI,MAAM;IAK5B,0DAA0D;IAC1D,OAAO,CAAC,iBAAiB;IAYzB,6DAA6D;IAC7D,OAAO,CAAC,aAAa;IAOrB,+DAA+D;IAC/D,OAAO,CAAC,wBAAwB;IAuBhC,sDAAsD;IACtD,OAAO,CAAC,cAAc;IAUtB,wEAAwE;IACxE,OAAO,CAAC,gBAAgB;IA0BxB,2CAA2C;IAC3C,OAAO,CAAC,eAAe;CAsCxB"}
@@ -0,0 +1,131 @@
1
+ import picomatch from 'picomatch';
2
+ import path from 'node:path';
3
+ import { SmellBuilder } from './smell-builder.js';
4
+ import { collectFunctions } from '../models/arch-function.js';
5
+ import { buildFingerprint, computeSimilarity } from './fingerprint.js';
6
+ /** Test file patterns for ignoreTests(). */
7
+ const TEST_PATTERNS = ['**/*.test.ts', '**/*.spec.ts', '**/__tests__/**'];
8
+ export class DuplicateBodiesBuilder extends SmellBuilder {
9
+ _minSimilarity = 0.85;
10
+ constructor(project) {
11
+ super(project);
12
+ }
13
+ /** Set the AST similarity threshold. Default: 0.85. */
14
+ withMinSimilarity(threshold) {
15
+ this._minSimilarity = threshold;
16
+ return this;
17
+ }
18
+ detect() {
19
+ const functions = this.collectFilteredFunctions();
20
+ const fingerprinted = this.fingerprintAll(functions);
21
+ const pairs = this.findSimilarPairs(fingerprinted);
22
+ return this.buildViolations(pairs);
23
+ }
24
+ describe() {
25
+ const scope = this._folders.length > 0 ? this._folders.join(', ') : 'all files';
26
+ return `No duplicate function bodies in ${scope} (similarity >= ${String(this._minSimilarity)})`;
27
+ }
28
+ /** Check if a file path passes all glob-based filters. */
29
+ passesFileFilters(filePath, folderMatchers, ignoreMatchers, testMatchers) {
30
+ if (folderMatchers.length > 0 && !folderMatchers.some((m) => m(filePath)))
31
+ return false;
32
+ if (ignoreMatchers.some((m) => m(filePath)))
33
+ return false;
34
+ if (testMatchers.some((m) => m(filePath)))
35
+ return false;
36
+ return true;
37
+ }
38
+ /** Check if a function body meets the minimum line count. */
39
+ meetsMinLines(fn) {
40
+ const body = fn.getBody();
41
+ if (!body)
42
+ return false;
43
+ const lineCount = body.getText().split('\n').length;
44
+ return lineCount >= this._minLines;
45
+ }
46
+ /** Collect all functions matching folder/path/test filters. */
47
+ collectFilteredFunctions() {
48
+ const sourceFiles = this.project.getSourceFiles();
49
+ const folderMatchers = this._folders.map((g) => picomatch(g));
50
+ const ignoreMatchers = this._ignorePaths.map((g) => picomatch(g));
51
+ const testMatchers = this._ignoreTests ? TEST_PATTERNS.map((g) => picomatch(g)) : [];
52
+ const allFunctions = [];
53
+ for (const sf of sourceFiles) {
54
+ if (!this.passesFileFilters(sf.getFilePath(), folderMatchers, ignoreMatchers, testMatchers)) {
55
+ continue;
56
+ }
57
+ for (const fn of collectFunctions(sf)) {
58
+ if (this.meetsMinLines(fn)) {
59
+ allFunctions.push(fn);
60
+ }
61
+ }
62
+ }
63
+ return allFunctions;
64
+ }
65
+ /** Build fingerprints for all collected functions. */
66
+ fingerprintAll(functions) {
67
+ const result = [];
68
+ for (const fn of functions) {
69
+ const body = fn.getBody();
70
+ if (!body)
71
+ continue;
72
+ result.push({ fn, fingerprint: buildFingerprint(body) });
73
+ }
74
+ return result;
75
+ }
76
+ /** Compare all pairs of fingerprints, collect those above threshold. */
77
+ findSimilarPairs(items) {
78
+ const pairs = [];
79
+ for (let i = 0; i < items.length; i++) {
80
+ for (let j = i + 1; j < items.length; j++) {
81
+ const a = items[i];
82
+ const b = items[j];
83
+ if (!a || !b)
84
+ continue;
85
+ // Fast rejection: if node counts differ too much, similarity cannot reach threshold
86
+ const maxCount = Math.max(a.fingerprint.nodeCount, b.fingerprint.nodeCount);
87
+ const minCount = Math.min(a.fingerprint.nodeCount, b.fingerprint.nodeCount);
88
+ if (maxCount > 0 && minCount / maxCount < this._minSimilarity) {
89
+ continue;
90
+ }
91
+ const similarity = computeSimilarity(a.fingerprint, b.fingerprint);
92
+ if (similarity >= this._minSimilarity) {
93
+ pairs.push({ a: a.fn, b: b.fn, similarity });
94
+ }
95
+ }
96
+ }
97
+ return pairs;
98
+ }
99
+ /** Build violations from similar pairs. */
100
+ buildViolations(pairs) {
101
+ const ruleDescription = this.describe();
102
+ const violations = [];
103
+ // Optionally sort pairs by folder for grouped output
104
+ const sortedPairs = this._groupByFolder
105
+ ? [...pairs].sort((x, y) => {
106
+ const folderA = path.dirname(x.a.getSourceFile().getFilePath());
107
+ const folderB = path.dirname(y.a.getSourceFile().getFilePath());
108
+ return folderA.localeCompare(folderB);
109
+ })
110
+ : pairs;
111
+ for (const pair of sortedPairs) {
112
+ const nameA = pair.a.getName() ?? '<anonymous>';
113
+ const fileA = pair.a.getSourceFile().getFilePath();
114
+ const lineA = pair.a.getStartLineNumber();
115
+ const nameB = pair.b.getName() ?? '<anonymous>';
116
+ const fileB = pair.b.getSourceFile().getFilePath();
117
+ const lineB = pair.b.getStartLineNumber();
118
+ const pct = Math.round(pair.similarity * 100);
119
+ violations.push({
120
+ rule: ruleDescription,
121
+ element: nameA,
122
+ file: fileA,
123
+ line: lineA,
124
+ message: `${nameA} (${fileA}:${String(lineA)}) is ${String(pct)}% similar to ${nameB} (${fileB}:${String(lineB)})`,
125
+ because: this._reason,
126
+ });
127
+ }
128
+ return violations;
129
+ }
130
+ }
131
+ //# sourceMappingURL=duplicate-bodies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duplicate-bodies.js","sourceRoot":"","sources":["../../src/smells/duplicate-bodies.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { type SyntaxKind, type Node } from 'ts-morph';
2
+ /**
3
+ * Structural fingerprint of a function body.
4
+ * Captures the shape (node kinds, call targets) while ignoring
5
+ * identifiers, literals, and whitespace.
6
+ */
7
+ export interface Fingerprint {
8
+ /** Ordered sequence of syntax node kinds in the body */
9
+ readonly kinds: readonly SyntaxKind[];
10
+ /** Normalized call targets (e.g. ['parseInt', 'this.extractCount']) */
11
+ readonly calls: readonly string[];
12
+ /** Total AST node count (for line-count filtering) */
13
+ readonly nodeCount: number;
14
+ }
15
+ /**
16
+ * Build a structural fingerprint from a function body AST node.
17
+ * Walks all descendants, records their SyntaxKind in order,
18
+ * and extracts call expression targets.
19
+ */
20
+ export declare function buildFingerprint(body: Node): Fingerprint;
21
+ /**
22
+ * Compute similarity between two fingerprints.
23
+ * Uses longest common subsequence on the kinds array,
24
+ * normalized to [0, 1].
25
+ */
26
+ export declare function computeSimilarity(a: Fingerprint, b: Fingerprint): number;
27
+ //# sourceMappingURL=fingerprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/smells/fingerprint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,IAAI,EAAqB,MAAM,UAAU,CAAA;AAExE;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAA;IACrC,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,sDAAsD;IACtD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,WAAW,CAYxD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,MAAM,CAMxE"}
@@ -0,0 +1,50 @@
1
+ import { Node as NodeClass } from 'ts-morph';
2
+ /**
3
+ * Build a structural fingerprint from a function body AST node.
4
+ * Walks all descendants, records their SyntaxKind in order,
5
+ * and extracts call expression targets.
6
+ */
7
+ export function buildFingerprint(body) {
8
+ const kinds = [];
9
+ const calls = [];
10
+ for (const node of body.getDescendants()) {
11
+ kinds.push(node.getKind());
12
+ if (NodeClass.isCallExpression(node)) {
13
+ calls.push(node.getExpression().getText().replace(/\?\./g, '.'));
14
+ }
15
+ }
16
+ return { kinds, calls, nodeCount: kinds.length };
17
+ }
18
+ /**
19
+ * Compute similarity between two fingerprints.
20
+ * Uses longest common subsequence on the kinds array,
21
+ * normalized to [0, 1].
22
+ */
23
+ export function computeSimilarity(a, b) {
24
+ if (a.kinds.length === 0 && b.kinds.length === 0)
25
+ return 1.0;
26
+ if (a.kinds.length === 0 || b.kinds.length === 0)
27
+ return 0.0;
28
+ const lcs = lcsLength(a.kinds, b.kinds);
29
+ return lcs / Math.max(a.kinds.length, b.kinds.length);
30
+ }
31
+ /** Standard LCS length computation (space-optimized two-row DP). */
32
+ function lcsLength(a, b) {
33
+ const m = a.length;
34
+ const n = b.length;
35
+ let prev = new Array(n + 1).fill(0);
36
+ let curr = new Array(n + 1).fill(0);
37
+ for (let i = 1; i <= m; i++) {
38
+ for (let j = 1; j <= n; j++) {
39
+ const prevDiag = prev[j - 1] ?? 0;
40
+ const prevAbove = prev[j] ?? 0;
41
+ const currLeft = curr[j - 1] ?? 0;
42
+ curr[j] = a[i - 1] === b[j - 1] ? prevDiag + 1 : Math.max(prevAbove, currLeft);
43
+ }
44
+ ;
45
+ [prev, curr] = [curr, prev];
46
+ curr.fill(0);
47
+ }
48
+ return prev[n] ?? 0;
49
+ }
50
+ //# sourceMappingURL=fingerprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/smells/fingerprint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { SmellBuilder } from './smell-builder.js';
2
+ import type { ExpressionMatcher } from '../helpers/matchers.js';
3
+ import type { ArchViolation } from '../core/violation.js';
4
+ import type { ArchProject } from '../core/project.js';
5
+ export declare class InconsistentSiblingsBuilder extends SmellBuilder {
6
+ private _pattern?;
7
+ constructor(project: ArchProject);
8
+ /** The pattern that most siblings should follow. */
9
+ forPattern(matcher: ExpressionMatcher): this;
10
+ /** Check if a source file contains any function matching the pattern. */
11
+ private fileMatchesPattern;
12
+ /** Partition files into matching and non-matching based on the pattern. */
13
+ private partitionByPattern;
14
+ /** Build violations for non-matching files in a folder where the majority matches. */
15
+ private buildFolderViolations;
16
+ protected detect(): ArchViolation[];
17
+ protected describe(): string;
18
+ /** Group source files by parent folder, applying all filters. */
19
+ private groupFilesByFolder;
20
+ }
21
+ //# sourceMappingURL=inconsistent-siblings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inconsistent-siblings.d.ts","sourceRoot":"","sources":["../../src/smells/inconsistent-siblings.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAGjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAQrD,qBAAa,2BAA4B,SAAQ,YAAY;IAC3D,OAAO,CAAC,QAAQ,CAAC,CAAmB;gBAExB,OAAO,EAAE,WAAW;IAIhC,oDAAoD;IACpD,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAK5C,yEAAyE;IACzE,OAAO,CAAC,kBAAkB;IAa1B,2EAA2E;IAC3E,OAAO,CAAC,kBAAkB;IAgB1B,sFAAsF;IACtF,OAAO,CAAC,qBAAqB;IAyB7B,SAAS,CAAC,MAAM,IAAI,aAAa,EAAE;IAqCnC,SAAS,CAAC,QAAQ,IAAI,MAAM;IAK5B,iEAAiE;IACjE,OAAO,CAAC,kBAAkB;CAqC3B"}