@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,188 @@
1
+ import { TerminalBuilder } from '@nielspeter/eess';
2
+ import { queries as queriesPredicate, mutations as mutationsPredicate, typesNamed as typesNamedPredicate, returnListOf as returnListOfPredicate, } from './schema-predicates.js';
3
+ import { haveFields as haveFieldsCondition, acceptArgs as acceptArgsCondition, haveMatchingResolver as haveMatchingResolverCondition, } from './schema-conditions.js';
4
+ /**
5
+ * Structural type guard: check if a GraphQL type has `getFields()`.
6
+ * Only GraphQLObjectType, GraphQLInterfaceType, and GraphQLInputObjectType have getFields.
7
+ * Scalars, enums, and unions do not.
8
+ */
9
+ function isObjectType(type) {
10
+ if (typeof type !== 'object' || type === null)
11
+ return false;
12
+ if (!('getFields' in type))
13
+ return false;
14
+ // At this point TypeScript knows type has 'getFields', verify it's a function
15
+ const candidate = type;
16
+ return typeof candidate.getFields === 'function';
17
+ }
18
+ /**
19
+ * Fluent rule builder for GraphQL schema architecture rules.
20
+ *
21
+ * Operates on SchemaElements extracted from .graphql files.
22
+ * Follows the same builder pattern as SliceRuleBuilder (standalone, not extending RuleBuilder).
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * schema(p, 'src/schema/*.graphql')
27
+ * .typesNamed(/Collection$/)
28
+ * .should()
29
+ * .haveFields('total', 'skip', 'limit', 'items')
30
+ * .check()
31
+ * ```
32
+ */
33
+ export class SchemaRuleBuilder extends TerminalBuilder {
34
+ loaded;
35
+ _predicates = [];
36
+ _conditions = [];
37
+ constructor(loaded) {
38
+ super();
39
+ this.loaded = loaded;
40
+ }
41
+ // --- Predicate methods ---
42
+ /**
43
+ * Filter to only Query root type fields.
44
+ */
45
+ queries() {
46
+ this._predicates.push(queriesPredicate());
47
+ return this;
48
+ }
49
+ /**
50
+ * Filter to only Mutation root type fields.
51
+ */
52
+ mutations() {
53
+ this._predicates.push(mutationsPredicate());
54
+ return this;
55
+ }
56
+ /**
57
+ * Filter to object types matching the given name pattern.
58
+ */
59
+ typesNamed(pattern) {
60
+ this._predicates.push(typesNamedPredicate(pattern));
61
+ return this;
62
+ }
63
+ /**
64
+ * Filter to fields returning a list of the given type.
65
+ */
66
+ returnListOf(typeName) {
67
+ this._predicates.push(returnListOfPredicate(typeName));
68
+ return this;
69
+ }
70
+ // --- Chain methods ---
71
+ /**
72
+ * Begin the predicate phase. Purely a readability marker.
73
+ */
74
+ that() {
75
+ return this;
76
+ }
77
+ /**
78
+ * Add another predicate (AND).
79
+ */
80
+ and() {
81
+ return this;
82
+ }
83
+ /**
84
+ * Begin the condition phase.
85
+ */
86
+ should() {
87
+ return this;
88
+ }
89
+ /**
90
+ * Add another condition (AND).
91
+ */
92
+ andShould() {
93
+ return this;
94
+ }
95
+ // --- Condition methods ---
96
+ /**
97
+ * Assert that types have all listed fields.
98
+ */
99
+ haveFields(...names) {
100
+ this._conditions.push(haveFieldsCondition(...names));
101
+ return this;
102
+ }
103
+ /**
104
+ * Assert that fields accept all listed arguments.
105
+ */
106
+ acceptArgs(...names) {
107
+ this._conditions.push(acceptArgsCondition(...names));
108
+ return this;
109
+ }
110
+ /**
111
+ * Assert that schema fields have matching resolver implementations.
112
+ *
113
+ * @param resolverFileTexts - Map of file paths to source text
114
+ */
115
+ haveMatchingResolver(resolverFileTexts) {
116
+ this._conditions.push(haveMatchingResolverCondition(resolverFileTexts));
117
+ return this;
118
+ }
119
+ // --- Evaluation ---
120
+ collectViolations() {
121
+ const allElements = this.getElements();
122
+ const filtered = allElements.filter((element) => this._predicates.every((predicate) => predicate.test(element)));
123
+ if (filtered.length === 0) {
124
+ return [];
125
+ }
126
+ if (this._conditions.length === 0) {
127
+ const ruleId = this._metadata?.id ?? 'unnamed';
128
+ console.warn(`[eess] Schema rule '${ruleId}' has predicates but no conditions. ` +
129
+ `Did you forget to add a condition after .should()?`);
130
+ return [];
131
+ }
132
+ const context = {
133
+ rule: this.buildRuleDescription(),
134
+ because: this._reason,
135
+ ruleId: this._metadata?.id,
136
+ suggestion: this._metadata?.suggestion,
137
+ docs: this._metadata?.docs,
138
+ };
139
+ const violations = [];
140
+ for (const condition of this._conditions) {
141
+ violations.push(...condition.evaluate(filtered, context));
142
+ }
143
+ return violations;
144
+ }
145
+ getElements() {
146
+ const elements = [];
147
+ const typeMap = this.loaded.schema.getTypeMap();
148
+ const firstFile = this.loaded.documents[0]?.filePath;
149
+ for (const [typeName, typeObj] of Object.entries(typeMap)) {
150
+ // Skip introspection types (start with __)
151
+ if (typeName.startsWith('__'))
152
+ continue;
153
+ // Skip scalar types that don't have getFields — use structural type guard
154
+ if (!isObjectType(typeObj))
155
+ continue;
156
+ const objectType = typeObj;
157
+ // Add type-level element
158
+ elements.push({
159
+ typeName,
160
+ objectType,
161
+ filePath: firstFile,
162
+ });
163
+ // Add field-level elements
164
+ const fields = objectType.getFields();
165
+ for (const [fieldName, field] of Object.entries(fields)) {
166
+ elements.push({
167
+ typeName,
168
+ fieldName,
169
+ objectType,
170
+ field,
171
+ filePath: firstFile,
172
+ });
173
+ }
174
+ }
175
+ return elements;
176
+ }
177
+ buildRuleDescription() {
178
+ const predicateDesc = this._predicates.map((p) => p.description).join(' and ');
179
+ const conditionDesc = this._conditions.map((c) => c.description).join(' and ');
180
+ const parts = ['schema'];
181
+ if (predicateDesc)
182
+ parts.push(`that ${predicateDesc}`);
183
+ if (conditionDesc)
184
+ parts.push(`should ${conditionDesc}`);
185
+ return parts.join(' ');
186
+ }
187
+ }
188
+ //# sourceMappingURL=schema-rule-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-rule-builder.js","sourceRoot":"","sources":["../../src/graphql/schema-rule-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import { type Node, type ClassDeclaration, type SourceFile } from 'ts-morph';
2
+ import type { ExpressionMatcher } from './matchers.js';
3
+ import type { ArchFunction } from '../models/arch-function.js';
4
+ /**
5
+ * Options for module body analysis.
6
+ */
7
+ export interface ModuleBodyOptions {
8
+ /**
9
+ * When true, only traverse top-level (module-scope) statements.
10
+ * Skips class bodies, function bodies, and arrow function bodies.
11
+ * Default: false (full file traversal).
12
+ */
13
+ scopeToModule?: boolean;
14
+ }
15
+ /**
16
+ * Result of searching a body for matcher hits.
17
+ */
18
+ export interface MatchResult {
19
+ /** Whether at least one match was found */
20
+ found: boolean;
21
+ /** The matching nodes (for violation reporting: file, line, text) */
22
+ matchingNodes: Node[];
23
+ }
24
+ /**
25
+ * Find all nodes in a subtree that match the given matcher.
26
+ *
27
+ * Uses getDescendantsOfKind when the matcher specifies syntaxKinds
28
+ * (efficient — only walks nodes of that kind). Falls back to
29
+ * getDescendants() for matchers without syntaxKinds (expression()).
30
+ */
31
+ export declare function findMatchesInNode(node: Node, matcher: ExpressionMatcher): Node[];
32
+ /**
33
+ * Search all method bodies in a class for matches.
34
+ *
35
+ * Iterates over every method (instance and static), gets the body,
36
+ * and tests each body against the matcher. Returns aggregated results.
37
+ */
38
+ export declare function searchClassBody(cls: ClassDeclaration, matcher: ExpressionMatcher): MatchResult;
39
+ /**
40
+ * Search a function body for matches.
41
+ *
42
+ * Uses ArchFunction.getBody() which returns the function/arrow body.
43
+ * For expression-bodied arrows (`() => expr`), getDescendantsOfKind
44
+ * still works — it walks the expression subtree.
45
+ */
46
+ export declare function searchFunctionBody(fn: ArchFunction, matcher: ExpressionMatcher): MatchResult;
47
+ /**
48
+ * Extract the body from a function-like argument node.
49
+ *
50
+ * Handles:
51
+ * - ArrowFunction: () => { ... } or () => expr
52
+ * - FunctionExpression: function() { ... }
53
+ *
54
+ * Returns undefined if the node is not a function-like expression.
55
+ */
56
+ export declare function getFunctionBody(node: Node): Node | undefined;
57
+ export declare function searchModuleBody(sourceFile: SourceFile, matcher: ExpressionMatcher, options?: ModuleBodyOptions): MatchResult;
58
+ //# sourceMappingURL=body-traversal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body-traversal.d.ts","sourceRoot":"","sources":["../../src/helpers/body-traversal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,gBAAgB,EAAE,KAAK,UAAU,EAAqB,MAAM,UAAU,CAAA;AAC/F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAE9D;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED;;GAEG;AAEH,MAAM,WAAW,WAAW;IAC1B,2CAA2C;IAC3C,KAAK,EAAE,OAAO,CAAA;IACd,qEAAqE;IACrE,aAAa,EAAE,IAAI,EAAE,CAAA;CACtB;AAuCD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI,EAAE,CAKhF;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,iBAAiB,GAAG,WAAW,CAqC9F;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,iBAAiB,GAAG,WAAW,CAW5F;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,CAQ5D;AAiCD,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,CAAC,EAAE,iBAAiB,GAC1B,WAAW,CA4Bb"}
@@ -0,0 +1,180 @@
1
+ import { Node as NodeUtils } from 'ts-morph';
2
+ /**
3
+ * Targeted traversal: only check nodes of the specified syntax kinds.
4
+ */
5
+ function findMatchesByKind(node, matcher) {
6
+ const matches = [];
7
+ for (const kind of matcher.syntaxKinds ?? []) {
8
+ for (const descendant of node.getDescendantsOfKind(kind)) {
9
+ if (matcher.matches(descendant)) {
10
+ matches.push(descendant);
11
+ }
12
+ }
13
+ }
14
+ return matches;
15
+ }
16
+ /**
17
+ * Broad traversal: check every descendant, then deduplicate.
18
+ *
19
+ * Parent nodes' getText() includes children's text, so regex-based
20
+ * matchers (expression()) match at multiple ancestor levels.
21
+ * Keep only the deepest (most specific) matching nodes.
22
+ */
23
+ function findMatchesBroad(node, matcher) {
24
+ const matches = [];
25
+ for (const descendant of node.getDescendants()) {
26
+ if (matcher.matches(descendant)) {
27
+ matches.push(descendant);
28
+ }
29
+ }
30
+ return matches.filter((m) => !matches.some((other) => other !== m && other.getStart() >= m.getStart() && other.getEnd() <= m.getEnd()));
31
+ }
32
+ /**
33
+ * Find all nodes in a subtree that match the given matcher.
34
+ *
35
+ * Uses getDescendantsOfKind when the matcher specifies syntaxKinds
36
+ * (efficient — only walks nodes of that kind). Falls back to
37
+ * getDescendants() for matchers without syntaxKinds (expression()).
38
+ */
39
+ export function findMatchesInNode(node, matcher) {
40
+ if (matcher.syntaxKinds && matcher.syntaxKinds.length > 0) {
41
+ return findMatchesByKind(node, matcher);
42
+ }
43
+ return findMatchesBroad(node, matcher);
44
+ }
45
+ /**
46
+ * Search all method bodies in a class for matches.
47
+ *
48
+ * Iterates over every method (instance and static), gets the body,
49
+ * and tests each body against the matcher. Returns aggregated results.
50
+ */
51
+ export function searchClassBody(cls, matcher) {
52
+ const matchingNodes = [];
53
+ for (const method of cls.getMethods()) {
54
+ const body = method.getBody();
55
+ if (!body)
56
+ continue;
57
+ matchingNodes.push(...findMatchesInNode(body, matcher));
58
+ }
59
+ // Also check constructor body (use last constructor — earlier ones are overload signatures without bodies)
60
+ const ctors = cls.getConstructors();
61
+ const ctor = ctors[ctors.length - 1];
62
+ if (ctor) {
63
+ const body = ctor.getBody();
64
+ if (body) {
65
+ matchingNodes.push(...findMatchesInNode(body, matcher));
66
+ }
67
+ }
68
+ // Also check getters and setters
69
+ for (const accessor of cls.getGetAccessors()) {
70
+ const body = accessor.getBody();
71
+ if (body) {
72
+ matchingNodes.push(...findMatchesInNode(body, matcher));
73
+ }
74
+ }
75
+ for (const accessor of cls.getSetAccessors()) {
76
+ const body = accessor.getBody();
77
+ if (body) {
78
+ matchingNodes.push(...findMatchesInNode(body, matcher));
79
+ }
80
+ }
81
+ return {
82
+ found: matchingNodes.length > 0,
83
+ matchingNodes,
84
+ };
85
+ }
86
+ /**
87
+ * Search a function body for matches.
88
+ *
89
+ * Uses ArchFunction.getBody() which returns the function/arrow body.
90
+ * For expression-bodied arrows (`() => expr`), getDescendantsOfKind
91
+ * still works — it walks the expression subtree.
92
+ */
93
+ export function searchFunctionBody(fn, matcher) {
94
+ const body = fn.getBody();
95
+ if (!body) {
96
+ return { found: false, matchingNodes: [] };
97
+ }
98
+ const matchingNodes = findMatchesInNode(body, matcher);
99
+ return {
100
+ found: matchingNodes.length > 0,
101
+ matchingNodes,
102
+ };
103
+ }
104
+ /**
105
+ * Extract the body from a function-like argument node.
106
+ *
107
+ * Handles:
108
+ * - ArrowFunction: () => { ... } or () => expr
109
+ * - FunctionExpression: function() { ... }
110
+ *
111
+ * Returns undefined if the node is not a function-like expression.
112
+ */
113
+ export function getFunctionBody(node) {
114
+ if (NodeUtils.isArrowFunction(node)) {
115
+ return node.getBody();
116
+ }
117
+ if (NodeUtils.isFunctionExpression(node)) {
118
+ return node.getBody();
119
+ }
120
+ return undefined;
121
+ }
122
+ /**
123
+ * Search a module (SourceFile) for matches.
124
+ *
125
+ * Default: walks the entire file (all descendants), including inside
126
+ * class methods and function bodies. This makes `modules().notContain()`
127
+ * a file-level policy check.
128
+ *
129
+ * With `scopeToModule: true`: walks only top-level statements,
130
+ * skipping class bodies, function declaration bodies, and arrow/function
131
+ * expression bodies. Use when you already have class/function rules and
132
+ * want to avoid duplicate violations.
133
+ */
134
+ /**
135
+ * Collect matches from top-level variable statement initializers,
136
+ * skipping arrow/function expressions (covered by function rules).
137
+ */
138
+ function collectVariableStatementMatches(statement, matcher) {
139
+ if (!NodeUtils.isVariableStatement(statement))
140
+ return [];
141
+ const matches = [];
142
+ for (const decl of statement.getDeclarationList().getDeclarations()) {
143
+ const initializer = decl.getInitializer();
144
+ if (!initializer)
145
+ continue;
146
+ // Skip arrow/function expressions entirely — function rules cover them
147
+ if (NodeUtils.isArrowFunction(initializer) || NodeUtils.isFunctionExpression(initializer)) {
148
+ continue;
149
+ }
150
+ matches.push(...findMatchesInNode(initializer, matcher));
151
+ }
152
+ return matches;
153
+ }
154
+ export function searchModuleBody(sourceFile, matcher, options) {
155
+ if (!options?.scopeToModule) {
156
+ // Full file traversal — walk all descendants
157
+ const matchingNodes = findMatchesInNode(sourceFile, matcher);
158
+ return { found: matchingNodes.length > 0, matchingNodes };
159
+ }
160
+ // Module-scope only — walk each top-level statement but skip class/function internals
161
+ const matchingNodes = [];
162
+ for (const statement of sourceFile.getStatements()) {
163
+ // Skip class declarations entirely (their bodies are covered by class rules)
164
+ if (NodeUtils.isClassDeclaration(statement))
165
+ continue;
166
+ // Skip function declarations entirely (their bodies are covered by function rules)
167
+ if (NodeUtils.isFunctionDeclaration(statement))
168
+ continue;
169
+ // For variable statements (const/let/var), check the initializer but skip
170
+ // arrow function and function expression bodies within it
171
+ if (NodeUtils.isVariableStatement(statement)) {
172
+ matchingNodes.push(...collectVariableStatementMatches(statement, matcher));
173
+ continue;
174
+ }
175
+ // All other statements: walk their descendants
176
+ matchingNodes.push(...findMatchesInNode(statement, matcher));
177
+ }
178
+ return { found: matchingNodes.length > 0, matchingNodes };
179
+ }
180
+ //# sourceMappingURL=body-traversal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body-traversal.js","sourceRoot":"","sources":["../../src/helpers/body-traversal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { type CallExpression } from 'ts-morph';
2
+ import type { ArchFunction } from '../models/arch-function.js';
3
+ /**
4
+ * Represents a callback function extracted from a call expression argument.
5
+ * Wraps the arrow function or function expression as an ArchFunction.
6
+ */
7
+ export interface ExtractedCallback {
8
+ /** The ArchFunction wrapping the callback. */
9
+ fn: ArchFunction;
10
+ /** The call expression this callback was extracted from. */
11
+ callSite: CallExpression;
12
+ /** Argument index within the call expression (0-based). */
13
+ argIndex: number;
14
+ }
15
+ /**
16
+ * Extract all inline function arguments from a call expression.
17
+ *
18
+ * Handles:
19
+ * - Arrow functions: `app.get('/path', (req, res) => { ... })`
20
+ * - Function expressions: `app.get('/path', function(req, res) { ... })`
21
+ *
22
+ * Does NOT resolve named references (e.g., `app.get('/path', myHandler)`).
23
+ * Reference resolution requires type-checker lookups and is deferred.
24
+ *
25
+ * @returns Array of extracted callbacks with their source metadata
26
+ */
27
+ export declare function extractCallbacks(callExpr: CallExpression): ExtractedCallback[];
28
+ //# sourceMappingURL=callback-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callback-extractor.d.ts","sourceRoot":"","sources":["../../src/helpers/callback-extractor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAA4C,MAAM,UAAU,CAAA;AACxF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAE9D;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,8CAA8C;IAC9C,EAAE,EAAE,YAAY,CAAA;IAChB,4DAA4D;IAC5D,QAAQ,EAAE,cAAc,CAAA;IACxB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,cAAc,GAAG,iBAAiB,EAAE,CAiB9E"}
@@ -0,0 +1,159 @@
1
+ import { Node as NodeUtils, SyntaxKind } from 'ts-morph';
2
+ /**
3
+ * Extract all inline function arguments from a call expression.
4
+ *
5
+ * Handles:
6
+ * - Arrow functions: `app.get('/path', (req, res) => { ... })`
7
+ * - Function expressions: `app.get('/path', function(req, res) { ... })`
8
+ *
9
+ * Does NOT resolve named references (e.g., `app.get('/path', myHandler)`).
10
+ * Reference resolution requires type-checker lookups and is deferred.
11
+ *
12
+ * @returns Array of extracted callbacks with their source metadata
13
+ */
14
+ export function extractCallbacks(callExpr) {
15
+ const callbacks = [];
16
+ const args = callExpr.getArguments();
17
+ for (let i = 0; i < args.length; i++) {
18
+ const arg = args[i];
19
+ if (!arg)
20
+ continue;
21
+ const fn = extractInlineFunction(arg, callExpr, i);
22
+ if (fn) {
23
+ callbacks.push(fn);
24
+ }
25
+ else {
26
+ // Search object literal arguments for function-valued properties
27
+ callbacks.push(...extractFromObjectLiteral(arg, callExpr, i, 0));
28
+ }
29
+ }
30
+ return callbacks;
31
+ }
32
+ /**
33
+ * Maximum depth to recurse into nested object literals.
34
+ * Prevents extracting unintended callbacks from deep config/schema structures.
35
+ */
36
+ const MAX_OBJECT_DEPTH = 3;
37
+ /**
38
+ * Recursively search an ObjectLiteralExpression for function-like property values.
39
+ *
40
+ * Handles:
41
+ * - Arrow function properties: `{ handler: (req) => { ... } }`
42
+ * - Function expression properties: `{ handler: function(req) { ... } }`
43
+ * - Method shorthand: `{ handler(req) { ... } }`
44
+ * - Nested object literals: `{ hooks: { onRequest: (req) => { ... } } }`
45
+ *
46
+ * Stops at MAX_OBJECT_DEPTH to avoid false positives from schema defaults.
47
+ */
48
+ function extractFromObjectLiteral(arg, callSite, argIndex, depth) {
49
+ if (!NodeUtils.isObjectLiteralExpression(arg))
50
+ return [];
51
+ if (depth >= MAX_OBJECT_DEPTH)
52
+ return [];
53
+ const results = [];
54
+ for (const prop of arg.getProperties()) {
55
+ // Method shorthand: { handler(req, res) { ... } }
56
+ if (NodeUtils.isMethodDeclaration(prop)) {
57
+ results.push({
58
+ fn: fromMethodDeclaration(prop),
59
+ callSite,
60
+ argIndex,
61
+ });
62
+ continue;
63
+ }
64
+ if (!NodeUtils.isPropertyAssignment(prop))
65
+ continue;
66
+ const init = prop.getInitializer();
67
+ if (!init)
68
+ continue;
69
+ // Direct function property
70
+ const direct = extractInlineFunction(init, callSite, argIndex);
71
+ if (direct) {
72
+ results.push(direct);
73
+ continue;
74
+ }
75
+ // Recurse into nested object literals (depth-limited)
76
+ results.push(...extractFromObjectLiteral(init, callSite, argIndex, depth + 1));
77
+ }
78
+ return results;
79
+ }
80
+ /**
81
+ * Try to extract an ArchFunction from a single argument node.
82
+ */
83
+ function extractInlineFunction(arg, callSite, argIndex) {
84
+ // Arrow function: (req, res) => { ... }
85
+ if (arg.getKind() === SyntaxKind.ArrowFunction) {
86
+ return {
87
+ fn: fromArrowExpression(arg),
88
+ callSite,
89
+ argIndex,
90
+ };
91
+ }
92
+ // Function expression: function(req, res) { ... }
93
+ if (arg.getKind() === SyntaxKind.FunctionExpression) {
94
+ return {
95
+ fn: fromFunctionExpression(arg),
96
+ callSite,
97
+ argIndex,
98
+ };
99
+ }
100
+ return null;
101
+ }
102
+ /**
103
+ * Wrap an arrow function argument as an ArchFunction.
104
+ * Unlike fromArrowVariableDeclaration (plan 0009), this has no variable name.
105
+ * The name is synthesized from the call site context.
106
+ */
107
+ function fromArrowExpression(node) {
108
+ const arrow = node.asKindOrThrow(SyntaxKind.ArrowFunction);
109
+ return {
110
+ getName: () => undefined, // anonymous --- name derived from context
111
+ getSourceFile: () => arrow.getSourceFile(),
112
+ isExported: () => false, // callbacks are never exported
113
+ isAsync: () => arrow.isAsync(),
114
+ getParameters: () => arrow.getParameters(),
115
+ getReturnType: () => arrow.getReturnType(),
116
+ getBody: () => arrow.getBody(),
117
+ getNode: () => arrow,
118
+ getStartLineNumber: () => arrow.getStartLineNumber(),
119
+ getScope: () => 'public',
120
+ };
121
+ }
122
+ /**
123
+ * Wrap a function expression argument as an ArchFunction.
124
+ */
125
+ function fromFunctionExpression(node) {
126
+ const funcExpr = node.asKindOrThrow(SyntaxKind.FunctionExpression);
127
+ return {
128
+ getName: () => funcExpr.getName(), // may have a name: `function handler() {}`
129
+ getSourceFile: () => funcExpr.getSourceFile(),
130
+ isExported: () => false,
131
+ isAsync: () => funcExpr.isAsync(),
132
+ getParameters: () => funcExpr.getParameters(),
133
+ getReturnType: () => funcExpr.getReturnType(),
134
+ getBody: () => funcExpr.getBody(),
135
+ getNode: () => funcExpr,
136
+ getStartLineNumber: () => funcExpr.getStartLineNumber(),
137
+ getScope: () => 'public',
138
+ };
139
+ }
140
+ /**
141
+ * Wrap an object literal method declaration as an ArchFunction.
142
+ * Handles: `{ handler(req, res) { ... } }`
143
+ */
144
+ function fromMethodDeclaration(node) {
145
+ const method = node.asKindOrThrow(SyntaxKind.MethodDeclaration);
146
+ return {
147
+ getName: () => method.getName(),
148
+ getSourceFile: () => method.getSourceFile(),
149
+ isExported: () => false,
150
+ isAsync: () => method.isAsync(),
151
+ getParameters: () => method.getParameters(),
152
+ getReturnType: () => method.getReturnType(),
153
+ getBody: () => method.getBody(),
154
+ getNode: () => method,
155
+ getStartLineNumber: () => method.getStartLineNumber(),
156
+ getScope: () => 'public',
157
+ };
158
+ }
159
+ //# sourceMappingURL=callback-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callback-extractor.js","sourceRoot":"","sources":["../../src/helpers/callback-extractor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,IAAI,IAAI,SAAS,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAgBxF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAwB;IACvD,MAAM,SAAS,GAAwB,EAAE,CAAA;IACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAA;IAEpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,IAAI,CAAC,GAAG;YAAE,SAAQ;QAClB,MAAM,EAAE,GAAG,qBAAqB,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAA;QAClD,IAAI,EAAE,EAAE,CAAC;YACP,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACpB,CAAC;aAAM,CAAC;YACN,iEAAiE;YACjE,SAAS,CAAC,IAAI,CAAC,GAAG,wBAAwB,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QAClE,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,gBAAgB,GAAG,CAAC,CAAA;AAE1B;;;;;;;;;;GAUG;AACH,SAAS,wBAAwB,CAC/B,GAAS,EACT,QAAwB,EACxB,QAAgB,EAChB,KAAa;IAEb,IAAI,CAAC,SAAS,CAAC,yBAAyB,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAA;IACxD,IAAI,KAAK,IAAI,gBAAgB;QAAE,OAAO,EAAE,CAAA;IACxC,MAAM,OAAO,GAAwB,EAAE,CAAA;IACvC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,aAAa,EAAE,EAAE,CAAC;QACvC,kDAAkD;QAClD,IAAI,SAAS,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;YACxC,OAAO,CAAC,IAAI,CAAC;gBACX,EAAE,EAAE,qBAAqB,CAAC,IAAI,CAAC;gBAC/B,QAAQ;gBACR,QAAQ;aACT,CAAC,CAAA;YACF,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC,IAAI,CAAC;YAAE,SAAQ;QACnD,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE,CAAA;QAClC,IAAI,CAAC,IAAI;YAAE,SAAQ;QACnB,2BAA2B;QAC3B,MAAM,MAAM,GAAG,qBAAqB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;QAC9D,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YACpB,SAAQ;QACV,CAAC;QACD,sDAAsD;QACtD,OAAO,CAAC,IAAI,CAAC,GAAG,wBAAwB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAA;IAChF,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAC5B,GAAS,EACT,QAAwB,EACxB,QAAgB;IAEhB,wCAAwC;IACxC,IAAI,GAAG,CAAC,OAAO,EAAE,KAAK,UAAU,CAAC,aAAa,EAAE,CAAC;QAC/C,OAAO;YACL,EAAE,EAAE,mBAAmB,CAAC,GAAG,CAAC;YAC5B,QAAQ;YACR,QAAQ;SACT,CAAA;IACH,CAAC;IAED,kDAAkD;IAClD,IAAI,GAAG,CAAC,OAAO,EAAE,KAAK,UAAU,CAAC,kBAAkB,EAAE,CAAC;QACpD,OAAO;YACL,EAAE,EAAE,sBAAsB,CAAC,GAAG,CAAC;YAC/B,QAAQ;YACR,QAAQ;SACT,CAAA;IACH,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;GAIG;AACH,SAAS,mBAAmB,CAAC,IAAU;IACrC,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,aAAa,CAAC,CAAA;IAC1D,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,0CAA0C;QACpE,aAAa,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE;QAC1C,UAAU,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,+BAA+B;QACxD,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE;QAC9B,aAAa,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE;QAC1C,aAAa,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE;QAC1C,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE;QAC9B,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK;QACpB,kBAAkB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,kBAAkB,EAAE;QACpD,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ;KACzB,CAAA;AACH,CAAC;AAED;;GAEG;AACH,SAAS,sBAAsB,CAAC,IAAU;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAA;IAClE,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,2CAA2C;QAC9E,aAAa,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,aAAa,EAAE;QAC7C,UAAU,EAAE,GAAG,EAAE,CAAC,KAAK;QACvB,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE;QACjC,aAAa,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,aAAa,EAAE;QAC7C,aAAa,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,aAAa,EAAE;QAC7C,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE;QACjC,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ;QACvB,kBAAkB,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,kBAAkB,EAAE;QACvD,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ;KACzB,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,qBAAqB,CAAC,IAAU;IACvC,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAA;IAC/D,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE;QAC/B,aAAa,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,aAAa,EAAE;QAC3C,UAAU,EAAE,GAAG,EAAE,CAAC,KAAK;QACvB,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE;QAC/B,aAAa,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,aAAa,EAAE;QAC3C,aAAa,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,aAAa,EAAE;QAC3C,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE;QAC/B,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM;QACrB,kBAAkB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,kBAAkB,EAAE;QACrD,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ;KACzB,CAAA;AACH,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { Node } from 'ts-morph';
2
+ import type { ClassDeclaration } from 'ts-morph';
3
+ /**
4
+ * Calculate cyclomatic complexity (McCabe) for a function body.
5
+ *
6
+ * Accepts the body Node directly (from ArchFunction.getBody(),
7
+ * MethodDeclaration.getBody(), etc.).
8
+ *
9
+ * Complexity = 1 + number of decision points.
10
+ * Returns 1 for an undefined/empty body (one path through).
11
+ */
12
+ export declare function cyclomaticComplexity(body: Node | undefined): number;
13
+ /**
14
+ * Count lines spanned by a node (from first line to last line, inclusive).
15
+ *
16
+ * This is a "span lines" count — it includes blank lines and comments
17
+ * within the node's range. This is consistent with how editors report
18
+ * function/class length, and avoids the fragility of text-based
19
+ * comment stripping.
20
+ */
21
+ export declare function linesOfCode(node: Node): number;
22
+ /**
23
+ * Count the number of methods on a class.
24
+ */
25
+ export declare function methodCount(cls: ClassDeclaration): number;
26
+ //# sourceMappingURL=complexity.d.ts.map