@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,224 @@
1
+ import { Node, } from 'ts-morph';
2
+ import { createViolation, getElementName } from '../core/violation.js';
3
+ import { elementCondition } from './helpers.js';
4
+ /**
5
+ * Extract property symbols from a property-bearing node.
6
+ * Resolves through the type system (handles Partial<>, Pick<>, etc.).
7
+ */
8
+ function getPropertySymbols(node) {
9
+ return node.getType().getProperties();
10
+ }
11
+ /**
12
+ * Check if a property symbol is readonly.
13
+ *
14
+ * Strategy:
15
+ * 1. Check direct declarations — works for explicit `readonly` on
16
+ * interface properties and class properties.
17
+ * 2. For mapped types like Readonly<T>, declarations point to the
18
+ * source type where isReadonly() returns false. Fall back to the
19
+ * TypeScript compiler's internal CheckFlags.Readonly (bit 3 = 8)
20
+ * on the symbol's links.
21
+ *
22
+ * Spike test confirmed: for Readonly<T>, Symbol.getDeclarations()
23
+ * returns the inner type's declarations (not readonly), but
24
+ * compilerSymbol.links.checkFlags has the Readonly bit set (8).
25
+ */
26
+ function isPropertyReadonly(prop) {
27
+ // Strategy 1: Check direct declarations for explicit `readonly` keyword.
28
+ // Works for interface properties and class properties that are directly
29
+ // declared with the readonly modifier.
30
+ const decls = prop.getDeclarations();
31
+ for (const d of decls) {
32
+ if (Node.isPropertySignature(d) || Node.isPropertyDeclaration(d)) {
33
+ if (d.isReadonly())
34
+ return true;
35
+ }
36
+ }
37
+ // Strategy 2: Check TS compiler's CheckFlags.Readonly (bit 3 = 8).
38
+ // For mapped types like Readonly<T>, Symbol.getDeclarations() returns
39
+ // the *original* type's declarations where isReadonly() is false,
40
+ // but the compiler tracks the readonly modifier on the symbol itself.
41
+ //
42
+ // Spike results (ts-morph 27 / TS ~5.9):
43
+ // Readonly<{a: string}>.a → decl.isReadonly() = false, but
44
+ // compilerSymbol.links.checkFlags & 8 = 8 (readonly)
45
+ //
46
+ // eess-exclude eess/adr005-no-type-assertions: reaches TS compiler-internal Symbol.links (not on the public ts.Symbol type) to read CheckFlags for mapped-type readonly detection
47
+ const links = prop.compilerSymbol.links;
48
+ if (typeof links === 'object' && links !== null && 'checkFlags' in links) {
49
+ const flags = links.checkFlags;
50
+ if (typeof flags === 'number' && (flags & 8) !== 0) {
51
+ return true;
52
+ }
53
+ }
54
+ // Conservative: treat as mutable if neither strategy detected readonly.
55
+ return false;
56
+ }
57
+ /**
58
+ * Assert that all named properties exist on the element.
59
+ * Every name must be present — violation per missing name.
60
+ *
61
+ * @param names At least one property name required. Throws if called with zero arguments.
62
+ *
63
+ * @example
64
+ * types(p).that().haveNameMatching(/Config$/)
65
+ * .should().havePropertyNamed('version', 'name')
66
+ * .check()
67
+ */
68
+ export function havePropertyNamed(...names) {
69
+ if (names.length === 0) {
70
+ throw new Error('havePropertyNamed() requires at least one property name');
71
+ }
72
+ const quotedNames = names.map((n) => `"${n}"`).join(', ');
73
+ return {
74
+ description: `have properties named ${quotedNames}`,
75
+ evaluate(elements, context) {
76
+ const violations = [];
77
+ for (const element of elements) {
78
+ const props = getPropertySymbols(element);
79
+ const propNames = new Set(props.map((p) => p.getName()));
80
+ for (const name of names) {
81
+ if (!propNames.has(name)) {
82
+ violations.push(createViolation(element, `${getElementName(element)} is missing required property "${name}"`, context));
83
+ }
84
+ }
85
+ }
86
+ return violations;
87
+ },
88
+ };
89
+ }
90
+ /**
91
+ * Assert that none of the named properties exist on the element.
92
+ * Violation per element per forbidden name found.
93
+ *
94
+ * @param names At least one property name required. Throws if called with zero arguments.
95
+ *
96
+ * @example
97
+ * types(p).that().resideInFolder('src/api')
98
+ * .should().notHavePropertyNamed('offset', 'pageSize', 'page', 'size')
99
+ * .because('use skip/limit for pagination')
100
+ * .check()
101
+ */
102
+ export function notHavePropertyNamed(...names) {
103
+ if (names.length === 0) {
104
+ throw new Error('notHavePropertyNamed() requires at least one property name');
105
+ }
106
+ const nameSet = new Set(names);
107
+ const quotedNames = names.map((n) => `"${n}"`).join(', ');
108
+ return {
109
+ description: `not have properties named ${quotedNames}`,
110
+ evaluate(elements, context) {
111
+ const violations = [];
112
+ for (const element of elements) {
113
+ const props = getPropertySymbols(element);
114
+ for (const prop of props) {
115
+ if (nameSet.has(prop.getName())) {
116
+ violations.push(createViolation(element, `${getElementName(element)} has forbidden property "${prop.getName()}"`, context));
117
+ }
118
+ }
119
+ }
120
+ return violations;
121
+ },
122
+ };
123
+ }
124
+ /**
125
+ * Assert at least one property name matches the regex.
126
+ * Semantics: EXISTS — violation if *no* property name matches.
127
+ *
128
+ * Note: this checks for existence of at least one match, unlike
129
+ * `havePropertyNamed(...names)` which requires ALL names to exist.
130
+ *
131
+ * @example
132
+ * types(p).that().haveNameMatching(/Entity$/)
133
+ * .should().havePropertyMatching(/^id$/)
134
+ * .check()
135
+ */
136
+ export function havePropertyMatching(pattern) {
137
+ return elementCondition(`have a property matching ${String(pattern)}`, (element) => {
138
+ // Clone regex to avoid /g flag statefulness across calls
139
+ const re = new RegExp(pattern.source, pattern.flags);
140
+ const props = getPropertySymbols(element);
141
+ return props.some((p) => re.test(p.getName()));
142
+ }, (element) => `${getElementName(element)} has no property matching ${String(pattern)}`);
143
+ }
144
+ /**
145
+ * Assert no property name matches the regex.
146
+ * Violation per matching property found.
147
+ *
148
+ * @example
149
+ * types(p).should().notHavePropertyMatching(/^(data|info|stuff|item)$/).check()
150
+ */
151
+ export function notHavePropertyMatching(pattern) {
152
+ return {
153
+ description: `not have properties matching ${String(pattern)}`,
154
+ evaluate(elements, context) {
155
+ const violations = [];
156
+ for (const element of elements) {
157
+ // Clone regex to avoid /g flag statefulness across elements
158
+ const re = new RegExp(pattern.source, pattern.flags);
159
+ const props = getPropertySymbols(element);
160
+ for (const prop of props) {
161
+ if (re.test(prop.getName())) {
162
+ violations.push(createViolation(element, `${getElementName(element)} has property "${prop.getName()}" matching ${String(pattern)}`, context));
163
+ }
164
+ }
165
+ }
166
+ return violations;
167
+ },
168
+ };
169
+ }
170
+ /**
171
+ * Assert all properties are readonly.
172
+ *
173
+ * Checks direct declarations for explicit `readonly` keyword, and
174
+ * falls back to TypeScript compiler's CheckFlags for mapped types
175
+ * like Readonly<T>.
176
+ *
177
+ * @example
178
+ * types(p).that().resideInFolder('src/state')
179
+ * .should().haveOnlyReadonlyProperties()
180
+ * .because('state objects must be immutable')
181
+ * .check()
182
+ */
183
+ export function haveOnlyReadonlyProperties() {
184
+ return {
185
+ description: 'have only readonly properties',
186
+ evaluate(elements, context) {
187
+ const violations = [];
188
+ for (const element of elements) {
189
+ const props = getPropertySymbols(element);
190
+ for (const prop of props) {
191
+ if (!isPropertyReadonly(prop)) {
192
+ violations.push(createViolation(element, `${getElementName(element)} has mutable property "${prop.getName()}"`, context));
193
+ }
194
+ }
195
+ }
196
+ return violations;
197
+ },
198
+ };
199
+ }
200
+ /**
201
+ * Assert property count does not exceed the maximum.
202
+ * Detects god objects / oversized DTOs.
203
+ *
204
+ * @example
205
+ * types(p).should().maxProperties(15)
206
+ * .because('large interfaces indicate a missing abstraction')
207
+ * .check()
208
+ */
209
+ export function maxProperties(max) {
210
+ return {
211
+ description: `have at most ${String(max)} properties`,
212
+ evaluate(elements, context) {
213
+ const violations = [];
214
+ for (const element of elements) {
215
+ const count = getPropertySymbols(element).length;
216
+ if (count > max) {
217
+ violations.push(createViolation(element, `${getElementName(element)} has ${String(count)} properties, max allowed is ${String(max)}`, context));
218
+ }
219
+ }
220
+ return violations;
221
+ },
222
+ };
223
+ }
224
+ //# sourceMappingURL=members.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"members.js","sourceRoot":"","sources":["../../src/conditions/members.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { Condition } from '@nielspeter/eess';
2
+ import type { ArchPattern } from '../helpers/pattern.js';
3
+ import type { ArchFunction } from '../models/arch-function.js';
4
+ /**
5
+ * Condition: functions must return a type matching the pattern's returnShape.
6
+ *
7
+ * For each property in `pattern.returnShape`:
8
+ * 1. The return type must have a property with that name.
9
+ * 2. The property's type must satisfy the constraint.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * functions(p)
14
+ * .that().resideInFolder('src/routes/**')
15
+ * .should().followPattern(paginatedCollection)
16
+ * .check()
17
+ * ```
18
+ */
19
+ export declare function followPattern(pattern: ArchPattern): Condition<ArchFunction>;
20
+ //# sourceMappingURL=pattern.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pattern.d.ts","sourceRoot":"","sources":["../../src/conditions/pattern.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,kBAAkB,CAAA;AAEnE,OAAO,KAAK,EAAE,WAAW,EAAsB,MAAM,uBAAuB,CAAA;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAG9D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,CAAC,YAAY,CAAC,CA6B3E"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Condition: functions must return a type matching the pattern's returnShape.
3
+ *
4
+ * For each property in `pattern.returnShape`:
5
+ * 1. The return type must have a property with that name.
6
+ * 2. The property's type must satisfy the constraint.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * functions(p)
11
+ * .that().resideInFolder('src/routes/**')
12
+ * .should().followPattern(paginatedCollection)
13
+ * .check()
14
+ * ```
15
+ */
16
+ export function followPattern(pattern) {
17
+ return {
18
+ description: `follow pattern "${pattern.name}"`,
19
+ evaluate(elements, context) {
20
+ const violations = [];
21
+ for (const fn of elements) {
22
+ const returnType = fn.getReturnType();
23
+ // Unwrap Promise<T> to inspect the resolved type
24
+ const resolvedType = unwrapPromise(returnType);
25
+ const missing = getMissingProperties(resolvedType, pattern);
26
+ if (missing.length > 0) {
27
+ const fnName = fn.getName() ?? '<anonymous>';
28
+ const node = fn.getNode();
29
+ violations.push({
30
+ rule: context.rule,
31
+ element: fnName,
32
+ file: node.getSourceFile().getFilePath(),
33
+ line: fn.getStartLineNumber(),
34
+ message: `"${fnName}" does not follow pattern "${pattern.name}": ${missing.join('; ')}`,
35
+ because: context.because,
36
+ });
37
+ }
38
+ }
39
+ return violations;
40
+ },
41
+ };
42
+ }
43
+ /**
44
+ * Unwrap Promise<T> -> T so async functions can be checked against
45
+ * the same pattern as sync ones.
46
+ */
47
+ function unwrapPromise(type) {
48
+ const typeText = type.getText();
49
+ if (typeText.startsWith('Promise<')) {
50
+ const typeArgs = type.getTypeArguments();
51
+ if (typeArgs.length === 1 && typeArgs[0] !== undefined) {
52
+ return typeArgs[0];
53
+ }
54
+ }
55
+ return type;
56
+ }
57
+ /**
58
+ * Check each property constraint in the pattern against the resolved type.
59
+ * Returns human-readable descriptions of missing/mismatched properties.
60
+ */
61
+ function getMissingProperties(type, pattern) {
62
+ const problems = [];
63
+ for (const [propName, constraint] of Object.entries(pattern.returnShape)) {
64
+ const prop = type.getProperty(propName);
65
+ if (prop === undefined) {
66
+ problems.push(`missing property "${propName}"`);
67
+ continue;
68
+ }
69
+ // Get a declaration node for resolving property type.
70
+ // Try the type's own symbol declarations first, then fall back to the property's declarations.
71
+ const typeDeclarations = type.getSymbol()?.getDeclarations();
72
+ const propDeclarations = prop.getDeclarations();
73
+ const declarationNode = (typeDeclarations !== undefined && typeDeclarations.length > 0
74
+ ? typeDeclarations[0]
75
+ : undefined) ?? (propDeclarations.length > 0 ? propDeclarations[0] : undefined);
76
+ if (declarationNode === undefined) {
77
+ problems.push(`property "${propName}" has no resolvable declaration`);
78
+ continue;
79
+ }
80
+ const propType = prop.getTypeAtLocation(declarationNode);
81
+ if (!matchesConstraint(propType, constraint)) {
82
+ const actual = propType.getNonNullableType().getText();
83
+ const expected = typeof constraint === 'string' ? constraint : '<custom matcher>';
84
+ problems.push(`property "${propName}" has type '${actual}', expected '${expected}'`);
85
+ }
86
+ }
87
+ return problems;
88
+ }
89
+ /**
90
+ * Test whether a resolved property type satisfies a PropertyConstraint.
91
+ */
92
+ function matchesConstraint(propType, constraint) {
93
+ const stripped = propType.getNonNullableType();
94
+ if (typeof constraint === 'function') {
95
+ // TypeMatcher — delegate directly
96
+ return constraint(propType);
97
+ }
98
+ // String constraint
99
+ if (constraint === 'T[]') {
100
+ // Special: any array type
101
+ return stripped.isArray();
102
+ }
103
+ // Match constraint as literal string against type text
104
+ const escaped = constraint.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
105
+ const regex = new RegExp(`^${escaped}$`);
106
+ return regex.test(stripped.getText());
107
+ }
108
+ //# sourceMappingURL=pattern.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pattern.js","sourceRoot":"","sources":["../../src/conditions/pattern.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { type SourceFile } from 'ts-morph';
2
+ import type { Condition } from '@nielspeter/eess';
3
+ /**
4
+ * Every file that imports this module must match at least one of the globs.
5
+ *
6
+ * Enforces barrel/facade patterns: internal modules should only be
7
+ * imported through their public API (e.g., index.ts).
8
+ *
9
+ * Modules with zero importers pass vacuously. Chain `.andShould().beImported()`
10
+ * if you also want to catch orphaned files.
11
+ *
12
+ * Both static `import` declarations and dynamic `import()` expressions with
13
+ * string-literal specifiers are resolved. `require()` calls are not resolved.
14
+ */
15
+ export declare function onlyBeImportedVia(...globs: string[]): Condition<SourceFile>;
16
+ /**
17
+ * Module must be imported by at least one other file in the project.
18
+ *
19
+ * Detects dead/orphaned modules that nobody references.
20
+ * Use `.excluding('index.ts', 'main.ts')` to skip entry points.
21
+ *
22
+ * Both static `import` declarations and dynamic `import()` expressions with
23
+ * string-literal specifiers are resolved. Modules loaded via `require()` or
24
+ * dynamic imports with computed specifiers will still be falsely reported.
25
+ */
26
+ export declare function beImported(): Condition<SourceFile>;
27
+ export declare function haveNoUnusedExports(): Condition<SourceFile>;
28
+ //# sourceMappingURL=reverse-dependency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reverse-dependency.d.ts","sourceRoot":"","sources":["../../src/conditions/reverse-dependency.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAkC,MAAM,UAAU,CAAA;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,kBAAkB,CAAA;AAwInE;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,UAAU,CAAC,CAgC3E;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,IAAI,SAAS,CAAC,UAAU,CAAC,CA0BlD;AA0CD,wBAAgB,mBAAmB,IAAI,SAAS,CAAC,UAAU,CAAC,CAW3D"}