@shortlink-org/portolan 0.1.0 → 0.2.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 (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 +22 -4
  36. package/scripts/local-api.test.mjs +84 -2
  37. package/scripts/manifest.mjs +3 -2
  38. package/scripts/package-smoke.mjs +6 -2
  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 +12 -8
  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,41 +0,0 @@
1
- // Package main is portolan-extract-project: a repository component in, a
2
- // neutral catalog fragment out. It deliberately makes no DDD assumptions.
3
- package main
4
-
5
- import (
6
- "fmt"
7
- "io"
8
- "os"
9
-
10
- "github.com/shortlink-org/portolan/plugin"
11
- )
12
-
13
- type Options struct {
14
- Group string `json:"group,omitempty"`
15
- GroupName string `json:"groupName,omitempty"`
16
- GroupSummary string `json:"groupSummary,omitempty"`
17
- GroupKind string `json:"groupKind,omitempty"`
18
-
19
- Component string `json:"component,omitempty"`
20
- ComponentName string `json:"componentName,omitempty"`
21
- ComponentKind string `json:"componentKind,omitempty"`
22
- Technologies []string `json:"technologies,omitempty"`
23
- Repo string `json:"repo,omitempty"`
24
- Out string `json:"out,omitempty"`
25
- }
26
-
27
- func main() {
28
- if err := run(os.Stdin, os.Stdout); err != nil {
29
- fmt.Fprintln(os.Stderr, "portolan-extract-project:", err)
30
- os.Exit(1)
31
- }
32
- }
33
-
34
- func run(stdin io.Reader, stdout io.Writer) error {
35
- return plugin.Serve(stdin, stdout, descriptor(), func(req plugin.Request, opts Options) (plugin.Response, error) {
36
- if req.Input.Root == "" {
37
- return plugin.Response{}, fmt.Errorf("no input root: an extractor has nothing to read")
38
- }
39
- return extract(req.Input, opts)
40
- })
41
- }
@@ -1,125 +0,0 @@
1
- package main
2
-
3
- // What a .proto file says, as it says it.
4
- //
5
- // Types are kept AS WRITTEN - `repeated Money`, `map<string, LineItem>`, the
6
- // `optional` keyword, the author's declaration order. The catalog already
7
- // takes this stance for schemas ("the db type as declared - uuid, timestamptz,
8
- // jsonb - never normalised"), and a reader comparing a page against the file it
9
- // came from should recognise what they are looking at.
10
-
11
- // File is one parsed .proto.
12
- type File struct {
13
- // Path is the file as a reader would type it, relative to the repo root.
14
- Path string
15
-
16
- // Doc is the comment at the very top of the file, above `syntax`.
17
- //
18
- // On a vendored copy this is where the header lives that says which module
19
- // it came from - docs/adr/org.0001.md requires one - so it is worth keeping
20
- // apart from the documentation of any declaration inside.
21
- Doc string
22
-
23
- Syntax string // "proto2", "proto3", "editions", or "" when unstated
24
- Package string
25
- Imports []Import
26
- Options []Option
27
- Messages []*Message
28
- Enums []*Enum
29
- Services []*Service
30
- }
31
-
32
- type Import struct {
33
- Path string
34
- Public bool
35
- Weak bool
36
- Line int
37
- }
38
-
39
- type Option struct {
40
- Name string
41
- Value string
42
- Line int
43
- }
44
-
45
- type Message struct {
46
- Name string
47
- Doc string
48
- Line int
49
-
50
- // Fields holds every field of the message, including the members of its
51
- // oneofs, in declaration order. A oneof is a constraint on which of them may
52
- // be set, not a separate place a field lives, so a reader asking "what is in
53
- // this message" gets one list.
54
- Fields []*Field
55
- Oneofs []*Oneof
56
- Messages []*Message // nested
57
- Enums []*Enum
58
- Reserved []string
59
- }
60
-
61
- type Field struct {
62
- Name string
63
- Doc string
64
- Line int
65
-
66
- // Type as written: "string", "Money", "shop.v1.Money", "map<string, Money>".
67
- Type string
68
- Label string // "", "repeated", "optional", "required"
69
- Number int
70
-
71
- // Oneof names the oneof this field belongs to, empty when it is not in one.
72
- Oneof string
73
- Deprecated bool
74
- Default string
75
- }
76
-
77
- type Oneof struct {
78
- Name string
79
- Doc string
80
- Line int
81
- Fields []*Field
82
- }
83
-
84
- type Enum struct {
85
- Name string
86
- Doc string
87
- Line int
88
- Values []*EnumValue
89
- }
90
-
91
- type EnumValue struct {
92
- Name string
93
- Doc string
94
- Number int
95
- Line int
96
- }
97
-
98
- type Service struct {
99
- Name string
100
- Doc string
101
- Line int
102
- Methods []*Method
103
- }
104
-
105
- type Method struct {
106
- Name string
107
- Doc string
108
- Line int
109
-
110
- Request string
111
- Response string
112
- ClientStreaming bool
113
- ServerStreaming bool
114
- Deprecated bool
115
- }
116
-
117
- // Note is something the parser declined to model, named rather than dropped.
118
- //
119
- // A construct the parser skips silently is a construct nobody knows is missing.
120
- // Every one of these becomes a plugin diagnostic, so an estate using `extend`
121
- // or a proto2 `group` finds out that portolan read past it.
122
- type Note struct {
123
- Line int
124
- Message string
125
- }
@@ -1,77 +0,0 @@
1
- package main
2
-
3
- // What a service CALLS, read from the client copies it vendors.
4
- //
5
- // docs/adr/org.0001.md puts a narrowed copy of the producer's proto in the
6
- // consumer's infrastructure layer, with a header comment saying where it came
7
- // from. That copy is a statement about what this service intends to call, and
8
- // reading it is how a call edge gets into the catalog from the calling end.
9
-
10
- import (
11
- "sort"
12
-
13
- "github.com/shortlink-org/portolan/catalog"
14
- "github.com/shortlink-org/portolan/plugin"
15
- )
16
-
17
- // calls turns every method in the vendored files into a catalog call.
18
- //
19
- // STATUS IS ALWAYS "declared", NEVER "verified". Three reasons, and the test
20
- // that holds this is deliberate:
21
- //
22
- // 1. `problems()` treats status as authored, not derived.
23
- // 2. Verification is a property of the UNION, and every extractor runs before
24
- // one exists - `plugin.Request.Catalog` is the zero value for an extractor.
25
- // 3. In the shipped catalog `verified` already means something a proto cannot
26
- // supply: it sits next to a note naming the integration test that covers
27
- // the call end to end.
28
- //
29
- // Reading a .proto proves the call was WRITTEN DOWN, which is what `declared`
30
- // means. Whether it is exercised is not a question this file can answer.
31
- func calls(files []*File, peers map[string]string, moduleID string, b *plugin.Builder) []catalog.RpcCall {
32
- var out []catalog.RpcCall
33
-
34
- for _, file := range files {
35
- peer, named := peers[file.Package]
36
- if !named {
37
- // The raw package name, which is exactly what `RpcCall.peer`
38
- // documents: "service id if resolved, else raw name". Guessing a
39
- // service id from a proto package would be inventing an edge.
40
- peer = file.Package
41
- }
42
-
43
- for _, svc := range file.Services {
44
- iface := interfaceID(file.Package, svc.Name)
45
- if !named {
46
- b.Warn(iface, "no peer is mapped for proto package "+file.Package+
47
- "; the call is listed against the package name")
48
- }
49
-
50
- for _, m := range svc.Methods {
51
- out = append(out, catalog.RpcCall{
52
- ID: callID(iface, m.Name),
53
- Peer: peer,
54
- Status: catalog.StatusDeclared,
55
- Source: sourceRef(file.Path, m.Line),
56
- Note: file.headerNote(),
57
- Module: moduleID,
58
- })
59
- }
60
- }
61
- }
62
-
63
- sort.Slice(out, func(i, j int) bool { return out[i].ID < out[j].ID })
64
-
65
- return out
66
- }
67
-
68
- // headerNote is the comment at the top of a vendored copy.
69
- //
70
- // The ADR already requires that header - "the header comment on every vendored
71
- // copy says so" - so surfacing it costs nothing and makes the boundary
72
- // self-documenting on the page rather than only in the file. It sits above
73
- // `syntax` rather than above a declaration, which is why the parser keeps it
74
- // on the file instead of on whatever happens to come first.
75
- func (f *File) headerNote() string {
76
- return f.Doc
77
- }
@@ -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-proto",
15
- Summary: "Reads .proto files and answers with what a service provides from the modules it publishes and what it calls from the copies it vendors.",
16
- Phases: []string{plugin.PhaseExtract},
17
- Options: optionsSchema,
18
- }
19
- }
@@ -1,293 +0,0 @@
1
- package main
2
-
3
- // Protos in, a catalog fragment out.
4
- //
5
- // This extractor describes ONE aspect of a service - what it answers and what
6
- // it calls - and nothing else. The aggregates come from a different extractor
7
- // reading a different part of the tree, and the two meet in the merge. Neither
8
- // knows the other exists, which is the whole reason each of them stays small.
9
- //
10
- // It reads no clock, opens no socket and looks at no environment. Fetching a
11
- // module from a registry is the other plugin's job, and keeping the two apart
12
- // is what lets this one be replayed byte-for-byte from a checkout.
13
- //
14
- // A note on proto event schemas: a message named `OrderPlaced` in an
15
- // `events.proto` is the WIRE SCHEMA OF a domain event, not the event. It stays
16
- // an RpcMessage rather than becoming a catalog Event, because `Event.id` is
17
- // `<service>.<aggregate>.<Name>` and this extractor knows the package, not the
18
- // aggregate. A guess would either collide with the event extract-go already
19
- // emits from the domain package, or create a ghost under an invented aggregate
20
- // - and since aggregates merge whole-object by id, that ghost would sit beside
21
- // the real one forever.
22
-
23
- import (
24
- "encoding/json"
25
- "fmt"
26
- "os"
27
- "path/filepath"
28
- "sort"
29
- "strings"
30
-
31
- "github.com/shortlink-org/portolan/catalog"
32
- "github.com/shortlink-org/portolan/plugin"
33
- )
34
-
35
- func extract(in plugin.Input, opts Options) (plugin.Response, error) {
36
- b := &plugin.Builder{}
37
- root := in.Root
38
-
39
- if opts.Context == "" {
40
- opts.Context = filepath.Base(root)
41
- }
42
- if opts.Service == "" {
43
- opts.Service = filepath.Base(root)
44
- }
45
- serviceID := opts.Context + "." + opts.Service
46
-
47
- owned, err := readDirs(root, opts.Paths, b)
48
- if err != nil {
49
- return plugin.Response{}, err
50
- }
51
- vendored, err := readDirs(root, opts.Vendored, b)
52
- if err != nil {
53
- return plugin.Response{}, err
54
- }
55
-
56
- if len(owned) == 0 && len(vendored) == 0 {
57
- b.Warn(serviceID, "no .proto files were found under "+root)
58
- }
59
-
60
- // One index over everything read. A vendored copy may well refer to a type
61
- // the owned protos declare, and refusing to look would report an unresolved
62
- // name the tree can plainly answer.
63
- all := append(append([]*File{}, filesOf(owned)...), filesOf(vendored)...)
64
- ix := NewIndex(all)
65
-
66
- sh := newShared(opts.Defs != "off")
67
-
68
- var provides []catalog.RpcService
69
- var consumes []catalog.RpcCall
70
- var modules []catalog.ProtoModule
71
- moduleIDs := map[string]bool{}
72
-
73
- for _, dir := range owned {
74
- module := describe(root, dir, opts, b)
75
- if module.ID != "" && !moduleIDs[module.ID] {
76
- // Owned: this service publishes it, so the estate knows the owner.
77
- module.Owner = serviceID
78
- modules = append(modules, module)
79
- moduleIDs[module.ID] = true
80
- }
81
- provides = append(provides, interfaces(ix, dir.files, module.ID, sh, b)...)
82
- }
83
-
84
- for _, dir := range vendored {
85
- module := describe(root, dir, opts, b)
86
- if module.ID != "" && !moduleIDs[module.ID] {
87
- // Vendored: somebody else publishes it. Owner is left empty rather
88
- // than guessed - a module whose publisher is outside the estate is
89
- // the ordinary case, not a defect.
90
- modules = append(modules, module)
91
- moduleIDs[module.ID] = true
92
- }
93
- consumes = append(consumes, calls(dir.files, opts.Peers, module.ID, b)...)
94
- }
95
-
96
- sort.Slice(modules, func(i, j int) bool { return modules[i].ID < modules[j].ID })
97
-
98
- service := catalog.Service{
99
- ID: serviceID,
100
- Slug: opts.Service,
101
- // Named by whichever source knows the name. This one describes what the
102
- // service answers and calls, not what it is called, and a fragment that
103
- // filled these in from a proto package would be inventing.
104
- Provides: nonNilProvides(provides),
105
- Consumes: nonNilCalls(consumes),
106
- Aggregates: []catalog.Aggregate{},
107
- Modules: sortedCopy(keysOf(moduleIDs)),
108
- }
109
-
110
- fragment := catalog.Catalog{
111
- GeneratedAt: in.GeneratedAt,
112
- Commit: in.Commit,
113
- Contexts: []catalog.BoundedContext{{
114
- ID: opts.Context,
115
- Slug: opts.Context,
116
- Services: []catalog.Service{service},
117
- }},
118
- Defs: sh.defs,
119
- Flows: []catalog.Flow{},
120
- Adrs: []catalog.Adr{},
121
- Modules: modules,
122
- }
123
-
124
- encoded, err := json.MarshalIndent(fragment, "", " ")
125
- if err != nil {
126
- return plugin.Response{}, err
127
- }
128
-
129
- b.File(firstNonEmpty(opts.Out, "proto.json"), string(encoded)+"\n")
130
-
131
- return b.Response(), nil
132
- }
133
-
134
- // dir is one directory of protos and everything parsed out of it.
135
- type dir struct {
136
- path string
137
- files []*File
138
- lock *lockFile
139
- }
140
-
141
- func filesOf(dirs []dir) []*File {
142
- var out []*File
143
- for _, d := range dirs {
144
- out = append(out, d.files...)
145
- }
146
-
147
- return out
148
- }
149
-
150
- // readDirs walks each directory for .proto files and parses them.
151
- //
152
- // Files are visited in sorted order and parsed in that order, because the
153
- // fragment is committed and compared by `gen:check`: a filesystem walk that
154
- // came back differently would rewrite the file for no reason.
155
- func readDirs(root string, paths []string, b *plugin.Builder) ([]dir, error) {
156
- var out []dir
157
-
158
- for _, rel := range paths {
159
- at := filepath.Join(root, filepath.FromSlash(rel))
160
- info, err := os.Stat(at)
161
- if os.IsNotExist(err) {
162
- b.Warn(rel, "no such directory: "+filepath.ToSlash(at))
163
-
164
- continue
165
- }
166
- if err != nil {
167
- return nil, err
168
- }
169
- if !info.IsDir() {
170
- return nil, fmt.Errorf("%s is not a directory", filepath.ToSlash(at))
171
- }
172
-
173
- var found []string
174
- err = filepath.Walk(at, func(path string, info os.FileInfo, err error) error {
175
- if err != nil {
176
- return err
177
- }
178
- if !info.IsDir() && strings.HasSuffix(path, ".proto") {
179
- found = append(found, path)
180
- }
181
-
182
- return nil
183
- })
184
- if err != nil {
185
- return nil, err
186
- }
187
- sort.Strings(found)
188
-
189
- d := dir{path: trimSlash(at)}
190
- for _, path := range found {
191
- src, err := os.ReadFile(path)
192
- if err != nil {
193
- return nil, err
194
- }
195
- file, notes, err := Parse(filepath.ToSlash(path), string(src))
196
- if err != nil {
197
- // The file could not be tokenised. Past that the parser is not
198
- // reading proto any more, so it is reported and skipped rather
199
- // than half-described.
200
- b.Warn(filepath.ToSlash(path), err.Error())
201
-
202
- continue
203
- }
204
- for _, note := range notes {
205
- b.Warn(fmt.Sprintf("%s:%d", filepath.ToSlash(path), note.Line), note.Message)
206
- }
207
- d.files = append(d.files, file)
208
- }
209
-
210
- lock, err := readLock(at)
211
- if err != nil {
212
- b.Warn(rel, "the lock beside these protos could not be read: "+err.Error())
213
- }
214
- d.lock = lock
215
-
216
- out = append(out, d)
217
- }
218
-
219
- return out, nil
220
- }
221
-
222
- // describe names the module a directory of protos belongs to.
223
- //
224
- // A lock written by fetch-bsr wins, because it is the only thing that knows the
225
- // commit. Failing that the manifest may say, and failing that the directory
226
- // gets a `local:` id so nobody mistakes the path for something fetchable.
227
- func describe(root string, d dir, opts Options, b *plugin.Builder) catalog.ProtoModule {
228
- rel := relativeTo(root, d.path)
229
-
230
- id := ""
231
- var lock *lockModule
232
- if d.lock != nil && len(d.lock.Modules) > 0 {
233
- lock = &d.lock.Modules[0]
234
- id = lock.Module
235
- if len(d.lock.Modules) > 1 {
236
- b.Warn(rel, "the lock names more than one module for this directory; the first is used")
237
- }
238
- }
239
- if id == "" {
240
- id = opts.Modules[rel]
241
- }
242
- if id == "" {
243
- id = localModuleID(relativeTo(root, d.path))
244
- b.Warn(rel, "these protos are not pinned to a published module; listed as "+id)
245
- }
246
-
247
- module := moduleFor(id, d.path, d.files)
248
- module.Source = filepath.ToSlash(d.path)
249
- if lock != nil {
250
- module.Commit = lock.Commit
251
- module.Digest = lock.Digest
252
- module.Deps = sortedCopy(lock.Deps)
253
- }
254
-
255
- return module
256
- }
257
-
258
- func keysOf(set map[string]bool) []string {
259
- out := make([]string, 0, len(set))
260
- for k := range set {
261
- out = append(out, k)
262
- }
263
-
264
- return out
265
- }
266
-
267
- // A fragment states what it knows and nothing else, but a list the schema calls
268
- // required has to be present even when it is empty.
269
- func nonNilProvides(in []catalog.RpcService) []catalog.RpcService {
270
- if in == nil {
271
- return []catalog.RpcService{}
272
- }
273
-
274
- return in
275
- }
276
-
277
- func nonNilCalls(in []catalog.RpcCall) []catalog.RpcCall {
278
- if in == nil {
279
- return []catalog.RpcCall{}
280
- }
281
-
282
- return in
283
- }
284
-
285
- func firstNonEmpty(values ...string) string {
286
- for _, v := range values {
287
- if v != "" {
288
- return v
289
- }
290
- }
291
-
292
- return ""
293
- }