@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
package/src/enrich.ts ADDED
@@ -0,0 +1,672 @@
1
+ // Edges the flows already know.
2
+ //
3
+ // A flow step saying `bus -> payments.ledger : OrderPlaced` is the same fact as
4
+ // a consumer entry on the event, written in the other place. The extractors
5
+ // cannot put it on the event - a service's repository knows what the service
6
+ // hears, not who else listens to what it says - so after the merge the host
7
+ // reads it out of the steps and writes it where the graph, the Problems page
8
+ // and the generators look.
9
+ //
10
+ // Three rules keep this from inventing anything:
11
+ //
12
+ // - A derived edge inherits the step's status and never becomes `verified`
13
+ // on its own. A step nobody observed running gives an edge nobody observed.
14
+ // - A declared edge wins. If a source already names the consumer or the call,
15
+ // the step adds nothing; and between two flows implying the same edge, the
16
+ // first in catalog order is the one recorded.
17
+ // - A derived edge says where it came from. `via` names the flow and the step,
18
+ // so a reader can tell "the service declares this" from "a flow shows it".
19
+
20
+ import type {
21
+ Catalog,
22
+ EdgeVia,
23
+ EventConsumer,
24
+ Flow,
25
+ FlowNode,
26
+ RpcCall,
27
+ Service,
28
+ Status,
29
+ Step,
30
+ } from "./catalog";
31
+ // With the extension: scripts/catalog-sources.mjs runs this file under Node
32
+ // without a bundler, and Node resolves nothing it is not told.
33
+ import { walkSteps } from "./catalog.ts";
34
+
35
+ export interface DerivedEdge {
36
+ kind: "consumer" | "rpc";
37
+ /** Event id for a consumer, RpcCall id for a call. */
38
+ ref: string;
39
+ /** The consumer of the event, or the caller of the method. */
40
+ service: string;
41
+ /** rpc only: the step's `to`, the service the call was made to. */
42
+ peer?: string;
43
+ status: Status;
44
+ via: EdgeVia;
45
+ }
46
+
47
+ export interface Enriched {
48
+ catalog: Catalog;
49
+ derived: DerivedEdge[];
50
+ }
51
+
52
+ /**
53
+ * Returns a catalog whose consumers and calls include every edge its flows
54
+ * imply, plus the list of what was added. Pure: the input is never written to,
55
+ * and enriching twice yields the same catalog as enriching once.
56
+ */
57
+ export function enrichCatalog(input: Catalog): Enriched {
58
+ // A step naming an event by the name it travels under is resolved first, so
59
+ // everything below - and every consumer derived from it - sees the event
60
+ // rather than the name.
61
+ const catalog = resolveForeignKeys(
62
+ composeExecutionContinuations(resolveWireNames(input)),
63
+ );
64
+
65
+ const serviceById = new Map<string, Service>();
66
+ const eventOwner = new Map<string, string>();
67
+ const providedMethods = new Set<string>(); // "<provider>|<interface>/<method>"
68
+ const declaredRpcIds = new Set<string>();
69
+ const haveConsumer = new Set<string>(); // "<event>|<service>"
70
+ const haveCall = new Set<string>(); // "<service>|<call>"
71
+
72
+ // A system outside the estate answers on a contract too, and a step reaching
73
+ // it on an operation its document declares is as resolvable as one reaching
74
+ // a service of ours. Keyed by the external's id, which is what the lane says.
75
+ for (const external of catalog.externals ?? []) {
76
+ for (const provided of external.provides) {
77
+ for (const method of provided.methods) {
78
+ providedMethods.add(`${external.id}|${provided.id}/${method.name}`);
79
+ }
80
+ }
81
+ }
82
+
83
+ for (const context of catalog.contexts) {
84
+ for (const service of context.services) {
85
+ serviceById.set(service.id, service);
86
+ for (const provided of service.provides) {
87
+ for (const method of provided.methods) {
88
+ providedMethods.add(`${service.id}|${provided.id}/${method.name}`);
89
+ }
90
+ }
91
+ for (const call of service.consumes) {
92
+ declaredRpcIds.add(call.id);
93
+ haveCall.add(`${service.id}|${call.id}`);
94
+ }
95
+ for (const aggregate of service.aggregates) {
96
+ for (const event of aggregate.events) {
97
+ eventOwner.set(event.id, service.id);
98
+ for (const consumer of event.consumers) {
99
+ haveConsumer.add(`${event.id}|${consumer.service}`);
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }
105
+
106
+ const derived: DerivedEdge[] = [];
107
+ const consumersFor = new Map<string, EventConsumer[]>();
108
+ const callsFor = new Map<string, RpcCall[]>();
109
+
110
+ // Atomic source fragments are the strongest provenance for a derived edge.
111
+ // Composed roots repeat those steps for reading, so inspect them afterwards;
112
+ // they only become evidence when their source fragment was intentionally
113
+ // consumed and removed from the catalog.
114
+ const evidenceFlows = [...catalog.flows].sort(
115
+ (left, right) =>
116
+ Number(Boolean(left.includes)) - Number(Boolean(right.includes)),
117
+ );
118
+ for (const flow of evidenceFlows) {
119
+ const lanes = new Map(flow.participants.map((p) => [p.id, p]));
120
+
121
+ for (const step of walkSteps(flow.steps)) {
122
+ if (!step.ref) continue;
123
+ const via: EdgeVia = { flow: flow.slug, step: step.id };
124
+
125
+ if (step.kind === "event") {
126
+ if (!eventOwner.has(step.ref)) continue;
127
+ // A self-message is in-process; a broker, a store or an actor on the
128
+ // receiving end is a publish, a write or a notification, none of
129
+ // which is a service listening.
130
+ if (step.from === step.to) continue;
131
+ const lane = lanes.get(step.to);
132
+ if (!lane) continue;
133
+ if (
134
+ lane.kind === "broker" ||
135
+ lane.kind === "store" ||
136
+ lane.kind === "actor"
137
+ )
138
+ continue;
139
+
140
+ const key = `${step.ref}|${step.to}`;
141
+ if (haveConsumer.has(key)) continue;
142
+ haveConsumer.add(key);
143
+
144
+ const known = lane.kind === "service" && serviceById.has(step.to);
145
+ const status: Status = known ? step.status : "unresolved";
146
+ push(consumersFor, step.ref, { service: step.to, status, via });
147
+ derived.push({
148
+ kind: "consumer",
149
+ ref: step.ref,
150
+ service: step.to,
151
+ status,
152
+ via,
153
+ });
154
+
155
+ continue;
156
+ }
157
+
158
+ if (step.kind === "rpc") {
159
+ // Only a service has a `consumes` list to put the call on.
160
+ if (!serviceById.has(step.from)) continue;
161
+ const key = `${step.from}|${step.ref}`;
162
+ if (haveCall.has(key)) continue;
163
+
164
+ // The call has to be resolvable before this pass. Derived calls feed
165
+ // the validator's set of known call ids, and a call derived from a
166
+ // step naming a method nobody provides would make that step its own
167
+ // evidence.
168
+ const provided = providedMethods.has(`${step.to}|${step.ref}`);
169
+ if (!provided && !declaredRpcIds.has(step.ref)) continue;
170
+ haveCall.add(key);
171
+
172
+ const status: Status = provided ? step.status : "unresolved";
173
+ push(callsFor, step.from, {
174
+ id: step.ref,
175
+ peer: step.to,
176
+ status,
177
+ source: flow.source ?? `flow:${flow.slug}`,
178
+ via,
179
+ });
180
+ derived.push({
181
+ kind: "rpc",
182
+ ref: step.ref,
183
+ service: step.from,
184
+ peer: step.to,
185
+ status,
186
+ via,
187
+ });
188
+ }
189
+ }
190
+ }
191
+
192
+ if (derived.length === 0) return { catalog, derived };
193
+
194
+ const contexts = catalog.contexts.map((context) => ({
195
+ ...context,
196
+ services: context.services.map((service) => {
197
+ const calls = callsFor.get(service.id);
198
+ const touched =
199
+ calls !== undefined ||
200
+ service.aggregates.some((a) =>
201
+ a.events.some((e) => consumersFor.has(e.id)),
202
+ );
203
+ if (!touched) return service;
204
+
205
+ return {
206
+ ...service,
207
+ consumes: calls ? [...service.consumes, ...calls] : service.consumes,
208
+ aggregates: service.aggregates.map((aggregate) => {
209
+ if (!aggregate.events.some((e) => consumersFor.has(e.id)))
210
+ return aggregate;
211
+
212
+ return {
213
+ ...aggregate,
214
+ events: aggregate.events.map((event) => {
215
+ const added = consumersFor.get(event.id);
216
+ return added
217
+ ? { ...event, consumers: [...event.consumers, ...added] }
218
+ : event;
219
+ }),
220
+ };
221
+ }),
222
+ };
223
+ }),
224
+ }));
225
+
226
+ return { catalog: { ...catalog, contexts }, derived };
227
+ }
228
+
229
+ /**
230
+ * Composes independently extracted protocol fragments into root-oriented
231
+ * execution flows.
232
+ *
233
+ * There are three deliberately exact seams: a source function entered after a
234
+ * step, a source function proven reachable on the same path, and an
235
+ * asynchronous handoff whose kind/channel/message tuple matches a receiving
236
+ * flow's opening step. Display labels and ordinary domain-event refs never
237
+ * participate. Ambiguous seams compose nothing.
238
+ */
239
+ function composeExecutionContinuations(input: Catalog): Catalog {
240
+ const byEntry = new Map<string, Flow | null>();
241
+ const byHandoff = new Map<string, Flow | null>();
242
+ for (const flow of input.flows) {
243
+ if (flow.entrypoint) addUniqueFlow(byEntry, flow.entrypoint, flow);
244
+ // A task extractor often keeps the locally observed enqueue before the
245
+ // worker receive in one standalone flow. External producers must join at
246
+ // the receive boundary, not replay that local enqueue. Top-level slicing
247
+ // preserves everything the worker does afterwards, including branches.
248
+ for (let index = 0; index < flow.steps.length; index += 1) {
249
+ const opening = flow.steps[index];
250
+ if (
251
+ opening?.type !== "step" ||
252
+ opening.handoff?.direction !== "receive"
253
+ ) {
254
+ continue;
255
+ }
256
+ addUniqueFlow(byHandoff, handoffKey(opening.handoff), {
257
+ ...flow,
258
+ steps: flow.steps.slice(index),
259
+ });
260
+ }
261
+ }
262
+ if (byEntry.size === 0 && byHandoff.size === 0) {
263
+ return input;
264
+ }
265
+
266
+ const consumed = new Set<string>();
267
+ let any = false;
268
+ const flows = input.flows.map((flow) => {
269
+ const existing = new Set(flow.includes ?? []);
270
+ const expansion = expandExecution(
271
+ flow,
272
+ flow.steps,
273
+ [flow.slug],
274
+ existing,
275
+ byEntry,
276
+ byHandoff,
277
+ consumed,
278
+ );
279
+ if (expansion.includes.length === 0) return flow;
280
+ any = true;
281
+
282
+ const participants = [...flow.participants];
283
+ const seen = new Set(participants.map((participant) => participant.id));
284
+ for (const continuation of expansion.fragments) {
285
+ for (const participant of continuation.participants) {
286
+ if (seen.has(participant.id)) continue;
287
+ seen.add(participant.id);
288
+ participants.push(participant);
289
+ }
290
+ }
291
+ return {
292
+ ...flow,
293
+ summary:
294
+ flow.summary.replace(/\s*$/, "") +
295
+ " Source-backed cross-protocol continuations are included.",
296
+ includes: unique([...(flow.includes ?? []), ...expansion.includes]),
297
+ participants,
298
+ steps: expansion.nodes,
299
+ };
300
+ });
301
+
302
+ if (!any) return input;
303
+ return {
304
+ ...input,
305
+ flows: flows.filter(
306
+ (flow) =>
307
+ !consumed.has(flow.slug) ||
308
+ (flow.trigger !== undefined && flow.trigger.kind !== "unproven"),
309
+ ),
310
+ };
311
+ }
312
+
313
+ interface ExecutionExpansion {
314
+ nodes: FlowNode[];
315
+ includes: string[];
316
+ fragments: Flow[];
317
+ }
318
+
319
+ function expandExecution(
320
+ root: Flow,
321
+ nodes: FlowNode[],
322
+ path: string[],
323
+ existing: ReadonlySet<string>,
324
+ byEntry: ReadonlyMap<string, Flow | null>,
325
+ byHandoff: ReadonlyMap<string, Flow | null>,
326
+ consumed: Set<string>,
327
+ ): ExecutionExpansion {
328
+ const out: FlowNode[] = [];
329
+ const includes: string[] = [];
330
+ const fragments: Flow[] = [];
331
+ for (const node of nodes) {
332
+ switch (node.type) {
333
+ case "step": {
334
+ out.push(node);
335
+ if (path.length > 12) break;
336
+ for (const continuation of continuationsFor(
337
+ root,
338
+ node,
339
+ byEntry,
340
+ byHandoff,
341
+ )) {
342
+ if (
343
+ path.includes(continuation.slug) ||
344
+ existing.has(continuation.slug)
345
+ ) {
346
+ continue;
347
+ }
348
+ const nestedExisting = new Set(continuation.includes ?? []);
349
+ const nested = expandExecution(
350
+ continuation,
351
+ continuation.steps,
352
+ [...path, continuation.slug],
353
+ nestedExisting,
354
+ byEntry,
355
+ byHandoff,
356
+ consumed,
357
+ );
358
+ const prefix = `continuation-${continuation.slug}-${node.id}`;
359
+ out.push(...prefixFlowNodes(nested.nodes, prefix));
360
+ includes.push(
361
+ continuation.slug,
362
+ ...(continuation.includes ?? []),
363
+ ...nested.includes,
364
+ );
365
+ fragments.push(continuation, ...nested.fragments);
366
+ if (
367
+ continuation.entrypoint &&
368
+ (!continuation.trigger || continuation.trigger.kind === "unproven")
369
+ ) {
370
+ consumed.add(continuation.slug);
371
+ }
372
+ }
373
+ break;
374
+ }
375
+ case "alt":
376
+ {
377
+ const branches = node.branches.map((branch) => {
378
+ const expanded = expandExecution(
379
+ root,
380
+ branch.steps,
381
+ path,
382
+ existing,
383
+ byEntry,
384
+ byHandoff,
385
+ consumed,
386
+ );
387
+ includes.push(...expanded.includes);
388
+ fragments.push(...expanded.fragments);
389
+ return { ...branch, steps: expanded.nodes };
390
+ });
391
+ out.push({
392
+ ...node,
393
+ branches,
394
+ });
395
+ }
396
+ break;
397
+ case "parallel":
398
+ {
399
+ const branches = node.branches.map((branch) => {
400
+ const expanded = expandExecution(
401
+ root,
402
+ branch,
403
+ path,
404
+ existing,
405
+ byEntry,
406
+ byHandoff,
407
+ consumed,
408
+ );
409
+ includes.push(...expanded.includes);
410
+ fragments.push(...expanded.fragments);
411
+ return expanded.nodes;
412
+ });
413
+ out.push({
414
+ ...node,
415
+ branches,
416
+ });
417
+ }
418
+ break;
419
+ case "loop":
420
+ {
421
+ const expanded = expandExecution(
422
+ root,
423
+ node.steps,
424
+ path,
425
+ existing,
426
+ byEntry,
427
+ byHandoff,
428
+ consumed,
429
+ );
430
+ includes.push(...expanded.includes);
431
+ fragments.push(...expanded.fragments);
432
+ out.push({
433
+ ...node,
434
+ steps: expanded.nodes,
435
+ });
436
+ }
437
+ break;
438
+ }
439
+ }
440
+ return {
441
+ nodes: out,
442
+ includes: unique(includes),
443
+ fragments: uniqueFlows(fragments),
444
+ };
445
+ }
446
+
447
+ function continuationsFor(
448
+ root: Flow,
449
+ step: Step,
450
+ byEntry: ReadonlyMap<string, Flow | null>,
451
+ byHandoff: ReadonlyMap<string, Flow | null>,
452
+ ): Flow[] {
453
+ const found: Flow[] = [];
454
+ const sourceEntries = [step.continuesAt, ...(step.reaches ?? [])].filter(
455
+ (entry): entry is string => Boolean(entry),
456
+ );
457
+ for (const entry of sourceEntries) {
458
+ const continuation = byEntry.get(entry);
459
+ if (!continuation || continuation.owner !== root.owner) continue;
460
+ found.push(continuation);
461
+ }
462
+ if (step.handoff?.direction === "send") {
463
+ const continuation = byHandoff.get(handoffKey(step.handoff));
464
+ if (continuation) found.push(continuation);
465
+ }
466
+ return uniqueFlows(found);
467
+ }
468
+
469
+ function handoffKey(handoff: NonNullable<Step["handoff"]>): string {
470
+ return [
471
+ handoff.kind,
472
+ handoff.transport,
473
+ handoff.channel,
474
+ handoff.message ?? "",
475
+ ].join("\u0000");
476
+ }
477
+
478
+ function addUniqueFlow(
479
+ index: Map<string, Flow | null>,
480
+ key: string,
481
+ flow: Flow,
482
+ ): void {
483
+ index.set(key, index.has(key) ? null : flow);
484
+ }
485
+
486
+ function unique(values: string[]): string[] {
487
+ return [...new Set(values)];
488
+ }
489
+
490
+ function uniqueFlows(flows: Flow[]): Flow[] {
491
+ const seen = new Set<string>();
492
+ return flows.filter((flow) => {
493
+ if (seen.has(flow.slug)) return false;
494
+ seen.add(flow.slug);
495
+ return true;
496
+ });
497
+ }
498
+
499
+ function prefixFlowNodes(nodes: FlowNode[], prefix: string): FlowNode[] {
500
+ return nodes.map((node) => {
501
+ const id = `${prefix}-${node.id}`;
502
+ switch (node.type) {
503
+ case "step":
504
+ return { ...node, id };
505
+ case "alt":
506
+ return {
507
+ ...node,
508
+ id,
509
+ branches: node.branches.map((branch) => ({
510
+ ...branch,
511
+ steps: prefixFlowNodes(branch.steps, prefix),
512
+ })),
513
+ };
514
+ case "parallel":
515
+ return {
516
+ ...node,
517
+ id,
518
+ branches: node.branches.map((branch) =>
519
+ prefixFlowNodes(branch, prefix),
520
+ ),
521
+ };
522
+ case "loop":
523
+ return { ...node, id, steps: prefixFlowNodes(node.steps, prefix) };
524
+ }
525
+ });
526
+ }
527
+
528
+ /**
529
+ * Steps that name an event by the name it travels under, resolved to the event
530
+ * that travels under it.
531
+ *
532
+ * An extractor can only resolve what its own repository declares. A policy
533
+ * reacting to somebody else's message has the wire name and nothing else —
534
+ * `ledger.PaymentAuthorized` — so the step names it, says `unresolved`, and
535
+ * leaves the other end to the merge. This is where it arrives, and the match is
536
+ * the one verify-otel already makes against a trace: the event whose wire name
537
+ * that is, or failing that the one event whose wire name ends in that segment.
538
+ * Two candidates resolve to neither, because a guess here would put a service
539
+ * on somebody else's event.
540
+ *
541
+ * A resolved step becomes `declared` and never `verified`: reading a name in
542
+ * source is a claim that it listens, not a record of it having listened.
543
+ */
544
+ function resolveWireNames(catalog: Catalog): Catalog {
545
+ const byWire = new Map<string, string>();
546
+ const bySegment = new Map<string, string | null>();
547
+
548
+ for (const context of catalog.contexts) {
549
+ for (const service of context.services) {
550
+ for (const aggregate of service.aggregates) {
551
+ for (const event of aggregate.events) {
552
+ const wire = event.wire?.name;
553
+ if (!wire) continue;
554
+ if (!byWire.has(wire)) byWire.set(wire, event.id);
555
+ const segment = wire.slice(wire.lastIndexOf(".") + 1);
556
+ bySegment.set(segment, bySegment.has(segment) ? null : event.id);
557
+ }
558
+ }
559
+ }
560
+ }
561
+ if (byWire.size === 0) return catalog;
562
+
563
+ const resolve = (step: Step): Step => {
564
+ if (step.kind !== "event" || step.ref || step.status !== "unresolved")
565
+ return step;
566
+ const named = step.label;
567
+ if (!named) return step;
568
+ const found = byWire.get(named) ?? bySegment.get(named) ?? null;
569
+ if (!found) return step;
570
+
571
+ return { ...step, ref: found, status: "declared" };
572
+ };
573
+
574
+ let any = false;
575
+ const flows = catalog.flows.map((flow) => {
576
+ let changed = false;
577
+ const steps = mapSteps(flow.steps, (step) => {
578
+ const resolved = resolve(step);
579
+ changed ||= resolved !== step;
580
+
581
+ return resolved;
582
+ });
583
+ any ||= changed;
584
+
585
+ return changed ? { ...flow, steps } : flow;
586
+ });
587
+
588
+ return any ? { ...catalog, flows } : catalog;
589
+ }
590
+
591
+ /**
592
+ * Foreign keys naming a table this store does not have, resolved against the
593
+ * estate's other stores.
594
+ *
595
+ * A migration says `REFERENCES orders (id)`, and the extractor that read it
596
+ * knows only the store it was reading: a key into another service's table
597
+ * keeps the raw name, because no extractor sees two schemas. The merge sees
598
+ * all of them, and a name exactly one table in the estate answers to is that
599
+ * table - which is what turns a dangling key into the crossing it is, on the
600
+ * page and on Problems. Two tables of that name resolve to neither.
601
+ */
602
+ function resolveForeignKeys(catalog: Catalog): Catalog {
603
+ const stores = catalog.stores ?? [];
604
+ if (stores.length === 0) return catalog;
605
+
606
+ const known = new Set<string>();
607
+ const byName = new Map<string, string | null>();
608
+ for (const store of stores) {
609
+ for (const table of store.tables) {
610
+ known.add(table.id);
611
+ byName.set(table.name, byName.has(table.name) ? null : table.id);
612
+ }
613
+ }
614
+
615
+ let any = false;
616
+ const resolved = stores.map((store) => {
617
+ let touched = false;
618
+ const tables = store.tables.map((table) => {
619
+ let changed = false;
620
+ const columns = table.columns.map((column) => {
621
+ if (!column.fk || known.has(column.fk.table)) return column;
622
+ const found = byName.get(column.fk.table);
623
+ if (!found) return column;
624
+ changed = true;
625
+
626
+ return { ...column, fk: { ...column.fk, table: found } };
627
+ });
628
+ touched ||= changed;
629
+
630
+ return changed ? { ...table, columns } : table;
631
+ });
632
+ any ||= touched;
633
+
634
+ return touched ? { ...store, tables } : store;
635
+ });
636
+
637
+ return any ? { ...catalog, stores: resolved } : catalog;
638
+ }
639
+
640
+ /** The same tree, with every step handed to `resolve`. */
641
+ function mapSteps(
642
+ nodes: FlowNode[],
643
+ resolve: (step: Step) => Step,
644
+ ): FlowNode[] {
645
+ return nodes.map((node) => {
646
+ switch (node.type) {
647
+ case "step":
648
+ return resolve(node);
649
+ case "alt":
650
+ return {
651
+ ...node,
652
+ branches: node.branches.map((branch) => ({
653
+ ...branch,
654
+ steps: mapSteps(branch.steps, resolve),
655
+ })),
656
+ };
657
+ case "parallel":
658
+ return {
659
+ ...node,
660
+ branches: node.branches.map((branch) => mapSteps(branch, resolve)),
661
+ };
662
+ case "loop":
663
+ return { ...node, steps: mapSteps(node.steps, resolve) };
664
+ }
665
+ });
666
+ }
667
+
668
+ function push<T>(into: Map<string, T[]>, key: string, item: T): void {
669
+ const list = into.get(key);
670
+ if (list) list.push(item);
671
+ else into.set(key, [item]);
672
+ }