@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,470 @@
1
+ import { Node, SyntaxKind } from 'ts-morph';
2
+ /**
3
+ * Normalize expression text for matching.
4
+ * Replaces optional chaining `?.` with `.` so users don't need to
5
+ * account for both forms.
6
+ *
7
+ * PoC finding: `this?.normalizeCount` getText() includes the `?`.
8
+ */
9
+ function normalizeText(text) {
10
+ return text.replace(/\?\./g, '.');
11
+ }
12
+ /**
13
+ * Match a CallExpression by function/method name.
14
+ *
15
+ * Matches against `CallExpression.getExpression().getText()` after
16
+ * normalizing optional chaining.
17
+ *
18
+ * @param nameOrRegex - Exact name (e.g. 'parseInt', 'this.normalizeCount')
19
+ * or regex for flexible matching.
20
+ *
21
+ * @example
22
+ * call('parseInt') // matches parseInt(x)
23
+ * call('this.normalizeCount') // matches this.normalizeCount(x) AND this?.normalizeCount(x)
24
+ * call(/^console\./) // matches console.log, console.warn, etc.
25
+ */
26
+ export function call(nameOrRegex) {
27
+ if (typeof nameOrRegex === 'string') {
28
+ return {
29
+ description: `call to '${nameOrRegex}'`,
30
+ syntaxKinds: [SyntaxKind.CallExpression],
31
+ matches(node) {
32
+ if (!Node.isCallExpression(node))
33
+ return false;
34
+ const text = normalizeText(node.getExpression().getText());
35
+ return text === nameOrRegex;
36
+ },
37
+ };
38
+ }
39
+ return {
40
+ description: `call matching ${String(nameOrRegex)}`,
41
+ syntaxKinds: [SyntaxKind.CallExpression],
42
+ matches(node) {
43
+ if (!Node.isCallExpression(node))
44
+ return false;
45
+ const text = normalizeText(node.getExpression().getText());
46
+ return nameOrRegex.test(text);
47
+ },
48
+ };
49
+ }
50
+ /**
51
+ * Match a PropertyAccessExpression by the dotted chain.
52
+ *
53
+ * Matches against `PropertyAccessExpression.getText()` after normalizing
54
+ * optional chaining. Useful for detecting direct property access patterns
55
+ * like `process.env`, `this.db`, `window.location`.
56
+ *
57
+ * @param chain - Exact dotted chain (e.g. 'process.env') or regex.
58
+ *
59
+ * @example
60
+ * access('process.env') // matches process.env.FOO (the inner access)
61
+ * access(/^this\.db/) // matches this.db, this.db.query, etc.
62
+ */
63
+ export function access(chain) {
64
+ if (typeof chain === 'string') {
65
+ return {
66
+ description: `access to '${chain}'`,
67
+ syntaxKinds: [SyntaxKind.PropertyAccessExpression],
68
+ matches(node) {
69
+ if (!Node.isPropertyAccessExpression(node))
70
+ return false;
71
+ const text = normalizeText(node.getText());
72
+ return text === chain;
73
+ },
74
+ };
75
+ }
76
+ return {
77
+ description: `access matching ${String(chain)}`,
78
+ syntaxKinds: [SyntaxKind.PropertyAccessExpression],
79
+ matches(node) {
80
+ if (!Node.isPropertyAccessExpression(node))
81
+ return false;
82
+ const text = normalizeText(node.getText());
83
+ return chain.test(text);
84
+ },
85
+ };
86
+ }
87
+ /**
88
+ * Match a NewExpression by constructor name.
89
+ *
90
+ * Matches against `NewExpression.getExpression().getText()`.
91
+ * The PoC confirmed this correctly distinguishes 'Error' from 'DomainError'.
92
+ *
93
+ * @param nameOrRegex - Exact constructor name or regex.
94
+ *
95
+ * @example
96
+ * newExpr('Error') // matches new Error(...) but NOT new DomainError(...)
97
+ * newExpr('DomainError') // matches new DomainError(...)
98
+ * newExpr(/Error$/) // matches new Error, new DomainError, new TypeError, etc.
99
+ */
100
+ export function newExpr(nameOrRegex) {
101
+ if (typeof nameOrRegex === 'string') {
102
+ return {
103
+ description: `new '${nameOrRegex}'`,
104
+ syntaxKinds: [SyntaxKind.NewExpression],
105
+ matches(node) {
106
+ if (!Node.isNewExpression(node))
107
+ return false;
108
+ const text = node.getExpression().getText();
109
+ return text === nameOrRegex;
110
+ },
111
+ };
112
+ }
113
+ return {
114
+ description: `new matching ${String(nameOrRegex)}`,
115
+ syntaxKinds: [SyntaxKind.NewExpression],
116
+ matches(node) {
117
+ if (!Node.isNewExpression(node))
118
+ return false;
119
+ const text = node.getExpression().getText();
120
+ return nameOrRegex.test(text);
121
+ },
122
+ };
123
+ }
124
+ /**
125
+ * Escape hatch: match any node whose getText() contains or matches the given pattern.
126
+ *
127
+ * This is intentionally broad and should be used sparingly. It walks ALL
128
+ * descendant nodes and checks getText() against the pattern. A runtime
129
+ * console.warn is emitted the first time expression() is used, encouraging
130
+ * users to prefer call/access/newExpr where possible.
131
+ *
132
+ * @param textOrRegex - Substring to search for (string) or regex pattern.
133
+ *
134
+ * @example
135
+ * expression('eval') // matches any node containing 'eval'
136
+ * expression(/document\.write/) // matches document.write calls
137
+ */
138
+ export function expression(textOrRegex) {
139
+ let warned = false;
140
+ if (typeof textOrRegex === 'string') {
141
+ return {
142
+ description: `expression containing '${textOrRegex}'`,
143
+ // No syntaxKinds — walks all descendants
144
+ matches(node) {
145
+ if (!warned) {
146
+ console.warn(`[eess] expression('${textOrRegex}') is a broad matcher. ` +
147
+ `Prefer call(), access(), or newExpr() for precise matching.`);
148
+ warned = true;
149
+ }
150
+ return node.getText().includes(textOrRegex);
151
+ },
152
+ };
153
+ }
154
+ return {
155
+ description: `expression matching ${String(textOrRegex)}`,
156
+ // No syntaxKinds — walks all descendants
157
+ matches(node) {
158
+ if (!warned) {
159
+ console.warn(`[eess] expression(${String(textOrRegex)}) is a broad matcher. ` +
160
+ `Prefer call(), access(), or newExpr() for precise matching.`);
161
+ warned = true;
162
+ }
163
+ return textOrRegex.test(node.getText());
164
+ },
165
+ };
166
+ }
167
+ /**
168
+ * Match a PropertyAssignment by name and optional value.
169
+ *
170
+ * Targets `SyntaxKind.PropertyAssignment` for efficient traversal via
171
+ * `getDescendantsOfKind`. Does NOT match ShorthandPropertyAssignment
172
+ * (`{ schema }`) — those have no initializer.
173
+ *
174
+ * Value matching uses semantic comparison for primitives:
175
+ * - `boolean` — matches TrueKeyword / FalseKeyword
176
+ * - `number` — matches NumericLiteral via getLiteralValue()
177
+ * - `string` — matches StringLiteral via getLiteralValue() (no quotes needed)
178
+ * - `RegExp` — matches initializer getText() (raw text including quotes)
179
+ *
180
+ * @param name - Exact property name or regex for flexible matching.
181
+ * @param value - Optional value constraint. Omit for name-only matching.
182
+ *
183
+ * @example
184
+ * property('additionalProperties', true) // matches additionalProperties: true
185
+ * property('type', 'object') // matches type: 'object'
186
+ * property('maximum', 100) // matches maximum: 100
187
+ * property(/^additional/) // matches any property starting with 'additional'
188
+ * property('mode', /^'(strict|loose)'$/) // matches mode: 'strict' or 'loose' (getText() includes quotes)
189
+ */
190
+ /**
191
+ * Test whether an initializer matches the expected value.
192
+ */
193
+ function matchPropertyValue(initializer, value) {
194
+ if (typeof value === 'boolean') {
195
+ const kind = initializer.getKind();
196
+ return value ? kind === SyntaxKind.TrueKeyword : kind === SyntaxKind.FalseKeyword;
197
+ }
198
+ if (typeof value === 'number') {
199
+ return Node.isNumericLiteral(initializer) && initializer.getLiteralValue() === value;
200
+ }
201
+ if (typeof value === 'string') {
202
+ return Node.isStringLiteral(initializer) && initializer.getLiteralValue() === value;
203
+ }
204
+ return value.test(initializer.getText());
205
+ }
206
+ /**
207
+ * Test whether a property assignment's name matches the expected pattern.
208
+ */
209
+ function matchPropertyName(node, name) {
210
+ if (!Node.isPropertyAssignment(node))
211
+ return false;
212
+ if (node.getNameNode().getKind() === SyntaxKind.ComputedPropertyName)
213
+ return false;
214
+ const nameNode = node.getNameNode();
215
+ const propName = Node.isStringLiteral(nameNode) ? nameNode.getLiteralValue() : node.getName();
216
+ if (typeof name === 'string')
217
+ return propName === name;
218
+ return name.test(propName);
219
+ }
220
+ export function property(name, value) {
221
+ const nameDesc = typeof name === 'string' ? `'${name}'` : String(name);
222
+ const valueDesc = value === undefined ? '' : ` = ${String(value)}`;
223
+ const description = `property ${nameDesc}${valueDesc}`;
224
+ return {
225
+ description,
226
+ syntaxKinds: [SyntaxKind.PropertyAssignment],
227
+ matches(node) {
228
+ if (!matchPropertyName(node, name))
229
+ return false;
230
+ if (value === undefined)
231
+ return true;
232
+ const initializer = Node.isPropertyAssignment(node) ? node.getInitializer() : undefined;
233
+ if (!initializer)
234
+ return false;
235
+ return matchPropertyValue(initializer, value);
236
+ },
237
+ };
238
+ }
239
+ /**
240
+ * Default stub/deferred-work patterns found in comments.
241
+ * Matches common markers (see regex) and phrases like
242
+ * "not implemented" or "coming soon".
243
+ *
244
+ * Exported as a constant for use with `comment()`. Users can pass
245
+ * their own RegExp to `comment()` for narrower matching.
246
+ */
247
+ export const STUB_PATTERNS = /\b(TODO|FIXME|HACK|XXX|STUB|DEFERRED|PLACEHOLDER)\b|\bnot\s+implemented\b|\bcoming\s+soon\b/i;
248
+ /**
249
+ * Match comments attached to AST nodes.
250
+ *
251
+ * Unlike other matchers that test AST nodes, this matcher tests the
252
+ * leading and trailing comment ranges of each node. It uses
253
+ * `syntaxKinds: undefined` so the broad traversal path visits every node,
254
+ * and `matches(node)` checks that node's comment ranges.
255
+ *
256
+ * A Set tracks matched comment positions to avoid duplicates (the same
257
+ * comment may be visited as leading trivia of multiple nested nodes).
258
+ *
259
+ * @param pattern - String substring or RegExp to test against comment text.
260
+ *
261
+ * @example
262
+ * comment(/HACK/) // matches hack marker comments
263
+ * comment(STUB_PATTERNS) // matches all common stub markers
264
+ * comment('HACK') // matches hack comments
265
+ */
266
+ export function comment(pattern) {
267
+ // Dedup by (filePath, pos) — prevents the same comment from matching
268
+ // multiple times when visited as leading trivia of nested nodes.
269
+ // Using a composite string key avoids cross-file collisions.
270
+ const matchedComments = new Set();
271
+ function testComment(range) {
272
+ const text = range.getText();
273
+ if (typeof pattern === 'string') {
274
+ return text.includes(pattern);
275
+ }
276
+ // Reset lastIndex for stateful (g-flag) regexes
277
+ pattern.lastIndex = 0;
278
+ return pattern.test(text);
279
+ }
280
+ return {
281
+ description: typeof pattern === 'string'
282
+ ? `comment containing '${pattern}'`
283
+ : `comment matching ${String(pattern)}`,
284
+ // No syntaxKinds — broad traversal to visit all nodes and their comments
285
+ matches(node) {
286
+ const filePath = node.getSourceFile().getFilePath();
287
+ const ranges = [...node.getLeadingCommentRanges(), ...node.getTrailingCommentRanges()];
288
+ for (const range of ranges) {
289
+ const key = `${filePath}:${String(range.getPos())}`;
290
+ if (matchedComments.has(key))
291
+ continue;
292
+ if (testComment(range)) {
293
+ matchedComments.add(key);
294
+ return true;
295
+ }
296
+ }
297
+ return false;
298
+ },
299
+ };
300
+ }
301
+ /**
302
+ * Extract the tag name from a JsxElement or JsxSelfClosingElement node.
303
+ */
304
+ function getJsxTagName(node) {
305
+ if (Node.isJsxElement(node)) {
306
+ return node.getOpeningElement().getTagNameNode().getText();
307
+ }
308
+ if (Node.isJsxSelfClosingElement(node)) {
309
+ return node.getTagNameNode().getText();
310
+ }
311
+ return undefined;
312
+ }
313
+ /**
314
+ * Match a JSX element by tag name.
315
+ *
316
+ * Targets `JsxElement` (has children) and `JsxSelfClosingElement` (no children).
317
+ * This is a **tag-only** matcher — it cannot check attributes. Use the
318
+ * `jsxElements()` entry point for attribute-level rules.
319
+ *
320
+ * @param tagOrRegex - Exact tag name (e.g. 'div', 'Button') or regex.
321
+ *
322
+ * @example
323
+ * jsxElement('div') // matches <div>...</div> and <div />
324
+ * jsxElement('Button') // matches <Button>...</Button>
325
+ * jsxElement(/^motion\./) // matches <motion.div>, <motion.span>, etc.
326
+ */
327
+ export function jsxElement(tagOrRegex) {
328
+ if (typeof tagOrRegex === 'string') {
329
+ return {
330
+ description: `JSX element <${tagOrRegex}>`,
331
+ syntaxKinds: [SyntaxKind.JsxElement, SyntaxKind.JsxSelfClosingElement],
332
+ matches(node) {
333
+ const tag = getJsxTagName(node);
334
+ return tag === tagOrRegex;
335
+ },
336
+ };
337
+ }
338
+ return {
339
+ description: `JSX element matching ${String(tagOrRegex)}`,
340
+ syntaxKinds: [SyntaxKind.JsxElement, SyntaxKind.JsxSelfClosingElement],
341
+ matches(node) {
342
+ const tag = getJsxTagName(node);
343
+ if (tag === undefined)
344
+ return false;
345
+ return tagOrRegex.test(tag);
346
+ },
347
+ };
348
+ }
349
+ /**
350
+ * Match hardcoded JSX text content — the children of JSX elements.
351
+ *
352
+ * Where {@link jsxElement} matches elements by tag and the `jsxElements()`
353
+ * entry point handles attribute values, this matcher covers the remaining
354
+ * gap: literal text rendered as element children. Composes with
355
+ * `notContain()` for i18n-style rules ("no hardcoded user-facing text").
356
+ *
357
+ * Matches:
358
+ * - `JsxText` nodes with non-whitespace content (`<button>Save</button>`).
359
+ * - `JsxExpression` wrapping a bare string literal (`<div>{"Save"}</div>`)
360
+ * or a no-substitution template (`` <div>{`Save`}</div> ``) — these render
361
+ * identically to plain text and would otherwise be a trivial bypass.
362
+ *
363
+ * Does NOT match: inter-element whitespace, `{expr}` wrapping an identifier
364
+ * or call (`<div>{t("save")}</div>`), templates with substitution
365
+ * (`` <div>{`Hi ${name}`}</div> ``), or attribute values whether braced or
366
+ * quoted (`title={"Save"}`, `title="Save"`) — those belong to the
367
+ * `jsxElements()` entry point. No letter-presence filter is baked in —
368
+ * `<div>123</div>` matches; the matcher takes no options, so to narrow which
369
+ * text is flagged, scope the rule with folder/file predicates or
370
+ * `.excluding(...)`. Note: text inside translation wrappers like `<Trans>`
371
+ * also matches — scope those out the same way if your i18n setup uses them.
372
+ *
373
+ * @example
374
+ * modules(p)
375
+ * .that()
376
+ * .resideInFolder('src/components/**')
377
+ * .should()
378
+ * .notContain(jsxText())
379
+ * .because('User-facing text must go through t()')
380
+ * .check()
381
+ */
382
+ export function jsxText() {
383
+ return {
384
+ description: 'JSX text content',
385
+ syntaxKinds: [SyntaxKind.JsxText, SyntaxKind.JsxExpression],
386
+ matches(node) {
387
+ if (Node.isJsxText(node)) {
388
+ return node.getLiteralText().trim().length > 0;
389
+ }
390
+ if (Node.isJsxExpression(node)) {
391
+ // A JsxExpression appears in two positions: as an element child
392
+ // (`<div>{"x"}</div>`) or as an attribute value (`<div title={"x"} />`).
393
+ // Attribute values are the domain of the `jsxElements()` entry point —
394
+ // only match child position (parent is a JsxElement or JsxFragment).
395
+ const parent = node.getParent();
396
+ if (!Node.isJsxElement(parent) && !Node.isJsxFragment(parent))
397
+ return false;
398
+ const expr = node.getExpression();
399
+ if (!expr)
400
+ return false;
401
+ if (Node.isStringLiteral(expr))
402
+ return true;
403
+ if (Node.isNoSubstitutionTemplateLiteral(expr))
404
+ return true;
405
+ return false;
406
+ }
407
+ return false;
408
+ },
409
+ };
410
+ }
411
+ /**
412
+ * Match type assertion expressions — both `as Type` and the legacy
413
+ * angle-bracket `<Type>value` form.
414
+ *
415
+ * By default, `as const` is excluded from matches (it narrows types rather
416
+ * than widening them, so it's idiomatic for literal preservation). The
417
+ * `allowConst` option does not affect angle-bracket assertions — those
418
+ * can't express `as const` and are always matched.
419
+ *
420
+ * Does NOT match `satisfies` expressions — those are validation, not
421
+ * assertions, and should not be banned.
422
+ *
423
+ * @example
424
+ * // Allow `as const` in user code (default)
425
+ * classes(p).should().notContain(typeAssertion()).check()
426
+ *
427
+ * @example
428
+ * // Ban `as const` too — no `as` expressions of any kind
429
+ * modules(p).should().notContain(typeAssertion({ allowConst: false })).check()
430
+ */
431
+ export function typeAssertion(options) {
432
+ const allowConst = options?.allowConst ?? true;
433
+ return {
434
+ description: 'type assertion',
435
+ syntaxKinds: [SyntaxKind.AsExpression, SyntaxKind.TypeAssertionExpression],
436
+ matches(node) {
437
+ // Angle-bracket `<Type>value` — can't be `as const`, always matches
438
+ if (Node.isTypeAssertion(node))
439
+ return true;
440
+ if (!Node.isAsExpression(node))
441
+ return false;
442
+ if (!allowConst)
443
+ return true;
444
+ const typeNode = node.getTypeNode();
445
+ if (typeNode && Node.isTypeReference(typeNode)) {
446
+ const typeName = typeNode.getTypeName();
447
+ if (Node.isIdentifier(typeName) && typeName.getText() === 'const') {
448
+ return false;
449
+ }
450
+ }
451
+ return true;
452
+ },
453
+ };
454
+ }
455
+ /**
456
+ * Match `!` non-null assertion expressions.
457
+ *
458
+ * @example
459
+ * functions(p).should().notContain(nonNullAssertion()).check()
460
+ */
461
+ export function nonNullAssertion() {
462
+ return {
463
+ description: 'non-null assertion',
464
+ syntaxKinds: [SyntaxKind.NonNullExpression],
465
+ matches(node) {
466
+ return Node.isNonNullExpression(node);
467
+ },
468
+ };
469
+ }
470
+ //# sourceMappingURL=matchers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matchers.js","sourceRoot":"","sources":["../../src/helpers/matchers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { TypeMatcher } from '../helpers/type-matchers.js';
2
+ /**
3
+ * A shape constraint for a single property in a return type.
4
+ *
5
+ * - `string` — matched as regex against `Type.getText()` (e.g. `'number'`, `'string'`)
6
+ * - `'T[]'` — matches any array type regardless of element type
7
+ * - `TypeMatcher` — full programmatic control (reuse existing matchers)
8
+ */
9
+ export type PropertyConstraint = string | TypeMatcher;
10
+ /**
11
+ * A named architectural pattern that describes expected return type shape.
12
+ */
13
+ export interface ArchPattern {
14
+ /** Human-readable pattern name, e.g. 'paginated-collection' */
15
+ readonly name: string;
16
+ /** Required properties and their type constraints on the return type */
17
+ readonly returnShape: Record<string, PropertyConstraint>;
18
+ }
19
+ /**
20
+ * Define a reusable architectural pattern.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * const paginatedCollection = definePattern('paginated-collection', {
25
+ * returnShape: {
26
+ * total: 'number',
27
+ * skip: 'number',
28
+ * limit: 'number',
29
+ * items: 'T[]',
30
+ * },
31
+ * })
32
+ * ```
33
+ */
34
+ export declare function definePattern(name: string, options: {
35
+ returnShape: Record<string, PropertyConstraint>;
36
+ }): ArchPattern;
37
+ //# sourceMappingURL=pattern.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pattern.d.ts","sourceRoot":"","sources":["../../src/helpers/pattern.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAE9D;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,WAAW,CAAA;AAErD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,wEAAwE;IACxE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;CACzD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;CAAE,GAC3D,WAAW,CAKb"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Define a reusable architectural pattern.
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * const paginatedCollection = definePattern('paginated-collection', {
7
+ * returnShape: {
8
+ * total: 'number',
9
+ * skip: 'number',
10
+ * limit: 'number',
11
+ * items: 'T[]',
12
+ * },
13
+ * })
14
+ * ```
15
+ */
16
+ export function definePattern(name, options) {
17
+ return {
18
+ name,
19
+ returnShape: options.returnShape,
20
+ };
21
+ }
22
+ //# sourceMappingURL=pattern.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pattern.js","sourceRoot":"","sources":["../../src/helpers/pattern.ts"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAY,EACZ,OAA4D;IAE5D,OAAO;QACL,IAAI;QACJ,WAAW,EAAE,OAAO,CAAC,WAAW;KACjC,CAAA;AACH,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { SourceFile } from 'ts-morph';
2
+ import type { Slice } from '../models/slice.js';
3
+ /**
4
+ * An edge in the slice dependency graph.
5
+ * Represents: a file in `from` imports a file in `to`.
6
+ */
7
+ export interface SliceEdge {
8
+ from: string;
9
+ to: string;
10
+ }
11
+ /**
12
+ * Build a reverse lookup map: file path -> slice name.
13
+ * Shared by buildSliceDependencyGraph and findSliceDependencyDetails.
14
+ */
15
+ export declare function buildFileToSliceMap(slices: Slice[]): Map<string, string>;
16
+ export declare function buildSliceDependencyGraph(slices: Slice[], fileToSlice?: Map<string, string>): SliceEdge[];
17
+ /**
18
+ * Find which specific files cause a dependency from one slice to another.
19
+ * Used for detailed violation messages.
20
+ *
21
+ * @param slices - The resolved slices
22
+ * @param fromSliceName - Source slice name
23
+ * @param toSliceName - Target slice name
24
+ * @param fileToSlice - Pre-built file-to-slice map (optional, built internally if not provided)
25
+ * @returns Array of { sourceFile, importPath, importLine }
26
+ */
27
+ export declare function findSliceDependencyDetails(slices: Slice[], fromSliceName: string, toSliceName: string, fileToSlice?: Map<string, string>): Array<{
28
+ sourceFile: SourceFile;
29
+ importPath: string;
30
+ importLine: number;
31
+ }>;
32
+ //# sourceMappingURL=slice-graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slice-graph.d.ts","sourceRoot":"","sources":["../../src/helpers/slice-graph.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAG/C;;;GAGG;AAEH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;CACX;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAQxE;AAsCD,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,KAAK,EAAE,EACf,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,SAAS,EAAE,CAcb;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,KAAK,EAAE,EACf,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,KAAK,CAAC;IAAE,UAAU,EAAE,UAAU,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAwB3E"}
@@ -0,0 +1,89 @@
1
+ import { getDependencyDecls } from '../core/module-dependencies.js';
2
+ /**
3
+ * Build a reverse lookup map: file path -> slice name.
4
+ * Shared by buildSliceDependencyGraph and findSliceDependencyDetails.
5
+ */
6
+ export function buildFileToSliceMap(slices) {
7
+ const fileToSlice = new Map();
8
+ for (const slice of slices) {
9
+ for (const file of slice.files) {
10
+ fileToSlice.set(file.getFilePath(), slice.name);
11
+ }
12
+ }
13
+ return fileToSlice;
14
+ }
15
+ /**
16
+ * Build a directed dependency graph between slices.
17
+ *
18
+ * For each file in each slice, resolve its imports. If an imported file
19
+ * belongs to a different slice, add a directed edge from the importing
20
+ * slice to the imported slice.
21
+ *
22
+ * @param slices - The resolved slices
23
+ * @param fileToSlice - Pre-built file-to-slice map (optional, built internally if not provided)
24
+ * @returns Unique directed edges between slices
25
+ */
26
+ /**
27
+ * Collect unique slice edges from a single file's imports.
28
+ */
29
+ function collectEdgesFromFile(file, sliceName, fileToSlice, edgeSet, edges) {
30
+ for (const importDecl of getDependencyDecls(file)) {
31
+ const resolved = importDecl.getModuleSpecifierSourceFile();
32
+ if (!resolved)
33
+ continue;
34
+ const targetSlice = fileToSlice.get(resolved.getFilePath());
35
+ if (targetSlice && targetSlice !== sliceName) {
36
+ const edgeKey = `${sliceName}->${targetSlice}`;
37
+ if (!edgeSet.has(edgeKey)) {
38
+ edgeSet.add(edgeKey);
39
+ edges.push({ from: sliceName, to: targetSlice });
40
+ }
41
+ }
42
+ }
43
+ }
44
+ export function buildSliceDependencyGraph(slices, fileToSlice) {
45
+ const map = fileToSlice ?? buildFileToSliceMap(slices);
46
+ // Collect unique edges
47
+ const edgeSet = new Set();
48
+ const edges = [];
49
+ for (const slice of slices) {
50
+ for (const file of slice.files) {
51
+ collectEdgesFromFile(file, slice.name, map, edgeSet, edges);
52
+ }
53
+ }
54
+ return edges;
55
+ }
56
+ /**
57
+ * Find which specific files cause a dependency from one slice to another.
58
+ * Used for detailed violation messages.
59
+ *
60
+ * @param slices - The resolved slices
61
+ * @param fromSliceName - Source slice name
62
+ * @param toSliceName - Target slice name
63
+ * @param fileToSlice - Pre-built file-to-slice map (optional, built internally if not provided)
64
+ * @returns Array of { sourceFile, importPath, importLine }
65
+ */
66
+ export function findSliceDependencyDetails(slices, fromSliceName, toSliceName, fileToSlice) {
67
+ const map = fileToSlice ?? buildFileToSliceMap(slices);
68
+ const fromSlice = slices.find((s) => s.name === fromSliceName);
69
+ if (!fromSlice)
70
+ return [];
71
+ const details = [];
72
+ for (const file of fromSlice.files) {
73
+ for (const importDecl of getDependencyDecls(file)) {
74
+ const resolved = importDecl.getModuleSpecifierSourceFile();
75
+ if (!resolved)
76
+ continue;
77
+ const targetSlice = map.get(resolved.getFilePath());
78
+ if (targetSlice === toSliceName) {
79
+ details.push({
80
+ sourceFile: file,
81
+ importPath: resolved.getFilePath(),
82
+ importLine: importDecl.getStartLineNumber(),
83
+ });
84
+ }
85
+ }
86
+ }
87
+ return details;
88
+ }
89
+ //# sourceMappingURL=slice-graph.js.map