@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,130 @@
1
+ import { Node } from 'ts-morph';
2
+ import { generateCodeFrame } from '@nielspeter/eess';
3
+ /**
4
+ * Check if a node is a named declaration and return its name, or undefined.
5
+ * Constructors return "constructor" since they have no getName().
6
+ */
7
+ function getNodeName(node) {
8
+ if (Node.isConstructorDeclaration(node))
9
+ return 'constructor';
10
+ if (Node.isClassDeclaration(node) ||
11
+ Node.isFunctionDeclaration(node) ||
12
+ Node.isInterfaceDeclaration(node) ||
13
+ Node.isTypeAliasDeclaration(node) ||
14
+ Node.isEnumDeclaration(node) ||
15
+ Node.isMethodDeclaration(node) ||
16
+ Node.isGetAccessorDeclaration(node) ||
17
+ Node.isSetAccessorDeclaration(node) ||
18
+ Node.isPropertyDeclaration(node) ||
19
+ Node.isVariableDeclaration(node)) {
20
+ return node.getName();
21
+ }
22
+ return undefined;
23
+ }
24
+ /**
25
+ * Check if a node is a structural member that should appear in
26
+ * qualified element names (e.g., "ClassName.methodName").
27
+ * Returns the member name, or undefined to skip.
28
+ */
29
+ function getStructuralName(node) {
30
+ if (Node.isConstructorDeclaration(node))
31
+ return 'constructor';
32
+ if (Node.isMethodDeclaration(node) ||
33
+ Node.isGetAccessorDeclaration(node) ||
34
+ Node.isSetAccessorDeclaration(node) ||
35
+ Node.isPropertyDeclaration(node)) {
36
+ return node.getName();
37
+ }
38
+ // Arrow/function expressions: check if assigned to a named variable
39
+ if (Node.isArrowFunction(node) || Node.isFunctionExpression(node)) {
40
+ const parent = node.getParent();
41
+ if (parent && Node.isVariableDeclaration(parent)) {
42
+ return parent.getName();
43
+ }
44
+ }
45
+ return undefined;
46
+ }
47
+ /**
48
+ * Check if a node is a top-level architectural boundary where
49
+ * the ancestor walk should stop.
50
+ */
51
+ function isTopLevelDeclaration(node) {
52
+ return (Node.isClassDeclaration(node) ||
53
+ Node.isInterfaceDeclaration(node) ||
54
+ Node.isTypeAliasDeclaration(node) ||
55
+ Node.isEnumDeclaration(node) ||
56
+ Node.isFunctionDeclaration(node));
57
+ }
58
+ /**
59
+ * Extract a human-readable name from a ts-morph Node.
60
+ *
61
+ * If the node itself is a named declaration (class, function, method, etc.),
62
+ * returns its name directly. Otherwise, walks up the AST ancestors to find
63
+ * the nearest named declaration and builds a qualified name like
64
+ * "ClassName.methodName". This ensures that inner nodes (e.g., AsExpression,
65
+ * CallExpression) produce meaningful element names for `.excluding()` matching.
66
+ *
67
+ * Falls back to the node's kind name only if no named ancestor is found
68
+ * (e.g., top-level expressions in a module).
69
+ */
70
+ export function getElementName(node) {
71
+ const directName = getNodeName(node);
72
+ if (directName !== undefined)
73
+ return directName;
74
+ // Walk up ancestors collecting structural names: method/constructor/accessor
75
+ // at the member level, class/function at the top level. Skips variables,
76
+ // properties, and expressions — those are implementation detail.
77
+ const parts = [];
78
+ let current = node.getParent();
79
+ while (current) {
80
+ // Top-level declarations: collect name and stop
81
+ if (isTopLevelDeclaration(current)) {
82
+ const name = getNodeName(current);
83
+ if (name !== undefined)
84
+ parts.unshift(name);
85
+ break;
86
+ }
87
+ // Structural members: collect name and keep walking to find the parent class
88
+ const memberName = getStructuralName(current);
89
+ if (memberName !== undefined) {
90
+ parts.unshift(memberName);
91
+ }
92
+ current = current.getParent();
93
+ }
94
+ return parts.length > 0 ? parts.join('.') : node.getKindName();
95
+ }
96
+ /**
97
+ * Get the absolute file path for a ts-morph Node.
98
+ */
99
+ export function getElementFile(node) {
100
+ return node.getSourceFile().getFilePath();
101
+ }
102
+ /**
103
+ * Get the start line number for a ts-morph Node.
104
+ */
105
+ export function getElementLine(node) {
106
+ return node.getStartLineNumber();
107
+ }
108
+ /**
109
+ * Create an ArchViolation from a ts-morph Node and context.
110
+ *
111
+ * Convenience function used by all condition implementations to produce
112
+ * consistent violation objects.
113
+ */
114
+ export function createViolation(node, message, context) {
115
+ const line = getElementLine(node);
116
+ const sourceText = node.getSourceFile().getFullText();
117
+ return {
118
+ rule: context.rule,
119
+ ruleId: context.ruleId,
120
+ element: getElementName(node),
121
+ file: getElementFile(node),
122
+ line,
123
+ message,
124
+ because: context.because,
125
+ suggestion: context.suggestion,
126
+ docs: context.docs,
127
+ codeFrame: generateCodeFrame(sourceText, line),
128
+ };
129
+ }
130
+ //# sourceMappingURL=violation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"violation.js","sourceRoot":"","sources":["../../src/core/violation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * GraphQL extension for eess-ts.
3
+ *
4
+ * Sub-path export: `import { schema, resolvers } from '@nielspeter/eess-ts/graphql'`
5
+ *
6
+ * Requires the `graphql` npm package as an optional peer dependency.
7
+ * Schema loading will throw a clear error if graphql is not installed.
8
+ */
9
+ import type { ArchProject } from '../core/project.js';
10
+ import { SchemaRuleBuilder } from './schema-rule-builder.js';
11
+ import { ResolverRuleBuilder } from './resolver-rule-builder.js';
12
+ /**
13
+ * Create a schema rule builder scoped to .graphql files matching the glob.
14
+ *
15
+ * @param projectOrRoot - ArchProject (uses tsconfig root) or a directory path
16
+ * @param glob - Glob pattern for .graphql files (e.g. 'schema/*.graphql')
17
+ * @returns A SchemaRuleBuilder for defining schema architecture rules
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * import { project } from '@nielspeter/eess-ts'
22
+ * import { schema } from '@nielspeter/eess-ts/graphql'
23
+ *
24
+ * const p = project('tsconfig.json')
25
+ * schema(p, 'src/schema/*.graphql')
26
+ * .typesNamed(/Collection$/)
27
+ * .should()
28
+ * .haveFields('total', 'skip', 'limit', 'items')
29
+ * .check()
30
+ * ```
31
+ */
32
+ export declare function schema(projectOrRoot: ArchProject | string, glob: string): SchemaRuleBuilder;
33
+ /**
34
+ * Create a schema rule builder from a raw SDL string.
35
+ *
36
+ * @param sdl - GraphQL Schema Definition Language string
37
+ * @param sourcePath - Optional file path for error reporting
38
+ * @returns A SchemaRuleBuilder
39
+ */
40
+ export declare function schemaFromSDL(sdl: string, sourcePath?: string): SchemaRuleBuilder;
41
+ /**
42
+ * Create a resolver rule builder scoped to TypeScript files matching the glob.
43
+ *
44
+ * Resolver files are regular TypeScript — analyzed via ts-morph, not the graphql package.
45
+ * Conditions like contain(call('loader.load')) reuse the body analysis engine.
46
+ *
47
+ * @param p - The loaded ArchProject
48
+ * @param glob - Glob pattern for resolver files (e.g. 'src/resolvers/**')
49
+ * @returns A ResolverRuleBuilder
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * import { project } from '@nielspeter/eess-ts'
54
+ * import { resolvers } from '@nielspeter/eess-ts/graphql'
55
+ * import { call } from '@nielspeter/eess-ts'
56
+ *
57
+ * const p = project('tsconfig.json')
58
+ * resolvers(p, 'src/resolvers/**')
59
+ * .that()
60
+ * .resolveFieldReturning(/^[A-Z]/)
61
+ * .should()
62
+ * .contain(call('loader.load'))
63
+ * .because('prevent N+1 queries')
64
+ * .check()
65
+ * ```
66
+ */
67
+ export declare function resolvers(p: ArchProject, glob: string): ResolverRuleBuilder;
68
+ export { SchemaRuleBuilder } from './schema-rule-builder.js';
69
+ export { ResolverRuleBuilder } from './resolver-rule-builder.js';
70
+ export { resolveFieldReturning } from './resolver-rule-builder.js';
71
+ export { queries, mutations, typesNamed, returnListOf } from './schema-predicates.js';
72
+ export type { SchemaElement } from './schema-predicates.js';
73
+ export { haveFields, acceptArgs, haveMatchingResolver } from './schema-conditions.js';
74
+ export { loadSchemaFromGlob, loadSchemaFromSDL, isGraphQLAvailable } from './schema-loader.js';
75
+ export type { LoadedSchema, GraphQLSchemaLike, GraphQLObjectTypeLike, GraphQLFieldLike, GraphQLArgumentLike, GraphQLTypeLike, } from './schema-loader.js';
76
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/graphql/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAErD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAIhE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,MAAM,CAAC,aAAa,EAAE,WAAW,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAK3F;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAGjF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,mBAAmB,CAM3E;AAID,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAGlE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACrF,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAG3D,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAGrF,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAC9F,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,EACrB,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,GAChB,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * GraphQL extension for eess-ts.
3
+ *
4
+ * Sub-path export: `import { schema, resolvers } from '@nielspeter/eess-ts/graphql'`
5
+ *
6
+ * Requires the `graphql` npm package as an optional peer dependency.
7
+ * Schema loading will throw a clear error if graphql is not installed.
8
+ */
9
+ import { loadSchemaFromGlob, loadSchemaFromSDL } from './schema-loader.js';
10
+ import { SchemaRuleBuilder } from './schema-rule-builder.js';
11
+ import { ResolverRuleBuilder } from './resolver-rule-builder.js';
12
+ // --- Entry points ---
13
+ /**
14
+ * Create a schema rule builder scoped to .graphql files matching the glob.
15
+ *
16
+ * @param projectOrRoot - ArchProject (uses tsconfig root) or a directory path
17
+ * @param glob - Glob pattern for .graphql files (e.g. 'schema/*.graphql')
18
+ * @returns A SchemaRuleBuilder for defining schema architecture rules
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * import { project } from '@nielspeter/eess-ts'
23
+ * import { schema } from '@nielspeter/eess-ts/graphql'
24
+ *
25
+ * const p = project('tsconfig.json')
26
+ * schema(p, 'src/schema/*.graphql')
27
+ * .typesNamed(/Collection$/)
28
+ * .should()
29
+ * .haveFields('total', 'skip', 'limit', 'items')
30
+ * .check()
31
+ * ```
32
+ */
33
+ export function schema(projectOrRoot, glob) {
34
+ const rootDir = typeof projectOrRoot === 'string' ? projectOrRoot : extractRootDir(projectOrRoot.tsConfigPath);
35
+ const loaded = loadSchemaFromGlob(rootDir, glob);
36
+ return new SchemaRuleBuilder(loaded);
37
+ }
38
+ /**
39
+ * Create a schema rule builder from a raw SDL string.
40
+ *
41
+ * @param sdl - GraphQL Schema Definition Language string
42
+ * @param sourcePath - Optional file path for error reporting
43
+ * @returns A SchemaRuleBuilder
44
+ */
45
+ export function schemaFromSDL(sdl, sourcePath) {
46
+ const loaded = loadSchemaFromSDL(sdl, sourcePath);
47
+ return new SchemaRuleBuilder(loaded);
48
+ }
49
+ /**
50
+ * Create a resolver rule builder scoped to TypeScript files matching the glob.
51
+ *
52
+ * Resolver files are regular TypeScript — analyzed via ts-morph, not the graphql package.
53
+ * Conditions like contain(call('loader.load')) reuse the body analysis engine.
54
+ *
55
+ * @param p - The loaded ArchProject
56
+ * @param glob - Glob pattern for resolver files (e.g. 'src/resolvers/**')
57
+ * @returns A ResolverRuleBuilder
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * import { project } from '@nielspeter/eess-ts'
62
+ * import { resolvers } from '@nielspeter/eess-ts/graphql'
63
+ * import { call } from '@nielspeter/eess-ts'
64
+ *
65
+ * const p = project('tsconfig.json')
66
+ * resolvers(p, 'src/resolvers/**')
67
+ * .that()
68
+ * .resolveFieldReturning(/^[A-Z]/)
69
+ * .should()
70
+ * .contain(call('loader.load'))
71
+ * .because('prevent N+1 queries')
72
+ * .check()
73
+ * ```
74
+ */
75
+ export function resolvers(p, glob) {
76
+ const sourceFiles = p.getSourceFiles().filter((sf) => {
77
+ const filePath = sf.getFilePath();
78
+ return picomatchFilter(filePath, glob, extractRootDir(p.tsConfigPath));
79
+ });
80
+ return new ResolverRuleBuilder(sourceFiles);
81
+ }
82
+ // --- Re-exports ---
83
+ export { SchemaRuleBuilder } from './schema-rule-builder.js';
84
+ export { ResolverRuleBuilder } from './resolver-rule-builder.js';
85
+ export { resolveFieldReturning } from './resolver-rule-builder.js';
86
+ // Schema predicates (standalone)
87
+ export { queries, mutations, typesNamed, returnListOf } from './schema-predicates.js';
88
+ // Schema conditions (standalone)
89
+ export { haveFields, acceptArgs, haveMatchingResolver } from './schema-conditions.js';
90
+ // Schema loader utilities
91
+ export { loadSchemaFromGlob, loadSchemaFromSDL, isGraphQLAvailable } from './schema-loader.js';
92
+ // --- Internal helpers ---
93
+ import path from 'node:path';
94
+ import picomatch from 'picomatch';
95
+ function extractRootDir(tsConfigPath) {
96
+ return path.dirname(tsConfigPath);
97
+ }
98
+ const matcherCache = new Map();
99
+ function picomatchFilter(filePath, glob, rootDir) {
100
+ const relativePath = path.relative(rootDir, filePath);
101
+ let matcher = matcherCache.get(glob);
102
+ if (!matcher) {
103
+ matcher = picomatch(glob);
104
+ matcherCache.set(glob, matcher);
105
+ }
106
+ return matcher(relativePath);
107
+ }
108
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/graphql/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAEhE,uBAAuB;AAEvB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,MAAM,CAAC,aAAmC,EAAE,IAAY;IACtE,MAAM,OAAO,GACX,OAAO,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,cAAc,CAAC,aAAa,CAAC,YAAY,CAAC,CAAA;IAChG,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IAChD,OAAO,IAAI,iBAAiB,CAAC,MAAM,CAAC,CAAA;AACtC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,UAAmB;IAC5D,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,EAAE,UAAU,CAAC,CAAA;IACjD,OAAO,IAAI,iBAAiB,CAAC,MAAM,CAAC,CAAA;AACtC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,SAAS,CAAC,CAAc,EAAE,IAAY;IACpD,MAAM,WAAW,GAAG,CAAC,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE;QACnD,MAAM,QAAQ,GAAG,EAAE,CAAC,WAAW,EAAE,CAAA;QACjC,OAAO,eAAe,CAAC,QAAQ,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAA;IACxE,CAAC,CAAC,CAAA;IACF,OAAO,IAAI,mBAAmB,CAAC,WAAW,CAAC,CAAA;AAC7C,CAAC;AAED,qBAAqB;AAErB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAElE,iCAAiC;AACjC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAGrF,iCAAiC;AACjC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAErF,0BAA0B;AAC1B,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAU9F,2BAA2B;AAE3B,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,SAAS,MAAM,WAAW,CAAA;AAEjC,SAAS,cAAc,CAAC,YAAoB;IAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;AACnC,CAAC;AAED,MAAM,YAAY,GAAG,IAAI,GAAG,EAA6B,CAAA;AAEzD,SAAS,eAAe,CAAC,QAAgB,EAAE,IAAY,EAAE,OAAe;IACtE,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;IACrD,IAAI,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACpC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;QACzB,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IACjC,CAAC;IACD,OAAO,OAAO,CAAC,YAAY,CAAC,CAAA;AAC9B,CAAC"}
@@ -0,0 +1,75 @@
1
+ import type { SourceFile } from 'ts-morph';
2
+ import type { ArchViolation } from '../core/violation.js';
3
+ import type { Predicate } from '@nielspeter/eess';
4
+ import { TerminalBuilder } from '@nielspeter/eess';
5
+ import type { ExpressionMatcher } from '../helpers/matchers.js';
6
+ import type { ArchFunction } from '../models/arch-function.js';
7
+ /**
8
+ * Predicate: filter to resolver functions for fields returning types matching the pattern.
9
+ *
10
+ * Heuristic: a resolver function is one whose name starts with an uppercase letter
11
+ * (type name) or matches common resolver naming conventions. The return type is
12
+ * checked against the pattern.
13
+ *
14
+ * @param pattern - Regex or string to match against the resolved return type text
15
+ */
16
+ export declare function resolveFieldReturning(pattern: RegExp | string): Predicate<ArchFunction>;
17
+ /**
18
+ * Fluent rule builder for GraphQL resolver architecture rules.
19
+ *
20
+ * Operates on TypeScript resolver files analyzed through the ArchFunction model.
21
+ * Reuses the body analysis engine from plan 0011 for conditions like contain/notContain.
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * resolvers(p, 'src/resolvers/**')
26
+ * .that()
27
+ * .resolveFieldReturning(/^[A-Z]/)
28
+ * .should()
29
+ * .contain(call('loader.load'))
30
+ * .because('prevent N+1 queries')
31
+ * .check()
32
+ * ```
33
+ */
34
+ export declare class ResolverRuleBuilder extends TerminalBuilder {
35
+ private readonly sourceFiles;
36
+ private readonly _predicates;
37
+ private readonly _conditions;
38
+ constructor(sourceFiles: SourceFile[]);
39
+ /**
40
+ * Filter to resolver functions for fields returning types matching the pattern.
41
+ */
42
+ resolveFieldReturning(pattern: RegExp | string): this;
43
+ /**
44
+ * Begin the predicate phase. Purely a readability marker.
45
+ */
46
+ that(): this;
47
+ /**
48
+ * Add another predicate (AND).
49
+ */
50
+ and(): this;
51
+ /**
52
+ * Begin the condition phase.
53
+ */
54
+ should(): this;
55
+ /**
56
+ * Add another condition (AND).
57
+ */
58
+ andShould(): this;
59
+ /**
60
+ * Assert that the resolver body contains at least one match.
61
+ */
62
+ contain(matcher: ExpressionMatcher): this;
63
+ /**
64
+ * Assert that the resolver body does NOT contain any match.
65
+ */
66
+ notContain(matcher: ExpressionMatcher): this;
67
+ /**
68
+ * Assert: must NOT contain 'bad' AND must contain 'good'.
69
+ */
70
+ useInsteadOf(bad: ExpressionMatcher, good: ExpressionMatcher): this;
71
+ protected collectViolations(): ArchViolation[];
72
+ private getElements;
73
+ private buildRuleDescription;
74
+ }
75
+ //# sourceMappingURL=resolver-rule-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver-rule-builder.d.ts","sourceRoot":"","sources":["../../src/graphql/resolver-rule-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAQ9D;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,YAAY,CAAC,CAYvF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,mBAAoB,SAAQ,eAAe;IAI1C,OAAO,CAAC,QAAQ,CAAC,WAAW;IAHxC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgC;IAC5D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgC;gBAE/B,WAAW,EAAE,UAAU,EAAE;IAMtD;;OAEG;IACH,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAOrD;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;OAEG;IACH,GAAG,IAAI,IAAI;IAIX;;OAEG;IACH,MAAM,IAAI,IAAI;IAId;;OAEG;IACH,SAAS,IAAI,IAAI;IAMjB;;OAEG;IACH,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAKzC;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAK5C;;OAEG;IACH,YAAY,CAAC,GAAG,EAAE,iBAAiB,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI;IAOnE,SAAS,CAAC,iBAAiB,IAAI,aAAa,EAAE;IAmC9C,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,oBAAoB;CAQ7B"}
@@ -0,0 +1,146 @@
1
+ import { TerminalBuilder } from '@nielspeter/eess';
2
+ import { collectFunctions } from '../models/arch-function.js';
3
+ import { functionContain, functionNotContain, functionUseInsteadOf, } from '../conditions/body-analysis-function.js';
4
+ /**
5
+ * Predicate: filter to resolver functions for fields returning types matching the pattern.
6
+ *
7
+ * Heuristic: a resolver function is one whose name starts with an uppercase letter
8
+ * (type name) or matches common resolver naming conventions. The return type is
9
+ * checked against the pattern.
10
+ *
11
+ * @param pattern - Regex or string to match against the resolved return type text
12
+ */
13
+ export function resolveFieldReturning(pattern) {
14
+ const desc = typeof pattern === 'string' ? `"${pattern}"` : String(pattern);
15
+ return {
16
+ description: `resolve field returning ${desc}`,
17
+ test(fn) {
18
+ const returnType = fn.getReturnType().getText();
19
+ if (typeof pattern === 'string') {
20
+ return returnType.includes(pattern);
21
+ }
22
+ return pattern.test(returnType);
23
+ },
24
+ };
25
+ }
26
+ /**
27
+ * Fluent rule builder for GraphQL resolver architecture rules.
28
+ *
29
+ * Operates on TypeScript resolver files analyzed through the ArchFunction model.
30
+ * Reuses the body analysis engine from plan 0011 for conditions like contain/notContain.
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * resolvers(p, 'src/resolvers/**')
35
+ * .that()
36
+ * .resolveFieldReturning(/^[A-Z]/)
37
+ * .should()
38
+ * .contain(call('loader.load'))
39
+ * .because('prevent N+1 queries')
40
+ * .check()
41
+ * ```
42
+ */
43
+ export class ResolverRuleBuilder extends TerminalBuilder {
44
+ sourceFiles;
45
+ _predicates = [];
46
+ _conditions = [];
47
+ constructor(sourceFiles) {
48
+ super();
49
+ this.sourceFiles = sourceFiles;
50
+ }
51
+ // --- Predicate methods ---
52
+ /**
53
+ * Filter to resolver functions for fields returning types matching the pattern.
54
+ */
55
+ resolveFieldReturning(pattern) {
56
+ this._predicates.push(resolveFieldReturning(pattern));
57
+ return this;
58
+ }
59
+ // --- Chain methods ---
60
+ /**
61
+ * Begin the predicate phase. Purely a readability marker.
62
+ */
63
+ that() {
64
+ return this;
65
+ }
66
+ /**
67
+ * Add another predicate (AND).
68
+ */
69
+ and() {
70
+ return this;
71
+ }
72
+ /**
73
+ * Begin the condition phase.
74
+ */
75
+ should() {
76
+ return this;
77
+ }
78
+ /**
79
+ * Add another condition (AND).
80
+ */
81
+ andShould() {
82
+ return this;
83
+ }
84
+ // --- Condition methods (reuse body analysis) ---
85
+ /**
86
+ * Assert that the resolver body contains at least one match.
87
+ */
88
+ contain(matcher) {
89
+ this._conditions.push(functionContain(matcher));
90
+ return this;
91
+ }
92
+ /**
93
+ * Assert that the resolver body does NOT contain any match.
94
+ */
95
+ notContain(matcher) {
96
+ this._conditions.push(functionNotContain(matcher));
97
+ return this;
98
+ }
99
+ /**
100
+ * Assert: must NOT contain 'bad' AND must contain 'good'.
101
+ */
102
+ useInsteadOf(bad, good) {
103
+ this._conditions.push(functionUseInsteadOf(bad, good));
104
+ return this;
105
+ }
106
+ // --- Evaluation ---
107
+ collectViolations() {
108
+ const allElements = this.getElements();
109
+ const filtered = allElements.filter((element) => this._predicates.every((predicate) => predicate.test(element)));
110
+ if (filtered.length === 0) {
111
+ return [];
112
+ }
113
+ if (this._conditions.length === 0) {
114
+ const ruleId = this._metadata?.id ?? 'unnamed';
115
+ console.warn(`[eess] Resolver rule '${ruleId}' has predicates but no conditions. ` +
116
+ `Did you forget to add a condition after .should()?`);
117
+ return [];
118
+ }
119
+ const context = {
120
+ rule: this.buildRuleDescription(),
121
+ because: this._reason,
122
+ ruleId: this._metadata?.id,
123
+ suggestion: this._metadata?.suggestion,
124
+ docs: this._metadata?.docs,
125
+ };
126
+ const violations = [];
127
+ for (const condition of this._conditions) {
128
+ violations.push(...condition.evaluate(filtered, context));
129
+ }
130
+ return violations;
131
+ }
132
+ getElements() {
133
+ return this.sourceFiles.flatMap((sf) => collectFunctions(sf));
134
+ }
135
+ buildRuleDescription() {
136
+ const predicateDesc = this._predicates.map((p) => p.description).join(' and ');
137
+ const conditionDesc = this._conditions.map((c) => c.description).join(' and ');
138
+ const parts = ['resolvers'];
139
+ if (predicateDesc)
140
+ parts.push(`that ${predicateDesc}`);
141
+ if (conditionDesc)
142
+ parts.push(`should ${conditionDesc}`);
143
+ return parts.join(' ');
144
+ }
145
+ }
146
+ //# sourceMappingURL=resolver-rule-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver-rule-builder.js","sourceRoot":"","sources":["../../src/graphql/resolver-rule-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { Condition } from '@nielspeter/eess';
2
+ import type { SchemaElement } from './schema-predicates.js';
3
+ /**
4
+ * Assert that a type has all listed fields.
5
+ *
6
+ * When applied to a type-level SchemaElement, checks that the object type
7
+ * defines all the named fields. When applied to a field-level element,
8
+ * checks the parent type.
9
+ *
10
+ * @param names - Field names that must exist on the type
11
+ */
12
+ export declare function haveFields(...names: string[]): Condition<SchemaElement>;
13
+ /**
14
+ * Assert that a field accepts all listed arguments.
15
+ *
16
+ * Only applies to field-level SchemaElements. Type-level elements are skipped.
17
+ *
18
+ * @param names - Argument names that must exist on the field
19
+ */
20
+ export declare function acceptArgs(...names: string[]): Condition<SchemaElement>;
21
+ /**
22
+ * Assert that each schema field has a matching resolver export.
23
+ *
24
+ * Cross-references schema fields with TypeScript resolver files.
25
+ * A field "users" on type "Query" is matched if any resolver file exports
26
+ * a function/variable named "users" or contains a property assignment "Query.users".
27
+ *
28
+ * @param resolverFileTexts - Map of file paths to their source text (for matching)
29
+ */
30
+ export declare function haveMatchingResolver(resolverFileTexts: ReadonlyMap<string, string>): Condition<SchemaElement>;
31
+ //# sourceMappingURL=schema-conditions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-conditions.d.ts","sourceRoot":"","sources":["../../src/graphql/schema-conditions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,kBAAkB,CAAA;AAEnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAE3D;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,aAAa,CAAC,CA2BvE;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,aAAa,CAAC,CA2BvE;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,iBAAiB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7C,SAAS,CAAC,aAAa,CAAC,CAqC1B"}