@shortlink-org/portolan 0.1.0 → 0.2.1

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 (381) hide show
  1. package/README.md +69 -205
  2. package/cli/init.mjs +285 -0
  3. package/cli/init.test.mjs +158 -0
  4. package/cli/portolan.mjs +37 -73
  5. package/index.html +19 -0
  6. package/package.json +5 -10
  7. package/plugins/README.md +66 -27
  8. package/plugins/portolan-go.wasm +0 -0
  9. package/portolan.json +52 -73
  10. package/public/landing/cats/bug-hunter.webp +0 -0
  11. package/public/landing/cats/compass-nap.webp +0 -0
  12. package/public/landing/cats/diagrammer.webp +0 -0
  13. package/public/landing/cats/docs-reader.webp +0 -0
  14. package/public/landing/cats/laptop.webp +0 -0
  15. package/public/landing/cats/map-inspector.webp +0 -0
  16. package/public/landing/cats/server-break.webp +0 -0
  17. package/public/landing/cats/star-mapper.webp +0 -0
  18. package/public/landing/cats/system-builder.webp +0 -0
  19. package/public/landing/cats/thread-tangle.webp +0 -0
  20. package/public/og.png +0 -0
  21. package/public/readme-header.webp +0 -0
  22. package/schema/portolan.schema.json +180 -0
  23. package/scripts/builtin-plugins.mjs +14 -0
  24. package/scripts/delivery-presets.mjs +353 -0
  25. package/scripts/gen.mjs +37 -4
  26. package/scripts/history.mjs +126 -0
  27. package/scripts/history.test.mjs +110 -0
  28. package/scripts/host-plugins/fetch-bsr.mjs +351 -0
  29. package/{plugins/fetch-bsr/options.schema.json → scripts/host-plugins/fetch-bsr.options.json} +4 -0
  30. package/scripts/host-plugins/fetch-bsr.test.mjs +212 -0
  31. package/scripts/host-plugins/fetch-csr.mjs +386 -0
  32. package/scripts/host-plugins/fetch-csr.test.mjs +178 -0
  33. package/scripts/host-plugins/fetch-git.mjs +379 -0
  34. package/scripts/host-plugins/fetch-git.test.mjs +210 -0
  35. package/scripts/local-api.mjs +27 -10
  36. package/scripts/local-api.test.mjs +85 -2
  37. package/scripts/manifest.mjs +3 -2
  38. package/scripts/package-smoke.mjs +24 -3
  39. package/scripts/plugin-host.mjs +77 -18
  40. package/scripts/plugin-host.test.mjs +50 -1
  41. package/scripts/plugin-wasm-worker.mjs +6 -3
  42. package/scripts/run-builtin.mjs +6 -26
  43. package/scripts/schema.mjs +6 -1
  44. package/src/app/App.tsx +24 -429
  45. package/src/app/Breadcrumbs.test.ts +7 -0
  46. package/src/app/Breadcrumbs.tsx +15 -2
  47. package/src/app/CatalogApp.tsx +436 -0
  48. package/src/app/Sidebar.tsx +0 -1
  49. package/src/chat/ChatPanel.tsx +98 -41
  50. package/src/chat/Composer.tsx +4 -2
  51. package/src/chat/Conversation.tsx +79 -15
  52. package/src/chat/Header.tsx +43 -9
  53. package/src/chat/Starter.tsx +64 -3
  54. package/src/chat/Steps.tsx +1 -1
  55. package/src/chat/flags.test.ts +51 -14
  56. package/src/chat/flags.ts +8 -2
  57. package/src/chat/page-context.test.ts +51 -0
  58. package/src/chat/page-context.ts +128 -0
  59. package/src/chat/prompt.test.ts +49 -1
  60. package/src/chat/prompt.ts +42 -1
  61. package/src/chat/tools.ts +7 -2
  62. package/src/chat/transport.ts +16 -4
  63. package/src/components/ProblemRow.tsx +182 -0
  64. package/src/data.ts +20 -5
  65. package/src/er/ErCanvas.tsx +1 -1
  66. package/src/graph/DependencyGraph.tsx +10 -1
  67. package/src/graph/FocusedEventGraph.tsx +1 -1
  68. package/src/graph/GraphToolbar.tsx +2 -4
  69. package/src/index.css +220 -2
  70. package/src/landing/DraggableReveal.tsx +168 -0
  71. package/src/landing/EstateGraph.tsx +28 -0
  72. package/src/landing/FlowPlayback.tsx +282 -0
  73. package/src/landing/HeroMap.tsx +128 -0
  74. package/src/landing/LandingPage.tsx +757 -0
  75. package/src/landing/ProductFrame.tsx +68 -0
  76. package/src/landing/ProductTour.tsx +371 -0
  77. package/src/landing/catalog.ts +25 -0
  78. package/src/landing/motion.tsx +52 -0
  79. package/src/lib/all-problems.ts +28 -0
  80. package/src/lib/local-api.ts +35 -1
  81. package/src/lib/setup-info.test.ts +8 -0
  82. package/src/lib/setup-info.ts +3 -2
  83. package/src/lib/source-code.ts +2 -1
  84. package/src/likec4/C4View.tsx +5 -0
  85. package/src/likec4/InteractiveView.tsx +5 -1
  86. package/src/map/ContextMapGraph.tsx +47 -20
  87. package/src/pages/ContextMap.tsx +5 -1
  88. package/src/pages/FlowDetail.tsx +24 -7
  89. package/src/pages/Overview.tsx +68 -12
  90. package/src/pages/Problems.tsx +6 -193
  91. package/src/pages/Settings.tsx +133 -108
  92. package/src/pages/settings/DeliverySettings.tsx +229 -0
  93. package/src/pages/settings/PreferencesSettings.tsx +101 -0
  94. package/src/routes.test.ts +20 -0
  95. package/src/routes.ts +13 -1
  96. package/vite.config.ts +17 -9
  97. package/catalog/enum_test.go +0 -46
  98. package/catalog/model.go +0 -932
  99. package/catalog/roundtrip_test.go +0 -185
  100. package/catalog/via_test.go +0 -38
  101. package/go.mod +0 -14
  102. package/go.sum +0 -14
  103. package/internal/commands/cargo.go +0 -154
  104. package/internal/commands/commands.go +0 -143
  105. package/internal/commands/commands_test.go +0 -323
  106. package/internal/commands/gradle.go +0 -77
  107. package/internal/commands/justfile.go +0 -82
  108. package/internal/commands/makefile.go +0 -106
  109. package/internal/commands/maven.go +0 -93
  110. package/internal/commands/packagejson.go +0 -159
  111. package/internal/commands/pyproject.go +0 -169
  112. package/internal/commands/taskfile.go +0 -101
  113. package/internal/commands/testdata/estate/.cargo/config.toml +0 -7
  114. package/internal/commands/testdata/estate/Makefile +0 -33
  115. package/internal/commands/testdata/estate/Taskfile.yml +0 -21
  116. package/internal/commands/testdata/estate/build.gradle.kts +0 -21
  117. package/internal/commands/testdata/estate/justfile +0 -20
  118. package/internal/commands/testdata/estate/package.json +0 -13
  119. package/internal/commands/testdata/estate/pom.xml +0 -29
  120. package/internal/commands/testdata/estate/pyproject.toml +0 -27
  121. package/internal/commands/testdata/estate/xtask/src/main.rs +0 -27
  122. package/internal/commands/testdata/golden/commands.json +0 -305
  123. package/internal/gohttp/analyze.go +0 -2500
  124. package/internal/gohttp/endpoints.go +0 -1067
  125. package/internal/gohttp/roots.go +0 -320
  126. package/internal/gohttp/typed.go +0 -143
  127. package/internal/goscan/constants.go +0 -85
  128. package/internal/goscan/goscan_test.go +0 -227
  129. package/internal/goscan/names.go +0 -52
  130. package/internal/goscan/parse_test.go +0 -11
  131. package/internal/goscan/source.go +0 -36
  132. package/internal/goscan/tree.go +0 -155
  133. package/internal/goscan/types.go +0 -99
  134. package/internal/wsdl/ids.go +0 -127
  135. package/internal/wsdl/ids_test.go +0 -21
  136. package/internal/wsdl/model.go +0 -62
  137. package/internal/wsdl/parse.go +0 -920
  138. package/internal/wsdl/parse_test.go +0 -133
  139. package/plugin/describe.go +0 -107
  140. package/plugin/describe_test.go +0 -114
  141. package/plugin/protocol.go +0 -117
  142. package/plugin/schematest/schematest.go +0 -126
  143. package/plugins/extract-adr/describe.go +0 -19
  144. package/plugins/extract-adr/describe_test.go +0 -11
  145. package/plugins/extract-adr/extract.go +0 -153
  146. package/plugins/extract-adr/extract_test.go +0 -350
  147. package/plugins/extract-adr/history.go +0 -99
  148. package/plugins/extract-adr/main.go +0 -65
  149. package/plugins/extract-adr/parse.go +0 -642
  150. package/plugins/extract-adr/parse_test.go +0 -405
  151. package/plugins/extract-asyncapi/describe.go +0 -19
  152. package/plugins/extract-asyncapi/describe_test.go +0 -11
  153. package/plugins/extract-asyncapi/extract.go +0 -315
  154. package/plugins/extract-asyncapi/extract_test.go +0 -197
  155. package/plugins/extract-asyncapi/main.go +0 -48
  156. package/plugins/extract-asyncapi/spec.go +0 -151
  157. package/plugins/extract-commands/describe.go +0 -19
  158. package/plugins/extract-commands/describe_test.go +0 -11
  159. package/plugins/extract-commands/extract.go +0 -79
  160. package/plugins/extract-commands/extract_test.go +0 -92
  161. package/plugins/extract-commands/main.go +0 -55
  162. package/plugins/extract-csr/avro.go +0 -258
  163. package/plugins/extract-csr/describe.go +0 -19
  164. package/plugins/extract-csr/describe_test.go +0 -11
  165. package/plugins/extract-csr/extract.go +0 -338
  166. package/plugins/extract-csr/extract_test.go +0 -374
  167. package/plugins/extract-csr/jsonschema.go +0 -343
  168. package/plugins/extract-csr/lock.go +0 -25
  169. package/plugins/extract-csr/main.go +0 -84
  170. package/plugins/extract-csr/subject.go +0 -102
  171. package/plugins/extract-flows/describe.go +0 -19
  172. package/plugins/extract-flows/describe_test.go +0 -11
  173. package/plugins/extract-flows/extract.go +0 -91
  174. package/plugins/extract-flows/main.go +0 -45
  175. package/plugins/extract-flows/parse.go +0 -593
  176. package/plugins/extract-flows/parse_test.go +0 -204
  177. package/plugins/extract-glossary/describe.go +0 -19
  178. package/plugins/extract-glossary/describe_test.go +0 -11
  179. package/plugins/extract-glossary/extract.go +0 -115
  180. package/plugins/extract-glossary/extract_test.go +0 -220
  181. package/plugins/extract-glossary/main.go +0 -59
  182. package/plugins/extract-glossary/parse.go +0 -214
  183. package/plugins/extract-glossary/parse_test.go +0 -203
  184. package/plugins/extract-go/aggregate.go +0 -214
  185. package/plugins/extract-go/client.go +0 -409
  186. package/plugins/extract-go/client_test.go +0 -266
  187. package/plugins/extract-go/describe.go +0 -19
  188. package/plugins/extract-go/describe_test.go +0 -11
  189. package/plugins/extract-go/enum.go +0 -195
  190. package/plugins/extract-go/enum_test.go +0 -82
  191. package/plugins/extract-go/event.go +0 -99
  192. package/plugins/extract-go/extract.go +0 -191
  193. package/plugins/extract-go/extract_test.go +0 -261
  194. package/plugins/extract-go/flow.go +0 -1441
  195. package/plugins/extract-go/flow_test.go +0 -609
  196. package/plugins/extract-go/httpclient.go +0 -174
  197. package/plugins/extract-go/httpclient_test.go +0 -296
  198. package/plugins/extract-go/ids.go +0 -92
  199. package/plugins/extract-go/layout.go +0 -225
  200. package/plugins/extract-go/layout_test.go +0 -125
  201. package/plugins/extract-go/lifecycle.go +0 -324
  202. package/plugins/extract-go/lifecycle_test.go +0 -108
  203. package/plugins/extract-go/main.go +0 -79
  204. package/plugins/extract-go/operation.go +0 -157
  205. package/plugins/extract-go/source.go +0 -316
  206. package/plugins/extract-go/transport.go +0 -321
  207. package/plugins/extract-go/transport_test.go +0 -145
  208. package/plugins/extract-go/wiring.go +0 -434
  209. package/plugins/extract-go-nats/describe.go +0 -19
  210. package/plugins/extract-go-nats/describe_test.go +0 -11
  211. package/plugins/extract-go-nats/extract.go +0 -177
  212. package/plugins/extract-go-nats/extract_test.go +0 -389
  213. package/plugins/extract-go-nats/index.go +0 -379
  214. package/plugins/extract-go-nats/main.go +0 -42
  215. package/plugins/extract-go-nats/resolve.go +0 -161
  216. package/plugins/extract-go-nats/sites.go +0 -224
  217. package/plugins/extract-graphql/describe.go +0 -19
  218. package/plugins/extract-graphql/describe_test.go +0 -11
  219. package/plugins/extract-graphql/extract.go +0 -433
  220. package/plugins/extract-graphql/extract_test.go +0 -256
  221. package/plugins/extract-graphql/ids.go +0 -49
  222. package/plugins/extract-graphql/lex.go +0 -237
  223. package/plugins/extract-graphql/main.go +0 -51
  224. package/plugins/extract-graphql/parse.go +0 -621
  225. package/plugins/extract-graphql/parse_test.go +0 -122
  226. package/plugins/extract-http-clients/describe.go +0 -19
  227. package/plugins/extract-http-clients/describe_test.go +0 -11
  228. package/plugins/extract-http-clients/extract.go +0 -705
  229. package/plugins/extract-http-clients/extract_test.go +0 -1263
  230. package/plugins/extract-http-clients/main.go +0 -42
  231. package/plugins/extract-openapi/describe.go +0 -19
  232. package/plugins/extract-openapi/describe_test.go +0 -11
  233. package/plugins/extract-openapi/discover.go +0 -243
  234. package/plugins/extract-openapi/extract.go +0 -526
  235. package/plugins/extract-openapi/extract_test.go +0 -545
  236. package/plugins/extract-openapi/main.go +0 -75
  237. package/plugins/extract-openapi/spec.go +0 -350
  238. package/plugins/extract-project/describe.go +0 -19
  239. package/plugins/extract-project/describe_test.go +0 -11
  240. package/plugins/extract-project/extract.go +0 -221
  241. package/plugins/extract-project/extract_test.go +0 -109
  242. package/plugins/extract-project/main.go +0 -41
  243. package/plugins/extract-proto/ast.go +0 -125
  244. package/plugins/extract-proto/consumes.go +0 -77
  245. package/plugins/extract-proto/describe.go +0 -19
  246. package/plugins/extract-proto/extract.go +0 -293
  247. package/plugins/extract-proto/extract_test.go +0 -459
  248. package/plugins/extract-proto/ids.go +0 -89
  249. package/plugins/extract-proto/ids_test.go +0 -57
  250. package/plugins/extract-proto/lex.go +0 -285
  251. package/plugins/extract-proto/main.go +0 -100
  252. package/plugins/extract-proto/module.go +0 -120
  253. package/plugins/extract-proto/parse.go +0 -720
  254. package/plugins/extract-proto/parse_test.go +0 -307
  255. package/plugins/extract-proto/provides.go +0 -236
  256. package/plugins/extract-proto/resolve.go +0 -222
  257. package/plugins/extract-proto/resolve_test.go +0 -119
  258. package/plugins/extract-redis/describe.go +0 -19
  259. package/plugins/extract-redis/describe_test.go +0 -11
  260. package/plugins/extract-redis/extract.go +0 -183
  261. package/plugins/extract-redis/extract_test.go +0 -168
  262. package/plugins/extract-redis/keyspaces.go +0 -469
  263. package/plugins/extract-redis/main.go +0 -44
  264. package/plugins/extract-river/describe.go +0 -19
  265. package/plugins/extract-river/describe_test.go +0 -11
  266. package/plugins/extract-river/extract.go +0 -507
  267. package/plugins/extract-river/extract_test.go +0 -132
  268. package/plugins/extract-river/main.go +0 -42
  269. package/plugins/extract-sql/ddl.go +0 -893
  270. package/plugins/extract-sql/ddl_test.go +0 -401
  271. package/plugins/extract-sql/describe.go +0 -19
  272. package/plugins/extract-sql/describe_test.go +0 -11
  273. package/plugins/extract-sql/layout.go +0 -221
  274. package/plugins/extract-sql/layout_test.go +0 -55
  275. package/plugins/extract-sql/lineage.go +0 -107
  276. package/plugins/extract-sql/main.go +0 -141
  277. package/plugins/extract-sql/maps.go +0 -564
  278. package/plugins/extract-sql/maps_java.go +0 -117
  279. package/plugins/extract-sql/maps_rust.go +0 -333
  280. package/plugins/extract-sql/maps_rust_test.go +0 -70
  281. package/plugins/extract-sql/maps_test.go +0 -204
  282. package/plugins/extract-sql/maps_ts.go +0 -398
  283. package/plugins/extract-sql/maps_ts_test.go +0 -136
  284. package/plugins/extract-sql/projection.go +0 -70
  285. package/plugins/extract-sql/projection_test.go +0 -50
  286. package/plugins/extract-sql/store.go +0 -420
  287. package/plugins/extract-sql/store_test.go +0 -233
  288. package/plugins/extract-sql/view.go +0 -295
  289. package/plugins/extract-watermill/describe.go +0 -19
  290. package/plugins/extract-watermill/describe_test.go +0 -11
  291. package/plugins/extract-watermill/extract.go +0 -1228
  292. package/plugins/extract-watermill/extract_test.go +0 -234
  293. package/plugins/extract-watermill/main.go +0 -41
  294. package/plugins/extract-wsdl/describe.go +0 -19
  295. package/plugins/extract-wsdl/describe_test.go +0 -11
  296. package/plugins/extract-wsdl/extract.go +0 -148
  297. package/plugins/extract-wsdl/extract_test.go +0 -45
  298. package/plugins/extract-wsdl/main.go +0 -53
  299. package/plugins/fetch-bsr/auth.go +0 -114
  300. package/plugins/fetch-bsr/bsr.go +0 -240
  301. package/plugins/fetch-bsr/cache.go +0 -66
  302. package/plugins/fetch-bsr/describe.go +0 -19
  303. package/plugins/fetch-bsr/fetch.go +0 -192
  304. package/plugins/fetch-bsr/fetch_test.go +0 -465
  305. package/plugins/fetch-bsr/lock.go +0 -71
  306. package/plugins/fetch-bsr/main.go +0 -117
  307. package/plugins/fetch-csr/auth.go +0 -95
  308. package/plugins/fetch-csr/cache.go +0 -69
  309. package/plugins/fetch-csr/describe.go +0 -19
  310. package/plugins/fetch-csr/describe_test.go +0 -11
  311. package/plugins/fetch-csr/fetch.go +0 -254
  312. package/plugins/fetch-csr/fetch_test.go +0 -494
  313. package/plugins/fetch-csr/lock.go +0 -95
  314. package/plugins/fetch-csr/main.go +0 -122
  315. package/plugins/fetch-csr/registry.go +0 -209
  316. package/plugins/fetch-git/cache.go +0 -65
  317. package/plugins/fetch-git/describe.go +0 -19
  318. package/plugins/fetch-git/describe_test.go +0 -11
  319. package/plugins/fetch-git/fetch.go +0 -181
  320. package/plugins/fetch-git/fetch_test.go +0 -332
  321. package/plugins/fetch-git/git.go +0 -169
  322. package/plugins/fetch-git/lock.go +0 -72
  323. package/plugins/fetch-git/main.go +0 -127
  324. package/plugins/fetch-git/offline.go +0 -39
  325. package/plugins/fetch-git/pin.go +0 -90
  326. package/plugins/fetch-git/pin_test.go +0 -74
  327. package/plugins/gen-backstage/describe.go +0 -17
  328. package/plugins/gen-backstage/main.go +0 -22
  329. package/plugins/gen-backstage/plugin.go +0 -473
  330. package/plugins/gen-backstage/plugin_test.go +0 -145
  331. package/plugins/gen-backstage.wasm +0 -0
  332. package/plugins/gen-markdown/adr.go +0 -162
  333. package/plugins/gen-markdown/aggregate.go +0 -362
  334. package/plugins/gen-markdown/canonical.go +0 -93
  335. package/plugins/gen-markdown/context.go +0 -90
  336. package/plugins/gen-markdown/coverage_test.go +0 -89
  337. package/plugins/gen-markdown/describe.go +0 -19
  338. package/plugins/gen-markdown/describe_test.go +0 -11
  339. package/plugins/gen-markdown/external.go +0 -71
  340. package/plugins/gen-markdown/flow.go +0 -277
  341. package/plugins/gen-markdown/glossary.go +0 -76
  342. package/plugins/gen-markdown/glossary_test.go +0 -148
  343. package/plugins/gen-markdown/llms.go +0 -302
  344. package/plugins/gen-markdown/main.go +0 -22
  345. package/plugins/gen-markdown/markdown.go +0 -254
  346. package/plugins/gen-markdown/markdown_test.go +0 -100
  347. package/plugins/gen-markdown/module.go +0 -107
  348. package/plugins/gen-markdown/plugin.go +0 -39
  349. package/plugins/gen-markdown/quality_test.go +0 -176
  350. package/plugins/gen-markdown/redis_test.go +0 -38
  351. package/plugins/gen-markdown/render.go +0 -344
  352. package/plugins/gen-markdown/render_test.go +0 -186
  353. package/plugins/gen-markdown/service.go +0 -456
  354. package/plugins/gen-markdown/source.go +0 -177
  355. package/plugins/gen-markdown/store.go +0 -201
  356. package/plugins/gen-markdown.wasm +0 -0
  357. package/plugins/gen-mermaid/describe.go +0 -17
  358. package/plugins/gen-mermaid/main.go +0 -22
  359. package/plugins/gen-mermaid/plugin.go +0 -104
  360. package/plugins/gen-mermaid/plugin_test.go +0 -33
  361. package/plugins/gen-mermaid.wasm +0 -0
  362. package/plugins/openapi/ids.go +0 -261
  363. package/plugins/openapi/ids_test.go +0 -98
  364. package/plugins/verify-codeowners/describe.go +0 -19
  365. package/plugins/verify-codeowners/describe_test.go +0 -11
  366. package/plugins/verify-codeowners/main.go +0 -75
  367. package/plugins/verify-codeowners/match.go +0 -85
  368. package/plugins/verify-codeowners/match_test.go +0 -47
  369. package/plugins/verify-codeowners/owners.go +0 -164
  370. package/plugins/verify-codeowners/owners_test.go +0 -225
  371. package/plugins/verify-codeowners/parse.go +0 -90
  372. package/plugins/verify-codeowners/parse_test.go +0 -62
  373. package/plugins/verify-otel/describe.go +0 -19
  374. package/plugins/verify-otel/describe_test.go +0 -11
  375. package/plugins/verify-otel/main.go +0 -53
  376. package/plugins/verify-otel/match.go +0 -336
  377. package/plugins/verify-otel/otlp.go +0 -200
  378. package/plugins/verify-otel/verify.go +0 -734
  379. package/plugins/verify-otel/verify_test.go +0 -460
  380. /package/{plugins/fetch-csr/options.schema.json → scripts/host-plugins/fetch-csr.options.json} +0 -0
  381. /package/{plugins/fetch-git/options.schema.json → scripts/host-plugins/fetch-git.options.json} +0 -0
