@shortlink-org/portolan 0.1.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 (826) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +387 -0
  3. package/catalog/enum_test.go +46 -0
  4. package/catalog/model.go +932 -0
  5. package/catalog/roundtrip_test.go +185 -0
  6. package/catalog/via_test.go +38 -0
  7. package/cli/portolan.mjs +368 -0
  8. package/go.mod +14 -0
  9. package/go.sum +14 -0
  10. package/index.html +13 -0
  11. package/internal/commands/cargo.go +154 -0
  12. package/internal/commands/commands.go +143 -0
  13. package/internal/commands/commands_test.go +323 -0
  14. package/internal/commands/gradle.go +77 -0
  15. package/internal/commands/justfile.go +82 -0
  16. package/internal/commands/makefile.go +106 -0
  17. package/internal/commands/maven.go +93 -0
  18. package/internal/commands/packagejson.go +159 -0
  19. package/internal/commands/pyproject.go +169 -0
  20. package/internal/commands/taskfile.go +101 -0
  21. package/internal/commands/testdata/estate/.cargo/config.toml +7 -0
  22. package/internal/commands/testdata/estate/Makefile +33 -0
  23. package/internal/commands/testdata/estate/Taskfile.yml +21 -0
  24. package/internal/commands/testdata/estate/build.gradle.kts +21 -0
  25. package/internal/commands/testdata/estate/justfile +20 -0
  26. package/internal/commands/testdata/estate/package.json +13 -0
  27. package/internal/commands/testdata/estate/pom.xml +29 -0
  28. package/internal/commands/testdata/estate/pyproject.toml +27 -0
  29. package/internal/commands/testdata/estate/xtask/src/main.rs +27 -0
  30. package/internal/commands/testdata/golden/commands.json +305 -0
  31. package/internal/gohttp/analyze.go +2500 -0
  32. package/internal/gohttp/endpoints.go +1067 -0
  33. package/internal/gohttp/roots.go +320 -0
  34. package/internal/gohttp/typed.go +143 -0
  35. package/internal/goscan/constants.go +85 -0
  36. package/internal/goscan/goscan_test.go +227 -0
  37. package/internal/goscan/names.go +52 -0
  38. package/internal/goscan/parse_test.go +11 -0
  39. package/internal/goscan/source.go +36 -0
  40. package/internal/goscan/tree.go +155 -0
  41. package/internal/goscan/types.go +99 -0
  42. package/internal/wsdl/ids.go +127 -0
  43. package/internal/wsdl/ids_test.go +21 -0
  44. package/internal/wsdl/model.go +62 -0
  45. package/internal/wsdl/parse.go +920 -0
  46. package/internal/wsdl/parse_test.go +133 -0
  47. package/package.json +117 -0
  48. package/plugin/describe.go +107 -0
  49. package/plugin/describe_test.go +114 -0
  50. package/plugin/protocol.go +117 -0
  51. package/plugin/schematest/schematest.go +126 -0
  52. package/plugins/README.md +1160 -0
  53. package/plugins/extract-adr/describe.go +19 -0
  54. package/plugins/extract-adr/describe_test.go +11 -0
  55. package/plugins/extract-adr/extract.go +153 -0
  56. package/plugins/extract-adr/extract_test.go +350 -0
  57. package/plugins/extract-adr/history.go +99 -0
  58. package/plugins/extract-adr/main.go +65 -0
  59. package/plugins/extract-adr/options.schema.json +26 -0
  60. package/plugins/extract-adr/parse.go +642 -0
  61. package/plugins/extract-adr/parse_test.go +405 -0
  62. package/plugins/extract-asyncapi/describe.go +19 -0
  63. package/plugins/extract-asyncapi/describe_test.go +11 -0
  64. package/plugins/extract-asyncapi/extract.go +315 -0
  65. package/plugins/extract-asyncapi/extract_test.go +197 -0
  66. package/plugins/extract-asyncapi/main.go +48 -0
  67. package/plugins/extract-asyncapi/options.schema.json +26 -0
  68. package/plugins/extract-asyncapi/spec.go +151 -0
  69. package/plugins/extract-celery/README.md +169 -0
  70. package/plugins/extract-celery/extract.py +346 -0
  71. package/plugins/extract-celery/extract_test.py +192 -0
  72. package/plugins/extract-celery/main.py +66 -0
  73. package/plugins/extract-celery/options.py +31 -0
  74. package/plugins/extract-celery/options.schema.json +31 -0
  75. package/plugins/extract-celery/producers.py +156 -0
  76. package/plugins/extract-celery/routes_test.py +106 -0
  77. package/plugins/extract-commands/describe.go +19 -0
  78. package/plugins/extract-commands/describe_test.go +11 -0
  79. package/plugins/extract-commands/extract.go +79 -0
  80. package/plugins/extract-commands/extract_test.go +92 -0
  81. package/plugins/extract-commands/main.go +55 -0
  82. package/plugins/extract-commands/options.schema.json +20 -0
  83. package/plugins/extract-csr/avro.go +258 -0
  84. package/plugins/extract-csr/describe.go +19 -0
  85. package/plugins/extract-csr/describe_test.go +11 -0
  86. package/plugins/extract-csr/extract.go +338 -0
  87. package/plugins/extract-csr/extract_test.go +374 -0
  88. package/plugins/extract-csr/jsonschema.go +343 -0
  89. package/plugins/extract-csr/lock.go +25 -0
  90. package/plugins/extract-csr/main.go +84 -0
  91. package/plugins/extract-csr/options.schema.json +43 -0
  92. package/plugins/extract-csr/subject.go +102 -0
  93. package/plugins/extract-django/README.md +386 -0
  94. package/plugins/extract-django/apps.py +100 -0
  95. package/plugins/extract-django/auth.py +302 -0
  96. package/plugins/extract-django/auth_test.py +188 -0
  97. package/plugins/extract-django/clients.py +121 -0
  98. package/plugins/extract-django/contracts.py +458 -0
  99. package/plugins/extract-django/database.py +119 -0
  100. package/plugins/extract-django/domain.py +318 -0
  101. package/plugins/extract-django/events.py +86 -0
  102. package/plugins/extract-django/extract.py +601 -0
  103. package/plugins/extract-django/extract_test.py +397 -0
  104. package/plugins/extract-django/flows.py +1278 -0
  105. package/plugins/extract-django/flows_test.py +338 -0
  106. package/plugins/extract-django/ids.py +42 -0
  107. package/plugins/extract-django/ids_test.py +30 -0
  108. package/plugins/extract-django/lifecycle.py +222 -0
  109. package/plugins/extract-django/lifecycle_test.py +76 -0
  110. package/plugins/extract-django/main.py +66 -0
  111. package/plugins/extract-django/openapi.py +229 -0
  112. package/plugins/extract-django/openapi_test.py +60 -0
  113. package/plugins/extract-django/operations.py +96 -0
  114. package/plugins/extract-django/options.py +61 -0
  115. package/plugins/extract-django/options.schema.json +126 -0
  116. package/plugins/extract-django/routing.py +214 -0
  117. package/plugins/extract-django/routing_test.py +198 -0
  118. package/plugins/extract-django/serializers.py +558 -0
  119. package/plugins/extract-django/store.py +434 -0
  120. package/plugins/extract-django/transport.py +242 -0
  121. package/plugins/extract-flows/describe.go +19 -0
  122. package/plugins/extract-flows/describe_test.go +11 -0
  123. package/plugins/extract-flows/extract.go +91 -0
  124. package/plugins/extract-flows/main.go +45 -0
  125. package/plugins/extract-flows/options.schema.json +16 -0
  126. package/plugins/extract-flows/parse.go +593 -0
  127. package/plugins/extract-flows/parse_test.go +204 -0
  128. package/plugins/extract-glossary/describe.go +19 -0
  129. package/plugins/extract-glossary/describe_test.go +11 -0
  130. package/plugins/extract-glossary/extract.go +115 -0
  131. package/plugins/extract-glossary/extract_test.go +220 -0
  132. package/plugins/extract-glossary/main.go +59 -0
  133. package/plugins/extract-glossary/options.schema.json +21 -0
  134. package/plugins/extract-glossary/parse.go +214 -0
  135. package/plugins/extract-glossary/parse_test.go +203 -0
  136. package/plugins/extract-go/aggregate.go +214 -0
  137. package/plugins/extract-go/client.go +409 -0
  138. package/plugins/extract-go/client_test.go +266 -0
  139. package/plugins/extract-go/describe.go +19 -0
  140. package/plugins/extract-go/describe_test.go +11 -0
  141. package/plugins/extract-go/enum.go +195 -0
  142. package/plugins/extract-go/enum_test.go +82 -0
  143. package/plugins/extract-go/event.go +99 -0
  144. package/plugins/extract-go/extract.go +191 -0
  145. package/plugins/extract-go/extract_test.go +261 -0
  146. package/plugins/extract-go/flow.go +1441 -0
  147. package/plugins/extract-go/flow_test.go +609 -0
  148. package/plugins/extract-go/httpclient.go +174 -0
  149. package/plugins/extract-go/httpclient_test.go +296 -0
  150. package/plugins/extract-go/ids.go +92 -0
  151. package/plugins/extract-go/layout.go +225 -0
  152. package/plugins/extract-go/layout_test.go +125 -0
  153. package/plugins/extract-go/lifecycle.go +324 -0
  154. package/plugins/extract-go/lifecycle_test.go +108 -0
  155. package/plugins/extract-go/main.go +79 -0
  156. package/plugins/extract-go/operation.go +157 -0
  157. package/plugins/extract-go/options.schema.json +66 -0
  158. package/plugins/extract-go/source.go +316 -0
  159. package/plugins/extract-go/transport.go +321 -0
  160. package/plugins/extract-go/transport_test.go +145 -0
  161. package/plugins/extract-go/wiring.go +434 -0
  162. package/plugins/extract-go-nats/describe.go +19 -0
  163. package/plugins/extract-go-nats/describe_test.go +11 -0
  164. package/plugins/extract-go-nats/extract.go +177 -0
  165. package/plugins/extract-go-nats/extract_test.go +389 -0
  166. package/plugins/extract-go-nats/index.go +379 -0
  167. package/plugins/extract-go-nats/main.go +42 -0
  168. package/plugins/extract-go-nats/options.schema.json +21 -0
  169. package/plugins/extract-go-nats/resolve.go +161 -0
  170. package/plugins/extract-go-nats/sites.go +224 -0
  171. package/plugins/extract-graphql/describe.go +19 -0
  172. package/plugins/extract-graphql/describe_test.go +11 -0
  173. package/plugins/extract-graphql/extract.go +433 -0
  174. package/plugins/extract-graphql/extract_test.go +256 -0
  175. package/plugins/extract-graphql/ids.go +49 -0
  176. package/plugins/extract-graphql/lex.go +237 -0
  177. package/plugins/extract-graphql/main.go +51 -0
  178. package/plugins/extract-graphql/options.schema.json +31 -0
  179. package/plugins/extract-graphql/parse.go +621 -0
  180. package/plugins/extract-graphql/parse_test.go +122 -0
  181. package/plugins/extract-http-clients/describe.go +19 -0
  182. package/plugins/extract-http-clients/describe_test.go +11 -0
  183. package/plugins/extract-http-clients/extract.go +705 -0
  184. package/plugins/extract-http-clients/extract_test.go +1263 -0
  185. package/plugins/extract-http-clients/main.go +42 -0
  186. package/plugins/extract-http-clients/options.schema.json +33 -0
  187. package/plugins/extract-java/README.md +190 -0
  188. package/plugins/extract-java/build/org/portolan/extract/Catalog.class +0 -0
  189. package/plugins/extract-java/build/org/portolan/extract/Clients$1.class +0 -0
  190. package/plugins/extract-java/build/org/portolan/extract/Clients$2.class +0 -0
  191. package/plugins/extract-java/build/org/portolan/extract/Clients$Call.class +0 -0
  192. package/plugins/extract-java/build/org/portolan/extract/Clients$Client.class +0 -0
  193. package/plugins/extract-java/build/org/portolan/extract/Clients$Route.class +0 -0
  194. package/plugins/extract-java/build/org/portolan/extract/Clients.class +0 -0
  195. package/plugins/extract-java/build/org/portolan/extract/Domain$Aggregate.class +0 -0
  196. package/plugins/extract-java/build/org/portolan/extract/Domain.class +0 -0
  197. package/plugins/extract-java/build/org/portolan/extract/Events$Found.class +0 -0
  198. package/plugins/extract-java/build/org/portolan/extract/Events.class +0 -0
  199. package/plugins/extract-java/build/org/portolan/extract/Extract.class +0 -0
  200. package/plugins/extract-java/build/org/portolan/extract/Flows$1.class +0 -0
  201. package/plugins/extract-java/build/org/portolan/extract/Flows$Binding.class +0 -0
  202. package/plugins/extract-java/build/org/portolan/extract/Flows$Draft.class +0 -0
  203. package/plugins/extract-java/build/org/portolan/extract/Flows$Frame.class +0 -0
  204. package/plugins/extract-java/build/org/portolan/extract/Flows$Options.class +0 -0
  205. package/plugins/extract-java/build/org/portolan/extract/Flows.class +0 -0
  206. package/plugins/extract-java/build/org/portolan/extract/Ids.class +0 -0
  207. package/plugins/extract-java/build/org/portolan/extract/Json$Reader.class +0 -0
  208. package/plugins/extract-java/build/org/portolan/extract/Json.class +0 -0
  209. package/plugins/extract-java/build/org/portolan/extract/Lifecycle$1.class +0 -0
  210. package/plugins/extract-java/build/org/portolan/extract/Lifecycle$Move.class +0 -0
  211. package/plugins/extract-java/build/org/portolan/extract/Lifecycle.class +0 -0
  212. package/plugins/extract-java/build/org/portolan/extract/Main.class +0 -0
  213. package/plugins/extract-java/build/org/portolan/extract/OpenApi$Operation.class +0 -0
  214. package/plugins/extract-java/build/org/portolan/extract/OpenApi$Spec.class +0 -0
  215. package/plugins/extract-java/build/org/portolan/extract/OpenApi.class +0 -0
  216. package/plugins/extract-java/build/org/portolan/extract/Operations$1.class +0 -0
  217. package/plugins/extract-java/build/org/portolan/extract/Operations$UseCase.class +0 -0
  218. package/plugins/extract-java/build/org/portolan/extract/Operations.class +0 -0
  219. package/plugins/extract-java/build/org/portolan/extract/Proto$Rpc.class +0 -0
  220. package/plugins/extract-java/build/org/portolan/extract/Proto$Service.class +0 -0
  221. package/plugins/extract-java/build/org/portolan/extract/Proto.class +0 -0
  222. package/plugins/extract-java/build/org/portolan/extract/Protocol$Builder.class +0 -0
  223. package/plugins/extract-java/build/org/portolan/extract/Protocol$Input.class +0 -0
  224. package/plugins/extract-java/build/org/portolan/extract/Protocol$Options.class +0 -0
  225. package/plugins/extract-java/build/org/portolan/extract/Protocol.class +0 -0
  226. package/plugins/extract-java/build/org/portolan/extract/Source$Project.class +0 -0
  227. package/plugins/extract-java/build/org/portolan/extract/Source$Unit.class +0 -0
  228. package/plugins/extract-java/build/org/portolan/extract/Source.class +0 -0
  229. package/plugins/extract-java/build/org/portolan/extract/Transport$Endpoint.class +0 -0
  230. package/plugins/extract-java/build/org/portolan/extract/Transport.class +0 -0
  231. package/plugins/extract-java/build/org/portolan/extract/Yaml$Line.class +0 -0
  232. package/plugins/extract-java/build/org/portolan/extract/Yaml$Reader.class +0 -0
  233. package/plugins/extract-java/build/org/portolan/extract/Yaml.class +0 -0
  234. package/plugins/extract-java/options.schema.json +70 -0
  235. package/plugins/extract-openapi/describe.go +19 -0
  236. package/plugins/extract-openapi/describe_test.go +11 -0
  237. package/plugins/extract-openapi/discover.go +243 -0
  238. package/plugins/extract-openapi/extract.go +526 -0
  239. package/plugins/extract-openapi/extract_test.go +545 -0
  240. package/plugins/extract-openapi/main.go +75 -0
  241. package/plugins/extract-openapi/options.schema.json +62 -0
  242. package/plugins/extract-openapi/spec.go +350 -0
  243. package/plugins/extract-project/README.md +22 -0
  244. package/plugins/extract-project/describe.go +19 -0
  245. package/plugins/extract-project/describe_test.go +11 -0
  246. package/plugins/extract-project/extract.go +221 -0
  247. package/plugins/extract-project/extract_test.go +109 -0
  248. package/plugins/extract-project/main.go +41 -0
  249. package/plugins/extract-project/options.schema.json +48 -0
  250. package/plugins/extract-proto/ast.go +125 -0
  251. package/plugins/extract-proto/consumes.go +77 -0
  252. package/plugins/extract-proto/describe.go +19 -0
  253. package/plugins/extract-proto/extract.go +293 -0
  254. package/plugins/extract-proto/extract_test.go +459 -0
  255. package/plugins/extract-proto/ids.go +89 -0
  256. package/plugins/extract-proto/ids_test.go +57 -0
  257. package/plugins/extract-proto/lex.go +285 -0
  258. package/plugins/extract-proto/main.go +100 -0
  259. package/plugins/extract-proto/module.go +120 -0
  260. package/plugins/extract-proto/options.schema.json +51 -0
  261. package/plugins/extract-proto/parse.go +720 -0
  262. package/plugins/extract-proto/parse_test.go +307 -0
  263. package/plugins/extract-proto/provides.go +236 -0
  264. package/plugins/extract-proto/resolve.go +222 -0
  265. package/plugins/extract-proto/resolve_test.go +119 -0
  266. package/plugins/extract-python-kafka/README.md +36 -0
  267. package/plugins/extract-python-kafka/extract.py +211 -0
  268. package/plugins/extract-python-kafka/extract_test.py +68 -0
  269. package/plugins/extract-python-kafka/main.py +59 -0
  270. package/plugins/extract-python-kafka/options.py +29 -0
  271. package/plugins/extract-python-kafka/options.schema.json +31 -0
  272. package/plugins/extract-redis/README.md +11 -0
  273. package/plugins/extract-redis/describe.go +19 -0
  274. package/plugins/extract-redis/describe_test.go +11 -0
  275. package/plugins/extract-redis/extract.go +183 -0
  276. package/plugins/extract-redis/extract_test.go +168 -0
  277. package/plugins/extract-redis/keyspaces.go +469 -0
  278. package/plugins/extract-redis/main.go +44 -0
  279. package/plugins/extract-redis/options.schema.json +30 -0
  280. package/plugins/extract-river/describe.go +19 -0
  281. package/plugins/extract-river/describe_test.go +11 -0
  282. package/plugins/extract-river/extract.go +507 -0
  283. package/plugins/extract-river/extract_test.go +132 -0
  284. package/plugins/extract-river/main.go +42 -0
  285. package/plugins/extract-river/options.schema.json +21 -0
  286. package/plugins/extract-rust/Cargo.lock +133 -0
  287. package/plugins/extract-rust/Cargo.toml +23 -0
  288. package/plugins/extract-rust/README.md +204 -0
  289. package/plugins/extract-rust/options.schema.json +65 -0
  290. package/plugins/extract-rust/rustfmt.toml +1 -0
  291. package/plugins/extract-sql/ddl.go +893 -0
  292. package/plugins/extract-sql/ddl_test.go +401 -0
  293. package/plugins/extract-sql/describe.go +19 -0
  294. package/plugins/extract-sql/describe_test.go +11 -0
  295. package/plugins/extract-sql/layout.go +221 -0
  296. package/plugins/extract-sql/layout_test.go +55 -0
  297. package/plugins/extract-sql/lineage.go +107 -0
  298. package/plugins/extract-sql/main.go +141 -0
  299. package/plugins/extract-sql/maps.go +564 -0
  300. package/plugins/extract-sql/maps_java.go +117 -0
  301. package/plugins/extract-sql/maps_rust.go +333 -0
  302. package/plugins/extract-sql/maps_rust_test.go +70 -0
  303. package/plugins/extract-sql/maps_test.go +204 -0
  304. package/plugins/extract-sql/maps_ts.go +398 -0
  305. package/plugins/extract-sql/maps_ts_test.go +136 -0
  306. package/plugins/extract-sql/options.schema.json +53 -0
  307. package/plugins/extract-sql/projection.go +70 -0
  308. package/plugins/extract-sql/projection_test.go +50 -0
  309. package/plugins/extract-sql/store.go +420 -0
  310. package/plugins/extract-sql/store_test.go +233 -0
  311. package/plugins/extract-sql/view.go +295 -0
  312. package/plugins/extract-ts/README.md +306 -0
  313. package/plugins/extract-ts/ast.test.ts +178 -0
  314. package/plugins/extract-ts/ast.ts +648 -0
  315. package/plugins/extract-ts/clients.ts +185 -0
  316. package/plugins/extract-ts/domain.ts +164 -0
  317. package/plugins/extract-ts/extract.test.ts +208 -0
  318. package/plugins/extract-ts/extract.ts +200 -0
  319. package/plugins/extract-ts/flows.ts +783 -0
  320. package/plugins/extract-ts/graphql.test.ts +73 -0
  321. package/plugins/extract-ts/graphql.ts +181 -0
  322. package/plugins/extract-ts/ids.test.ts +21 -0
  323. package/plugins/extract-ts/ids.ts +52 -0
  324. package/plugins/extract-ts/lifecycle.ts +138 -0
  325. package/plugins/extract-ts/main.ts +48 -0
  326. package/plugins/extract-ts/openapi.test.ts +64 -0
  327. package/plugins/extract-ts/openapi.ts +99 -0
  328. package/plugins/extract-ts/operations.ts +93 -0
  329. package/plugins/extract-ts/options.schema.json +96 -0
  330. package/plugins/extract-ts/source.test.ts +174 -0
  331. package/plugins/extract-ts/source.ts +465 -0
  332. package/plugins/extract-ts/transport.ts +147 -0
  333. package/plugins/extract-ts/tsconfig.json +13 -0
  334. package/plugins/extract-ts/wiring.ts +190 -0
  335. package/plugins/extract-watermill/describe.go +19 -0
  336. package/plugins/extract-watermill/describe_test.go +11 -0
  337. package/plugins/extract-watermill/extract.go +1228 -0
  338. package/plugins/extract-watermill/extract_test.go +234 -0
  339. package/plugins/extract-watermill/main.go +41 -0
  340. package/plugins/extract-watermill/options.schema.json +21 -0
  341. package/plugins/extract-wsdl/describe.go +19 -0
  342. package/plugins/extract-wsdl/describe_test.go +11 -0
  343. package/plugins/extract-wsdl/extract.go +148 -0
  344. package/plugins/extract-wsdl/extract_test.go +45 -0
  345. package/plugins/extract-wsdl/main.go +53 -0
  346. package/plugins/extract-wsdl/options.schema.json +59 -0
  347. package/plugins/fetch-bsr/auth.go +114 -0
  348. package/plugins/fetch-bsr/bsr.go +240 -0
  349. package/plugins/fetch-bsr/cache.go +66 -0
  350. package/plugins/fetch-bsr/describe.go +19 -0
  351. package/plugins/fetch-bsr/fetch.go +192 -0
  352. package/plugins/fetch-bsr/fetch_test.go +465 -0
  353. package/plugins/fetch-bsr/lock.go +71 -0
  354. package/plugins/fetch-bsr/main.go +117 -0
  355. package/plugins/fetch-bsr/options.schema.json +42 -0
  356. package/plugins/fetch-csr/auth.go +95 -0
  357. package/plugins/fetch-csr/cache.go +69 -0
  358. package/plugins/fetch-csr/describe.go +19 -0
  359. package/plugins/fetch-csr/describe_test.go +11 -0
  360. package/plugins/fetch-csr/fetch.go +254 -0
  361. package/plugins/fetch-csr/fetch_test.go +494 -0
  362. package/plugins/fetch-csr/lock.go +95 -0
  363. package/plugins/fetch-csr/main.go +122 -0
  364. package/plugins/fetch-csr/options.schema.json +42 -0
  365. package/plugins/fetch-csr/registry.go +209 -0
  366. package/plugins/fetch-git/cache.go +65 -0
  367. package/plugins/fetch-git/describe.go +19 -0
  368. package/plugins/fetch-git/describe_test.go +11 -0
  369. package/plugins/fetch-git/fetch.go +181 -0
  370. package/plugins/fetch-git/fetch_test.go +332 -0
  371. package/plugins/fetch-git/git.go +169 -0
  372. package/plugins/fetch-git/lock.go +72 -0
  373. package/plugins/fetch-git/main.go +127 -0
  374. package/plugins/fetch-git/offline.go +39 -0
  375. package/plugins/fetch-git/options.schema.json +42 -0
  376. package/plugins/fetch-git/pin.go +90 -0
  377. package/plugins/fetch-git/pin_test.go +74 -0
  378. package/plugins/gen-backstage/describe.go +17 -0
  379. package/plugins/gen-backstage/main.go +22 -0
  380. package/plugins/gen-backstage/options.schema.json +30 -0
  381. package/plugins/gen-backstage/plugin.go +473 -0
  382. package/plugins/gen-backstage/plugin_test.go +145 -0
  383. package/plugins/gen-backstage.wasm +0 -0
  384. package/plugins/gen-markdown/adr.go +162 -0
  385. package/plugins/gen-markdown/aggregate.go +362 -0
  386. package/plugins/gen-markdown/canonical.go +93 -0
  387. package/plugins/gen-markdown/context.go +90 -0
  388. package/plugins/gen-markdown/coverage_test.go +89 -0
  389. package/plugins/gen-markdown/describe.go +19 -0
  390. package/plugins/gen-markdown/describe_test.go +11 -0
  391. package/plugins/gen-markdown/external.go +71 -0
  392. package/plugins/gen-markdown/flow.go +277 -0
  393. package/plugins/gen-markdown/glossary.go +76 -0
  394. package/plugins/gen-markdown/glossary_test.go +148 -0
  395. package/plugins/gen-markdown/llms.go +302 -0
  396. package/plugins/gen-markdown/main.go +22 -0
  397. package/plugins/gen-markdown/markdown.go +254 -0
  398. package/plugins/gen-markdown/markdown_test.go +100 -0
  399. package/plugins/gen-markdown/module.go +107 -0
  400. package/plugins/gen-markdown/options.schema.json +16 -0
  401. package/plugins/gen-markdown/plugin.go +39 -0
  402. package/plugins/gen-markdown/quality_test.go +176 -0
  403. package/plugins/gen-markdown/redis_test.go +38 -0
  404. package/plugins/gen-markdown/render.go +344 -0
  405. package/plugins/gen-markdown/render_test.go +186 -0
  406. package/plugins/gen-markdown/service.go +456 -0
  407. package/plugins/gen-markdown/source.go +177 -0
  408. package/plugins/gen-markdown/store.go +201 -0
  409. package/plugins/gen-markdown.wasm +0 -0
  410. package/plugins/gen-mermaid/describe.go +17 -0
  411. package/plugins/gen-mermaid/main.go +22 -0
  412. package/plugins/gen-mermaid/options.schema.json +10 -0
  413. package/plugins/gen-mermaid/plugin.go +104 -0
  414. package/plugins/gen-mermaid/plugin_test.go +33 -0
  415. package/plugins/gen-mermaid.wasm +0 -0
  416. package/plugins/openapi/ids.go +261 -0
  417. package/plugins/openapi/ids_test.go +98 -0
  418. package/plugins/pyplugin/catalog.py +209 -0
  419. package/plugins/pyplugin/celery_conf.py +436 -0
  420. package/plugins/pyplugin/celery_tasks.py +76 -0
  421. package/plugins/pyplugin/kafka.py +570 -0
  422. package/plugins/pyplugin/names.py +38 -0
  423. package/plugins/pyplugin/protocol.py +79 -0
  424. package/plugins/pyplugin/source.py +285 -0
  425. package/plugins/verify-codeowners/describe.go +19 -0
  426. package/plugins/verify-codeowners/describe_test.go +11 -0
  427. package/plugins/verify-codeowners/main.go +75 -0
  428. package/plugins/verify-codeowners/match.go +85 -0
  429. package/plugins/verify-codeowners/match_test.go +47 -0
  430. package/plugins/verify-codeowners/options.schema.json +15 -0
  431. package/plugins/verify-codeowners/owners.go +164 -0
  432. package/plugins/verify-codeowners/owners_test.go +225 -0
  433. package/plugins/verify-codeowners/parse.go +90 -0
  434. package/plugins/verify-codeowners/parse_test.go +62 -0
  435. package/plugins/verify-otel/describe.go +19 -0
  436. package/plugins/verify-otel/describe_test.go +11 -0
  437. package/plugins/verify-otel/main.go +53 -0
  438. package/plugins/verify-otel/match.go +336 -0
  439. package/plugins/verify-otel/options.schema.json +30 -0
  440. package/plugins/verify-otel/otlp.go +200 -0
  441. package/plugins/verify-otel/verify.go +734 -0
  442. package/plugins/verify-otel/verify_test.go +460 -0
  443. package/portolan.json +1073 -0
  444. package/public/favicon.svg +12 -0
  445. package/schema/portolan.schema.json +2558 -0
  446. package/scripts/README.md +53 -0
  447. package/scripts/build-report.mjs +60 -0
  448. package/scripts/build-report.test.mjs +44 -0
  449. package/scripts/builtin-plugins.mjs +49 -0
  450. package/scripts/catalog-sources.mjs +67 -0
  451. package/scripts/diff.mjs +315 -0
  452. package/scripts/diff.test.mjs +151 -0
  453. package/scripts/forge-comment.mjs +144 -0
  454. package/scripts/forge-comment.test.mjs +151 -0
  455. package/scripts/forge-release.mjs +138 -0
  456. package/scripts/forge-release.test.mjs +106 -0
  457. package/scripts/forge.mjs +61 -0
  458. package/scripts/gen-likec4.mjs +854 -0
  459. package/scripts/gen-likec4.test.mjs +258 -0
  460. package/scripts/gen.mjs +603 -0
  461. package/scripts/generated-docs.test.mjs +66 -0
  462. package/scripts/local-api.mjs +1192 -0
  463. package/scripts/local-api.test.mjs +387 -0
  464. package/scripts/manifest.mjs +214 -0
  465. package/scripts/manifest.test.mjs +148 -0
  466. package/scripts/output-path.mjs +79 -0
  467. package/scripts/output-path.test.mjs +45 -0
  468. package/scripts/package-smoke.mjs +37 -0
  469. package/scripts/plugin-host.mjs +419 -0
  470. package/scripts/plugin-host.test.mjs +109 -0
  471. package/scripts/plugin-wasm-worker.mjs +34 -0
  472. package/scripts/run-builtin.mjs +81 -0
  473. package/scripts/schema.mjs +357 -0
  474. package/scripts/site-docs.mjs +295 -0
  475. package/scripts/site-docs.test.mjs +181 -0
  476. package/scripts/vendor-lock.mjs +58 -0
  477. package/scripts/vendor-lock.test.mjs +69 -0
  478. package/src/README.md +38 -0
  479. package/src/app/App.tsx +448 -0
  480. package/src/app/BranchPicker.test.ts +46 -0
  481. package/src/app/BranchPicker.tsx +153 -0
  482. package/src/app/Breadcrumbs.test.ts +38 -0
  483. package/src/app/Breadcrumbs.tsx +223 -0
  484. package/src/app/BuildStamp.tsx +146 -0
  485. package/src/app/CommandPalette.tsx +292 -0
  486. package/src/app/HashScroll.tsx +45 -0
  487. package/src/app/Sidebar.tsx +1742 -0
  488. package/src/app/TopBar.tsx +393 -0
  489. package/src/app/density.tsx +64 -0
  490. package/src/app/forge-access.test.ts +27 -0
  491. package/src/app/forge-access.tsx +80 -0
  492. package/src/app/panels.tsx +141 -0
  493. package/src/app/pins.tsx +242 -0
  494. package/src/app/query-client.ts +24 -0
  495. package/src/app/responsive.ts +55 -0
  496. package/src/app/shortcuts.test.ts +39 -0
  497. package/src/app/shortcuts.tsx +282 -0
  498. package/src/app/theme.tsx +51 -0
  499. package/src/app/title.test.ts +14 -0
  500. package/src/app/title.ts +30 -0
  501. package/src/app/toast.tsx +59 -0
  502. package/src/app/tree-keys.test.ts +80 -0
  503. package/src/app/tree-keys.ts +87 -0
  504. package/src/app/ui-store.ts +52 -0
  505. package/src/catalog-error.test.ts +105 -0
  506. package/src/catalog-profile.test.ts +59 -0
  507. package/src/catalog-profile.ts +101 -0
  508. package/src/catalog-stores.test.ts +431 -0
  509. package/src/catalog.test.ts +1215 -0
  510. package/src/catalog.ts +3125 -0
  511. package/src/chat/Cards.tsx +408 -0
  512. package/src/chat/ChatPanel.tsx +79 -0
  513. package/src/chat/ChatSettings.tsx +219 -0
  514. package/src/chat/Composer.tsx +99 -0
  515. package/src/chat/Conversation.tsx +281 -0
  516. package/src/chat/Header.tsx +46 -0
  517. package/src/chat/Message.tsx +49 -0
  518. package/src/chat/Notice.tsx +195 -0
  519. package/src/chat/Starter.tsx +67 -0
  520. package/src/chat/Steps.tsx +45 -0
  521. package/src/chat/Waiting.tsx +87 -0
  522. package/src/chat/flags.test.ts +59 -0
  523. package/src/chat/flags.ts +155 -0
  524. package/src/chat/linkify.test.ts +30 -0
  525. package/src/chat/linkify.ts +45 -0
  526. package/src/chat/prefs.ts +56 -0
  527. package/src/chat/prompt.test.ts +43 -0
  528. package/src/chat/prompt.ts +157 -0
  529. package/src/chat/store.ts +35 -0
  530. package/src/chat/tools.ts +58 -0
  531. package/src/chat/transport.ts +70 -0
  532. package/src/components/AdrRow.tsx +29 -0
  533. package/src/components/AnchorLink.tsx +67 -0
  534. package/src/components/ApiReference.tsx +134 -0
  535. package/src/components/AsyncApiReference.tsx +120 -0
  536. package/src/components/CatalogStamp.tsx +155 -0
  537. package/src/components/ChannelRows.tsx +132 -0
  538. package/src/components/CommandRows.tsx +139 -0
  539. package/src/components/DiagramSkeleton.tsx +71 -0
  540. package/src/components/EditorLink.tsx +85 -0
  541. package/src/components/FieldTree.tsx +305 -0
  542. package/src/components/FlowTrigger.tsx +34 -0
  543. package/src/components/Ident.tsx +89 -0
  544. package/src/components/Integrations.tsx +243 -0
  545. package/src/components/LifecycleDiagram.tsx +110 -0
  546. package/src/components/MachineDocs.tsx +42 -0
  547. package/src/components/Markdown.tsx +173 -0
  548. package/src/components/MarkdownTable.tsx +206 -0
  549. package/src/components/Mermaid.tsx +211 -0
  550. package/src/components/MethodRows.tsx +309 -0
  551. package/src/components/Overlay.tsx +125 -0
  552. package/src/components/PageHeader.tsx +189 -0
  553. package/src/components/RowActions.tsx +97 -0
  554. package/src/components/SchemaDocument.tsx +89 -0
  555. package/src/components/Select.tsx +126 -0
  556. package/src/components/ShapeRows.tsx +118 -0
  557. package/src/components/SourceDoc.tsx +82 -0
  558. package/src/components/SourcePreview.tsx +441 -0
  559. package/src/components/TabRow.tsx +182 -0
  560. package/src/components/TechIcon.tsx +34 -0
  561. package/src/components/Toc.tsx +132 -0
  562. package/src/components/WhatLinksHere.tsx +273 -0
  563. package/src/components/WsdlReference.tsx +84 -0
  564. package/src/components/ddd-icons.tsx +107 -0
  565. package/src/components/kind.tsx +157 -0
  566. package/src/components/logo.tsx +61 -0
  567. package/src/components/primitives.tsx +264 -0
  568. package/src/data.test.ts +18 -0
  569. package/src/data.ts +202 -0
  570. package/src/enrich.test.ts +1150 -0
  571. package/src/enrich.ts +672 -0
  572. package/src/er/ErCanvas.tsx +533 -0
  573. package/src/er/RedisSchema.tsx +74 -0
  574. package/src/er/RelationCard.tsx +267 -0
  575. package/src/er/StoreHeader.tsx +155 -0
  576. package/src/er/TableNode.tsx +84 -0
  577. package/src/er/ViewNode.tsx +83 -0
  578. package/src/er/layout.test.ts +115 -0
  579. package/src/er/layout.ts +77 -0
  580. package/src/er/lineage.test.ts +140 -0
  581. package/src/er/lineage.ts +107 -0
  582. package/src/er/markers.tsx +79 -0
  583. package/src/er/spec.test.ts +344 -0
  584. package/src/er/spec.ts +426 -0
  585. package/src/flow/ChainList.tsx +162 -0
  586. package/src/flow/FlowTable.tsx +123 -0
  587. package/src/flow/FlowToolbar.tsx +372 -0
  588. package/src/flow/StepDetail.tsx +380 -0
  589. package/src/flow/StepRail.tsx +428 -0
  590. package/src/flow/answers.test.ts +50 -0
  591. package/src/flow/answers.ts +58 -0
  592. package/src/flow/chain.test.ts +383 -0
  593. package/src/flow/chain.ts +353 -0
  594. package/src/flow/chapters.test.ts +185 -0
  595. package/src/flow/chapters.ts +225 -0
  596. package/src/flow/continues.test.ts +102 -0
  597. package/src/flow/continues.ts +65 -0
  598. package/src/flow/cross-context.test.ts +97 -0
  599. package/src/flow/cross-context.ts +35 -0
  600. package/src/flow/mermaid.test.ts +22 -0
  601. package/src/flow/mermaid.ts +141 -0
  602. package/src/flow/outline.test.ts +212 -0
  603. package/src/flow/outline.ts +170 -0
  604. package/src/flow/paths.test.ts +129 -0
  605. package/src/flow/paths.ts +147 -0
  606. package/src/flow/prefs.test.ts +80 -0
  607. package/src/flow/prefs.ts +104 -0
  608. package/src/graph/DependencyGraph.tsx +283 -0
  609. package/src/graph/DependencyNodes.tsx +162 -0
  610. package/src/graph/EdgeLabel.tsx +61 -0
  611. package/src/graph/FocusedEventGraph.tsx +211 -0
  612. package/src/graph/GraphToolbar.tsx +187 -0
  613. package/src/graph/RoutedEdge.tsx +80 -0
  614. package/src/graph/dependency-layout.test.ts +360 -0
  615. package/src/graph/dependency-layout.ts +444 -0
  616. package/src/graph/elk.test.ts +70 -0
  617. package/src/graph/elk.ts +287 -0
  618. package/src/graph/nodes.tsx +97 -0
  619. package/src/graph/theme.ts +81 -0
  620. package/src/graph/useElkFlow.ts +125 -0
  621. package/src/index.css +1547 -0
  622. package/src/language/InLanguage.tsx +40 -0
  623. package/src/language/TermCard.tsx +132 -0
  624. package/src/language/cards.test.ts +114 -0
  625. package/src/language/cards.ts +111 -0
  626. package/src/lib/admonition.test.ts +49 -0
  627. package/src/lib/admonition.ts +48 -0
  628. package/src/lib/adr.test.ts +131 -0
  629. package/src/lib/adr.ts +68 -0
  630. package/src/lib/api.test.ts +122 -0
  631. package/src/lib/api.ts +135 -0
  632. package/src/lib/backlinks.test.ts +330 -0
  633. package/src/lib/backlinks.ts +567 -0
  634. package/src/lib/branch-compare.ts +16 -0
  635. package/src/lib/build-info.test.ts +76 -0
  636. package/src/lib/build-info.ts +80 -0
  637. package/src/lib/catalog-diff.test.ts +275 -0
  638. package/src/lib/catalog-diff.ts +655 -0
  639. package/src/lib/clipboard.ts +43 -0
  640. package/src/lib/comparison-memory.test.ts +40 -0
  641. package/src/lib/comparison-memory.ts +39 -0
  642. package/src/lib/context-color.ts +27 -0
  643. package/src/lib/context-map.test.ts +148 -0
  644. package/src/lib/context-map.ts +399 -0
  645. package/src/lib/data-model.test.ts +245 -0
  646. package/src/lib/data-model.ts +399 -0
  647. package/src/lib/data-problems.test.ts +178 -0
  648. package/src/lib/data-problems.ts +314 -0
  649. package/src/lib/derive.test.ts +251 -0
  650. package/src/lib/derive.ts +515 -0
  651. package/src/lib/editor-link.test.ts +125 -0
  652. package/src/lib/editor-link.ts +96 -0
  653. package/src/lib/editor-prefs.ts +27 -0
  654. package/src/lib/event-graph.test.ts +237 -0
  655. package/src/lib/event-graph.ts +327 -0
  656. package/src/lib/export-canvas.ts +37 -0
  657. package/src/lib/export-file.test.ts +30 -0
  658. package/src/lib/export-file.ts +20 -0
  659. package/src/lib/flow-tree.test.ts +177 -0
  660. package/src/lib/flow-tree.ts +160 -0
  661. package/src/lib/forge-refs.test.ts +50 -0
  662. package/src/lib/forge-refs.ts +60 -0
  663. package/src/lib/format.test.ts +35 -0
  664. package/src/lib/format.ts +64 -0
  665. package/src/lib/github-catalog.test.ts +301 -0
  666. package/src/lib/github-catalog.ts +610 -0
  667. package/src/lib/integrations.test.ts +119 -0
  668. package/src/lib/integrations.ts +133 -0
  669. package/src/lib/kinds.test.ts +91 -0
  670. package/src/lib/kinds.ts +204 -0
  671. package/src/lib/lifecycle.test.ts +93 -0
  672. package/src/lib/lifecycle.ts +165 -0
  673. package/src/lib/local-api.ts +194 -0
  674. package/src/lib/motion-features.ts +11 -0
  675. package/src/lib/motion.test.ts +120 -0
  676. package/src/lib/motion.tsx +269 -0
  677. package/src/lib/palette-recent.test.ts +80 -0
  678. package/src/lib/palette-recent.ts +90 -0
  679. package/src/lib/palette.test.ts +365 -0
  680. package/src/lib/palette.ts +593 -0
  681. package/src/lib/pins.test.ts +139 -0
  682. package/src/lib/pins.ts +130 -0
  683. package/src/lib/problems.test.ts +112 -0
  684. package/src/lib/project-preview.ts +5 -0
  685. package/src/lib/proto-problems.test.ts +121 -0
  686. package/src/lib/proto-problems.ts +65 -0
  687. package/src/lib/queries.test.ts +113 -0
  688. package/src/lib/queries.ts +131 -0
  689. package/src/lib/registry.test.ts +219 -0
  690. package/src/lib/registry.ts +208 -0
  691. package/src/lib/scenarios.ts +547 -0
  692. package/src/lib/setup-info.test.ts +199 -0
  693. package/src/lib/setup-info.ts +415 -0
  694. package/src/lib/shape.test.ts +289 -0
  695. package/src/lib/shape.ts +454 -0
  696. package/src/lib/sidebar-prefs.test.ts +32 -0
  697. package/src/lib/sidebar-prefs.ts +75 -0
  698. package/src/lib/source-code.test.ts +159 -0
  699. package/src/lib/source-code.ts +286 -0
  700. package/src/lib/source-doc.test.ts +131 -0
  701. package/src/lib/source-doc.ts +103 -0
  702. package/src/lib/source-highlight.test.ts +29 -0
  703. package/src/lib/source-highlight.ts +24 -0
  704. package/src/lib/source-link.test.ts +153 -0
  705. package/src/lib/source-link.ts +201 -0
  706. package/src/lib/spec-files.test.ts +24 -0
  707. package/src/lib/spec-files.ts +23 -0
  708. package/src/lib/table-directive.test.ts +139 -0
  709. package/src/lib/table-directive.ts +106 -0
  710. package/src/lib/tech.test.ts +120 -0
  711. package/src/lib/tech.ts +421 -0
  712. package/src/lib/terms.test.ts +67 -0
  713. package/src/lib/terms.ts +179 -0
  714. package/src/lib/wire-problems.test.ts +263 -0
  715. package/src/lib/wire-problems.ts +281 -0
  716. package/src/likec4/C4View.tsx +55 -0
  717. package/src/likec4/CanvasBridge.tsx +187 -0
  718. package/src/likec4/FlowView.tsx +235 -0
  719. package/src/likec4/InteractiveView.tsx +144 -0
  720. package/src/likec4/canvas-viewport.test.ts +149 -0
  721. package/src/likec4/canvas-viewport.ts +135 -0
  722. package/src/likec4/flow-edges.test.ts +51 -0
  723. package/src/likec4/flow-edges.ts +89 -0
  724. package/src/likec4/frame-theme.test.ts +76 -0
  725. package/src/likec4/frame-theme.ts +101 -0
  726. package/src/likec4/highlight-css.test.ts +49 -0
  727. package/src/likec4/highlight-css.ts +52 -0
  728. package/src/likec4/ids.test.ts +151 -0
  729. package/src/likec4/ids.ts +115 -0
  730. package/src/likec4/levels.tsx +70 -0
  731. package/src/likec4/mapping.test.ts +66 -0
  732. package/src/likec4/mapping.ts +54 -0
  733. package/src/likec4/reserved.json +141 -0
  734. package/src/likec4/view-index.ts +78 -0
  735. package/src/main.tsx +13 -0
  736. package/src/map/ContextMapGraph.tsx +274 -0
  737. package/src/map/ContextNode.tsx +70 -0
  738. package/src/map/FloatingEdge.tsx +86 -0
  739. package/src/merge.test.ts +1038 -0
  740. package/src/merge.ts +1004 -0
  741. package/src/pages/AdrDetail.tsx +242 -0
  742. package/src/pages/AdrIndex.tsx +114 -0
  743. package/src/pages/AggregatePage.tsx +727 -0
  744. package/src/pages/BlockPage.tsx +478 -0
  745. package/src/pages/CatalogFailure.tsx +111 -0
  746. package/src/pages/Changes.tsx +313 -0
  747. package/src/pages/ContextMap.tsx +534 -0
  748. package/src/pages/ContextPage.tsx +346 -0
  749. package/src/pages/EnumPage.tsx +282 -0
  750. package/src/pages/EventPage.tsx +686 -0
  751. package/src/pages/ExternalPage.tsx +204 -0
  752. package/src/pages/FlowDetail.tsx +663 -0
  753. package/src/pages/FlowIndex.tsx +303 -0
  754. package/src/pages/GraphPage.tsx +217 -0
  755. package/src/pages/Language.tsx +257 -0
  756. package/src/pages/ModulePage.tsx +366 -0
  757. package/src/pages/NotFound.tsx +54 -0
  758. package/src/pages/Overview.tsx +344 -0
  759. package/src/pages/Problems.tsx +360 -0
  760. package/src/pages/RegistryIndex.tsx +118 -0
  761. package/src/pages/ServicePage.tsx +746 -0
  762. package/src/pages/Settings.tsx +975 -0
  763. package/src/pages/StorePage.tsx +114 -0
  764. package/src/peek/PeekCard.test.ts +35 -0
  765. package/src/peek/PeekCard.tsx +118 -0
  766. package/src/peek/PeekLayer.tsx +147 -0
  767. package/src/peek/model.test.ts +156 -0
  768. package/src/peek/model.ts +253 -0
  769. package/src/routes.test.ts +222 -0
  770. package/src/routes.ts +449 -0
  771. package/src/selection/DetailPanel.tsx +1407 -0
  772. package/src/selection/hash.test.ts +73 -0
  773. package/src/selection/hash.ts +58 -0
  774. package/src/selection/model.test.ts +199 -0
  775. package/src/selection/model.ts +473 -0
  776. package/src/selection/pages.test.ts +115 -0
  777. package/src/selection/pages.ts +268 -0
  778. package/src/selection/store.test.ts +62 -0
  779. package/src/selection/store.ts +46 -0
  780. package/src/selection/sync.tsx +99 -0
  781. package/src/table/ColumnsMenu.tsx +72 -0
  782. package/src/table/DataTable.tsx +780 -0
  783. package/src/table/Facets.tsx +54 -0
  784. package/src/table/GroupMenu.tsx +69 -0
  785. package/src/table/Toolbar.tsx +190 -0
  786. package/src/table/cells.tsx +117 -0
  787. package/src/table/compare.test.ts +117 -0
  788. package/src/table/compare.ts +196 -0
  789. package/src/table/export.test.ts +88 -0
  790. package/src/table/export.ts +66 -0
  791. package/src/table/facet-groups.test.ts +74 -0
  792. package/src/table/facet-groups.ts +56 -0
  793. package/src/table/grouping.test.ts +84 -0
  794. package/src/table/grouping.ts +82 -0
  795. package/src/table/infer.test.ts +57 -0
  796. package/src/table/infer.ts +50 -0
  797. package/src/table/persist.test.ts +76 -0
  798. package/src/table/persist.ts +112 -0
  799. package/src/table/sort-url.test.ts +75 -0
  800. package/src/table/sort-url.ts +52 -0
  801. package/src/table/types.ts +80 -0
  802. package/src/table/useTableState.ts +220 -0
  803. package/src/test-catalog.ts +7 -0
  804. package/src/testing/estate/data__catalog.json +2847 -0
  805. package/src/testing/estate/data__flows.json +1724 -0
  806. package/src/testing/estate/examples__auth__portolan__api.json +212 -0
  807. package/src/testing/estate/examples__auth__portolan__domain.json +1204 -0
  808. package/src/testing/estate/examples__auth__portolan__glossary.json +226 -0
  809. package/src/testing/estate/examples__auth__portolan__observed.json +757 -0
  810. package/src/testing/estate/examples__auth__portolan__stores.json +195 -0
  811. package/src/testing/estate/examples__shop__cart__portolan__api.json +234 -0
  812. package/src/testing/estate/examples__shop__cart__portolan__commands.json +86 -0
  813. package/src/testing/estate/examples__shop__cart__portolan__domain.json +966 -0
  814. package/src/testing/estate/examples__shop__cart__portolan__observed.json +498 -0
  815. package/src/testing/estate/examples__shop__cart__portolan__stores.json +208 -0
  816. package/src/testing/estate/examples__shop__oms__portolan__glossary.json +98 -0
  817. package/src/testing/estate/examples__shop__oms__portolan__proto.json +186 -0
  818. package/src/testing/estate.ts +49 -0
  819. package/src/trail/Trail.tsx +81 -0
  820. package/src/trail/model.test.ts +157 -0
  821. package/src/trail/model.ts +189 -0
  822. package/src/trail/record.tsx +32 -0
  823. package/src/trail/store.test.ts +66 -0
  824. package/src/trail/store.ts +102 -0
  825. package/tsconfig.json +35 -0
  826. package/vite.config.ts +171 -0
