@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,162 +0,0 @@
1
- package main
2
-
3
- import (
4
- "strings"
5
-
6
- "github.com/shortlink-org/portolan/catalog"
7
- )
8
-
9
- func (s *site) renderAdrs() {
10
- if len(s.cat.Adrs) == 0 {
11
- return
12
- }
13
-
14
- const self = "adr/README.md"
15
-
16
- var b strings.Builder
17
- b.WriteString("# Decision records\n\n")
18
- b.WriteString(s.stamp() + "\n")
19
-
20
- rows := make([][]string, 0, len(s.cat.Adrs))
21
- for i := range s.cat.Adrs {
22
- adr := &s.cat.Adrs[i]
23
- rows = append(rows, []string{
24
- s.ref(self, adr.ID, adr.ID),
25
- adr.Title,
26
- string(adr.Status),
27
- adr.Date,
28
- s.scopeRef(self, adr.Scope),
29
- })
30
- }
31
- b.WriteString(table([]string{"ADR", "Title", "Status", "Date", "Scope"}, rows))
32
-
33
- s.b.file(self, b.String())
34
-
35
- for i := range s.cat.Adrs {
36
- s.renderAdr(&s.cat.Adrs[i])
37
- }
38
- }
39
-
40
- func (s *site) renderAdr(adr *catalog.Adr) {
41
- self := s.pathOf[adr.ID]
42
-
43
- var b strings.Builder
44
- b.WriteString("# " + adr.ID + " — " + adr.Title + "\n\n")
45
- b.WriteString(s.stamp() + "\n")
46
-
47
- meta := [][]string{
48
- {"Status", string(adr.Status)},
49
- {"Date", adr.Date},
50
- {"Scope", s.scopeRef(self, adr.Scope)},
51
- {"Source", s.source(self, adr.Source, s.adrOwner(adr))},
52
- }
53
- if adr.Created != nil {
54
- meta = append(meta, []string{"Committed", commitLine(adr.Created)})
55
- }
56
- if adr.Revised != nil {
57
- meta = append(meta, []string{"Revised", commitLine(adr.Revised)})
58
- }
59
- if adr.Note != "" {
60
- meta = append(meta, []string{"Note", adr.Note})
61
- }
62
- if adr.SupersededBy != "" {
63
- // Worth putting in the header rather than at the bottom: everything
64
- // below it is history the moment this is set.
65
- meta = append(meta, []string{"Superseded by", s.ref(self, adr.SupersededBy, adr.SupersededBy)})
66
- }
67
- if len(adr.Supersedes) > 0 {
68
- refs := make([]string, 0, len(adr.Supersedes))
69
- for _, id := range adr.Supersedes {
70
- refs = append(refs, s.ref(self, id, id))
71
- }
72
- meta = append(meta, []string{"Supersedes", strings.Join(refs, ", ")})
73
- }
74
- b.WriteString(defList(meta))
75
-
76
- // The body is the record. It is frozen history and is never regenerated
77
- // from the current catalog, so it goes in whole, one level down.
78
- if rendered := body(adr.Body, adr.Title); rendered != "" {
79
- b.WriteString("\n" + rendered + "\n")
80
- }
81
-
82
- section(&b, "Relates to", s.relatesList(self, adr.Relates))
83
-
84
- s.b.file(self, b.String())
85
- }
86
-
87
- func (s *site) adrOwner(adr *catalog.Adr) *catalog.Service {
88
- if adr.Scope.Kind == "service" {
89
- return s.services[adr.Scope.Service]
90
- }
91
- return s.serviceForSource(adr.Source)
92
- }
93
-
94
- func (s *site) relatesList(from string, relates catalog.AdrRelates) string {
95
- var b strings.Builder
96
-
97
- groups := []struct {
98
- label string
99
- ids []string
100
- }{
101
- {"Services", relates.Services},
102
- {"Events", relates.Events},
103
- {"Flows", relates.Flows},
104
- }
105
-
106
- for _, group := range groups {
107
- if len(group.ids) == 0 {
108
- continue
109
- }
110
-
111
- refs := make([]string, 0, len(group.ids))
112
- for _, id := range group.ids {
113
- // An event id belongs to the aggregate page that publishes it, so
114
- // it is resolved through its owner rather than looked up directly.
115
- if _, ok := s.eventPage[id]; ok {
116
- refs = append(refs, s.eventRef(from, id, id))
117
-
118
- continue
119
- }
120
- refs = append(refs, s.ref(from, id, id))
121
- }
122
- b.WriteString("- **" + group.label + ":** " + strings.Join(refs, ", ") + "\n")
123
- }
124
-
125
- return b.String()
126
- }
127
-
128
- func (s *site) scopeRef(from string, scope catalog.AdrScope) string {
129
- switch scope.Kind {
130
- case "context":
131
- return s.ref(from, scope.Context, scope.Context)
132
- case "service":
133
- return s.ref(from, scope.Service, scope.Service)
134
- default:
135
- return "org"
136
- }
137
- }
138
-
139
- // commitLine is who and when, and the commit itself short enough to read:
140
- // "Viktor Login, 2024-09-10 (`a6181fe`)".
141
- func commitLine(c *catalog.AdrCommit) string {
142
- date := c.Date
143
- if len(date) >= 10 {
144
- date = date[:10]
145
- }
146
- sha := c.Commit
147
- if len(sha) > 7 {
148
- sha = sha[:7]
149
- }
150
- parts := []string{}
151
- if c.Author != "" {
152
- parts = append(parts, c.Author)
153
- }
154
- if date != "" {
155
- parts = append(parts, date)
156
- }
157
- line := strings.Join(parts, ", ")
158
- if sha != "" {
159
- line += " (`" + sha + "`)"
160
- }
161
- return strings.TrimSpace(line)
162
- }
@@ -1,362 +0,0 @@
1
- package main
2
-
3
- import (
4
- "strconv"
5
- "strings"
6
-
7
- "github.com/shortlink-org/portolan/catalog"
8
- )
9
-
10
- func (s *site) renderAggregate(svc *catalog.Service, agg *catalog.Aggregate) {
11
- self := s.pathOf[agg.ID]
12
-
13
- var b strings.Builder
14
- b.WriteString("# " + agg.Name + "\n\n")
15
- b.WriteString(s.stamp() + "\n")
16
-
17
- b.WriteString(defList([][]string{
18
- {"Id", code(agg.ID)},
19
- {"Service", s.ref(self, svc.ID, svc.Name)},
20
- {"Root", code(agg.Root)},
21
- }))
22
-
23
- if readme := body(agg.Readme, agg.Name); readme != "" {
24
- b.WriteString("\n" + readme + "\n")
25
- }
26
-
27
- if !hasBlock(agg.Entities, agg.Root) {
28
- s.b.warn(agg.ID, "aggregate %q names %q as its root, which is not one of its entities", agg.ID, agg.Root)
29
- }
30
-
31
- section(&b, "Entities", s.blocks(self, agg.Entities, agg.Root))
32
- section(&b, "Value objects", s.blocks(self, agg.ValueObjects, ""))
33
- section(&b, "Enums", s.enums(agg.Enums))
34
- section(&b, "Lifecycle", s.lifecycle(self, svc, agg))
35
- section(&b, "Operations", s.operationsTable(agg))
36
- section(&b, "Events", s.eventsBlock(self, svc, agg))
37
-
38
- s.b.file(self, b.String())
39
- }
40
-
41
- // lifecycle draws the root's state machine as the code wrote it down, and
42
- // lists the moves under it with the event each one publishes. The first
43
- // state is where a new root starts; a state nothing leads out of ends.
44
- func (s *site) lifecycle(from string, svc *catalog.Service, agg *catalog.Aggregate) string {
45
- lc := agg.Lifecycle
46
- if lc == nil || len(lc.States) == 0 {
47
- return ""
48
- }
49
- alias := func(state string) string {
50
- var b strings.Builder
51
- for _, r := range state {
52
- if r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r >= '0' && r <= '9' {
53
- b.WriteRune(r)
54
- } else {
55
- b.WriteByte('_')
56
- }
57
- }
58
- return b.String()
59
- }
60
- leads := map[string]bool{}
61
- for _, t := range lc.Transitions {
62
- if t.From != t.To {
63
- leads[t.From] = true
64
- }
65
- }
66
- eventName := func(id string) string {
67
- for i := range agg.Events {
68
- if agg.Events[i].ID == id {
69
- return agg.Events[i].Name
70
- }
71
- }
72
- return id
73
- }
74
-
75
- var d strings.Builder
76
- d.WriteString("stateDiagram-v2\n")
77
- for _, state := range lc.States {
78
- if alias(state) != state {
79
- d.WriteString(" state \"" + mermaidText(state) + "\" as " + alias(state) + "\n")
80
- }
81
- }
82
- d.WriteString(" [*] --> " + alias(lc.States[0]) + "\n")
83
- for _, t := range lc.Transitions {
84
- label := t.On
85
- if t.Emits != "" {
86
- label += " · " + eventName(t.Emits)
87
- }
88
- d.WriteString(" " + alias(t.From) + " --> " + alias(t.To) + ": " + mermaidText(label) + "\n")
89
- }
90
- for _, state := range lc.States {
91
- if !leads[state] {
92
- d.WriteString(" " + alias(state) + " --> [*]\n")
93
- }
94
- }
95
-
96
- rows := make([][]string, 0, len(lc.Transitions))
97
- for _, t := range lc.Transitions {
98
- emits := ""
99
- if t.Emits != "" {
100
- emits = s.ref(from, t.Emits, eventName(t.Emits))
101
- }
102
- rows = append(rows, []string{code(t.From), code(t.To), code(t.On), emits, s.source(from, t.Source, svc)})
103
- }
104
-
105
- return fence("mermaid", d.String()) + "\n" + table([]string{"From", "To", "On", "Emits", "Source"}, rows)
106
- }
107
-
108
- func hasBlock(blocks []catalog.Block, name string) bool {
109
- for i := range blocks {
110
- if blocks[i].Name == name {
111
- return true
112
- }
113
- }
114
-
115
- return false
116
- }
117
-
118
- // blocks renders entities or value objects. A block is either a shape of its
119
- // own or a name for a shared one; both are shown with their fields, because a
120
- // reader asking what a value object holds should not have to follow a link to
121
- // find out.
122
- // enums lists each closed set with its values in declaration order: what a
123
- // consumer has to handle, next to the doc that says when each one comes.
124
- func (s *site) enums(enums []catalog.Enum) string {
125
- var b strings.Builder
126
-
127
- for i := range enums {
128
- set := &enums[i]
129
-
130
- heading := set.Name
131
- if set.Deprecated {
132
- heading += " — deprecated"
133
- }
134
- b.WriteString("### " + heading + "\n\n")
135
-
136
- if set.Doc != "" {
137
- b.WriteString(set.Doc + "\n\n")
138
- }
139
-
140
- rows := make([][]string, 0, len(set.Values))
141
- for _, value := range set.Values {
142
- name := code(value.Name)
143
- if value.Deprecated {
144
- name += " (deprecated)"
145
- }
146
- rows = append(rows, []string{name, value.Doc})
147
- }
148
- if rendered := table([]string{"Value", "Doc"}, rows); rendered != "" {
149
- b.WriteString(rendered + "\n")
150
- }
151
- }
152
-
153
- return b.String()
154
- }
155
-
156
- func (s *site) blocks(from string, blocks []catalog.Block, root string) string {
157
- var b strings.Builder
158
-
159
- for i := range blocks {
160
- block := &blocks[i]
161
-
162
- heading := block.Name
163
- if block.Name == root {
164
- heading += " — aggregate root"
165
- }
166
- b.WriteString("### " + heading + "\n\n")
167
-
168
- if block.Doc != "" {
169
- b.WriteString(block.Doc + "\n\n")
170
- }
171
-
172
- fields := block.Fields
173
- if block.Ref != "" {
174
- def, ok := s.cat.Defs[block.Ref]
175
- if !ok {
176
- s.b.warn(block.ID, "%q refers to shared type %q, which this catalog does not define", block.ID, block.Ref)
177
- } else {
178
- fields = def.Fields
179
- }
180
- b.WriteString("Shared type " + s.defRef(from, block.Ref) + ".\n\n")
181
- }
182
-
183
- if rendered := s.fieldTable(from, fields); rendered != "" {
184
- b.WriteString(rendered + "\n")
185
- }
186
- }
187
-
188
- return b.String()
189
- }
190
-
191
- func (s *site) operationsTable(agg *catalog.Aggregate) string {
192
- // Whether this service records what exposes an operation at all. A catalog
193
- // written before anything read a transport layer says nothing either way,
194
- // and printing "internal" from that silence would be inventing.
195
- recorded := false
196
- for i := range agg.Operations {
197
- if len(agg.Operations[i].ExposedBy) > 0 {
198
- recorded = true
199
-
200
- break
201
- }
202
- }
203
-
204
- rows := make([][]string, 0, len(agg.Operations))
205
- for i := range agg.Operations {
206
- op := &agg.Operations[i]
207
-
208
- exposed := ""
209
- switch {
210
- case len(op.ExposedBy) > 0:
211
- methods := make([]string, 0, len(op.ExposedBy))
212
- for _, method := range op.ExposedBy {
213
- methods = append(methods, code(method))
214
- }
215
- exposed = strings.Join(methods, ", ")
216
- case recorded:
217
- exposed = "*internal*"
218
- }
219
-
220
- rows = append(rows, []string{code(op.ID), string(op.Kind), exposed, op.Doc})
221
- }
222
-
223
- return table([]string{"Operation", "Kind", "Exposed by", "Doc"}, rows)
224
- }
225
-
226
- // eventsBlock renders every version of every event, oldest first.
227
- //
228
- // Older versions are kept rather than collapsed into the latest: a consumer
229
- // reading this page is very often the one still on v1, and a page that shows
230
- // only what the publisher sends today cannot answer their question.
231
- func (s *site) eventsBlock(from string, svc *catalog.Service, agg *catalog.Aggregate) string {
232
- var b strings.Builder
233
-
234
- for i := range agg.Events {
235
- event := &agg.Events[i]
236
- b.WriteString("<a id=\"event-" + anchorID(event.ID) + "\"></a>\n")
237
- b.WriteString("### " + event.Name + "\n\n")
238
- b.WriteString(code(event.ID) + "\n")
239
-
240
- if event.Wire != nil {
241
- line := "On the wire as " + code(event.Wire.Name)
242
- if event.Wire.Channel != "" {
243
- line += ", on " + code(event.Wire.Channel)
244
- }
245
- b.WriteString("\n" + line + ".\n")
246
- }
247
-
248
- if len(event.Versions) == 0 {
249
- s.b.warn(event.ID, "event %q has no versions", event.ID)
250
- }
251
-
252
- consumers := make([][]string, 0, len(event.Consumers))
253
- for _, consumer := range event.Consumers {
254
- consumers = append(consumers, []string{
255
- s.ref(from, consumer.Service, consumer.Service),
256
- string(consumer.Status),
257
- s.viaRef(from, consumer.Via),
258
- consumer.Note,
259
- })
260
- }
261
- if rendered := table([]string{"Consumer", "Status", "Via", "Note"}, consumers); rendered != "" {
262
- b.WriteString("\n" + rendered)
263
- }
264
-
265
- for j := range event.Versions {
266
- version := &event.Versions[j]
267
-
268
- label := version.Version
269
- if j == len(event.Versions)-1 {
270
- label += " — current"
271
- }
272
- b.WriteString("\n#### " + label + "\n\n")
273
-
274
- if version.Doc != "" {
275
- b.WriteString(version.Doc + "\n\n")
276
- }
277
- if version.Source != "" {
278
- b.WriteString("Source: " + s.source(from, version.Source, svc) + "\n\n")
279
- }
280
- b.WriteString(s.fieldTable(from, version.Fields))
281
- }
282
- b.WriteString("\n")
283
- }
284
-
285
- return b.String()
286
- }
287
-
288
- func (s *site) fieldTable(from string, fields []catalog.Field) string {
289
- rows := make([][]string, 0, len(fields))
290
- for i := range fields {
291
- field := &fields[i]
292
-
293
- typ := code(field.Type)
294
- if field.Ref != "" {
295
- typ = s.defRef(from, field.Ref)
296
- }
297
- rows = append(rows, []string{code(field.Name), typ, field.Doc})
298
- }
299
-
300
- return table([]string{"Field", "Type", "Doc"}, rows)
301
- }
302
-
303
- // defRef links a shared type to its entry on the types page. Shared types have
304
- // no page of their own: what a reader wants from `Money` is the same six lines
305
- // wherever it is mentioned, and six lines do not deserve twenty files.
306
- func (s *site) defRef(from, key string) string {
307
- if _, ok := s.cat.Defs[key]; !ok {
308
- return code(key)
309
- }
310
-
311
- return "[" + code(key) + "](" + rel(from, typesPage) + "#type-" + anchorID(key) + ")"
312
- }
313
-
314
- const typesPage = "types.md"
315
-
316
- // anchor is a GitHub-flavoured heading anchor: lowercased, spaces to dashes,
317
- // everything else dropped.
318
- func anchor(heading string) string {
319
- var b strings.Builder
320
- for _, r := range strings.ToLower(heading) {
321
- switch {
322
- case r >= 'a' && r <= 'z', r >= '0' && r <= '9', r == '-', r == '_':
323
- b.WriteRune(r)
324
- case r == ' ':
325
- b.WriteRune('-')
326
- }
327
- }
328
-
329
- return b.String()
330
- }
331
-
332
- func (s *site) renderTypes() {
333
- if len(s.cat.Defs) == 0 {
334
- return
335
- }
336
-
337
- var b strings.Builder
338
- b.WriteString("# Shared types\n\n")
339
- b.WriteString(s.stamp() + "\n")
340
- b.WriteString("Types named by more than one aggregate, event or message. A field that\n")
341
- b.WriteString("refers to one of these is knowably the same shape everywhere it appears.\n")
342
-
343
- for _, key := range sortedDefKeys(s.cat.Defs) {
344
- def := s.cat.Defs[key]
345
- b.WriteString("\n<a id=\"type-" + anchorID(key) + "\"></a>\n")
346
- b.WriteString("\n## " + key + "\n\n")
347
- b.WriteString(s.fieldTable(typesPage, def.Fields))
348
- }
349
-
350
- s.b.file(typesPage, b.String())
351
- }
352
-
353
- func plural(n int, word string, irregular ...string) string {
354
- if n == 1 {
355
- return "1 " + word
356
- }
357
- if len(irregular) > 0 {
358
- return strconv.Itoa(n) + " " + irregular[0]
359
- }
360
-
361
- return strconv.Itoa(n) + " " + word + "s"
362
- }
@@ -1,93 +0,0 @@
1
- package main
2
-
3
- import (
4
- "slices"
5
- "strings"
6
-
7
- "github.com/shortlink-org/portolan/catalog"
8
- )
9
-
10
- // canonicalCatalog sorts only collections whose order carries no meaning.
11
- // Fields, event versions, lifecycle transitions, flow participants and flow
12
- // nodes deliberately keep their declared order.
13
- func canonicalCatalog(cat catalog.Catalog) catalog.Catalog {
14
- out := cat
15
- out.Contexts = slices.Clone(cat.Contexts)
16
- slices.SortFunc(out.Contexts, func(a, b catalog.BoundedContext) int { return strings.Compare(a.ID, b.ID) })
17
- for i := range out.Contexts {
18
- ctx := &out.Contexts[i]
19
- ctx.Services = slices.Clone(ctx.Services)
20
- slices.SortFunc(ctx.Services, func(a, b catalog.Service) int { return strings.Compare(a.ID, b.ID) })
21
- for j := range ctx.Services {
22
- svc := &ctx.Services[j]
23
- svc.Aggregates = slices.Clone(svc.Aggregates)
24
- slices.SortFunc(svc.Aggregates, func(a, b catalog.Aggregate) int { return strings.Compare(a.ID, b.ID) })
25
- for k := range svc.Aggregates {
26
- agg := &svc.Aggregates[k]
27
- agg.Entities = slices.Clone(agg.Entities)
28
- slices.SortFunc(agg.Entities, func(a, b catalog.Block) int { return strings.Compare(a.ID, b.ID) })
29
- agg.ValueObjects = slices.Clone(agg.ValueObjects)
30
- slices.SortFunc(agg.ValueObjects, func(a, b catalog.Block) int { return strings.Compare(a.ID, b.ID) })
31
- agg.Operations = slices.Clone(agg.Operations)
32
- slices.SortFunc(agg.Operations, func(a, b catalog.Operation) int { return strings.Compare(a.ID, b.ID) })
33
- agg.Events = slices.Clone(agg.Events)
34
- slices.SortFunc(agg.Events, func(a, b catalog.Event) int { return strings.Compare(a.ID, b.ID) })
35
- agg.Enums = slices.Clone(agg.Enums)
36
- slices.SortFunc(agg.Enums, func(a, b catalog.Enum) int { return strings.Compare(a.ID, b.ID) })
37
- }
38
- svc.Provides = canonicalProvides(svc.Provides)
39
- svc.Consumes = slices.Clone(svc.Consumes)
40
- slices.SortFunc(svc.Consumes, func(a, b catalog.RpcCall) int { return strings.Compare(a.ID, b.ID) })
41
- svc.Stores = sortedStrings(svc.Stores)
42
- svc.Modules = sortedStrings(svc.Modules)
43
- svc.Channels = slices.Clone(svc.Channels)
44
- slices.SortFunc(svc.Channels, func(a, b catalog.Channel) int { return strings.Compare(a.Address, b.Address) })
45
- }
46
- }
47
- out.Stores = slices.Clone(cat.Stores)
48
- slices.SortFunc(out.Stores, func(a, b catalog.Store) int { return strings.Compare(a.ID, b.ID) })
49
- out.Flows = slices.Clone(cat.Flows)
50
- slices.SortFunc(out.Flows, func(a, b catalog.Flow) int { return strings.Compare(a.ID, b.ID) })
51
- out.Adrs = slices.Clone(cat.Adrs)
52
- slices.SortFunc(out.Adrs, func(a, b catalog.Adr) int { return strings.Compare(a.ID, b.ID) })
53
- out.Modules = slices.Clone(cat.Modules)
54
- slices.SortFunc(out.Modules, func(a, b catalog.ProtoModule) int { return strings.Compare(a.ID, b.ID) })
55
- for i := range out.Modules {
56
- out.Modules[i].Packages = sortedStrings(out.Modules[i].Packages)
57
- out.Modules[i].Files = sortedStrings(out.Modules[i].Files)
58
- out.Modules[i].Deps = sortedStrings(out.Modules[i].Deps)
59
- }
60
- out.Terms = slices.Clone(cat.Terms)
61
- slices.SortFunc(out.Terms, func(a, b catalog.Term) int {
62
- if a.Context != b.Context {
63
- return strings.Compare(a.Context, b.Context)
64
- }
65
- return strings.Compare(strings.ToLower(a.Name), strings.ToLower(b.Name))
66
- })
67
- out.Externals = slices.Clone(cat.Externals)
68
- slices.SortFunc(out.Externals, func(a, b catalog.External) int { return strings.Compare(a.ID, b.ID) })
69
- for i := range out.Externals {
70
- out.Externals[i].Provides = canonicalProvides(out.Externals[i].Provides)
71
- }
72
- return out
73
- }
74
-
75
- func canonicalProvides(input []catalog.RpcService) []catalog.RpcService {
76
- out := slices.Clone(input)
77
- slices.SortFunc(out, func(a, b catalog.RpcService) int { return strings.Compare(a.ID, b.ID) })
78
- for i := range out {
79
- out[i].Methods = slices.Clone(out[i].Methods)
80
- slices.SortFunc(out[i].Methods, func(a, b catalog.RpcMethod) int { return strings.Compare(a.Name, b.Name) })
81
- out[i].Messages = slices.Clone(out[i].Messages)
82
- slices.SortFunc(out[i].Messages, func(a, b catalog.RpcMessage) int { return strings.Compare(a.Name, b.Name) })
83
- out[i].Enums = slices.Clone(out[i].Enums)
84
- slices.SortFunc(out[i].Enums, func(a, b catalog.RpcEnum) int { return strings.Compare(a.Name, b.Name) })
85
- }
86
- return out
87
- }
88
-
89
- func sortedStrings(input []string) []string {
90
- out := slices.Clone(input)
91
- slices.Sort(out)
92
- return out
93
- }
@@ -1,90 +0,0 @@
1
- package main
2
-
3
- import (
4
- "strings"
5
-
6
- "github.com/shortlink-org/portolan/catalog"
7
- )
8
-
9
- func (s *site) renderContext(ctx *catalog.BoundedContext) {
10
- self := s.pathOf[ctx.ID]
11
-
12
- var b strings.Builder
13
- b.WriteString("# " + ctx.Name + "\n\n")
14
- b.WriteString(s.stamp() + "\n")
15
-
16
- meta := [][]string{{"Id", code(ctx.ID)}}
17
- if ctx.Kind != "" {
18
- meta = append(meta, []string{"Kind", string(ctx.Kind)})
19
- }
20
- if ctx.Classification != "" {
21
- meta = append(meta, []string{"Classification", string(ctx.Classification)})
22
- }
23
- b.WriteString(defList(meta))
24
-
25
- if ctx.Summary != "" {
26
- b.WriteString("\n" + ctx.Summary + "\n")
27
- }
28
-
29
- neutral := ctx.Kind != "" && ctx.Kind != catalog.GroupKindBoundedContext
30
- rows := make([][]string, 0, len(ctx.Services))
31
- for i := range ctx.Services {
32
- svc := &ctx.Services[i]
33
- if neutral {
34
- rows = append(rows, []string{
35
- s.ref(self, svc.ID, svc.Name),
36
- string(svc.Kind),
37
- strings.Join(svc.Technologies, ", "),
38
- code(svc.Path),
39
- })
40
- continue
41
- }
42
- aggregates := make([]string, 0, len(svc.Aggregates))
43
- for j := range svc.Aggregates {
44
- aggregates = append(aggregates, svc.Aggregates[j].Name)
45
- }
46
- rows = append(rows, []string{
47
- s.ref(self, svc.ID, svc.Name),
48
- code(svc.Path),
49
- strings.Join(aggregates, ", "),
50
- })
51
- }
52
- title := "Services"
53
- firstColumn := "Service"
54
- headings := []string{firstColumn, "Path", "Aggregates"}
55
- if neutral {
56
- title = "Components"
57
- firstColumn = "Component"
58
- headings = []string{firstColumn, "Kind", "Technologies", "Path"}
59
- }
60
- section(&b, title, table(headings, rows))
61
-
62
- // Before the decisions, because the decisions are written in these words.
63
- if terms := s.termsOf[ctx.ID]; len(terms) > 0 {
64
- section(&b, "Language", "- "+link("Glossary", self, s.glossaryPath(ctx))+
65
- " — "+plural(len(terms), "term")+" this context spells one way\n")
66
- }
67
-
68
- section(&b, "Decisions", s.adrTable(self, s.adrsFor[ctx.ID]))
69
-
70
- s.b.file(self, b.String())
71
- s.renderGlossary(ctx)
72
-
73
- for i := range ctx.Services {
74
- s.renderService(ctx, &ctx.Services[i])
75
- }
76
- }
77
-
78
- func (s *site) adrTable(from string, adrs []*catalog.Adr) string {
79
- rows := make([][]string, 0, len(adrs))
80
- for _, adr := range adrs {
81
- rows = append(rows, []string{
82
- s.ref(from, adr.ID, adr.ID),
83
- adr.Title,
84
- string(adr.Status),
85
- adr.Date,
86
- })
87
- }
88
-
89
- return table([]string{"ADR", "Title", "Status", "Date"}, rows)
90
- }