@@ -1,409 +0,0 @@
1
- package main
2
-
3
- import (
4
- "go/ast"
5
- "go/token"
6
- "go/types"
7
- "strconv"
8
- "strings"
9
-
10
- "github.com/shortlink-org/portolan/catalog"
11
- )
12
-
13
- // A call to another service is read off the generated client, because that is
14
- // where the fact is written down: protoc-gen-go-grpc emits one constant per
15
- // rpc holding the full method name, and the client interface beside it;
16
- // oapi-codegen emits a request builder per operation with its route, beside
17
- // the document it was generated from (httpclient.go). The use case never
18
- // names either - it holds a port - so the chain is port → provider → adapter
19
- // → client, and every link of it is in the tree.
20
-
21
- // client is one generated client and the calls it carries.
22
- type client struct {
23
- // pkg is what the manifest's peers map is keyed by: the proto package,
24
- // "risk.v1", or the api id, "auth.v1".
25
- pkg string
26
- // methods maps a Go method name to the call id: "risk.v1.RiskService/Assess",
27
- // "auth.v1.Sessions/login".
28
- methods map[string]string
29
- // source is the generated file, or the document, the names were read from.
30
- source string
31
- // external is the system the document beside an HTTP client is titled
32
- // after, as an id: what the far end is called when no peers line says it
33
- // is one of ours. Empty for a gRPC client, whose proto names no system.
34
- external string
35
- }
36
-
37
- // readClients finds every client a package declares, keyed by the type a port
38
- // would hold it as: "RiskServiceClient" for gRPC, "ClientWithResponses" and
39
- // its three siblings for HTTP. The problem, when there is one, says why an
40
- // HTTP client could not be named.
41
- func readClients(pkg *pkg) (map[string]client, string) {
42
- if isHTTPClient(pkg) {
43
- return readHTTPClient(pkg)
44
- }
45
- out := map[string]client{}
46
-
47
- for _, file := range pkg.files {
48
- for _, decl := range file.Decls {
49
- gen, ok := decl.(*ast.GenDecl)
50
- if !ok || gen.Tok != token.CONST {
51
- continue
52
- }
53
- for _, spec := range gen.Specs {
54
- value, ok := spec.(*ast.ValueSpec)
55
- if !ok {
56
- continue
57
- }
58
- for i, name := range value.Names {
59
- if i >= len(value.Values) {
60
- continue
61
- }
62
- lit, ok := value.Values[i].(*ast.BasicLit)
63
- if !ok || lit.Kind != token.STRING {
64
- continue
65
- }
66
- full, err := strconv.Unquote(lit.Value)
67
- if err != nil {
68
- continue
69
- }
70
- goService, service, method, ok := splitFullMethod(name.Name, full)
71
- if !ok {
72
- continue
73
- }
74
-
75
- key := goService + "Client"
76
- c, known := out[key]
77
- if !known {
78
- c = client{
79
- pkg: lastDotPrefix(service),
80
- methods: map[string]string{},
81
- source: pkg.paths[file],
82
- }
83
- }
84
- c.methods[method] = service + "/" + method
85
- out[key] = c
86
- }
87
- }
88
- }
89
- }
90
-
91
- return out, ""
92
- }
93
-
94
- // splitFullMethod reads `RiskService_Assess_FullMethodName = "/risk.v1.RiskService/Assess"`
95
- // into the Go service name, the proto service name and the rpc.
96
- func splitFullMethod(constName, full string) (goService, service, method string, ok bool) {
97
- if !strings.HasSuffix(constName, "_FullMethodName") || !strings.HasPrefix(full, "/") {
98
- return "", "", "", false
99
- }
100
- service, method, found := strings.Cut(full[1:], "/")
101
- if !found || service == "" || method == "" || strings.Contains(method, "/") {
102
- return "", "", "", false
103
- }
104
- goService, ok = strings.CutSuffix(constName, "_"+method+"_FullMethodName")
105
- if !ok || goService == "" {
106
- return "", "", "", false
107
- }
108
-
109
- return goService, service, method, true
110
- }
111
-
112
- // lastDotPrefix is "risk.v1" for "risk.v1.RiskService".
113
- func lastDotPrefix(name string) string {
114
- if i := strings.LastIndex(name, "."); i >= 0 {
115
- return name[:i]
116
- }
117
-
118
- return name
119
- }
120
-
121
- // clientPkg reads the clients of a package by import path, once.
122
- func (r *flowReader) clientPkg(importPath string) map[string]client {
123
- if cached, ok := r.clients[importPath]; ok {
124
- return cached
125
- }
126
-
127
- var out map[string]client
128
- if rel, ok := r.relDir(importPath); ok {
129
- if pkg, err := parsePkg(r.root, rel); err == nil {
130
- var problem string
131
- out, problem = readClients(pkg)
132
- if problem != "" {
133
- r.b.Warn(r.opts.svcID, problem)
134
- }
135
- }
136
- }
137
- r.clients[importPath] = out
138
-
139
- return out
140
- }
141
-
142
- // relDir maps an import path inside this module to a directory under root.
143
- // Anything outside the module is not in the tree, and this reads the tree.
144
- func (r *flowReader) relDir(importPath string) (string, bool) {
145
- if r.module == "" {
146
- return "", false
147
- }
148
-
149
- return strings.CutPrefix(importPath, r.module+"/")
150
- }
151
-
152
- // clientOf resolves a type written as `riskpb.RiskServiceClient` to the client
153
- // it names, or says the type is not a generated client.
154
- func (r *flowReader) clientOf(declared string, imports map[string]string) (client, bool) {
155
- selector, name, found := strings.Cut(strings.TrimPrefix(declared, "*"), ".")
156
- if !found {
157
- return client{}, false
158
- }
159
- client, ok := r.clientPkg(imports[selector])[name]
160
-
161
- return client, ok
162
- }
163
-
164
- // rpcHop is one call on a port that turns out to be another service's rpc.
165
- type rpcHop struct {
166
- client client
167
- method string
168
- }
169
-
170
- // clientCalls says which rpcs a call on a port amounts to: none when the port
171
- // is not a client, one when the port IS the generated client, and whatever the
172
- // adapter's method calls when the port is a local interface bound to one in
173
- // assembly.
174
- func (r *flowReader) clientCalls(s *scope, declared, method string) []rpcHop {
175
- if client, ok := r.clientOf(declared, s.imports); ok {
176
- if _, known := client.methods[method]; !known {
177
- r.b.Warn(s.key, "port `"+declared+"` is a generated client with no rpc named "+method+"; the call is left out of the flow")
178
-
179
- return nil
180
- }
181
-
182
- return []rpcHop{{client: client, method: method}}
183
- }
184
-
185
- binding, ok := r.adapters[s.key+"."+declared]
186
- if !ok {
187
- return nil
188
- }
189
-
190
- return r.adapterCalls(s.key, declared, binding, method)
191
- }
192
-
193
- // adapterCalls reads the provider that binds a port to a client, follows it to
194
- // the adapter type it builds, and reads which rpcs the adapter's method runs.
195
- func (r *flowReader) adapterCalls(key, declared string, binding adapterDecl, method string) []rpcHop {
196
- var client client
197
- var clientType string
198
- for _, param := range params(binding.fn) {
199
- written := types.ExprString(param)
200
- if c, ok := r.clientOf(written, binding.imports); ok {
201
- client, clientType = c, strings.TrimPrefix(written, "*")
202
-
203
- break
204
- }
205
- }
206
- if clientType == "" {
207
- // A provider that builds the port out of something other than a
208
- // client is a binding of a different kind, and not one this can
209
- // follow to another service.
210
- return nil
211
- }
212
-
213
- adapter, adapterPkg, ok := r.adapterOf(binding)
214
- if !ok {
215
- r.b.Warn(key, "port `"+declared+"` is bound to a client of "+client.pkg+" but the provider's result could not be followed to a type; its calls are left out of the flow")
216
-
217
- return nil
218
- }
219
-
220
- fn := adapterPkg.methods(adapter)[method]
221
- if fn == nil {
222
- r.b.Warn(key, "port `"+declared+"` is adapted by "+adapter+", which has no method "+method+"; the call is left out of the flow")
223
-
224
- return nil
225
- }
226
-
227
- // The field of the adapter that holds the client, by name, so a call on it
228
- // can be told apart from a call on anything else the adapter holds.
229
- fields := map[string]string{}
230
- for _, decl := range adapterPkg.structs() {
231
- if decl.name == adapter {
232
- fields = structFields(decl.fields)
233
- }
234
- }
235
- imports := importsOf(adapterPkg)
236
- recv := receiverIdent(fn)
237
-
238
- var out []rpcHop
239
- seen := map[string]bool{}
240
- for _, site := range callSites(fn) {
241
- selector, ok := site.call.Fun.(*ast.SelectorExpr)
242
- if !ok {
243
- continue
244
- }
245
- inner, ok := selector.X.(*ast.SelectorExpr)
246
- if !ok {
247
- continue
248
- }
249
- owner, ok := inner.X.(*ast.Ident)
250
- if !ok || owner.Name != recv {
251
- continue
252
- }
253
- held, ok := r.clientOf(fields[inner.Sel.Name], imports)
254
- if !ok || held.pkg != client.pkg {
255
- continue
256
- }
257
- rpc := selector.Sel.Name
258
- if _, known := held.methods[rpc]; !known || seen[rpc] {
259
- continue
260
- }
261
- seen[rpc] = true
262
- out = append(out, rpcHop{client: held, method: rpc})
263
- }
264
-
265
- if len(out) == 0 {
266
- r.b.Warn(key, "port `"+declared+"` is adapted by "+adapter+"."+method+", which calls no rpc of the client; the call is left out of the flow")
267
- }
268
-
269
- return out
270
- }
271
-
272
- // adapterOf follows a provider's return to the type it builds: a literal of a
273
- // type declared beside it, or a constructor in another package of this module.
274
- func (r *flowReader) adapterOf(binding adapterDecl) (string, *pkg, bool) {
275
- expr := returnedExpr(binding.fn)
276
- if expr == nil {
277
- return "", nil, false
278
- }
279
- if unary, ok := expr.(*ast.UnaryExpr); ok && unary.Op == token.AND {
280
- expr = unary.X
281
- }
282
-
283
- switch x := expr.(type) {
284
- case *ast.CompositeLit:
285
- return r.typeIn(x.Type, binding)
286
- case *ast.CallExpr:
287
- selector, ok := x.Fun.(*ast.SelectorExpr)
288
- if !ok {
289
- return "", nil, false
290
- }
291
- owner, ok := selector.X.(*ast.Ident)
292
- if !ok {
293
- return "", nil, false
294
- }
295
- rel, ok := r.relDir(binding.imports[owner.Name])
296
- if !ok {
297
- return "", nil, false
298
- }
299
- pkg, err := parsePkg(r.root, rel)
300
- if err != nil {
301
- return "", nil, false
302
- }
303
- for _, file := range pkg.files {
304
- for _, decl := range file.Decls {
305
- fn, ok := decl.(*ast.FuncDecl)
306
- if !ok || fn.Recv != nil || fn.Name.Name != selector.Sel.Name {
307
- continue
308
- }
309
- if fn.Type.Results == nil || len(fn.Type.Results.List) == 0 {
310
- return "", nil, false
311
- }
312
- name := strings.TrimPrefix(types.ExprString(fn.Type.Results.List[0].Type), "*")
313
- if strings.Contains(name, ".") {
314
- return "", nil, false
315
- }
316
-
317
- return name, pkg, true
318
- }
319
- }
320
- }
321
-
322
- return "", nil, false
323
- }
324
-
325
- // typeIn resolves the type of a composite literal: `adapter{}` is in the
326
- // provider's own package, `risk.Client{}` in an imported one.
327
- func (r *flowReader) typeIn(expr ast.Expr, binding adapterDecl) (string, *pkg, bool) {
328
- switch t := expr.(type) {
329
- case *ast.Ident:
330
- return t.Name, binding.pkg, true
331
- case *ast.SelectorExpr:
332
- owner, ok := t.X.(*ast.Ident)
333
- if !ok {
334
- return "", nil, false
335
- }
336
- rel, ok := r.relDir(binding.imports[owner.Name])
337
- if !ok {
338
- return "", nil, false
339
- }
340
- pkg, err := parsePkg(r.root, rel)
341
- if err != nil {
342
- return "", nil, false
343
- }
344
-
345
- return t.Sel.Name, pkg, true
346
- }
347
-
348
- return "", nil, false
349
- }
350
-
351
- // returnedExpr is the single value of the function's last return.
352
- func returnedExpr(fn *ast.FuncDecl) ast.Expr {
353
- if fn == nil || fn.Body == nil || len(fn.Body.List) == 0 {
354
- return nil
355
- }
356
- ret, ok := fn.Body.List[len(fn.Body.List)-1].(*ast.ReturnStmt)
357
- if !ok || len(ret.Results) != 1 {
358
- return nil
359
- }
360
-
361
- return ret.Results[0]
362
- }
363
-
364
- // peerLane is the lane a call to another service lands in, and what the step
365
- // can claim about it. The manifest says which service answers to a proto
366
- // package; without that line the far end is a package name, which is not a
367
- // thing the catalog has, and the step says so rather than guessing.
368
- func (r *flowReader) peerLane(d *flowDraft, client client) (lane, peer string, status catalog.Status) {
369
- if service, ok := r.opts.peers[client.pkg]; ok {
370
- context, _, _ := strings.Cut(service, ".")
371
-
372
- return d.lane(catalog.Participant{ID: service, Kind: catalog.ParticipantService, Context: &context}), service, catalog.StatusDeclared
373
- }
374
-
375
- // A system outside the estate, with a contract: the call lands on an
376
- // operation its document declares, so the step is declared, and the lane
377
- // says what the far end is rather than pretending it is ours. The manifest
378
- // may name the system; failing that, the document beside the client does,
379
- // because a service that vendors a document and generates a client from
380
- // it is calling whatever that document is titled, and nothing in this
381
- // tree implements it.
382
- external := r.opts.externals[client.pkg]
383
- if external == "" && client.external != "" {
384
- external = client.external
385
- if !r.warnedPeer[client.pkg] {
386
- r.b.Warn(r.opts.svcID, "calls "+client.pkg+", which no peers line claims; read as calling "+external+", the system the document beside the client is titled after - add the package under `peers` if it is one of ours")
387
- r.warnedPeer[client.pkg] = true
388
- }
389
- }
390
- if external != "" {
391
- return d.lane(catalog.Participant{ID: external, Kind: catalog.ParticipantExternal}), external, catalog.StatusDeclared
392
- }
393
-
394
- if !r.warnedPeer[client.pkg] {
395
- r.b.Warn(r.opts.svcID, "calls "+client.pkg+" and the manifest names no peer for that package; add it under `peers` to say which service answers, or under `externals` when the far end is outside the estate, until then the calls are unresolved")
396
- r.warnedPeer[client.pkg] = true
397
- }
398
-
399
- // A bare name for the lane, as for the store: a participant that is not
400
- // a service must not carry a dot, which the diagram model reads as
401
- // containment. The package stays on the label, and on the call.
402
- lane = d.lane(catalog.Participant{
403
- ID: strings.ReplaceAll(client.pkg, ".", "-"),
404
- Kind: catalog.ParticipantUnknown,
405
- Label: client.pkg,
406
- })
407
-
408
- return lane, client.pkg, catalog.StatusUnresolved
409
- }
@@ -1,266 +0,0 @@
1
- package main
2
-
3
- import (
4
- "os"
5
- "path/filepath"
6
- "testing"
7
-
8
- "github.com/shortlink-org/portolan/catalog"
9
- "github.com/shortlink-org/portolan/plugin"
10
- )
11
-
12
- const generatedClient = `package riskpb
13
-
14
- import "google.golang.org/grpc"
15
-
16
- const (
17
- RiskService_Assess_FullMethodName = "/risk.v1.RiskService/Assess"
18
- RiskService_Report_FullMethodName = "/risk.v1.RiskService/Report"
19
- unrelated = "/not/a/method/name"
20
- )
21
-
22
- type RiskServiceClient interface {
23
- Assess(ctx context.Context, in *AssessRequest, opts ...grpc.CallOption) (*AssessResponse, error)
24
- Report(ctx context.Context, in *ReportRequest, opts ...grpc.CallOption) (*ReportResponse, error)
25
- }
26
- `
27
-
28
- // The rpc is read off the constant protoc-gen-go-grpc writes for it, which is
29
- // the one place in the tree the full name appears as a string.
30
- func TestClientsAreReadOffTheGeneratedNames(t *testing.T) {
31
- pkg, err := parseSource("risk_grpc.pb.go", generatedClient)
32
- if err != nil {
33
- t.Fatal(err)
34
- }
35
-
36
- clients, problem := readClients(pkg)
37
- if problem != "" {
38
- t.Fatal(problem)
39
- }
40
- client, ok := clients["RiskServiceClient"]
41
- if !ok {
42
- t.Fatalf("clients = %v", clients)
43
- }
44
- if client.pkg != "risk.v1" {
45
- t.Errorf("pkg = %q", client.pkg)
46
- }
47
- if client.methods["Assess"] != "risk.v1.RiskService/Assess" || client.methods["Report"] != "risk.v1.RiskService/Report" {
48
- t.Errorf("methods = %v", client.methods)
49
- }
50
- if len(client.methods) != 2 {
51
- t.Errorf("methods = %v, want the two rpcs and not the unrelated constant", client.methods)
52
- }
53
- if client.source != "risk_grpc.pb.go" {
54
- t.Errorf("source = %q", client.source)
55
- }
56
- }
57
-
58
- // The peer is the manifest's to name. With a line for the package the step
59
- // lands on a service; without one the far end is a package name, which the
60
- // catalog does not have, and the step says so.
61
- func TestThePeerIsTheManifestsToName(t *testing.T) {
62
- client := client{pkg: "risk.v1", methods: map[string]string{"Assess": "risk.v1.RiskService/Assess"}, source: "gen/risk_grpc.pb.go"}
63
-
64
- named := newFlowReader(t.TempDir(), flowOptions{svcID: "auth.auth", peers: map[string]string{"risk.v1": "shop.risk"}}, &plugin.Builder{})
65
- d := newDraft()
66
- named.rpcHop(d, rpcHop{client: client, method: "Assess"}, "usecase.go:12")
67
-
68
- step := d.steps[0].(*catalog.Step)
69
- if step.To != "shop.risk" || step.Kind != catalog.StepRPC || step.Ref != "risk.v1.RiskService/Assess" || step.Status != catalog.StatusDeclared {
70
- t.Errorf("step = %+v", step)
71
- }
72
- if lane := d.lanes[0]; lane.Kind != catalog.ParticipantService || lane.Context == nil || *lane.Context != "shop" {
73
- t.Errorf("lane = %+v", lane)
74
- }
75
- calls := named.consumes()
76
- if len(calls) != 1 || calls[0].Peer != "shop.risk" || calls[0].Source != "gen/risk_grpc.pb.go" || calls[0].Status != catalog.StatusDeclared {
77
- t.Errorf("consumes = %+v", calls)
78
- }
79
-
80
- b := &plugin.Builder{}
81
- unnamed := newFlowReader(t.TempDir(), flowOptions{svcID: "auth.auth"}, b)
82
- d = newDraft()
83
- unnamed.rpcHop(d, rpcHop{client: client, method: "Assess"}, "")
84
- unnamed.rpcHop(d, rpcHop{client: client, method: "Assess"}, "")
85
-
86
- step = d.steps[0].(*catalog.Step)
87
- if step.To != "risk-v1" || step.Status != catalog.StatusUnresolved {
88
- t.Errorf("step = %+v", step)
89
- }
90
- if lane := d.lanes[0]; lane.Kind != catalog.ParticipantUnknown || lane.ID != "risk-v1" || lane.Label != "risk.v1" {
91
- t.Errorf("lane = %+v, want a bare id with the package on the label", lane)
92
- }
93
- if calls := unnamed.consumes(); len(calls) != 1 || calls[0].Status != catalog.StatusUnresolved || calls[0].Peer != "risk.v1" {
94
- t.Errorf("consumes = %+v", calls)
95
- }
96
- if n := len(b.Response().Warnings()); n != 1 {
97
- t.Errorf("diagnostics = %d, want the one warning about the unnamed peer, said once", n)
98
- }
99
- }
100
-
101
- // A policy on somebody else's event is still a policy. Its trigger has an id
102
- // this tree cannot form, so the step names the type and resolves to nothing.
103
- func TestAPolicyOnAForeignEventIsKeptAndUnresolved(t *testing.T) {
104
- const policy = `package policy
105
-
106
- import (
107
- shopevents "github.com/acme/shop/events/v1"
108
- "github.com/example/auth/internal/domain/user/event"
109
- "github.com/example/auth/internal/pkg/helper"
110
- )
111
-
112
- type OnOrderPlaced struct{}
113
-
114
- func (p OnOrderPlaced) Handle(ctx context.Context, e any) error {
115
- placed, ok := e.(shopevents.OrderPlaced)
116
- _ = placed
117
- return nil
118
- }
119
-
120
- type OnPasswordChanged struct{}
121
-
122
- func (p OnPasswordChanged) Handle(ctx context.Context, e any) error {
123
- _, ok := e.(event.PasswordChanged)
124
- return nil
125
- }
126
-
127
- type OnNothing struct{}
128
-
129
- func (p OnNothing) Handle(ctx context.Context, e any) error {
130
- _, ok := e.(helper.Thing)
131
- return nil
132
- }
133
- `
134
- pkg, err := parseSource("policy.go", policy)
135
- if err != nil {
136
- t.Fatal(err)
137
- }
138
- r := &flowReader{opts: flowOptions{svcID: "auth.auth"}, module: "github.com/example/auth"}
139
- imports := importsOf(pkg)
140
-
141
- foreign, ok := r.assertedEvent(pkg.methods("OnOrderPlaced")["Handle"], imports)
142
- if !ok || foreign.foreign != "github.com/acme/shop/events/v1" || foreign.name != "OrderPlaced" || foreign.id != "" {
143
- t.Errorf("foreign = %+v %v", foreign, ok)
144
- }
145
-
146
- own, ok := r.assertedEvent(pkg.methods("OnPasswordChanged")["Handle"], imports)
147
- if !ok || own.foreign != "" || own.id != "auth.auth.user.PasswordChanged" {
148
- t.Errorf("own = %+v %v", own, ok)
149
- }
150
-
151
- if ref, ok := r.assertedEvent(pkg.methods("OnNothing")["Handle"], imports); ok {
152
- t.Errorf("a helper type of this module was read as an event: %+v", ref)
153
- }
154
- }
155
-
156
- // The whole chain, on a tree: a use case holds a port of its own, assembly
157
- // fills it with an adapter over a generated client, and the adapter's method
158
- // is what says which rpc the port's method amounts to.
159
- func TestAPortBoundToAClientIsARpcHop(t *testing.T) {
160
- root := t.TempDir()
161
- write := func(rel, contents string) {
162
- t.Helper()
163
- if err := os.MkdirAll(filepath.Dir(filepath.Join(root, rel)), 0o755); err != nil {
164
- t.Fatal(err)
165
- }
166
- if err := os.WriteFile(filepath.Join(root, rel), []byte(contents), 0o644); err != nil {
167
- t.Fatal(err)
168
- }
169
- }
170
-
171
- write("go.mod", "module github.com/example/auth\n\ngo 1.27\n")
172
- write("internal/infrastructure/risk/gen/riskpb/risk_grpc.pb.go", generatedClient)
173
- write("internal/infrastructure/risk/client.go", `package risk
174
-
175
- import (
176
- "context"
177
-
178
- "github.com/example/auth/internal/infrastructure/risk/gen/riskpb"
179
- )
180
-
181
- type Client struct {
182
- rpc riskpb.RiskServiceClient
183
- }
184
-
185
- func New(rpc riskpb.RiskServiceClient) *Client { return &Client{rpc: rpc} }
186
-
187
- func (c *Client) Verdict(ctx context.Context, userID string) (bool, error) {
188
- out, err := c.rpc.Assess(ctx, &riskpb.AssessRequest{UserId: userID})
189
- if err != nil {
190
- return false, err
191
- }
192
- return out.Block, nil
193
- }
194
- `)
195
- write("internal/di/provider/risk.go", `package provider
196
-
197
- import (
198
- "github.com/example/auth/internal/application/session/usecases/login"
199
- "github.com/example/auth/internal/infrastructure/risk"
200
- "github.com/example/auth/internal/infrastructure/risk/gen/riskpb"
201
- )
202
-
203
- func ProvideRisk(rpc riskpb.RiskServiceClient) login.Risk {
204
- return risk.New(rpc)
205
- }
206
- `)
207
- write("internal/application/session/usecases/login/usecase.go", `package login
208
-
209
- import (
210
- "context"
211
-
212
- "github.com/example/auth/internal/domain/session"
213
- )
214
-
215
- type Risk interface {
216
- Verdict(ctx context.Context, userID string) (bool, error)
217
- }
218
-
219
- type UseCase struct {
220
- repo session.Repository
221
- risk Risk
222
- }
223
-
224
- func (uc *UseCase) Handle(ctx context.Context, in dto.Input) error {
225
- block, err := uc.risk.Verdict(ctx, in.UserID)
226
- if err != nil {
227
- return err
228
- }
229
- if block {
230
- if err := uc.repo.Save(ctx, nil); err != nil {
231
- return err
232
- }
233
- return ErrBlocked
234
- }
235
- return uc.repo.Save(ctx, nil)
236
- }
237
- `)
238
-
239
- b := &plugin.Builder{}
240
- r := newFlowReader(root, flowOptions{context: "auth", svcID: "auth.auth", service: "auth", store: "pg", peers: map[string]string{"risk.v1": "shop.risk"}}, b)
241
- d := newDraft()
242
- d.lane(r.serviceLane())
243
- r.walkUseCase(d, "session/login", 0)
244
-
245
- if got := dump(d.steps); got != "s1:Assess alt3{s2:Save } s4:Save " {
246
- t.Fatalf("nodes = %q", got)
247
- }
248
- rpc := d.steps[0].(*catalog.Step)
249
- if rpc.Kind != catalog.StepRPC || rpc.To != "shop.risk" || rpc.Ref != "risk.v1.RiskService/Assess" || rpc.Status != catalog.StatusDeclared {
250
- t.Errorf("rpc step = %+v", rpc)
251
- }
252
- if rpc.Line != "internal/application/session/usecases/login/usecase.go:19" && filepath.Base(rpc.Line) == "" {
253
- t.Errorf("line = %q", rpc.Line)
254
- }
255
- alt := d.steps[1].(*catalog.Alt)
256
- if alt.Branches[0].Title != "block" || !alt.Branches[0].Terminal {
257
- t.Errorf("arm = %+v", alt.Branches[0])
258
- }
259
- calls := r.consumes()
260
- if len(calls) != 1 || calls[0].ID != "risk.v1.RiskService/Assess" || calls[0].Peer != "shop.risk" {
261
- t.Errorf("consumes = %+v", calls)
262
- }
263
- if diags := b.Response().Warnings(); len(diags) != 0 {
264
- t.Errorf("diagnostics = %+v", diags)
265
- }
266
- }
@@ -1,19 +0,0 @@
1
- package main
2
-
3
- import (
4
- _ "embed"
5
-
6
- "github.com/shortlink-org/portolan/plugin"
7
- )
8
-
9
- //go:embed options.schema.json
10
- var optionsSchema []byte
11
-
12
- func descriptor() plugin.Descriptor {
13
- return plugin.Descriptor{
14
- Name: "extract-go",
15
- Summary: "Reads a Go service with go/parser alone and answers with its domain: aggregates, events, use cases and the flows they imply.",
16
- Phases: []string{plugin.PhaseExtract},
17
- Options: optionsSchema,
18
- }
19
- }
@@ -1,11 +0,0 @@
1
- package main
2
-
3
- import (
4
- "testing"
5
-
6
- "github.com/shortlink-org/portolan/plugin/schematest"
7
- )
8
-
9
- func TestOptionsSchemaMatchesStruct(t *testing.T) {
10
- schematest.Check(t, optionsSchema, Options{})
11
- }