@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,727 @@
1
+ import { useMemo } from "react";
2
+ import { Link, useParams } from "react-router";
3
+ import { catalog, index } from "../data";
4
+ import { blockCounts, blockFields, enumsOf, rootEntity } from "../catalog";
5
+ import { isStatusEnum } from "../lib/shape";
6
+ import type {
7
+ Aggregate,
8
+ Block,
9
+ BlockKind,
10
+ Operation,
11
+ Service,
12
+ Enum,
13
+ } from "../catalog";
14
+ import { markdownOutline } from "../lib/derive";
15
+ import { tablesPersisting, viewsPresenting } from "../lib/data-model";
16
+ import { plural } from "../lib/format";
17
+ import { KIND_LABEL, KIND_PLURAL } from "../lib/kinds";
18
+ import type { LeafKind } from "../lib/kinds";
19
+ import { KindIcon } from "../components/kind";
20
+ import {
21
+ AGGREGATE_ANCHOR,
22
+ AGGREGATE_SECTION,
23
+ EVENT_ANCHOR,
24
+ LINKS_HERE,
25
+ paths,
26
+ servicePath,
27
+ tablePath,
28
+ viewPath,
29
+ } from "../routes";
30
+ import { methodId } from "../lib/api";
31
+ import { Markdown } from "../components/Markdown";
32
+ import { Empty, PageHeader, SectionTitle } from "../components/PageHeader";
33
+ import { Ident } from "../components/Ident";
34
+ import { RowActions } from "../components/RowActions";
35
+ import { Toc } from "../components/Toc";
36
+ import type { TocItem } from "../components/Toc";
37
+ import { WhatLinksHere } from "../components/WhatLinksHere";
38
+ import { LifecycleDiagram } from "../components/LifecycleDiagram";
39
+ import { isTerminal } from "../lib/lifecycle";
40
+ import { InLanguage } from "../language/InLanguage";
41
+ import { NotFound } from "./NotFound";
42
+
43
+ /**
44
+ * The strip above the readme. It answers "what is in this aggregate" before
45
+ * the prose gets a chance to, and every count is a way into the section that
46
+ * holds the things counted.
47
+ */
48
+ function BuildingBlocks({
49
+ aggregate,
50
+ rootTo,
51
+ }: {
52
+ aggregate: Aggregate;
53
+ rootTo: string | null;
54
+ }) {
55
+ const counts = blockCounts(aggregate);
56
+ const chips: { kind: LeafKind; n: number; anchor: string }[] = [
57
+ { kind: "entity", n: counts.entities, anchor: AGGREGATE_ANCHOR.entities },
58
+ {
59
+ kind: "vo",
60
+ n: counts.valueObjects,
61
+ anchor: AGGREGATE_ANCHOR.valueObjects,
62
+ },
63
+ { kind: "enum", n: counts.enums, anchor: AGGREGATE_ANCHOR.enums },
64
+ { kind: "event", n: counts.events, anchor: AGGREGATE_ANCHOR.events },
65
+ { kind: "command", n: counts.commands, anchor: AGGREGATE_ANCHOR.commands },
66
+ { kind: "query", n: counts.queries, anchor: AGGREGATE_ANCHOR.queries },
67
+ ];
68
+
69
+ return (
70
+ <section className="mb-section overflow-hidden rounded-card border border-line shadow-xs">
71
+ <div className="label border-b border-line bg-surface px-4 py-2">
72
+ Building blocks
73
+ </div>
74
+ <div className="flex flex-wrap items-center gap-x-4 gap-y-2 px-4 py-3">
75
+ <span className="mono flex items-center gap-1.5 text-muted">
76
+ root
77
+ <KindIcon kind="entity" />
78
+ {rootTo ? (
79
+ <Link to={rootTo} className="text-ink hover:underline">
80
+ {aggregate.root}
81
+ </Link>
82
+ ) : (
83
+ <span className="text-ink">{aggregate.root}</span>
84
+ )}
85
+ </span>
86
+ <span aria-hidden className="h-4 w-px bg-line-strong" />
87
+ {chips.map(({ kind, n, anchor }) => (
88
+ <a
89
+ key={kind}
90
+ href={`#${anchor}`}
91
+ className="mono flex items-center gap-1.5 text-muted hover:text-ink"
92
+ title={`jump to ${KIND_PLURAL[kind]}`}
93
+ >
94
+ <KindIcon kind={kind} />
95
+ <span
96
+ className={n === 0 ? "text-muted" : "text-ink"}
97
+ style={
98
+ kind === "event" && n > 0
99
+ ? { color: "var(--kind-event)" }
100
+ : undefined
101
+ }
102
+ >
103
+ {n}
104
+ </span>
105
+ {n === 1 ? KIND_LABEL[kind] : KIND_PLURAL[kind]}
106
+ </a>
107
+ ))}
108
+ </div>
109
+ </section>
110
+ );
111
+ }
112
+
113
+ function BlockList({
114
+ kind,
115
+ blocks,
116
+ linkTo,
117
+ rootName,
118
+ }: {
119
+ kind: BlockKind;
120
+ blocks: Block[];
121
+ linkTo: (block: Block) => string;
122
+ rootName?: string;
123
+ }) {
124
+ if (blocks.length === 0) {
125
+ return (
126
+ <Empty>no {KIND_PLURAL[kind]} declared — the shape lives elsewhere</Empty>
127
+ );
128
+ }
129
+ return (
130
+ /* icon, the block itself, where its shape comes from, actions - one
131
+ column each, so the provenance holds the same column down the list. */
132
+ <div className="rows grid-cols-[auto_1fr_auto_auto]" data-nav-list>
133
+ {/* A div holding a link, not a link holding buttons: the shared-type id
134
+ copies itself and the row carries actions, and neither of those can
135
+ live inside an anchor. */}
136
+ {blocks.map((block) => {
137
+ const fields = blockFields(catalog, block);
138
+ return (
139
+ <div key={block.id} className="row items-start gap-2 px-3 py-2">
140
+ <span className="mt-0.5 flex shrink-0">
141
+ <KindIcon kind={kind} />
142
+ </span>
143
+ <span className="min-w-0 flex-1">
144
+ <Link
145
+ to={linkTo(block)}
146
+ data-nav-item
147
+ className="mono rounded-control"
148
+ title={block.name}
149
+ >
150
+ {block.name}
151
+ </Link>
152
+ {block.name === rootName ? (
153
+ <span className="mono ml-2 text-muted">root</span>
154
+ ) : null}
155
+ {block.deprecated ? (
156
+ <span className="chip ml-2" title="marked @deprecated in the source">
157
+ deprecated
158
+ </span>
159
+ ) : null}
160
+ <span className="meta block truncate" title={block.doc}>
161
+ {block.doc}
162
+ </span>
163
+ </span>
164
+ <span className="mono flex shrink-0 items-center gap-2 text-muted">
165
+ {block.ref ? (
166
+ <Ident value={block.ref} title={`shared type ${block.ref}`} />
167
+ ) : (
168
+ <span title="shape written inline">inline</span>
169
+ )}
170
+ <span>{fields.length}f</span>
171
+ </span>
172
+ <RowActions copy={block.id} label={block.name} />
173
+ </div>
174
+ );
175
+ })}
176
+ </div>
177
+ );
178
+ }
179
+
180
+ /**
181
+ * The closed sets, each with its values on the row: a reader scanning the
182
+ * aggregate wants to see "placed, confirmed, cancelled" without opening a
183
+ * page, and a set has few enough values that the row can hold them.
184
+ */
185
+ function EnumList({
186
+ aggregate,
187
+ linkTo,
188
+ }: {
189
+ aggregate: Aggregate;
190
+ linkTo: (item: Enum) => string;
191
+ }) {
192
+ const enums = enumsOf(aggregate);
193
+ if (enums.length === 0) {
194
+ return (
195
+ <Empty>no enums declared — every field here is a scalar or a shape</Empty>
196
+ );
197
+ }
198
+ const states = aggregate.lifecycle?.states ?? [];
199
+ return (
200
+ <div className="rows grid-cols-[auto_1fr_auto_auto]" data-nav-list>
201
+ {enums.map((item) => (
202
+ <div key={item.id} className="row items-start gap-2 px-3 py-2">
203
+ <span className="mt-0.5 flex shrink-0">
204
+ <KindIcon kind="enum" />
205
+ </span>
206
+ <span className="min-w-0 flex-1">
207
+ <Link
208
+ to={linkTo(item)}
209
+ data-nav-item
210
+ className="mono rounded-control"
211
+ title={item.name}
212
+ >
213
+ {item.name}
214
+ </Link>
215
+ {isStatusEnum(item, states) ? (
216
+ <a
217
+ href={`#${AGGREGATE_ANCHOR.lifecycle}`}
218
+ className="chip status-verified ml-2"
219
+ title="its values are the lifecycle's states"
220
+ >
221
+ <span aria-hidden className="dot" />
222
+ the status
223
+ </a>
224
+ ) : null}
225
+ {item.deprecated ? (
226
+ <span className="chip ml-2" title="marked deprecated in the source">
227
+ deprecated
228
+ </span>
229
+ ) : null}
230
+ <span className="meta block truncate" title={item.doc}>
231
+ {item.doc}
232
+ </span>
233
+ <span className="mono mt-0.5 flex flex-wrap gap-x-2 gap-y-0.5 text-muted">
234
+ {item.values.map((value) => (
235
+ <span
236
+ key={value.name}
237
+ className={value.deprecated ? "line-through" : undefined}
238
+ title={value.doc || undefined}
239
+ >
240
+ {value.name}
241
+ </span>
242
+ ))}
243
+ </span>
244
+ </span>
245
+ <span className="mono flex shrink-0 items-center gap-2 text-muted">
246
+ <span>{item.values.length}v</span>
247
+ </span>
248
+ <RowActions copy={item.id} label={item.name} />
249
+ </div>
250
+ ))}
251
+ </div>
252
+ );
253
+ }
254
+
255
+ /**
256
+ * Commands and queries with what each one actually does. The sentence is the
257
+ * point: a bare `CancelOrder` says nothing about when it is refused, and the
258
+ * precondition is exactly what a reader came to this page for.
259
+ */
260
+ function OperationList({
261
+ kind,
262
+ operations,
263
+ service,
264
+ }: {
265
+ kind: "command" | "query";
266
+ operations: Operation[];
267
+ service: Service;
268
+ }) {
269
+ // Whether this service records what exposes an operation at all. A catalog
270
+ // written before anything read a transport layer says nothing either way,
271
+ // and answering "no endpoint runs it" from that silence would be inventing.
272
+ const recorded = service.aggregates.some((aggregate) =>
273
+ aggregate.operations.some((operation) => operation.exposedBy?.length),
274
+ );
275
+ const to = servicePath(service.id);
276
+
277
+ return (
278
+ <ul className="flex flex-col gap-1">
279
+ {operations.map((op) => (
280
+ <li
281
+ key={op.id}
282
+ className={`flex items-start gap-2 border-l-2 px-2 py-1.5 bg-surface ${
283
+ kind === "command" ? "border-verified" : "border-line-strong"
284
+ }`}
285
+ >
286
+ <span className="mt-px shrink-0">
287
+ <KindIcon kind={kind} />
288
+ </span>
289
+ <div className="min-w-0">
290
+ <span className="flex flex-wrap items-center gap-x-2">
291
+ <Ident block value={op.id} className={op.deprecated ? "line-through" : undefined} />
292
+ {op.deprecated ? (
293
+ <span className="chip" title="marked @deprecated in the source">
294
+ deprecated
295
+ </span>
296
+ ) : null}
297
+ </span>
298
+ {op.doc ? <p className="mt-0.5 text-muted">{op.doc}</p> : null}
299
+ {op.exposedBy?.length ? (
300
+ <p className="mono mt-1 flex flex-wrap items-center gap-x-2 text-muted">
301
+ <span>exposed by</span>
302
+ {op.exposedBy.map((method) =>
303
+ to ? (
304
+ <Link
305
+ key={method}
306
+ to={`${to}?tab=provides`}
307
+ className="rounded-control hover:text-ink"
308
+ title="the interface method that runs this"
309
+ >
310
+ {methodId(service, method)}
311
+ </Link>
312
+ ) : (
313
+ <span key={method}>{methodId(service, method)}</span>
314
+ ),
315
+ )}
316
+ </p>
317
+ ) : recorded ? (
318
+ // Said out loud rather than left blank: an operation no endpoint
319
+ // runs is reachable only from inside, and here that is a design
320
+ // decision rather than an omission.
321
+ <p className="mono mt-1 text-muted">
322
+ no endpoint runs it — internal to the service
323
+ </p>
324
+ ) : null}
325
+ </div>
326
+ </li>
327
+ ))}
328
+ </ul>
329
+ );
330
+ }
331
+
332
+ export function AggregatePage() {
333
+ const {
334
+ context: contextId,
335
+ service: serviceSlug,
336
+ aggregate: aggSlug,
337
+ } = useParams();
338
+ const context = catalog.contexts.find((c) => c.id === contextId);
339
+ const service = context?.services.find((s) => s.slug === serviceSlug);
340
+ const aggregate = service?.aggregates.find((a) => a.slug === aggSlug);
341
+
342
+ const outline = useMemo(
343
+ () => (aggregate ? markdownOutline(aggregate.readme) : []),
344
+ [aggregate],
345
+ );
346
+
347
+ if (!context || !service || !aggregate)
348
+ return <NotFound kind="Aggregate" id={aggSlug} />;
349
+
350
+ const commands = aggregate.operations.filter((o) => o.kind === "command");
351
+ const queries = aggregate.operations.filter((o) => o.kind === "query");
352
+ const root = rootEntity(aggregate);
353
+ const persistence = tablesPersisting(index, aggregate.id);
354
+ const presented = viewsPresenting(index, aggregate.id);
355
+
356
+ // The readme's own headings first, then the five sections the page adds
357
+ // under it. One rail, in the order the page is actually written in.
358
+ const toc: TocItem[] = [
359
+ ...outline.map((h) => ({ id: h.slug, label: h.text, depth: h.depth })),
360
+ { id: AGGREGATE_ANCHOR.entities, label: "Entities" },
361
+ { id: AGGREGATE_ANCHOR.valueObjects, label: "Value objects" },
362
+ { id: AGGREGATE_ANCHOR.enums, label: "Enums" },
363
+ ...(aggregate.lifecycle ? [{ id: AGGREGATE_ANCHOR.lifecycle, label: "Lifecycle" }] : []),
364
+ { id: AGGREGATE_ANCHOR.events, label: "Events" },
365
+ { id: AGGREGATE_ANCHOR.commands, label: "Commands" },
366
+ { id: AGGREGATE_ANCHOR.queries, label: "Queries" },
367
+ { id: AGGREGATE_SECTION.persistence, label: "Persistence" },
368
+ { id: LINKS_HERE, label: "What links here" },
369
+ ];
370
+
371
+ const voPath = (block: Block) =>
372
+ paths.valueObject(context.id, service.slug, aggregate.slug, block.slug);
373
+ const entityPath = (block: Block) =>
374
+ paths.entity(context.id, service.slug, aggregate.slug, block.slug);
375
+ const enumPathOf = (item: Enum) =>
376
+ paths.enum(context.id, service.slug, aggregate.slug, item.slug);
377
+
378
+ return (
379
+ <div className="h-full overflow-y-auto">
380
+ <PageHeader
381
+ kind={
382
+ <>
383
+ aggregate ·{" "}
384
+ <Link
385
+ to={paths.service(context.id, service.slug)}
386
+ className="rounded-control hover:text-ink hover:underline"
387
+ >
388
+ {service.id}
389
+ </Link>
390
+ </>
391
+ }
392
+ name={aggregate.name}
393
+ id={aggregate.id}
394
+ contextId={context.id}
395
+ pin={{ kind: "aggregate", id: aggregate.id }}
396
+ />
397
+
398
+ <div className="flex gap-section p-gutter">
399
+ <div className="min-w-0 flex-1">
400
+ <InLanguage id={aggregate.id} />
401
+
402
+ <BuildingBlocks
403
+ aggregate={aggregate}
404
+ rootTo={root ? entityPath(root) : null}
405
+ />
406
+
407
+ <Markdown mermaid>{aggregate.readme}</Markdown>
408
+
409
+ <div
410
+ className="mt-section max-w-prose"
411
+ id={AGGREGATE_ANCHOR.entities}
412
+ >
413
+ <SectionTitle
414
+ anchor={AGGREGATE_ANCHOR.entities}
415
+ right={
416
+ <span>
417
+ identity matters — these are tracked over time
418
+ </span>
419
+ }
420
+ >
421
+ Entities
422
+ </SectionTitle>
423
+ <BlockList
424
+ kind="entity"
425
+ blocks={aggregate.entities}
426
+ linkTo={entityPath}
427
+ rootName={aggregate.root}
428
+ />
429
+ </div>
430
+
431
+ <div
432
+ className="mt-section max-w-prose"
433
+ id={AGGREGATE_ANCHOR.valueObjects}
434
+ >
435
+ <SectionTitle
436
+ anchor={AGGREGATE_ANCHOR.valueObjects}
437
+ right={
438
+ <span>
439
+ no identity — equal values are the same value
440
+ </span>
441
+ }
442
+ >
443
+ Value objects
444
+ </SectionTitle>
445
+ <BlockList
446
+ kind="vo"
447
+ blocks={aggregate.valueObjects}
448
+ linkTo={voPath}
449
+ />
450
+ </div>
451
+
452
+ <div
453
+ className="mt-section max-w-prose"
454
+ id={AGGREGATE_ANCHOR.enums}
455
+ >
456
+ <SectionTitle
457
+ anchor={AGGREGATE_ANCHOR.enums}
458
+ right={
459
+ <span>closed sets — a consumer handles every value</span>
460
+ }
461
+ >
462
+ Enums
463
+ </SectionTitle>
464
+ <EnumList aggregate={aggregate} linkTo={enumPathOf} />
465
+ </div>
466
+
467
+ {aggregate.lifecycle ? (
468
+ <div className="mt-section" id={AGGREGATE_ANCHOR.lifecycle}>
469
+ <SectionTitle
470
+ anchor={AGGREGATE_ANCHOR.lifecycle}
471
+ right={
472
+ <span className="tnum">
473
+ {aggregate.lifecycle.states.length}{" "}
474
+ {plural(aggregate.lifecycle.states.length, "state")} ·{" "}
475
+ {aggregate.lifecycle.transitions.length}{" "}
476
+ {plural(aggregate.lifecycle.transitions.length, "move")} ·{" "}
477
+ {aggregate.lifecycle.states.filter((s) => isTerminal(aggregate.lifecycle!, s)).length}{" "}
478
+ terminal
479
+ </span>
480
+ }
481
+ >
482
+ Lifecycle
483
+ </SectionTitle>
484
+ {/* Where the root can go from where it is, as the code wrote it
485
+ down: one table of moves, read off the source. The first
486
+ state is where a new one starts; a state nothing leads out
487
+ of is where it becomes a record. */}
488
+ <LifecycleDiagram
489
+ aggregate={aggregate}
490
+ eventPath={(id) => {
491
+ const event = aggregate.events.find((e) => e.id === id);
492
+ return event ? paths.event(context.id, service.slug, aggregate.slug, event.slug) : null;
493
+ }}
494
+ />
495
+ </div>
496
+ ) : null}
497
+
498
+ <div className="mt-section max-w-prose" id={AGGREGATE_ANCHOR.events}>
499
+ <SectionTitle anchor={AGGREGATE_ANCHOR.events}>Events</SectionTitle>
500
+ {aggregate.events.length === 0 ? (
501
+ <Empty>
502
+ nothing is announced from here — the readme says why
503
+ </Empty>
504
+ ) : (
505
+ /* The row is a div rather than a link so the consumer count can
506
+ be a link of its own: a count that says "4 consumers" and does
507
+ not take you to them is a count that lied. */
508
+ <div
509
+ className="rows grid-cols-[auto_auto_1fr_auto_auto]"
510
+ data-nav-list
511
+ >
512
+ {aggregate.events.map((event) => {
513
+ const to = paths.event(
514
+ context.id,
515
+ service.slug,
516
+ aggregate.slug,
517
+ event.slug,
518
+ );
519
+ return (
520
+ <div key={event.id} className="row gap-2 px-3 py-2">
521
+ <KindIcon kind="event" />
522
+ <Link
523
+ to={to}
524
+ data-nav-item
525
+ className="mono rounded-control"
526
+ style={{ color: "var(--kind-event)" }}
527
+ >
528
+ {event.name}
529
+ </Link>
530
+ <span className="flex gap-1">
531
+ {event.versions.map((v, i) => (
532
+ <span
533
+ key={v.version}
534
+ className="mono rounded-[4px] border px-1"
535
+ style={{
536
+ borderColor:
537
+ i === event.versions.length - 1
538
+ ? "var(--accent)"
539
+ : "var(--border)",
540
+ color:
541
+ i === event.versions.length - 1
542
+ ? "var(--accent)"
543
+ : "var(--fg-muted)",
544
+ }}
545
+ >
546
+ {v.version}
547
+ </span>
548
+ ))}
549
+ </span>
550
+ <Link
551
+ to={`${to}#${EVENT_ANCHOR.consumers}`}
552
+ className="mono rounded-control text-muted hover:text-ink"
553
+ title="open the consumers of this event"
554
+ >
555
+ <span className="tnum">{event.consumers.length}</span>{" "}
556
+ {event.consumers.length === 1
557
+ ? "consumer"
558
+ : "consumers"}
559
+ </Link>
560
+ <RowActions
561
+ copy={event.id}
562
+ reveal={event.id}
563
+ label={event.name}
564
+ />
565
+ </div>
566
+ );
567
+ })}
568
+ </div>
569
+ )}
570
+ </div>
571
+
572
+ {/* One column, not two: an operation whose precondition is written
573
+ down is a paragraph, and two prose columns half a page wide would
574
+ turn every one of them into a ladder. */}
575
+ <div className="mt-8 flex max-w-prose flex-col gap-section">
576
+ <div id={AGGREGATE_ANCHOR.commands}>
577
+ <SectionTitle
578
+ anchor={AGGREGATE_ANCHOR.commands}
579
+ right={
580
+ <span>
581
+ they change the aggregate — one row lock each
582
+ </span>
583
+ }
584
+ >
585
+ Commands
586
+ </SectionTitle>
587
+ {commands.length === 0 ? (
588
+ <Empty>nothing changes this aggregate from outside</Empty>
589
+ ) : null}
590
+ <OperationList kind="command" operations={commands} service={service} />
591
+ </div>
592
+ <div id={AGGREGATE_ANCHOR.queries}>
593
+ <SectionTitle
594
+ anchor={AGGREGATE_ANCHOR.queries}
595
+ right={
596
+ <span>
597
+ they change nothing — and may be behind
598
+ </span>
599
+ }
600
+ >
601
+ Queries
602
+ </SectionTitle>
603
+ {queries.length === 0 ? (
604
+ <Empty>nothing reads this aggregate by name</Empty>
605
+ ) : null}
606
+ <OperationList kind="query" operations={queries} service={service} />
607
+ </div>
608
+ </div>
609
+
610
+ {/* Where this aggregate actually lives. It sits after the model and
611
+ before the backlinks because it answers a question about THIS
612
+ aggregate — one a reader asks once they believe the model. */}
613
+ <div
614
+ className="mt-section max-w-table"
615
+ id={AGGREGATE_SECTION.persistence}
616
+ >
617
+ <SectionTitle
618
+ anchor={AGGREGATE_SECTION.persistence}
619
+ right={
620
+ <span>
621
+ one row per table that holds it
622
+ {presented.length > 0 ? ", then the views over it" : ""}
623
+ </span>
624
+ }
625
+ >
626
+ Persistence
627
+ </SectionTitle>
628
+ {persistence.length === 0 ? (
629
+ <Empty>
630
+ No persistence found for {aggregate.name} — the extractor maps
631
+ tables via `persists` in migrations metadata
632
+ </Empty>
633
+ ) : (
634
+ /* icon, name, what it is, store, width, actions. Tables and
635
+ views share the columns because a reader reads them as one
636
+ list - which is why a table with no role still emits the
637
+ cell the views put their kind in. */
638
+ <div
639
+ className="rows grid-cols-[auto_auto_auto_1fr_auto_auto]"
640
+ data-nav-list
641
+ >
642
+ {persistence.map(({ table, store }) => {
643
+ const to = tablePath(table.id);
644
+ return (
645
+ <div key={table.id} className="row px-2 py-1.5">
646
+ <KindIcon kind="table" />
647
+ {to ? (
648
+ <Link
649
+ to={to}
650
+ data-nav-item
651
+ className="mono rounded-control"
652
+ >
653
+ {table.name}
654
+ </Link>
655
+ ) : (
656
+ <span className="mono">{table.name}</span>
657
+ )}
658
+ {table.role ? (
659
+ <span className="chip">{table.role}</span>
660
+ ) : (
661
+ <span />
662
+ )}
663
+ <span className="mono text-muted">{store.slug}</span>
664
+ <span className="mono text-muted">
665
+ <span className="tnum">{table.columns.length}</span>{" "}
666
+ {plural(table.columns.length, "column")}
667
+ </span>
668
+ <RowActions
669
+ copy={table.id}
670
+ reveal={table.id}
671
+ label={table.name}
672
+ />
673
+ </div>
674
+ );
675
+ })}
676
+ {/* A view is not persistence — it holds nothing — but it is
677
+ how this aggregate is actually read back, and a reader who
678
+ has found the tables wants the reports over them next. */}
679
+ {presented.map(({ view, store }) => {
680
+ const to = viewPath(view.id);
681
+ return (
682
+ <div key={view.id} className="row px-2 py-1.5">
683
+ <KindIcon kind="view" />
684
+ {to ? (
685
+ <Link
686
+ to={to}
687
+ data-nav-item
688
+ className="mono rounded-control"
689
+ >
690
+ {view.name}
691
+ </Link>
692
+ ) : (
693
+ <span className="mono">{view.name}</span>
694
+ )}
695
+ <span className="chip">
696
+ {view.materialized ? "matview" : "view"}
697
+ </span>
698
+ <span className="mono text-muted">{store.slug}</span>
699
+ <span className="mono text-muted">
700
+ <span className="tnum">{view.columns.length}</span>{" "}
701
+ {plural(view.columns.length, "column")}
702
+ </span>
703
+ <RowActions
704
+ copy={view.id}
705
+ reveal={view.id}
706
+ label={view.name}
707
+ />
708
+ </div>
709
+ );
710
+ })}
711
+ </div>
712
+ )}
713
+ </div>
714
+
715
+ {/* An aggregate is reached through its events and nothing else, so
716
+ every row here arrived by way of one, and says which. */}
717
+ <WhatLinksHere
718
+ target={{ kind: "aggregate", id: aggregate.id }}
719
+ empty="nothing outside this aggregate names one of its events"
720
+ />
721
+ </div>
722
+
723
+ <Toc items={toc} label="Sections of this aggregate" title="Outline" />
724
+ </div>
725
+ </div>
726
+ );
727
+ }