@@ -0,0 +1,257 @@
1
+ // The estate's vocabulary, every glossary in one place.
2
+ //
3
+ // Cards rather than a table, and that is not a style choice: a term is two
4
+ // sentences, and two sentences in a cell are a cell nobody reads. The decisions
5
+ // index is a table because its rows differ by status, date and scope - things
6
+ // you scan down a column. Entries differ only by what they say.
7
+ //
8
+ // The homonyms come first when there are any. A vocabulary is something each
9
+ // context already keeps for itself; the same word meaning two things in two
10
+ // contexts is the one fact no single glossary can state, and it is what a
11
+ // reader crossing a boundary gets wrong.
12
+
13
+ import { useDocumentTitle } from "../app/title";
14
+ import { useMemo, useState } from "react";
15
+ import { Link, useSearchParams } from "react-router";
16
+ import { CATALOG_PATH, catalog, index } from "../data";
17
+ import { allTerms } from "../catalog";
18
+ import { Blank, Empty, SectionTitle } from "../components/PageHeader";
19
+ import { ContextPill } from "../components/primitives";
20
+ import { contextVar } from "../lib/context-color";
21
+ import { plural } from "../lib/format";
22
+ import { paths } from "../routes";
23
+ import { TermCard } from "../language/TermCard";
24
+ import { homonyms, matchTerms, vocabularies } from "../language/cards";
25
+ import { bindTerms } from "../lib/terms";
26
+
27
+ export function Language() {
28
+ useDocumentTitle("Language");
29
+ // `?context=` is how the sidebar arrives here: the reader clicked one
30
+ // vocabulary, so the page opens showing it. It seeds the chips rather than
31
+ // replacing them - once here, the filter is theirs to widen.
32
+ const [params] = useSearchParams();
33
+ const [active, setActive] = useState<Set<string>>(
34
+ () =>
35
+ new Set(
36
+ params
37
+ .getAll("context")
38
+ .filter((id) => catalog.contexts.some((c) => c.id === id)),
39
+ ),
40
+ );
41
+ const [query, setQuery] = useState("");
42
+
43
+ // One word, asked for by ⌘K or by a link. It overrides both filters rather
44
+ // than combining with them: a reader who picked a word is owed that word,
45
+ // not "no term matches" because a chip they set a minute ago excluded it.
46
+ const focused = index.termById.get(params.get("term") ?? "");
47
+
48
+ const all = useMemo(() => vocabularies(catalog), []);
49
+ const shared = useMemo(() => homonyms(catalog), []);
50
+ const bound = useMemo(() => bindTerms(catalog), []);
51
+ const total = allTerms(catalog).length;
52
+
53
+ const shown = useMemo(
54
+ () =>
55
+ all
56
+ .filter((v) => active.size === 0 || active.has(v.contextId))
57
+ .map((v) => ({ ...v, terms: matchTerms(v.terms, query) }))
58
+ .filter((v) => v.terms.length > 0),
59
+ [all, active, query],
60
+ );
61
+ const showing = shown.reduce((n, v) => n + v.terms.length, 0);
62
+
63
+ const toggle = (id: string) =>
64
+ setActive((prev) => {
65
+ const next = new Set(prev);
66
+ if (next.has(id)) next.delete(id);
67
+ else next.add(id);
68
+ return next;
69
+ });
70
+
71
+ if (total === 0) {
72
+ return (
73
+ <div className="h-full overflow-y-auto p-gutter">
74
+ <h1 className="text-lg font-semibold">Language</h1>
75
+ <div className="mt-section">
76
+ <Blank where={CATALOG_PATH}>
77
+ No glossary yet — one file per bounded context, beside its README,
78
+ saying what each word means inside the boundary and what it does
79
+ not. They are read from every <span className="text-ink">GLOSSARY.md</span>{" "}
80
+ the manifest points at and land in{" "}
81
+ <span className="text-ink">terms[]</span>.
82
+ </Blank>
83
+ </div>
84
+ </div>
85
+ );
86
+ }
87
+
88
+ return (
89
+ <div className="h-full overflow-y-auto p-gutter">
90
+ <div className="flex flex-wrap items-center gap-3">
91
+ <h1 className="text-lg font-semibold">Language</h1>
92
+ <span className="mono text-muted">
93
+ {showing === total
94
+ ? `${total} ${plural(total, "term")}`
95
+ : `${showing} of ${total}`}
96
+ </span>
97
+
98
+ {/* Both filters stand down while one word is asked for: they would be
99
+ controls that change nothing, and the way back is the link beside
100
+ the card. */}
101
+ {focused ? null : (
102
+ <input
103
+ type="search"
104
+ value={query}
105
+ onChange={(e) => setQuery(e.target.value)}
106
+ placeholder="a word, or something it says"
107
+ aria-label="Filter terms"
108
+ spellCheck={false}
109
+ className="mono w-56 rounded-control border bg-transparent px-2 py-1 outline-none border-line placeholder:text-faint focus:border-accent"
110
+ />
111
+ )}
112
+
113
+ {!focused && all.length > 1 ? (
114
+ <div className="seg ml-auto" role="group" aria-label="Filter by context">
115
+ {all.map((v) => {
116
+ const on = active.has(v.contextId);
117
+ return (
118
+ <button
119
+ key={v.contextId}
120
+ type="button"
121
+ onClick={() => toggle(v.contextId)}
122
+ aria-pressed={on}
123
+ className="flex items-center gap-1.5"
124
+ style={{
125
+ color: on ? contextVar(v.contextId) : "var(--fg-muted)",
126
+ background: on
127
+ ? `color-mix(in srgb, ${contextVar(v.contextId)} 12%, transparent)`
128
+ : undefined,
129
+ }}
130
+ >
131
+ <span
132
+ aria-hidden
133
+ className="size-1.5 rounded-[1px]"
134
+ style={{ background: contextVar(v.contextId) }}
135
+ />
136
+ {v.contextId}
137
+ <span className="tnum">{v.terms.length}</span>
138
+ </button>
139
+ );
140
+ })}
141
+ </div>
142
+ ) : null}
143
+ </div>
144
+
145
+ {focused ? (
146
+ <div className="mt-section">
147
+ <SectionTitle
148
+ right={
149
+ <Link to={paths.language()} className="text-accent">
150
+ show all {total} →
151
+ </Link>
152
+ }
153
+ >
154
+ <span className="flex items-center gap-2">
155
+ one word
156
+ <ContextPill id={focused.context} />
157
+ </span>
158
+ </SectionTitle>
159
+ <div className="grid gap-grid grid-cols-[repeat(auto-fill,minmax(340px,1fr))]">
160
+ <TermCard term={focused} targets={bound.byTerm.get(focused.id)} />
161
+ </div>
162
+ </div>
163
+ ) : null}
164
+
165
+ {/* Only while the reader is looking at everything. Narrowed to one
166
+ context, "the same word, twice" is a comparison with one side of it
167
+ hidden, which is worse than not drawing it. */}
168
+ {!focused && shared.length > 0 && active.size === 0 && query === "" ? (
169
+ <div className="mt-section">
170
+ <SectionTitle
171
+ anchor="homonyms"
172
+ right={
173
+ <span>
174
+ two meanings, both correct — each belongs to its own boundary
175
+ </span>
176
+ }
177
+ >
178
+ The same word, twice
179
+ </SectionTitle>
180
+ <div className="flex flex-col gap-grid">
181
+ {shared.map((homonym) => (
182
+ <div
183
+ key={homonym.slug}
184
+ className="grid gap-grid grid-cols-[repeat(auto-fit,minmax(320px,1fr))]"
185
+ >
186
+ {homonym.terms.map((term, i) => (
187
+ <TermCard
188
+ key={term.id}
189
+ term={term}
190
+ targets={bound.byTerm.get(term.id)}
191
+ index={i}
192
+ showContext
193
+ />
194
+ ))}
195
+ </div>
196
+ ))}
197
+ </div>
198
+ </div>
199
+ ) : null}
200
+
201
+ {focused ? null : shown.length === 0 ? (
202
+ <div className="mt-section">
203
+ <Empty>no term matches</Empty>
204
+ </div>
205
+ ) : (
206
+ shown.map((vocabulary) => (
207
+ <div key={vocabulary.contextId} className="mt-section">
208
+ <SectionTitle
209
+ anchor={`ctx-${vocabulary.contextId}`}
210
+ right={
211
+ <span className="mono">
212
+ {vocabulary.terms.length}{" "}
213
+ {plural(vocabulary.terms.length, "term")}
214
+ </span>
215
+ }
216
+ >
217
+ <span className="flex items-center gap-2">
218
+ {vocabulary.context ? (
219
+ <Link to={paths.context(vocabulary.contextId)}>
220
+ <ContextPill
221
+ id={vocabulary.contextId}
222
+ name={vocabulary.context.name}
223
+ />
224
+ </Link>
225
+ ) : (
226
+ <ContextPill id={vocabulary.contextId} />
227
+ )}
228
+ </span>
229
+ </SectionTitle>
230
+ {/* What the context is, in its own words, above the words it
231
+ uses. A context that has not said renders nothing rather than a
232
+ placeholder - the same silence every other page keeps about a
233
+ fact the estate has not stated. */}
234
+ {vocabulary.context?.summary ? (
235
+ <p className="mb-3 max-w-prose text-muted">
236
+ {vocabulary.context.summary}
237
+ </p>
238
+ ) : null}
239
+ <div
240
+ className="grid gap-grid grid-cols-[repeat(auto-fill,minmax(340px,1fr))]"
241
+ data-nav-list
242
+ >
243
+ {vocabulary.terms.map((term, i) => (
244
+ <TermCard
245
+ key={term.id}
246
+ term={term}
247
+ targets={bound.byTerm.get(term.id)}
248
+ index={i}
249
+ />
250
+ ))}
251
+ </div>
252
+ </div>
253
+ ))
254
+ )}
255
+ </div>
256
+ );
257
+ }
@@ -0,0 +1,366 @@
1
+ import { useState } from "react";
2
+ import { TabGroup, TabList, TabPanel, TabPanels } from "@headlessui/react";
3
+ import { Link, useParams, useSearchParams } from "react-router";
4
+ import { catalog, index } from "../data";
5
+ import { Empty, PageHeader, SectionTitle } from "../components/PageHeader";
6
+ import { Ident } from "../components/Ident";
7
+ import { TabButton, TabCount, TabRow } from "../components/TabRow";
8
+ import { KindIcon } from "../components/kind";
9
+ import { MessageList, MethodRows } from "../components/MethodRows";
10
+ import { RowActions } from "../components/RowActions";
11
+ import { MODULE_ANCHOR, packageAnchor, paths, servicePath } from "../routes";
12
+ import { plural } from "../lib/format";
13
+ import {
14
+ callsThrough,
15
+ consumersOf,
16
+ countsOf,
17
+ dependenciesOf,
18
+ dependentsOf,
19
+ interfacesOf,
20
+ packagesOf,
21
+ registryUrl,
22
+ } from "../lib/registry";
23
+ import { NotFound } from "./NotFound";
24
+
25
+ const TABS = ["overview", "interfaces", "types", "deps"] as const;
26
+ type Tab = (typeof TABS)[number];
27
+
28
+ function isTab(value: string | null): value is Tab {
29
+ return value !== null && (TABS as readonly string[]).includes(value);
30
+ }
31
+
32
+ /**
33
+ * One schema module.
34
+ *
35
+ * The page is assembled from the catalog rather than read off the module: a
36
+ * module carries identity and inventory, and its interfaces are found through
37
+ * `RpcService.module`. That keeps the shapes in one place — the interface that
38
+ * declares them — instead of two that can disagree.
39
+ */
40
+ export function ModulePage() {
41
+ const { module: slug } = useParams();
42
+ const [params, setParams] = useSearchParams();
43
+ const [openShapes, setOpenShapes] = useState<ReadonlySet<string>>(new Set());
44
+
45
+ const toggleShape = (id: string) =>
46
+ setOpenShapes((open) => {
47
+ const next = new Set(open);
48
+ if (!next.delete(id)) next.add(id);
49
+
50
+ return next;
51
+ });
52
+
53
+ const module = slug ? index.moduleBySlug.get(slug) : undefined;
54
+ const raw = params.get("tab");
55
+ const tab: Tab = isTab(raw) ? raw : "overview";
56
+
57
+ if (!module) return <NotFound kind="Module" id={slug} />;
58
+
59
+ const counts = countsOf(index, module);
60
+ const packages = packagesOf(index, module);
61
+ const declared = interfacesOf(index, module);
62
+ const consumers = consumersOf(index, module);
63
+ const deps = dependenciesOf(index, module);
64
+ const dependents = dependentsOf(catalog, module);
65
+ const calls = callsThrough(catalog, module);
66
+ const owner = module.owner ? index.serviceById.get(module.owner) : undefined;
67
+ const url = registryUrl(module);
68
+
69
+ const tabCounts: Record<Tab, number | null> = {
70
+ overview: null,
71
+ interfaces: counts.interfaces,
72
+ types: counts.messages,
73
+ deps: deps.length + dependents.length,
74
+ };
75
+
76
+ return (
77
+ <TabGroup
78
+ manual
79
+ as="div"
80
+ className="h-full overflow-y-auto"
81
+ selectedIndex={TABS.indexOf(tab)}
82
+ onChange={(at) => {
83
+ const next = TABS[at] ?? "overview";
84
+ setParams(next === "overview" ? {} : { tab: next }, { replace: true });
85
+ }}
86
+ >
87
+ <PageHeader
88
+ kind="buf module"
89
+ name={module.name}
90
+ id={module.id}
91
+ pin={{ kind: "module", id: module.id }}
92
+ right={
93
+ url ? (
94
+ <a
95
+ href={url}
96
+ target="_blank"
97
+ rel="noreferrer"
98
+ className="mono text-muted hover:text-ink"
99
+ >
100
+ {module.registry} ↗
101
+ </a>
102
+ ) : undefined
103
+ }
104
+ >
105
+ <div className="mono mt-2 flex flex-wrap items-center gap-x-4 gap-y-1 text-muted">
106
+ <span>
107
+ {counts.packages} {plural(counts.packages, "package")}
108
+ </span>
109
+ <span>
110
+ {counts.methods} {plural(counts.methods, "method")}
111
+ </span>
112
+ {module.commit ? (
113
+ <Ident value={module.commit.slice(0, 12)} />
114
+ ) : (
115
+ /* Unpinned means two builds a day apart can describe two different
116
+ modules under one name. Worth saying on the page, not only in a
117
+ diagnostic nobody reads twice. */
118
+ <span title="tracked by label rather than pinned to a commit">
119
+ not pinned
120
+ </span>
121
+ )}
122
+ </div>
123
+
124
+ {/* The same underline the service page uses, and the same scrolling
125
+ strip: these tabs switch the page under them rather than filtering
126
+ a list beside it, and they run out of row at the same width. */}
127
+ <div className="mt-4">
128
+ <TabRow active={tab}>
129
+ <TabList className="flex w-max gap-0">
130
+ {TABS.map((name) => (
131
+ <TabButton key={name}>
132
+ {name}
133
+ {tabCounts[name] !== null ? (
134
+ <TabCount>{tabCounts[name]}</TabCount>
135
+ ) : null}
136
+ </TabButton>
137
+ ))}
138
+ </TabList>
139
+ </TabRow>
140
+ </div>
141
+ </PageHeader>
142
+
143
+ <TabPanels className="p-gutter">
144
+ <TabPanel>
145
+ <>
146
+ <section id={MODULE_ANCHOR.packages} className="max-w-table">
147
+ <SectionTitle anchor={MODULE_ANCHOR.packages}>
148
+ Packages
149
+ </SectionTitle>
150
+ {packages.length === 0 ? (
151
+ <Empty>this module declares no packages</Empty>
152
+ ) : (
153
+ <div className="rows">
154
+ {packages.map((pkg) => (
155
+ <Link
156
+ key={pkg.name}
157
+ to={`?tab=interfaces#${packageAnchor(pkg.name)}`}
158
+ className="row mono hover:text-ink"
159
+ >
160
+ <span className="flex-1 truncate">{pkg.name}</span>
161
+ <span className="tnum text-muted">
162
+ {pkg.interfaces.length}{" "}
163
+ {plural(pkg.interfaces.length, "interface")}
164
+ </span>
165
+ </Link>
166
+ ))}
167
+ </div>
168
+ )}
169
+ </section>
170
+
171
+ <section id={MODULE_ANCHOR.used} className="mt-section max-w-table">
172
+ <SectionTitle anchor={MODULE_ANCHOR.used}>
173
+ Who uses it
174
+ </SectionTitle>
175
+ <div className="rows">
176
+ <div className="row">
177
+ <span className="flex-1">published by</span>
178
+ {owner ? (
179
+ <Link
180
+ to={servicePath(owner.id) ?? "#"}
181
+ className="mono hover:text-ink"
182
+ >
183
+ {owner.id}
184
+ </Link>
185
+ ) : (
186
+ /* A module published by another team is the ordinary case,
187
+ and the reason `owner` is optional at all. */
188
+ <span className="text-muted">nobody in this catalog</span>
189
+ )}
190
+ </div>
191
+ </div>
192
+
193
+ <div className="mt-3">
194
+ <SectionTitle>Read by</SectionTitle>
195
+ {consumers.length === 0 ? (
196
+ <Empty>
197
+ nothing in this catalog reads this module but the service
198
+ that publishes it
199
+ </Empty>
200
+ ) : (
201
+ <div className="rows">
202
+ {consumers.map((service) => (
203
+ <Link
204
+ key={service.id}
205
+ to={servicePath(service.id) ?? "#"}
206
+ className="row mono hover:text-ink"
207
+ >
208
+ <span className="flex-1 truncate">{service.id}</span>
209
+ <span className="tnum text-muted">
210
+ {
211
+ calls.filter((c) => c.service.id === service.id)
212
+ .length
213
+ }{" "}
214
+ calls
215
+ </span>
216
+ </Link>
217
+ ))}
218
+ </div>
219
+ )}
220
+ </div>
221
+ </section>
222
+
223
+ <section className="mt-section max-w-table">
224
+ <SectionTitle>Files</SectionTitle>
225
+ {module.files.length === 0 ? (
226
+ <Empty>no files were recorded for this module</Empty>
227
+ ) : (
228
+ <ul className="rows">
229
+ {module.files.map((file) => (
230
+ <li key={file} className="row mono text-muted">
231
+ {file}
232
+ </li>
233
+ ))}
234
+ </ul>
235
+ )}
236
+ </section>
237
+ </>
238
+ </TabPanel>
239
+
240
+ <TabPanel>
241
+ <div id={MODULE_ANCHOR.interfaces} className="flex flex-col gap-6">
242
+ {declared.length === 0 ? (
243
+ <Empty>
244
+ no interface in this catalog says it was declared in this module
245
+ </Empty>
246
+ ) : null}
247
+ {packages.map((pkg) =>
248
+ pkg.interfaces.length === 0 ? null : (
249
+ <section key={pkg.name} id={packageAnchor(pkg.name)}>
250
+ <SectionTitle anchor={packageAnchor(pkg.name)}>
251
+ {pkg.name}
252
+ </SectionTitle>
253
+ <div className="flex flex-col gap-4">
254
+ {pkg.interfaces.map(({ provided, service }) => (
255
+ <div
256
+ key={provided.id}
257
+ className="rounded-card border border-line"
258
+ >
259
+ <div className="mono flex flex-wrap items-center gap-x-3 border-b px-3 py-1.5 border-line bg-surface">
260
+ <KindIcon kind="endpoint" />
261
+ <Ident value={provided.id} className="text-ink" />
262
+ {/* Which service actually answers on it: a module is
263
+ a schema, and a schema does not serve requests. */}
264
+ <Link
265
+ to={servicePath(service.id) ?? "#"}
266
+ className="ml-auto hover:text-ink"
267
+ >
268
+ {service.id}
269
+ </Link>
270
+ </div>
271
+ <MethodRows
272
+ provided={provided}
273
+ open={openShapes}
274
+ onToggle={toggleShape}
275
+ />
276
+ </div>
277
+ ))}
278
+ </div>
279
+ </section>
280
+ ),
281
+ )}
282
+ </div>
283
+ </TabPanel>
284
+
285
+ <TabPanel>
286
+ <div id={MODULE_ANCHOR.types} className="flex flex-col gap-4">
287
+ {counts.messages === 0 ? (
288
+ <Empty>
289
+ no shapes were read from this module — its interfaces list their
290
+ methods but not the messages they move
291
+ </Empty>
292
+ ) : null}
293
+ {declared.map(({ provided }) =>
294
+ provided.messages?.length ? (
295
+ <div
296
+ key={provided.id}
297
+ className="rounded-card border border-line"
298
+ >
299
+ <div className="mono border-b px-3 py-1.5 border-line bg-surface">
300
+ <Ident value={provided.id} className="text-ink" />
301
+ </div>
302
+ <MessageList
303
+ provided={provided}
304
+ open={openShapes}
305
+ onToggle={toggleShape}
306
+ />
307
+ </div>
308
+ ) : null,
309
+ )}
310
+ </div>
311
+ </TabPanel>
312
+
313
+ <TabPanel>
314
+ <div id={MODULE_ANCHOR.deps} className="max-w-table">
315
+ <SectionTitle>Depends on</SectionTitle>
316
+ {deps.length === 0 ? (
317
+ <Empty>this module depends on nothing</Empty>
318
+ ) : (
319
+ <div className="rows">
320
+ {deps.map((dep) =>
321
+ dep.module ? (
322
+ <Link
323
+ key={dep.id}
324
+ to={paths.module(dep.module.slug)}
325
+ className="row mono hover:text-ink"
326
+ >
327
+ <span className="flex-1 truncate">{dep.module.name}</span>
328
+ <RowActions copy={dep.id} />
329
+ </Link>
330
+ ) : (
331
+ /* A module may depend on one the estate never vendored.
332
+ That is normal, not broken: naming it and saying the
333
+ catalog does not hold it beats a link into nothing. */
334
+ <div key={dep.id} className="row mono text-muted">
335
+ <span className="flex-1 truncate">{dep.id}</span>
336
+ <span>not in this catalog</span>
337
+ </div>
338
+ ),
339
+ )}
340
+ </div>
341
+ )}
342
+
343
+ <div className="mt-section">
344
+ <SectionTitle>Depended on by</SectionTitle>
345
+ {dependents.length === 0 ? (
346
+ <Empty>no module in this catalog depends on this one</Empty>
347
+ ) : (
348
+ <div className="rows">
349
+ {dependents.map((other) => (
350
+ <Link
351
+ key={other.id}
352
+ to={paths.module(other.slug)}
353
+ className="row mono hover:text-ink"
354
+ >
355
+ {other.name}
356
+ </Link>
357
+ ))}
358
+ </div>
359
+ )}
360
+ </div>
361
+ </div>
362
+ </TabPanel>
363
+ </TabPanels>
364
+ </TabGroup>
365
+ );
366
+ }
@@ -0,0 +1,54 @@
1
+ import { Link } from "react-router";
2
+ import { useDocumentTitle } from "../app/title";
3
+
4
+ /**
5
+ * Both shapes of "not here" end the same way: the one control that finds a
6
+ * thing by its current name. A reader who followed a stale link has a name in
7
+ * mind, and the palette is where that name still works.
8
+ */
9
+ function SearchHint() {
10
+ return (
11
+ <p className="mono mt-3 text-muted">
12
+ <kbd>⌘K</kbd> searches the whole catalog
13
+ </p>
14
+ );
15
+ }
16
+
17
+ export function NotFound({ kind, id }: { kind: string; id?: string }) {
18
+ useDocumentTitle(`${kind} not found`);
19
+ return (
20
+ <div className="glow p-gutter">
21
+ <h1 className="text-lg font-semibold">{kind} not found</h1>
22
+ <p className="mt-3 text-muted">
23
+ nothing in the catalog answers to “{id ?? ""}” — it may have been
24
+ renamed since this chart was drawn
25
+ </p>
26
+ <SearchHint />
27
+ <Link
28
+ to="/"
29
+ className="mono mt-6 inline-block rounded-control text-accent hover:underline"
30
+ >
31
+ ← overview
32
+ </Link>
33
+ </div>
34
+ );
35
+ }
36
+
37
+ export function NotFoundPage() {
38
+ useDocumentTitle("Not found");
39
+ return (
40
+ <div className="glow p-gutter">
41
+ <h1 className="text-lg font-semibold">Not found</h1>
42
+ <p className="mt-3 text-muted">
43
+ off the edge of the chart — no route runs through here
44
+ </p>
45
+ <SearchHint />
46
+ <Link
47
+ to="/"
48
+ className="mono mt-6 inline-block rounded-control text-accent hover:underline"
49
+ >
50
+ ← overview
51
+ </Link>
52
+ </div>
53
+ );
54
+ }