@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,261 +0,0 @@
1
- package main
2
-
3
- import (
4
- "encoding/json"
5
- "io"
6
- "os"
7
- "path/filepath"
8
- "strings"
9
- "testing"
10
-
11
- "github.com/shortlink-org/portolan/catalog"
12
- "github.com/shortlink-org/portolan/plugin"
13
- )
14
-
15
- // The extractor's own golden is examples/auth/portolan/domain.json, which is
16
- // committed and checked by `npm run gen:check`. What is worth testing here is
17
- // the handful of judgements it makes on the way: what a name becomes, what
18
- // counts as a command, and which prose is worth keeping.
19
-
20
- func TestSlug(t *testing.T) {
21
- cases := map[string]string{
22
- "User": "user",
23
- "PriceList": "price-list",
24
- "OrderLine": "order-line",
25
- "email.Address": "email-address",
26
- "ID": "id",
27
- "HTTPServer": "http-server",
28
- }
29
-
30
- for in, want := range cases {
31
- if got := slug(in); got != want {
32
- t.Errorf("slug(%q) = %q, want %q", in, got, want)
33
- }
34
- }
35
- }
36
-
37
- func TestCamelAndTitle(t *testing.T) {
38
- if got := camel("end_after_credential_change"); got != "EndAfterCredentialChange" {
39
- t.Errorf("camel = %q", got)
40
- }
41
- if got := title("price_list"); got != "Price List" {
42
- t.Errorf("title = %q", got)
43
- }
44
- }
45
-
46
- // token.Token adds nothing over Token; password.Hash says which Hash.
47
- func TestQualified(t *testing.T) {
48
- if got := qualified("token", "Token"); got != "Token" {
49
- t.Errorf("qualified = %q", got)
50
- }
51
- if got := qualified("password", "Hash"); got != "password.Hash" {
52
- t.Errorf("qualified = %q", got)
53
- }
54
- }
55
-
56
- func TestWithoutPackagePrefix(t *testing.T) {
57
- got := withoutPackagePrefix("user", "Package user holds the User aggregate: a person.")
58
- if got != "Holds the User aggregate: a person." {
59
- t.Errorf("withoutPackagePrefix = %q", got)
60
- }
61
-
62
- // A comment that does not follow the convention is left exactly as written.
63
- unchanged := "The User aggregate."
64
- if got := withoutPackagePrefix("user", unchanged); got != unchanged {
65
- t.Errorf("withoutPackagePrefix rewrote %q", got)
66
- }
67
- }
68
-
69
- func TestFirstParagraphAfterTitle(t *testing.T) {
70
- md := "# register\n\nCreates a user from an email address and a password.\n\n## What it does\n\n1. Normalises.\n"
71
- if got := firstParagraphAfterTitle(md); got != "Creates a user from an email address and a password." {
72
- t.Errorf("firstParagraphAfterTitle = %q", got)
73
- }
74
- }
75
-
76
- // The classification a reader most depends on: a use case that writes is a
77
- // command even when the write happens in a helper rather than in Handle.
78
- func TestOperationKindFollowsHelpers(t *testing.T) {
79
- pkg := mustParse(t, `package usecase
80
-
81
- type UseCase struct{ repo Repository }
82
- type Repository interface{ Save(any, string) error }
83
-
84
- func (uc *UseCase) Handle(ctx any, in any) error {
85
- for _, id := range uc.list() {
86
- if err := uc.end(ctx, id); err != nil {
87
- return err
88
- }
89
- }
90
- return nil
91
- }
92
-
93
- func (uc *UseCase) end(ctx any, id string) error { return uc.repo.Save(ctx, id) }
94
- `)
95
-
96
- if got := operationKind(pkg); got != catalog.OperationCommand {
97
- t.Errorf("a use case that saves in a helper is a command, got %q", got)
98
- }
99
- }
100
-
101
- func TestOperationKindReadOnlyIsQuery(t *testing.T) {
102
- pkg := mustParse(t, `package usecase
103
-
104
- type UseCase struct{}
105
-
106
- func (uc *UseCase) Handle(ctx any, in any) (any, error) { return uc.repo.ByID(ctx, "id") }
107
- `)
108
-
109
- if got := operationKind(pkg); got != catalog.OperationQuery {
110
- t.Errorf("a use case that only reads is a query, got %q", got)
111
- }
112
- }
113
-
114
- func TestOperationKindIgnoresWriteNamedCallsOutsidePorts(t *testing.T) {
115
- pkg := mustParse(t, `package usecase
116
-
117
- type helper struct{}
118
- func (helper) Save() {}
119
- type UseCase struct{ repo Repository }
120
- type Repository interface{ ByID(any, string) (any, error) }
121
- func (uc *UseCase) Handle(ctx any) (any, error) {
122
- helper{}.Save()
123
- return uc.repo.ByID(ctx, "id")
124
- }
125
- `)
126
-
127
- if got := operationKind(pkg); got != catalog.OperationQuery {
128
- t.Errorf("a Save call outside a use-case port must not make a command, got %q", got)
129
- }
130
- }
131
-
132
- // An extractor with nothing to read must say so rather than answer with an
133
- // empty service that looks like a service with no model.
134
- func TestExtractRefusesAnEmptyRoot(t *testing.T) {
135
- request := `{"portolanVersion":"0.1.0","input":{"root":""}}`
136
- if err := run(strings.NewReader(request), io.Discard); err == nil {
137
- t.Error("a request with no input root should be refused")
138
- }
139
- }
140
-
141
- func TestEventsNeedAName(t *testing.T) {
142
- pkg := mustParse(t, `package event
143
-
144
- // Envelope wraps a published event. It is not one.
145
- type Envelope struct{ payload string }
146
-
147
- // UserRegistered is published once per user.
148
- type UserRegistered struct{ userID string }
149
-
150
- func (UserRegistered) Name() string { return "auth.UserRegistered" }
151
- `)
152
-
153
- events := eventsIn(pkg, "auth.auth.user", "auth_user")
154
- if len(events) != 1 || events[0].Name != "UserRegistered" {
155
- t.Fatalf("expected only UserRegistered, got %v", names(events))
156
- }
157
- wire := events[0].Wire
158
- if wire == nil || wire.Name != "auth.UserRegistered" || wire.Channel != "auth_user" {
159
- t.Errorf("the name on the message and the channel should be the wire, got %+v", wire)
160
- }
161
- if got := events[0].Versions[0].Doc; got != "UserRegistered is published once per user." {
162
- t.Errorf("the doc should be the struct's own, got %q", got)
163
- }
164
- }
165
-
166
- func TestEventsWithoutAChannel(t *testing.T) {
167
- pkg := mustParse(t, `package event
168
-
169
- type Registered struct{}
170
-
171
- func (Registered) Name() string { return "auth.Registered" }
172
- `)
173
-
174
- events := eventsIn(pkg, "auth.auth.user", "")
175
- if len(events) != 1 || events[0].Wire == nil || events[0].Wire.Channel != "" {
176
- t.Fatalf("a named event with no dto.Topic keeps its name and no channel, got %+v", events)
177
- }
178
- }
179
-
180
- func names(events []catalog.Event) []string {
181
- out := make([]string, len(events))
182
- for i := range events {
183
- out[i] = events[i].Name
184
- }
185
-
186
- return out
187
- }
188
-
189
- func mustParse(t *testing.T, src string) *pkg {
190
- t.Helper()
191
-
192
- parsed, err := parseSource("source.go", src)
193
- if err != nil {
194
- t.Fatal(err)
195
- }
196
-
197
- return parsed
198
- }
199
-
200
- // A domain package with a README is described by it; one without falls back
201
- // to the package comment, headed so the page does not start mid-paragraph.
202
- func TestAggregateReadmePrefersTheFile(t *testing.T) {
203
- root := t.TempDir()
204
- dir := filepath.Join(root, "internal", "domain", "session")
205
- if err := os.MkdirAll(dir, 0o755); err != nil {
206
- t.Fatal(err)
207
- }
208
-
209
- if got := aggregateReadme(root, "internal/domain/session", "session", "Session", "Package session holds the Session aggregate."); got != "# Session\n\nHolds the Session aggregate." {
210
- t.Errorf("without a README = %q", got)
211
- }
212
-
213
- md := "# Session\n\n## States\n\n- Live\n"
214
- if err := os.WriteFile(filepath.Join(dir, "README.md"), []byte(md+"\n"), 0o644); err != nil {
215
- t.Fatal(err)
216
- }
217
- if got := aggregateReadme(root, "internal/domain/session", "session", "Session", "Package session holds the Session aggregate."); got != strings.TrimSpace(md) {
218
- t.Errorf("with a README = %q", got)
219
- }
220
- }
221
-
222
- // A package under internal/domain with no struct named after it is not an
223
- // aggregate, whatever else it declares. Taking the first struct as the root
224
- // would document a package of error types as a model, and a wrong table is
225
- // worse than no page.
226
- func TestAPackageWithoutItsRootIsNotAnAggregate(t *testing.T) {
227
- root := t.TempDir()
228
- dir := filepath.Join(root, "internal", "domain", "domainerrors")
229
- if err := os.MkdirAll(dir, 0o755); err != nil {
230
- t.Fatal(err)
231
- }
232
- src := "package domainerrors\n\n// WithNotifyError carries what to tell the user.\ntype WithNotifyError struct {\n\tCode string\n\tTitle string\n}\n"
233
- if err := os.WriteFile(filepath.Join(dir, "errors.go"), []byte(src), 0o644); err != nil {
234
- t.Fatal(err)
235
- }
236
- if err := os.WriteFile(filepath.Join(root, "go.mod"), []byte("module example.com/svc\n"), 0o644); err != nil {
237
- t.Fatal(err)
238
- }
239
-
240
- resp, err := extract(plugin.Input{Root: root, Commit: "abc1234", GeneratedAt: "2026-01-01T00:00:00Z"}, Options{Context: "avia", Service: "svc"})
241
- if err != nil {
242
- t.Fatal(err)
243
- }
244
- var out catalog.Catalog
245
- if err := json.Unmarshal([]byte(resp.Files[0].Contents), &out); err != nil {
246
- t.Fatal(err)
247
- }
248
- if got := out.Contexts[0].Services[0].Aggregates; len(got) != 0 {
249
- t.Errorf("read as aggregates: %+v", got)
250
- }
251
-
252
- var said bool
253
- for _, warning := range resp.Warnings() {
254
- if strings.Contains(warning.Message, "has no struct called Domainerrors, so it is not read as an aggregate") {
255
- said = true
256
- }
257
- }
258
- if !said {
259
- t.Errorf("nothing said why; warnings = %+v", resp.Warnings())
260
- }
261
- }