@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,185 +0,0 @@
1
- package catalog
2
-
3
- import (
4
- "encoding/json"
5
- "fmt"
6
- "os"
7
- "path/filepath"
8
- "sort"
9
- "testing"
10
- )
11
-
12
- // TestRoundTrip is what holds this package to src/catalog.ts.
13
- //
14
- // Every real catalog in the repository is unmarshalled into these structs and
15
- // marshalled straight back out. Anything the mirror does not know about is
16
- // dropped on the way in and missing on the way out, so a field added to the
17
- // TypeScript and forgotten here fails as a named path rather than as a blank
18
- // section in somebody's generated documentation.
19
- //
20
- // The comparison is semantic: key order differs by construction, and an
21
- // optional list that was written as [] is the same fact as one left out.
22
- func TestRoundTrip(t *testing.T) {
23
- files, err := filepath.Glob("../data/*.json")
24
- if err != nil {
25
- t.Fatal(err)
26
- }
27
- if len(files) == 0 {
28
- t.Fatal("no catalogs under ../data - this test proves nothing without one")
29
- }
30
-
31
- for _, path := range files {
32
- t.Run(filepath.Base(path), func(t *testing.T) {
33
- raw, err := os.ReadFile(path)
34
- if err != nil {
35
- t.Fatal(err)
36
- }
37
-
38
- var before any
39
- if err := json.Unmarshal(raw, &before); err != nil {
40
- t.Fatalf("source is not JSON: %v", err)
41
- }
42
-
43
- var parsed Catalog
44
- if err := json.Unmarshal(raw, &parsed); err != nil {
45
- t.Fatalf("catalog does not fit the mirror: %v", err)
46
- }
47
-
48
- out, err := json.Marshal(&parsed)
49
- if err != nil {
50
- t.Fatalf("mirror does not marshal: %v", err)
51
- }
52
-
53
- var after any
54
- if err := json.Unmarshal(out, &after); err != nil {
55
- t.Fatal(err)
56
- }
57
-
58
- diffs := compare("catalog", normalize(before), normalize(after))
59
- if len(diffs) == 0 {
60
- return
61
- }
62
-
63
- shown := diffs
64
- if len(shown) > 20 {
65
- shown = shown[:20]
66
- }
67
- for _, d := range shown {
68
- t.Error(d)
69
- }
70
- if len(diffs) > len(shown) {
71
- t.Errorf("... and %d more", len(diffs)-len(shown))
72
- }
73
- })
74
- }
75
- }
76
-
77
- // normalize drops keys whose value carries no information. An optional list
78
- // written as [] and one left out entirely say the same thing, and holding the
79
- // mirror to which of the two it produces would test encoding/json rather than
80
- // the shape.
81
- func normalize(v any) any {
82
- switch t := v.(type) {
83
- case map[string]any:
84
- out := make(map[string]any, len(t))
85
- for k, item := range t {
86
- switch inner := item.(type) {
87
- case []any:
88
- if len(inner) == 0 {
89
- continue
90
- }
91
- case map[string]any:
92
- if len(inner) == 0 {
93
- continue
94
- }
95
- }
96
- out[k] = normalize(item)
97
- }
98
-
99
- return out
100
- case []any:
101
- out := make([]any, len(t))
102
- for i, item := range t {
103
- out[i] = normalize(item)
104
- }
105
-
106
- return out
107
- default:
108
- return v
109
- }
110
- }
111
-
112
- // compare walks both trees together and names every place they part, as a path
113
- // a reader can find in the file.
114
- func compare(path string, before, after any) []string {
115
- switch b := before.(type) {
116
- case map[string]any:
117
- a, ok := after.(map[string]any)
118
- if !ok {
119
- return []string{fmt.Sprintf("%s: object in the source, %T after the round trip", path, after)}
120
- }
121
-
122
- var diffs []string
123
- for _, key := range sortedKeys(b, a) {
124
- bv, inSource := b[key]
125
- av, inMirror := a[key]
126
- switch {
127
- case inSource && !inMirror:
128
- diffs = append(diffs, fmt.Sprintf("%s.%s: dropped by the mirror (%s)", path, key, brief(bv)))
129
- case !inSource && inMirror:
130
- diffs = append(diffs, fmt.Sprintf("%s.%s: invented by the mirror (%s)", path, key, brief(av)))
131
- default:
132
- diffs = append(diffs, compare(path+"."+key, bv, av)...)
133
- }
134
- }
135
-
136
- return diffs
137
- case []any:
138
- a, ok := after.([]any)
139
- if !ok {
140
- return []string{fmt.Sprintf("%s: list in the source, %T after the round trip", path, after)}
141
- }
142
- if len(b) != len(a) {
143
- return []string{fmt.Sprintf("%s: %d entries in the source, %d after the round trip", path, len(b), len(a))}
144
- }
145
-
146
- var diffs []string
147
- for i := range b {
148
- diffs = append(diffs, compare(fmt.Sprintf("%s[%d]", path, i), b[i], a[i])...)
149
- }
150
-
151
- return diffs
152
- default:
153
- if before != after {
154
- return []string{fmt.Sprintf("%s: %s became %s", path, brief(before), brief(after))}
155
- }
156
-
157
- return nil
158
- }
159
- }
160
-
161
- func sortedKeys(maps ...map[string]any) []string {
162
- seen := map[string]bool{}
163
- for _, m := range maps {
164
- for k := range m {
165
- seen[k] = true
166
- }
167
- }
168
-
169
- keys := make([]string, 0, len(seen))
170
- for k := range seen {
171
- keys = append(keys, k)
172
- }
173
- sort.Strings(keys)
174
-
175
- return keys
176
- }
177
-
178
- func brief(v any) string {
179
- s := fmt.Sprintf("%v", v)
180
- if len(s) > 60 {
181
- return s[:57] + "..."
182
- }
183
-
184
- return s
185
- }
@@ -1,38 +0,0 @@
1
- package catalog
2
-
3
- import (
4
- "encoding/json"
5
- "testing"
6
- )
7
-
8
- // TestEdgeViaRoundTrip pins the one field no committed catalog carries: `via`
9
- // is written by the host after the merge, so the roundtrip over data/*.json
10
- // never sees it, and the mirror would drop it silently on the way to a
11
- // generator.
12
- func TestEdgeViaRoundTrip(t *testing.T) {
13
- in := `{"service":"payments.ledger","status":"declared","via":{"flow":"order-accepted","step":"a3"}}`
14
-
15
- var c EventConsumer
16
- if err := json.Unmarshal([]byte(in), &c); err != nil {
17
- t.Fatal(err)
18
- }
19
- if c.Via == nil || c.Via.Flow != "order-accepted" || c.Via.Step != "a3" {
20
- t.Fatalf("via not read: %+v", c.Via)
21
- }
22
-
23
- out, err := json.Marshal(&c)
24
- if err != nil {
25
- t.Fatal(err)
26
- }
27
- if string(out) != in {
28
- t.Fatalf("round trip changed the consumer:\n got %s\nwant %s", out, in)
29
- }
30
-
31
- var call RpcCall
32
- if err := json.Unmarshal([]byte(`{"id":"x/Y","peer":"p","status":"declared","source":"s"}`), &call); err != nil {
33
- t.Fatal(err)
34
- }
35
- if call.Via != nil {
36
- t.Fatalf("a call without via must round-trip without one: %+v", call.Via)
37
- }
38
- }
package/go.mod DELETED
@@ -1,14 +0,0 @@
1
- module github.com/shortlink-org/portolan
2
-
3
- go 1.27.0
4
-
5
- require (
6
- github.com/pgplex/pgparser v0.2.0
7
- golang.org/x/tools v0.49.0
8
- gopkg.in/yaml.v3 v3.0.1
9
- )
10
-
11
- require (
12
- golang.org/x/mod v0.39.0 // indirect
13
- golang.org/x/sync v0.22.0 // indirect
14
- )
package/go.sum DELETED
@@ -1,14 +0,0 @@
1
- github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
2
- github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
3
- github.com/pgplex/pgparser v0.2.0 h1:BB7I/Mrwetiw07PTq/AlXcKfajlCwoJfwB7KZ7V9irI=
4
- github.com/pgplex/pgparser v0.2.0/go.mod h1:DWhK7oZJn/16KTFeOQ+mk78+sRnEYya1XPghIoP9NFU=
5
- golang.org/x/mod v0.39.0 h1:UF5zwQdCRRUpHfyPwr7d4UrGiVeldIsogtzWVnczL74=
6
- golang.org/x/mod v0.39.0/go.mod h1:bvIbwjQ0HUFFf5AKukeeYQG4ZBUG9yxQbR9aEweIwYY=
7
- golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
8
- golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
9
- golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI=
10
- golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo=
11
- gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
12
- gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
13
- gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
14
- gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -1,154 +0,0 @@
1
- package commands
2
-
3
- import (
4
- "os"
5
- "path/filepath"
6
- "regexp"
7
- "slices"
8
- "strings"
9
-
10
- "github.com/shortlink-org/portolan/catalog"
11
- )
12
-
13
- var cargoAliasTable = regexp.MustCompile(`(?m)^\[alias\]\s*$`)
14
- var xtaskArm = regexp.MustCompile(`(?m)^[ \t]*(?:Some\()?"[a-z][a-z0-9-]*"\)?[ \t]*(?:\|[ \t]*(?:Some\()?"[a-z][a-z0-9-]*"\)?[ \t]*)*=>`)
15
- var xtaskLiteral = regexp.MustCompile(`"([a-z][a-z0-9-]*)"`)
16
- var xtaskVariant = regexp.MustCompile(`^[ \t]*([A-Z][A-Za-z0-9]*)\s*(?:\{[^}]*\}|\([^)]*\))?\s*,?\s*$`)
17
- var xtaskEnum = regexp.MustCompile(`(?s)#\[derive\([^)]*Subcommand[^)]*\)\][^{]*\benum\s+\w+\s*\{(.*?)\n\}`)
18
-
19
- // readCargoAliases lists the aliases a checkout gives cargo in
20
- // `.cargo/config.toml`. An alias is the one place a Cargo project declares a
21
- // command of its own - `cargo xtask`, `cargo gen` - and its expansion is the
22
- // body. When an alias runs the `xtask` package, that package's subcommands
23
- // are listed under it as well, because `cargo xtask` on its own does nothing.
24
- func readCargoAliases(root, file, src string) []catalog.Command {
25
- loc := cargoAliasTable.FindStringIndex(src)
26
- if loc == nil {
27
- return nil
28
- }
29
- lines := strings.Split(src, "\n")
30
- start := strings.Count(src[:loc[0]], "\n") + 1
31
-
32
- var out []catalog.Command
33
- for i := start; i < len(lines); i++ {
34
- text := strings.TrimSpace(lines[i])
35
- if tomlHeader.MatchString(text) {
36
- break
37
- }
38
- m := tomlKey.FindStringSubmatch(text)
39
- if m == nil {
40
- continue
41
- }
42
- name := strings.Trim(m[1], `"`)
43
- if !typeable(name) {
44
- continue
45
- }
46
- body, _ := tomlTask(strings.TrimSpace(m[2]))
47
- out = append(out, catalog.Command{Runner: "cargo", Name: name, Run: "cargo " + name, Body: body, Source: at(file, i+1)})
48
-
49
- if pkg := runsPackage(body); pkg != "" {
50
- out = append(out, readXtask(root, name, pkg)...)
51
- }
52
- }
53
-
54
- return out
55
- }
56
-
57
- // runsPackage is the package an alias expansion runs, when it is `run
58
- // --package <name>` or `run -p <name>` - the xtask convention - and the
59
- // alias leaves the subcommand to the caller. `gen = "run -p xtask -- gen"`
60
- // names one subcommand already, and is listed as the one command it is.
61
- func runsPackage(expansion string) string {
62
- fields := strings.Fields(expansion)
63
- if len(fields) == 0 || fields[0] != "run" {
64
- return ""
65
- }
66
- if i := slices.Index(fields, "--"); i >= 0 && i+1 < len(fields) {
67
- return ""
68
- }
69
- for i, f := range fields {
70
- if (f == "--package" || f == "-p") && i+1 < len(fields) {
71
- return fields[i+1]
72
- }
73
- if rest, ok := strings.CutPrefix(f, "--package="); ok {
74
- return rest
75
- }
76
- }
77
-
78
- return ""
79
- }
80
-
81
- // readXtask lists the subcommands of an xtask-style package by reading its
82
- // main.rs for the two shapes they are written in: a match on the first
83
- // argument (`"dist" => ...`, `Some("dist") => ...`), and a clap enum
84
- // deriving Subcommand, whose variants are the commands in kebab-case. A
85
- // `///` comment over a variant, or its `about`, is the doc.
86
- func readXtask(root, alias, pkg string) []catalog.Command {
87
- for _, candidate := range []string{filepath.Join(pkg, "src", "main.rs"), filepath.Join("xtask", "src", "main.rs")} {
88
- raw, err := os.ReadFile(filepath.Join(root, candidate))
89
- if err != nil {
90
- continue
91
- }
92
- src := string(raw)
93
- file := filepath.ToSlash(filepath.Join(root, candidate))
94
- var out []catalog.Command
95
- seen := map[string]bool{}
96
- add := func(name, doc string, line int) {
97
- if seen[name] || !typeable(name) {
98
- return
99
- }
100
- seen[name] = true
101
- out = append(out, catalog.Command{Runner: "cargo", Name: alias + " " + name, Run: "cargo " + alias + " " + name, Doc: doc, Source: at(file, line)})
102
- }
103
-
104
- if e := xtaskEnum.FindStringSubmatchIndex(src); e != nil {
105
- body := src[e[2]:e[3]]
106
- lines := strings.Split(body, "\n")
107
- base := strings.Count(src[:e[2]], "\n") + 1
108
- for i, line := range lines {
109
- m := xtaskVariant.FindStringSubmatch(line)
110
- if m == nil {
111
- continue
112
- }
113
- doc := commentAbove(lines, i, "///")
114
- if doc == "" {
115
- if a := regexp.MustCompile(`about\s*=\s*"([^"]*)"`).FindStringSubmatch(strings.Join(lines[max(0, i-3):i], "\n")); a != nil {
116
- doc = a[1]
117
- }
118
- }
119
- add(kebab(m[1]), doc, base+i)
120
- }
121
- }
122
- lines := strings.Split(src, "\n")
123
- for _, m := range xtaskArm.FindAllStringIndex(src, -1) {
124
- // `Some("bench") | Some("perf") =>` is one arm and two names, and
125
- // the `//` comment over the arm is what both are for.
126
- line := strings.Count(src[:m[0]], "\n")
127
- doc := commentAbove(lines, line, "//")
128
- for _, literal := range xtaskLiteral.FindAllStringSubmatch(src[m[0]:m[1]], -1) {
129
- add(literal[1], doc, line+1)
130
- }
131
- }
132
-
133
- return out
134
- }
135
-
136
- return nil
137
- }
138
-
139
- func kebab(name string) string {
140
- var b strings.Builder
141
- for i, r := range name {
142
- if r >= 'A' && r <= 'Z' {
143
- if i > 0 {
144
- b.WriteByte('-')
145
- }
146
- b.WriteRune(r + 'a' - 'A')
147
-
148
- continue
149
- }
150
- b.WriteRune(r)
151
- }
152
-
153
- return b.String()
154
- }
@@ -1,143 +0,0 @@
1
- // Package commands reads what a developer types against a checkout - the make
2
- // targets, npm scripts, just recipes and task-runner tasks a repository
3
- // declares - into catalog.Command values.
4
- //
5
- // It reads the runner files and nothing else. A README that says "run make
6
- // test" is a claim; a Makefile with a test target is the fact, and the two
7
- // drift apart exactly when the README stops being read. Every parser here is
8
- // deliberately shallow: it knows the file well enough to list its entries and
9
- // their descriptions, and it does not evaluate anything. A make target hidden
10
- // behind an `ifeq` is listed; a target spelled through a variable is not,
11
- // because the name it would have depends on a value nobody here can know.
12
- package commands
13
-
14
- import (
15
- "os"
16
- "path/filepath"
17
- "strconv"
18
- "strings"
19
-
20
- "github.com/shortlink-org/portolan/catalog"
21
- )
22
-
23
- // Read lists the commands declared at root, in a fixed order of files - make,
24
- // just, Taskfile, the package manifest, pyproject, pom, the Gradle script,
25
- // cargo's aliases - and in file order inside each. Source is spelled root-relative with the line, the way the rest of the
26
- // catalog spells one.
27
- //
28
- // Warnings name what was seen and not read: a Taskfile that is not YAML, a
29
- // package.json whose scripts are not an object.
30
- func Read(root string) ([]catalog.Command, []string) {
31
- var out []catalog.Command
32
- var warnings []string
33
-
34
- add := func(cmds []catalog.Command, warns []string) {
35
- out = append(out, cmds...)
36
- warnings = append(warnings, warns...)
37
- }
38
-
39
- if file, src, ok := first(root, "Makefile", "makefile", "GNUmakefile"); ok {
40
- add(readMakefile(file, src), nil)
41
- }
42
- if file, src, ok := first(root, "justfile", "Justfile", ".justfile"); ok {
43
- add(readJustfile(file, src), nil)
44
- }
45
- if file, src, ok := first(root, "Taskfile.yml", "Taskfile.yaml", "taskfile.yml", "taskfile.yaml", "Taskfile.dist.yml", "Taskfile.dist.yaml"); ok {
46
- add(readTaskfile(file, src))
47
- }
48
- if file, src, ok := first(root, "package.json"); ok {
49
- add(readPackageJSON(file, src, nodeRunner(root)))
50
- }
51
- if file, src, ok := first(root, "pyproject.toml"); ok {
52
- add(readPyproject(file, src), nil)
53
- }
54
- if file, src, ok := first(root, "pom.xml"); ok {
55
- add(readPom(root, file, src), nil)
56
- }
57
- if file, src, ok := first(root, "build.gradle.kts", "build.gradle"); ok {
58
- add(readGradle(root, file, src), nil)
59
- }
60
- if file, src, ok := first(root, ".cargo/config.toml", ".cargo/config"); ok {
61
- add(readCargoAliases(root, file, src), nil)
62
- }
63
-
64
- return out, warnings
65
- }
66
-
67
- // first opens the first of names that exists under root, answering its
68
- // root-relative path and contents.
69
- func first(root string, names ...string) (string, string, bool) {
70
- for _, name := range names {
71
- raw, err := os.ReadFile(filepath.Join(root, name))
72
- if err != nil {
73
- continue
74
- }
75
-
76
- return filepath.ToSlash(filepath.Join(root, name)), string(raw), true
77
- }
78
-
79
- return "", "", false
80
- }
81
-
82
- // nodeRunner is the package manager a checkout is set up for, read off the
83
- // lockfile it keeps - the one file that says which tool the last person used.
84
- func nodeRunner(root string) string {
85
- for _, lock := range []struct{ file, runner string }{
86
- {"pnpm-lock.yaml", "pnpm"},
87
- {"yarn.lock", "yarn"},
88
- {"bun.lockb", "bun"},
89
- {"bun.lock", "bun"},
90
- } {
91
- if _, err := os.Stat(filepath.Join(root, lock.file)); err == nil {
92
- return lock.runner
93
- }
94
- }
95
-
96
- return "npm"
97
- }
98
-
99
- func at(file string, line int) string {
100
- return file + ":" + strconv.Itoa(line)
101
- }
102
-
103
- // hooks drops the pre/post entries of a name that is itself listed, the way
104
- // npm and pdm run them: `pretest` is part of `test`, not a second command.
105
- func hooks(cmds []catalog.Command, prefixes ...string) []catalog.Command {
106
- named := map[string]bool{}
107
- for _, cmd := range cmds {
108
- named[cmd.Name] = true
109
- }
110
- kept := cmds[:0]
111
- for _, cmd := range cmds {
112
- hook := false
113
- for _, prefix := range prefixes {
114
- if rest, ok := strings.CutPrefix(cmd.Name, prefix); ok && rest != "" && named[rest] {
115
- hook = true
116
- }
117
- }
118
- if !hook {
119
- kept = append(kept, cmd)
120
- }
121
- }
122
-
123
- return kept
124
- }
125
-
126
- // commentAbove is the contiguous block of `#` lines ending at line i-1, as one
127
- // paragraph, or "" when the line above is not a comment. A blank line breaks
128
- // the block: a comment two lines up is about something else.
129
- func commentAbove(lines []string, i int, marker string) string {
130
- var block []string
131
- for j := i - 1; j >= 0; j-- {
132
- text := strings.TrimSpace(lines[j])
133
- if !strings.HasPrefix(text, marker) {
134
- break
135
- }
136
- text = strings.TrimSpace(strings.TrimPrefix(text, marker))
137
- // A `## help` line in a block is help; a `##` divider is not a word.
138
- text = strings.TrimSpace(strings.TrimLeft(text, "#"))
139
- block = append([]string{text}, block...)
140
- }
141
-
142
- return strings.TrimSpace(strings.Join(block, " "))
143
- }