@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,379 +0,0 @@
1
- package main
2
-
3
- import (
4
- "go/ast"
5
- "go/token"
6
- "reflect"
7
- "sort"
8
- "strconv"
9
-
10
- "github.com/shortlink-org/portolan/internal/goscan"
11
- )
12
-
13
- const (
14
- natsPkg = "github.com/nats-io/nats.go"
15
- jsPkg = "github.com/nats-io/nats.go/jetstream"
16
- )
17
-
18
- // structType is a struct as the reader needs it: what type each field has, so
19
- // that `b.conn` is known to be a connection, and what a field defaults to
20
- // when its tag says, so that a subject read off config resolves.
21
- type structType struct {
22
- key string
23
- fields map[string]string
24
- defaults map[string]string
25
- }
26
-
27
- // function is one declared function or method: its parameters by name and
28
- // type, what it returns, and what its body assigns to which name.
29
- type function struct {
30
- key string
31
- name string
32
- receiver string
33
- file *goscan.File
34
- decl *ast.FuncDecl
35
- params []string
36
- types map[string]string
37
- results []string
38
- assigned map[string]assignment
39
- }
40
-
41
- // assignment is the last thing a local name was given: the expression, and
42
- // which of its values when the expression yields several.
43
- type assignment struct {
44
- expr ast.Expr
45
- index int
46
- }
47
-
48
- // scanner is the tree, and the shapes in it a nats call is read against.
49
- type scanner struct {
50
- *goscan.Tree
51
- structs map[string]*structType
52
- interfaces map[string][]string
53
- functions map[string]*function
54
- methods map[string][]*function
55
- byName map[string][]*function
56
- // typing is the locals whose type is being worked out right now, so a
57
- // name shadowed by an expression of itself - `js := js.Sub()` in an
58
- // inner block - ends rather than recurses.
59
- typing map[string]bool
60
- }
61
-
62
- func newScanner(tree *goscan.Tree) *scanner {
63
- return &scanner{
64
- Tree: tree,
65
- structs: map[string]*structType{},
66
- interfaces: map[string][]string{},
67
- functions: map[string]*function{},
68
- methods: map[string][]*function{},
69
- byName: map[string][]*function{},
70
- typing: map[string]bool{},
71
- }
72
- }
73
-
74
- func (s *scanner) index() {
75
- for _, file := range s.Files {
76
- for _, decl := range file.Node.Decls {
77
- switch d := decl.(type) {
78
- case *ast.GenDecl:
79
- if d.Tok != token.TYPE {
80
- continue
81
- }
82
- for _, raw := range d.Specs {
83
- s.indexType(file, raw.(*ast.TypeSpec))
84
- }
85
- case *ast.FuncDecl:
86
- s.indexFunction(file, d)
87
- }
88
- }
89
- }
90
- }
91
-
92
- func (s *scanner) indexType(file *goscan.File, spec *ast.TypeSpec) {
93
- key := file.Pkg + "." + spec.Name.Name
94
- switch body := spec.Type.(type) {
95
- case *ast.StructType:
96
- st := &structType{key: key, fields: map[string]string{}, defaults: map[string]string{}}
97
- for _, field := range body.Fields.List {
98
- typeKey := s.TypeKey(field.Type, file)
99
- def := ""
100
- if field.Tag != nil {
101
- tag, _ := strconv.Unquote(field.Tag.Value)
102
- def = reflect.StructTag(tag).Get("default")
103
- }
104
- for _, name := range field.Names {
105
- st.fields[name.Name] = typeKey
106
- if def != "" {
107
- st.defaults[name.Name] = def
108
- }
109
- }
110
- }
111
- s.structs[key] = st
112
- case *ast.InterfaceType:
113
- // Embedded interfaces are not followed: the port a service writes for
114
- // its bus names its methods itself.
115
- var names []string
116
- for _, method := range body.Methods.List {
117
- for _, name := range method.Names {
118
- names = append(names, name.Name)
119
- }
120
- }
121
- sort.Strings(names)
122
- s.interfaces[key] = names
123
- }
124
- }
125
-
126
- func (s *scanner) indexFunction(file *goscan.File, decl *ast.FuncDecl) {
127
- key := file.Pkg + "." + decl.Name.Name
128
- receiver := ""
129
- if decl.Recv != nil && len(decl.Recv.List) > 0 {
130
- receiver = s.TypeKey(decl.Recv.List[0].Type, file)
131
- key = receiver + "." + decl.Name.Name
132
- }
133
- fn := &function{key: key, name: decl.Name.Name, receiver: receiver, file: file, decl: decl, types: map[string]string{}}
134
- if decl.Recv != nil {
135
- for _, field := range decl.Recv.List {
136
- for _, name := range field.Names {
137
- fn.types[name.Name] = receiver
138
- }
139
- }
140
- }
141
- if decl.Type.Params != nil {
142
- for _, field := range decl.Type.Params.List {
143
- typeKey := s.TypeKey(field.Type, file)
144
- for _, name := range field.Names {
145
- fn.params = append(fn.params, name.Name)
146
- fn.types[name.Name] = typeKey
147
- }
148
- }
149
- }
150
- if decl.Type.Results != nil {
151
- for _, field := range decl.Type.Results.List {
152
- typeKey := s.TypeKey(field.Type, file)
153
- if len(field.Names) == 0 {
154
- fn.results = append(fn.results, typeKey)
155
- }
156
- for range field.Names {
157
- fn.results = append(fn.results, typeKey)
158
- }
159
- }
160
- }
161
- s.functions[key] = fn
162
- if receiver != "" {
163
- s.methods[receiver] = append(s.methods[receiver], fn)
164
- s.byName[fn.name] = append(s.byName[fn.name], fn)
165
- }
166
- }
167
-
168
- // implements is whether a receiver type has every method an interface asks
169
- // for, by name. Names are what a port is: a type with the right names is
170
- // what the assembly hands over, and the compiler holds the signatures.
171
- func (s *scanner) implements(receiver, iface string) bool {
172
- want := s.interfaces[iface]
173
- if len(want) == 0 {
174
- return false
175
- }
176
- have := map[string]bool{}
177
- for _, fn := range s.methods[receiver] {
178
- have[fn.name] = true
179
- }
180
- for _, name := range want {
181
- if !have[name] {
182
- return false
183
- }
184
- }
185
- return true
186
- }
187
-
188
- // assignedTo is the last expression a local name was given in the function,
189
- // read once per function.
190
- func (s *scanner) assignedTo(fn *function, name string) (assignment, bool) {
191
- if fn.assigned == nil {
192
- fn.assigned = map[string]assignment{}
193
- if fn.decl.Body != nil {
194
- ast.Inspect(fn.decl.Body, func(node ast.Node) bool {
195
- switch stmt := node.(type) {
196
- case *ast.AssignStmt:
197
- record(fn.assigned, stmt.Lhs, stmt.Rhs)
198
- case *ast.ValueSpec:
199
- var lhs []ast.Expr
200
- for _, ident := range stmt.Names {
201
- lhs = append(lhs, ident)
202
- }
203
- record(fn.assigned, lhs, stmt.Values)
204
- }
205
- return true
206
- })
207
- }
208
- }
209
- found, ok := fn.assigned[name]
210
- return found, ok
211
- }
212
-
213
- func record(into map[string]assignment, lhs, rhs []ast.Expr) {
214
- if len(rhs) == 0 {
215
- return
216
- }
217
- for i, target := range lhs {
218
- ident, ok := target.(*ast.Ident)
219
- if !ok || ident.Name == "_" {
220
- continue
221
- }
222
- if len(rhs) == 1 && len(lhs) > 1 {
223
- into[ident.Name] = assignment{expr: rhs[0], index: i}
224
- } else if i < len(rhs) {
225
- into[ident.Name] = assignment{expr: rhs[i]}
226
- }
227
- }
228
- }
229
-
230
- // typeOf is the type key of an expression, as far as declarations say: a
231
- // parameter or receiver by its declared type, a local by what it was
232
- // assigned, a field by its struct, a call by what the callee returns.
233
- func (s *scanner) typeOf(expr ast.Expr, fn *function) string {
234
- switch value := goscan.Unwrap(expr).(type) {
235
- case *ast.Ident:
236
- if kind := fn.types[value.Name]; kind != "" {
237
- return kind
238
- }
239
- key := fn.key + ":" + value.Name
240
- if s.typing[key] {
241
- return ""
242
- }
243
- s.typing[key] = true
244
- defer delete(s.typing, key)
245
- if given, ok := s.assignedTo(fn, value.Name); ok {
246
- if call, isCall := goscan.Unwrap(given.expr).(*ast.CallExpr); isCall {
247
- results := s.resultsOf(call, fn)
248
- if given.index < len(results) {
249
- return results[given.index]
250
- }
251
- return ""
252
- }
253
- if given.index == 0 {
254
- return s.typeOf(given.expr, fn)
255
- }
256
- }
257
- case *ast.CompositeLit:
258
- return s.TypeKey(value.Type, fn.file)
259
- case *ast.SelectorExpr:
260
- if st := s.structs[s.typeOf(value.X, fn)]; st != nil {
261
- return st.fields[value.Sel.Name]
262
- }
263
- case *ast.CallExpr:
264
- if results := s.resultsOf(value, fn); len(results) > 0 {
265
- return results[0]
266
- }
267
- }
268
- return ""
269
- }
270
-
271
- // knownResults is what the nats.go constructors hand back, since their
272
- // declarations are not in the tree.
273
- var knownResults = map[string][]string{
274
- natsPkg + ".Connect": {natsPkg + ".Conn", "error"},
275
- natsPkg + ".Conn.JetStream": {natsPkg + ".JetStreamContext", "error"},
276
- jsPkg + ".New": {jsPkg + ".JetStream", "error"},
277
- jsPkg + ".NewWithAPIPrefix": {jsPkg + ".JetStream", "error"},
278
- jsPkg + ".NewWithDomain": {jsPkg + ".JetStream", "error"},
279
- jsPkg + ".JetStream.Stream": {jsPkg + ".Stream", "error"},
280
- jsPkg + ".JetStream.CreateStream": {jsPkg + ".Stream", "error"},
281
- jsPkg + ".JetStream.UpdateStream": {jsPkg + ".Stream", "error"},
282
- jsPkg + ".JetStream.CreateOrUpdateStream": {jsPkg + ".Stream", "error"},
283
- }
284
-
285
- // resultsOf is what a call returns: the callee's declared results when it is
286
- // in the tree, the table above when it is nats.go's.
287
- func (s *scanner) resultsOf(call *ast.CallExpr, fn *function) []string {
288
- for _, target := range s.callees(call, fn) {
289
- return target.results
290
- }
291
- if key := s.externalKey(call, fn); key != "" {
292
- return knownResults[key]
293
- }
294
- return nil
295
- }
296
-
297
- // externalKey names a call on something declared outside the tree: a
298
- // package function by import path, a method by the type of what it is
299
- // called on.
300
- func (s *scanner) externalKey(call *ast.CallExpr, fn *function) string {
301
- sel, ok := call.Fun.(*ast.SelectorExpr)
302
- if !ok {
303
- return ""
304
- }
305
- if base, ok := sel.X.(*ast.Ident); ok {
306
- if imported := fn.file.Imports[base.Name]; imported != "" && fn.types[base.Name] == "" {
307
- if _, local := s.assignedTo(fn, base.Name); !local {
308
- return imported + "." + sel.Sel.Name
309
- }
310
- }
311
- }
312
- if recv := s.typeOf(sel.X, fn); recv != "" {
313
- return recv + "." + sel.Sel.Name
314
- }
315
- return ""
316
- }
317
-
318
- // callees is every function in the tree a call may reach: the one named,
319
- // when it is a plain function or a method on a known type; every
320
- // implementation, when it is a method on an interface the tree declares.
321
- func (s *scanner) callees(call *ast.CallExpr, fn *function) []*function {
322
- switch callee := call.Fun.(type) {
323
- case *ast.Ident:
324
- if target := s.functions[fn.file.Pkg+"."+callee.Name]; target != nil {
325
- return []*function{target}
326
- }
327
- case *ast.SelectorExpr:
328
- if base, ok := callee.X.(*ast.Ident); ok && fn.types[base.Name] == "" {
329
- if imported := fn.file.Imports[base.Name]; imported != "" {
330
- if _, local := s.assignedTo(fn, base.Name); !local {
331
- if target := s.functions[imported+"."+callee.Sel.Name]; target != nil {
332
- return []*function{target}
333
- }
334
- return nil
335
- }
336
- }
337
- }
338
- recv := s.typeOf(callee.X, fn)
339
- if recv == "" {
340
- return nil
341
- }
342
- if target := s.functions[recv+"."+callee.Sel.Name]; target != nil {
343
- return []*function{target}
344
- }
345
- if s.interfaces[recv] != nil {
346
- var out []*function
347
- for _, candidate := range s.byName[callee.Sel.Name] {
348
- if s.implements(candidate.receiver, recv) {
349
- out = append(out, candidate)
350
- }
351
- }
352
- sort.Slice(out, func(i, j int) bool { return out[i].key < out[j].key })
353
- return out
354
- }
355
- }
356
- return nil
357
- }
358
-
359
- // paramIndex is which parameter a name is, or -1.
360
- func paramIndex(fn *function, name string) int {
361
- for i, param := range fn.params {
362
- if param == name {
363
- return i
364
- }
365
- }
366
- return -1
367
- }
368
-
369
- // sortedFunctions is every function with a body, in a fixed order.
370
- func (s *scanner) sortedFunctions() []*function {
371
- out := make([]*function, 0, len(s.functions))
372
- for _, fn := range s.functions {
373
- if fn.decl.Body != nil {
374
- out = append(out, fn)
375
- }
376
- }
377
- sort.Slice(out, func(i, j int) bool { return out[i].key < out[j].key })
378
- return out
379
- }
@@ -1,42 +0,0 @@
1
- // Package main is portolan-extract-go-nats: nats.go and JetStream calls in a
2
- // Go repository in, the subjects the service listens on and publishes to out.
3
- package main
4
-
5
- import (
6
- "fmt"
7
- "io"
8
- "os"
9
- "path/filepath"
10
-
11
- "github.com/shortlink-org/portolan/internal/goscan"
12
- "github.com/shortlink-org/portolan/plugin"
13
- )
14
-
15
- type Options struct {
16
- Context string `json:"context"`
17
- Service string `json:"service"`
18
- Out string `json:"out,omitempty"`
19
- }
20
-
21
- func main() {
22
- if err := run(os.Stdin, os.Stdout); err != nil {
23
- fmt.Fprintln(os.Stderr, "portolan-extract-go-nats:", err)
24
- os.Exit(1)
25
- }
26
- }
27
-
28
- func run(stdin io.Reader, stdout io.Writer) error {
29
- return plugin.Serve(stdin, stdout, descriptor(), func(req plugin.Request, opts Options) (plugin.Response, error) {
30
- if req.Input.Root == "" {
31
- return plugin.Response{}, fmt.Errorf("no input root: an extractor has nothing to read")
32
- }
33
- if opts.Context == "" {
34
- opts.Context = goscan.Slug(filepath.Base(req.Input.Root))
35
- }
36
- if opts.Service == "" {
37
- opts.Service = goscan.Slug(filepath.Base(req.Input.Root))
38
- }
39
-
40
- return extract(req.Input, opts)
41
- })
42
- }
@@ -1,161 +0,0 @@
1
- package main
2
-
3
- import (
4
- "go/ast"
5
- "go/token"
6
- "strconv"
7
-
8
- "github.com/shortlink-org/portolan/internal/goscan"
9
- )
10
-
11
- // hops is how far up the callers a subject is followed. One hop is the port:
12
- // the adapter takes the subject as a parameter and the assembly passes a
13
- // constant. Two is an assembly that itself was handed the subject. Further
14
- // than that is not a declaration any more.
15
- const hops = 2
16
-
17
- // resolved is one string an expression was found to be, where it was
18
- // written, and - when it came through a wrapper that also names the message -
19
- // what the message is called.
20
- type resolved struct {
21
- value string
22
- at goscan.Source
23
- name string
24
- }
25
-
26
- // resolve is the strings an expression can be worth: a literal; a constant,
27
- // the tree's own or an imported one; a config field's default; a call to a
28
- // function whose body is one return; a parameter, by what every caller
29
- // passes for it.
30
- func (s *scanner) resolve(expr ast.Expr, fn *function, depth int, visiting map[string]bool) []resolved {
31
- at := s.At(expr.Pos())
32
- switch value := goscan.Unwrap(expr).(type) {
33
- case *ast.BasicLit:
34
- if value.Kind == token.STRING {
35
- text, _ := strconv.Unquote(value.Value)
36
- return []resolved{{value: text, at: at}}
37
- }
38
- case *ast.Ident:
39
- if index := paramIndex(fn, value.Name); index >= 0 {
40
- return s.fromCallers(fn, index, depth, visiting)
41
- }
42
- key := fn.key + ":" + value.Name
43
- if visiting[key] {
44
- return nil
45
- }
46
- visiting[key] = true
47
- defer delete(visiting, key)
48
- if given, ok := s.assignedTo(fn, value.Name); ok {
49
- if given.index == 0 {
50
- return s.resolve(given.expr, fn, depth, visiting)
51
- }
52
- return nil
53
- }
54
- if text := s.StringOf(value, fn.file, nil); text != "" {
55
- return []resolved{{value: text, at: at}}
56
- }
57
- case *ast.SelectorExpr:
58
- if text := s.StringOf(value, fn.file, nil); text != "" {
59
- return []resolved{{value: text, at: at}}
60
- }
61
- if st := s.structs[s.typeOf(value.X, fn)]; st != nil {
62
- if def := st.defaults[value.Sel.Name]; def != "" {
63
- return []resolved{{value: def, at: at}}
64
- }
65
- }
66
- case *ast.CallExpr:
67
- var out []resolved
68
- for _, target := range s.callees(value, fn) {
69
- if ret := singleReturn(target); ret != nil {
70
- key := "call:" + target.key
71
- if visiting[key] {
72
- continue
73
- }
74
- visiting[key] = true
75
- out = append(out, s.resolve(ret, target, depth, visiting)...)
76
- delete(visiting, key)
77
- }
78
- }
79
- return out
80
- }
81
- return nil
82
- }
83
-
84
- // fromCallers is what a parameter is worth: whatever each call site passes
85
- // for it, resolved there. A call site that also passes a literal or constant
86
- // for the one other string parameter of the same function is taken to name
87
- // the message - the shape of a bus port, Subscribe(subject, name, handler).
88
- func (s *scanner) fromCallers(fn *function, index, depth int, visiting map[string]bool) []resolved {
89
- if depth >= hops {
90
- return nil
91
- }
92
- key := fn.key + "#" + strconv.Itoa(index)
93
- if visiting[key] {
94
- return nil
95
- }
96
- visiting[key] = true
97
- defer delete(visiting, key)
98
-
99
- nameIndex := s.companionString(fn, index)
100
- var out []resolved
101
- for _, caller := range s.sortedFunctions() {
102
- ast.Inspect(caller.decl.Body, func(node ast.Node) bool {
103
- call, ok := node.(*ast.CallExpr)
104
- if !ok || index >= len(call.Args) || !s.reaches(call, caller, fn) {
105
- return true
106
- }
107
- found := s.resolve(call.Args[index], caller, depth+1, visiting)
108
- if nameIndex >= 0 && nameIndex < len(call.Args) {
109
- names := s.resolve(call.Args[nameIndex], caller, depth+1, visiting)
110
- if len(names) == 1 {
111
- for i := range found {
112
- found[i].name = names[0].value
113
- }
114
- }
115
- }
116
- out = append(out, found...)
117
- return true
118
- })
119
- }
120
- return out
121
- }
122
-
123
- // reaches is whether a call lands on fn: directly, or through an interface
124
- // fn's receiver satisfies.
125
- func (s *scanner) reaches(call *ast.CallExpr, caller, fn *function) bool {
126
- for _, target := range s.callees(call, caller) {
127
- if target == fn {
128
- return true
129
- }
130
- }
131
- return false
132
- }
133
-
134
- // companionString is the one string parameter beside the subject, or -1
135
- // when there is none or more than one.
136
- func (s *scanner) companionString(fn *function, subject int) int {
137
- found := -1
138
- for i, param := range fn.params {
139
- if i == subject || fn.types[param] != "string" {
140
- continue
141
- }
142
- if found >= 0 {
143
- return -1
144
- }
145
- found = i
146
- }
147
- return found
148
- }
149
-
150
- // singleReturn is the expression a function is, when its whole body is
151
- // `return x`: the Name() of an event, the Topic() of a message.
152
- func singleReturn(fn *function) ast.Expr {
153
- if fn.decl.Body == nil || len(fn.decl.Body.List) != 1 {
154
- return nil
155
- }
156
- ret, ok := fn.decl.Body.List[0].(*ast.ReturnStmt)
157
- if !ok || len(ret.Results) != 1 {
158
- return nil
159
- }
160
- return ret.Results[0]
161
- }