@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,70 @@
1
+ // The C4 levels, in one vocabulary.
2
+ //
3
+ // Three pictures, three scopes, and a reader who has to be told which one they
4
+ // are looking at — a box called "Payments" is a system on one page and a
5
+ // container on the next, and the only thing that says which is the level.
6
+ //
7
+ // The levels are not a menu of everything LikeC4 could draw. They are the
8
+ // scopes the catalog actually holds facts about: the estate and what stands
9
+ // outside it, the containers of one context, and the parts of one service.
10
+ // There is no level 4 here, because code is what the repository is for.
11
+
12
+ import type { ReactNode } from "react";
13
+
14
+ export type C4Level = 1 | 2 | 3;
15
+
16
+ export const C4_LEVEL: Record<C4Level, { name: string; note: string }> = {
17
+ 1: {
18
+ name: "system context",
19
+ note: "every bounded context, and everything outside the estate that touches one",
20
+ },
21
+ 2: {
22
+ name: "containers",
23
+ note: "services, the stores they keep their state in, and the brokers between them",
24
+ },
25
+ 3: {
26
+ name: "components",
27
+ note: "the aggregates inside one service, and where each is persisted",
28
+ },
29
+ };
30
+
31
+ /** Says which level a canvas is drawn at, for a page that only draws one. */
32
+ export function LevelBadge({ level }: { level: C4Level }) {
33
+ return (
34
+ <span className="mono text-muted" title={C4_LEVEL[level].note}>
35
+ C4 L{level} · {C4_LEVEL[level].name}
36
+ </span>
37
+ );
38
+ }
39
+
40
+ /**
41
+ * Steps between the levels one page can draw. A segmented control rather than
42
+ * tabs: the picture underneath stays where it is, and only its scope changes.
43
+ */
44
+ export function LevelSwitch({
45
+ levels,
46
+ level,
47
+ onLevel,
48
+ }: {
49
+ /** The levels this page offers, with the word each one goes by here. */
50
+ levels: { level: C4Level; label: ReactNode }[];
51
+ level: C4Level;
52
+ onLevel: (level: C4Level) => void;
53
+ }) {
54
+ return (
55
+ <div className="seg">
56
+ {levels.map((option) => (
57
+ <button
58
+ key={option.level}
59
+ type="button"
60
+ onClick={() => onLevel(option.level)}
61
+ aria-pressed={option.level === level}
62
+ title={C4_LEVEL[option.level].note}
63
+ className={option.level === level ? "is-on" : ""}
64
+ >
65
+ L{option.level} {option.label}
66
+ </button>
67
+ ))}
68
+ </div>
69
+ );
70
+ }
@@ -0,0 +1,66 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { catalog } from "../data";
3
+ import { classify } from "../selection/model";
4
+ import { fqn, participantFqn } from "./ids";
5
+ import { catalogIdMap, catalogIdOf } from "./mapping";
6
+
7
+ describe("catalogIdOf", () => {
8
+ /**
9
+ * The ID contract, checked rather than assumed: every catalog id must survive
10
+ * the round trip through the LikeC4 identifier the generator emits for it.
11
+ */
12
+ it("inverts fqn for every element the generator emits", () => {
13
+ const ids: string[] = [];
14
+ for (const context of catalog.contexts) {
15
+ ids.push(context.id);
16
+ for (const service of context.services) {
17
+ ids.push(service.id);
18
+ for (const aggregate of service.aggregates) {
19
+ ids.push(aggregate.id);
20
+ for (const event of aggregate.events) ids.push(event.id);
21
+ }
22
+ }
23
+ }
24
+ for (const flow of catalog.flows) {
25
+ for (const participant of flow.participants) ids.push(participant.id);
26
+ }
27
+
28
+ for (const id of ids) {
29
+ expect(catalogIdOf(fqn(id)), id).toBe(id);
30
+ }
31
+ });
32
+
33
+ it("undoes the substitution LikeC4 identifiers force", () => {
34
+ // "ledger-pg" cannot be a LikeC4 identifier; "ledger_pg" can.
35
+ expect(fqn("ledger-pg")).toBe("ledger_pg");
36
+ expect(catalogIdOf("ledger_pg")).toBe("ledger-pg");
37
+ expect(catalogIdOf("shop.pricing.price_list")).toBe(
38
+ "shop.pricing.price-list",
39
+ );
40
+ });
41
+
42
+ it("maps a dotted root participant using the identifier the generator declares", () => {
43
+ const participant = {
44
+ id: "river.order-jobs",
45
+ kind: "broker" as const,
46
+ context: null,
47
+ };
48
+ const fixture = {
49
+ ...catalog,
50
+ flows: [
51
+ {
52
+ ...catalog.flows[0]!,
53
+ participants: [...catalog.flows[0]!.participants, participant],
54
+ },
55
+ ...catalog.flows.slice(1),
56
+ ],
57
+ };
58
+
59
+ expect(catalogIdMap(fixture).get(participantFqn(participant))).toBe(participant.id);
60
+ });
61
+
62
+ it("hands back an id it has never seen, so the click still lands", () => {
63
+ expect(catalogIdOf("nothing_here")).toBe("nothing_here");
64
+ expect(classify(catalogIdOf("nothing_here"))).toBe("unknown");
65
+ });
66
+ });
@@ -0,0 +1,54 @@
1
+ // The inverse of ids.ts.
2
+ //
3
+ // Going out, a catalog id becomes a LikeC4 identifier by replacing whatever
4
+ // LikeC4 will not accept. Coming back — from a clicked node to the thing it
5
+ // stands for — that substitution has to be undone, and the only honest way to
6
+ // undo it is to remember which catalog id produced which identifier.
7
+
8
+ import { catalog } from "../data";
9
+ import type { Catalog } from "../catalog";
10
+ import { fqn, participantFqn } from "./ids";
11
+
12
+ export function catalogIdMap(catalog: Catalog): Map<string, string> {
13
+ const result = new Map<string, string>();
14
+ const remember = (id: string): void => {
15
+ const likec4 = fqn(id);
16
+ // First writer wins: two catalog ids that collapse to one identifier would
17
+ // be a modelling bug, and silently reassigning would hide it.
18
+ if (!result.has(likec4)) result.set(likec4, id);
19
+ };
20
+
21
+ for (const context of catalog.contexts) {
22
+ remember(context.id);
23
+ for (const service of context.services) {
24
+ remember(service.id);
25
+ for (const aggregate of service.aggregates) {
26
+ remember(aggregate.id);
27
+ for (const event of aggregate.events) remember(event.id);
28
+ }
29
+ }
30
+ }
31
+ // A store is a container inside the service that owns it, and clicking one
32
+ // should open the schema rather than nothing.
33
+ for (const store of catalog.stores ?? []) remember(store.id);
34
+ // Brokers, actors and externals are model elements too, and a flow lane is
35
+ // the most likely thing on screen to be clicked.
36
+ for (const flow of catalog.flows) {
37
+ for (const participant of flow.participants) {
38
+ const likec4 = participantFqn(participant);
39
+ if (!result.has(likec4)) result.set(likec4, participant.id);
40
+ }
41
+ }
42
+
43
+ return result;
44
+ }
45
+
46
+ const toCatalogId = catalogIdMap(catalog);
47
+
48
+ /**
49
+ * The catalog id a LikeC4 element id stands for, or the id unchanged when the
50
+ * model holds something the catalog does not — an external participant, say.
51
+ */
52
+ export function catalogIdOf(likec4Id: string): string {
53
+ return toCatalogId.get(likec4Id) ?? likec4Id;
54
+ }
@@ -0,0 +1,141 @@
1
+ [
2
+ "BottomTop",
3
+ "LeftRight",
4
+ "RightLeft",
5
+ "TopBottom",
6
+ "alt",
7
+ "amber",
8
+ "and",
9
+ "autoLayout",
10
+ "blue",
11
+ "border",
12
+ "bottom",
13
+ "break",
14
+ "browser",
15
+ "bucket",
16
+ "catch",
17
+ "color",
18
+ "component",
19
+ "crow",
20
+ "cylinder",
21
+ "dashed",
22
+ "deployment",
23
+ "deploymentNode",
24
+ "description",
25
+ "diagram",
26
+ "diamond",
27
+ "document",
28
+ "dot",
29
+ "dotted",
30
+ "dynamic",
31
+ "dynamicPredicateGroup",
32
+ "element",
33
+ "else",
34
+ "exclude",
35
+ "extend",
36
+ "extends",
37
+ "finally",
38
+ "from",
39
+ "global",
40
+ "gray",
41
+ "green",
42
+ "group",
43
+ "head",
44
+ "icon",
45
+ "iconColor",
46
+ "iconPosition",
47
+ "iconSize",
48
+ "icons",
49
+ "if",
50
+ "import",
51
+ "include",
52
+ "includeAncestors",
53
+ "indigo",
54
+ "instance",
55
+ "instanceOf",
56
+ "is",
57
+ "kind",
58
+ "large",
59
+ "left",
60
+ "lg",
61
+ "likec4lib",
62
+ "line",
63
+ "link",
64
+ "loop",
65
+ "max",
66
+ "md",
67
+ "medium",
68
+ "metadata",
69
+ "min",
70
+ "mobile",
71
+ "model",
72
+ "multiple",
73
+ "muted",
74
+ "navigateTo",
75
+ "node",
76
+ "none",
77
+ "normal",
78
+ "not",
79
+ "notation",
80
+ "notes",
81
+ "odiamond",
82
+ "odot",
83
+ "of",
84
+ "onormal",
85
+ "opacity",
86
+ "open",
87
+ "opt",
88
+ "or",
89
+ "order",
90
+ "padding",
91
+ "par",
92
+ "parallel",
93
+ "person",
94
+ "predicate",
95
+ "predicateGroup",
96
+ "primary",
97
+ "queue",
98
+ "rank",
99
+ "rectangle",
100
+ "red",
101
+ "relationship",
102
+ "rgb",
103
+ "rgba",
104
+ "right",
105
+ "same",
106
+ "secondary",
107
+ "sequence",
108
+ "shape",
109
+ "sink",
110
+ "size",
111
+ "sky",
112
+ "slate",
113
+ "sm",
114
+ "small",
115
+ "solid",
116
+ "source",
117
+ "specification",
118
+ "storage",
119
+ "style",
120
+ "styleGroup",
121
+ "summary",
122
+ "tag",
123
+ "tail",
124
+ "target",
125
+ "technology",
126
+ "textSize",
127
+ "title",
128
+ "top",
129
+ "try",
130
+ "variant",
131
+ "vee",
132
+ "view",
133
+ "views",
134
+ "when",
135
+ "where",
136
+ "with",
137
+ "xl",
138
+ "xlarge",
139
+ "xs",
140
+ "xsmall"
141
+ ]
@@ -0,0 +1,78 @@
1
+ // What a generated view actually contains.
2
+ //
3
+ // Highlighting has to know two things before it touches the canvas: whether the
4
+ // view on screen holds the selected element at all, and — for flows — which
5
+ // edge draws which step. Both are answered from the generated model, so neither
6
+ // costs a render and neither can drift from what LikeC4 will draw.
7
+
8
+ import { pickViewBounds } from "likec4/react";
9
+ import { likec4model } from "./generated";
10
+ import type { Flow } from "../catalog";
11
+ import { drawnStepIds, pairEdgesToSteps } from "./flow-edges";
12
+ import type { EdgeStepPairing } from "./flow-edges";
13
+ import { EMPTY_PAIRING } from "./flow-edges";
14
+ import { flowCrossViewId, flowViewId } from "./ids";
15
+ import type { BBox } from "./canvas-viewport";
16
+
17
+ interface ViewShape {
18
+ nodeIds: Set<string>;
19
+ edgeIds: string[];
20
+ }
21
+
22
+ const shapes = new Map<string, ViewShape>();
23
+
24
+ function shapeOf(viewId: string): ViewShape {
25
+ const cached = shapes.get(viewId);
26
+ if (cached) return cached;
27
+ const view = likec4model.findView(viewId)?.$layouted;
28
+ const shape: ViewShape = view
29
+ ? {
30
+ nodeIds: new Set(view.nodes.map((n) => String(n.id))),
31
+ edgeIds: view.edges.map((e) => String(e.id)),
32
+ }
33
+ : { nodeIds: new Set(), edgeIds: [] };
34
+ shapes.set(viewId, shape);
35
+ return shape;
36
+ }
37
+
38
+ /** True when the view draws a node with this LikeC4 element id. */
39
+ export function viewHasNode(viewId: string, likec4Id: string): boolean {
40
+ return shapeOf(viewId).nodeIds.has(likec4Id);
41
+ }
42
+
43
+ /** The node ids a view draws, in LikeC4 model order. */
44
+ export function viewNodeIds(viewId: string): readonly string[] {
45
+ return [...shapeOf(viewId).nodeIds];
46
+ }
47
+
48
+ /** The edge ids a view draws, in the order LikeC4 emits them. */
49
+ export function viewEdgeIds(viewId: string): readonly string[] {
50
+ return shapeOf(viewId).edgeIds;
51
+ }
52
+
53
+ /**
54
+ * How big the picture is, in the units the viewport is set in. The two
55
+ * variants of a dynamic view are laid out separately and have different
56
+ * bounds, so the variant on screen has to be the one asked about.
57
+ */
58
+ export function viewBounds(
59
+ viewId: string,
60
+ variant: "diagram" | "sequence",
61
+ ): BBox | null {
62
+ const view = likec4model.findView(viewId)?.$layouted;
63
+ return view ? pickViewBounds(view, variant) : null;
64
+ }
65
+
66
+ const pairings = new Map<string, EdgeStepPairing>();
67
+
68
+ /** Edge-to-step pairing for one of a flow's two views. */
69
+ export function flowPairing(flow: Flow, crossOnly: boolean): EdgeStepPairing {
70
+ const viewId = crossOnly ? flowCrossViewId(flow) : flowViewId(flow);
71
+ const cached = pairings.get(viewId);
72
+ if (cached) return cached;
73
+ const pairing = shapeOf(viewId).edgeIds.length
74
+ ? pairEdgesToSteps(shapeOf(viewId).edgeIds, drawnStepIds(flow, crossOnly))
75
+ : EMPTY_PAIRING;
76
+ pairings.set(viewId, pairing);
77
+ return pairing;
78
+ }
package/src/main.tsx ADDED
@@ -0,0 +1,13 @@
1
+ import { StrictMode } from "react";
2
+ import { createRoot } from "react-dom/client";
3
+ import "./index.css";
4
+ import { App } from "./app/App";
5
+
6
+ const container = document.getElementById("root");
7
+ if (!container) throw new Error("#root is missing from index.html");
8
+
9
+ createRoot(container).render(
10
+ <StrictMode>
11
+ <App />
12
+ </StrictMode>,
13
+ );
@@ -0,0 +1,274 @@
1
+ // The map, drawn.
2
+ //
3
+ // ONE LINE PER RELATIONSHIP, which is what a context map is and what every
4
+ // other graph in this app is not. The dependency graph draws an arrow per
5
+ // event because an event is the thing it is about; here the thing is the
6
+ // relationship, and a pair that leans on each other both ways is not two
7
+ // facts - it is one fact called a partnership. Two arcs between the same two
8
+ // boxes would also force a layered layout to route one of them backwards
9
+ // around the whole diagram, which is how a map of three domains ends up
10
+ // looking like a circuit.
11
+ //
12
+ // So: the arrowheads say which way the leaning runs - one head for a customer
13
+ // and its supplier, two for a partnership, none for a pair that shares a type
14
+ // and nothing else - and the label says which pattern that makes, in the same
15
+ // word the list below uses. The dash is the app's usual three markers, worst
16
+ // status among everything the line carries: a relationship is known no better
17
+ // than its least-known hop.
18
+
19
+ import { useCallback, useEffect, useMemo, useState } from "react";
20
+ import { useNavigate } from "react-router";
21
+ import {
22
+ Background,
23
+ MarkerType,
24
+ Panel,
25
+ ReactFlow,
26
+ ReactFlowProvider,
27
+ } from "@xyflow/react";
28
+ import type { Edge, Node } from "@xyflow/react";
29
+ import "@xyflow/react/dist/style.css";
30
+ import type { Catalog, Status } from "../catalog";
31
+ import { DiagramSkeleton } from "../components/DiagramSkeleton";
32
+ import { layoutWithElk } from "../graph/elk";
33
+ import { ExportSeg } from "../graph/GraphToolbar";
34
+ import { EDGE_W, statusColor, statusDash } from "../graph/theme";
35
+ import type { PortolanNode } from "../graph/nodes";
36
+ import { PATTERN_LABEL } from "../lib/context-map";
37
+ import type { ContextRelation } from "../lib/context-map";
38
+ import { paths } from "../routes";
39
+ import { useSelectionStore } from "../selection/store";
40
+ import { CTX_NODE_H, CTX_NODE_W, contextNodeTypes } from "./ContextNode";
41
+ import { mapEdgeTypes } from "./FloatingEdge";
42
+
43
+ const DIM = 0.14;
44
+
45
+ /** A chain is known no better than its least-known hop. */
46
+ function worstStatus(statuses: readonly Status[]): Status {
47
+ if (statuses.includes("unresolved")) return "unresolved";
48
+ if (statuses.includes("declared")) return "declared";
49
+ return "verified";
50
+ }
51
+
52
+ /** The counted pattern the line stands for; the read ones are for the list. */
53
+ function lineLabel(relation: ContextRelation): string {
54
+ const counted = relation.patterns.find((p) => p.basis === "counted");
55
+ return counted ? PATTERN_LABEL[counted.name] : "";
56
+ }
57
+
58
+ interface Drawn {
59
+ nodes: PortolanNode[];
60
+ edges: Edge[];
61
+ ready: boolean;
62
+ }
63
+
64
+ export function ContextMapGraph({
65
+ catalog,
66
+ relations,
67
+ }: {
68
+ catalog: Catalog;
69
+ relations: readonly ContextRelation[];
70
+ }) {
71
+ const navigate = useNavigate();
72
+ const selectionId = useSelectionStore((s) => s.selection?.id ?? null);
73
+ const select = useSelectionStore((s) => s.select);
74
+ const clear = useSelectionStore((s) => s.clear);
75
+ const [drawn, setDrawn] = useState<Drawn>({
76
+ nodes: [],
77
+ edges: [],
78
+ ready: false,
79
+ });
80
+
81
+ // One entry per pair the catalog has anything to say about. `back` is what
82
+ // turns an arrow into a double-headed one; elk only ever sees a -> b, so the
83
+ // layout never has a cycle to route around.
84
+ const lines = useMemo(
85
+ () =>
86
+ relations
87
+ .filter((r) => r.dependencies.length > 0 || r.shared.length > 0)
88
+ .map((relation) => {
89
+ const forward = relation.dependencies.find(
90
+ (d) => d.upstream === relation.a,
91
+ );
92
+ const back = relation.dependencies.find(
93
+ (d) => d.upstream === relation.b,
94
+ );
95
+ const links = relation.dependencies.flatMap((d) => d.links);
96
+ return {
97
+ relation,
98
+ // Source is the upstream end wherever there is only one, so a
99
+ // single arrowhead always points from supplier to customer.
100
+ source: forward || !back ? relation.a : relation.b,
101
+ target: forward || !back ? relation.b : relation.a,
102
+ heads: relation.dependencies.length,
103
+ status: worstStatus(links.map((l) => l.status)),
104
+ label: lineLabel(relation),
105
+ };
106
+ }),
107
+ [relations],
108
+ );
109
+
110
+ useEffect(() => {
111
+ let cancelled = false;
112
+ const run = async (): Promise<void> => {
113
+ const { positions } = await layoutWithElk({
114
+ nodes: catalog.contexts.map((c) => ({
115
+ id: c.id,
116
+ width: CTX_NODE_W,
117
+ height: CTX_NODE_H,
118
+ })),
119
+ edges: lines.map((line) => ({
120
+ id: line.relation.id,
121
+ source: line.source,
122
+ target: line.target,
123
+ labelWidth: Math.max(60, line.label.length * 6),
124
+ })),
125
+ algorithm: "stress",
126
+ // Far enough apart that a pattern name fits in the gap: "customer /
127
+ // supplier" is 110px of mono, and a label wider than the space between
128
+ // two boxes is a label lying across one of them.
129
+ edgeLength: 300,
130
+ nodeSpacing: 130,
131
+ });
132
+ if (cancelled) return;
133
+
134
+ const nodes: PortolanNode[] = catalog.contexts.map((context) => ({
135
+ id: context.id,
136
+ type: "portolan",
137
+ position: positions[context.id] ?? { x: 0, y: 0 },
138
+ data: {
139
+ label: context.id,
140
+ sub: context.name,
141
+ context: context.id,
142
+ ghost: false,
143
+ kind: "context",
144
+ ...(context.classification ? { tag: context.classification } : {}),
145
+ },
146
+ initialWidth: CTX_NODE_W,
147
+ initialHeight: CTX_NODE_H,
148
+ width: CTX_NODE_W,
149
+ height: CTX_NODE_H,
150
+ draggable: false,
151
+ connectable: false,
152
+ }));
153
+
154
+ const edges: Edge[] = lines.map((line) => {
155
+ const color = statusColor(line.status);
156
+ const dash = statusDash(line.status);
157
+ const head = {
158
+ type: MarkerType.ArrowClosed,
159
+ color,
160
+ width: 14,
161
+ height: 14,
162
+ };
163
+ return {
164
+ id: line.relation.id,
165
+ source: line.source,
166
+ target: line.target,
167
+ label: line.label,
168
+ type: "floating",
169
+ style: {
170
+ stroke: color,
171
+ strokeWidth: EDGE_W,
172
+ ...(dash ? { strokeDasharray: dash } : {}),
173
+ // A pair joined by a shared type and nothing else gets a line
174
+ // with no heads at all; it is a fact about both, not a direction.
175
+ ...(line.heads === 0 ? { strokeDasharray: "1 4" } : {}),
176
+ },
177
+ ...(line.heads > 0 ? { markerEnd: head } : {}),
178
+ ...(line.heads === 2 ? { markerStart: head } : {}),
179
+ };
180
+ });
181
+
182
+ setDrawn({ nodes, edges, ready: true });
183
+ };
184
+ void run();
185
+ return () => {
186
+ cancelled = true;
187
+ };
188
+ }, [catalog, lines]);
189
+
190
+ const fitKey = drawn.ready
191
+ ? `fit-${drawn.nodes.length}-${drawn.edges.length}`
192
+ : "pending";
193
+
194
+ // A selected domain lights the lines it is on and dims the rest, so "who
195
+ // does shop answer to" is one click rather than a reading of the whole map.
196
+ const shownEdges = useMemo(() => {
197
+ if (!selectionId) return drawn.edges;
198
+ return drawn.edges.map((edge) => {
199
+ const lit = edge.source === selectionId || edge.target === selectionId;
200
+ // The label reads its opacity off the same style object, so a dimmed
201
+ // line and its dimmed label can never disagree.
202
+ return {
203
+ ...edge,
204
+ style: { ...edge.style, opacity: lit ? 1 : DIM },
205
+ zIndex: lit ? 10 : 0,
206
+ };
207
+ });
208
+ }, [drawn.edges, selectionId]);
209
+
210
+ const shownNodes = useMemo(
211
+ () =>
212
+ drawn.nodes.map((node) => ({
213
+ ...node,
214
+ selected: node.id === selectionId,
215
+ style: {
216
+ ...node.style,
217
+ opacity: selectionId && selectionId !== node.id ? 0.55 : 1,
218
+ },
219
+ })),
220
+ [drawn.nodes, selectionId],
221
+ );
222
+
223
+ const onNodeClick = useCallback(
224
+ (_: React.MouseEvent, node: Node) => select(node.id, "diagram"),
225
+ [select],
226
+ );
227
+
228
+ const onNodeDoubleClick = useCallback(
229
+ (_: React.MouseEvent, node: Node) => navigate(paths.context(node.id)),
230
+ [navigate],
231
+ );
232
+
233
+ return (
234
+ <div className="relative h-full w-full">
235
+ {drawn.ready ? null : <DiagramSkeleton />}
236
+ <ReactFlow
237
+ nodes={shownNodes}
238
+ edges={shownEdges}
239
+ nodeTypes={contextNodeTypes}
240
+ edgeTypes={mapEdgeTypes}
241
+ onNodeClick={onNodeClick}
242
+ onNodeDoubleClick={onNodeDoubleClick}
243
+ onPaneClick={() => clear("diagram")}
244
+ nodesDraggable={false}
245
+ nodesConnectable={false}
246
+ elementsSelectable
247
+ proOptions={{ hideAttribution: true }}
248
+ fitView
249
+ fitViewOptions={{ padding: 0.16 }}
250
+ minZoom={0.2}
251
+ maxZoom={1.6}
252
+ key={fitKey}
253
+ >
254
+ <Background gap={20} size={2} />
255
+ {/* The map has no modes to switch, so its only control is the way
256
+ out: the drawing as a file, for the page that explains it. */}
257
+ <Panel position="top-right">
258
+ <ExportSeg name="context-map" />
259
+ </Panel>
260
+ </ReactFlow>
261
+ </div>
262
+ );
263
+ }
264
+
265
+ export function ContextMapPane(props: {
266
+ catalog: Catalog;
267
+ relations: readonly ContextRelation[];
268
+ }) {
269
+ return (
270
+ <ReactFlowProvider>
271
+ <ContextMapGraph {...props} />
272
+ </ReactFlowProvider>
273
+ );
274
+ }