@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,106 @@
1
+ // The author's say over a table in a README.
2
+ //
3
+ // Enhancement is the default because a README table is usually a list someone
4
+ // would like to sort. It is not always: a two-column key/value block, or a
5
+ // table whose row order IS the content, is worse for being made interactive.
6
+ // So there is an escape hatch, and it is an HTML comment - the one thing that
7
+ // can sit in a markdown file, mean something here, and remain invisible
8
+ // everywhere else the file is read.
9
+ //
10
+ // <!-- table: static --> render it as written, no toolbar, no sort
11
+ // <!-- table: sort=name.desc --> open it sorted, by column id and direction
12
+
13
+ /** The attribute the remark plugin leaves on a table for the renderer to find. */
14
+ export const TABLE_DIRECTIVE_ATTR = "data-table";
15
+
16
+ const COMMENT_RE = /^<!--\s*table:\s*(.*?)\s*-->$/;
17
+
18
+ export interface TableDirective {
19
+ /** Render as written: this table is not a list, it is a layout. */
20
+ static: boolean;
21
+ /** Column id and direction, as `<id>.asc` or `<id>.desc`. */
22
+ sort: { id: string; desc: boolean } | null;
23
+ }
24
+
25
+ export const NO_DIRECTIVE: TableDirective = { static: false, sort: null };
26
+
27
+ /**
28
+ * Reads the body of a `table:` comment. Returns null for a comment that is not
29
+ * one of ours, so an ordinary HTML comment above a table stays an ordinary
30
+ * HTML comment.
31
+ */
32
+ export function parseTableComment(raw: string): string | null {
33
+ const match = COMMENT_RE.exec(raw.trim());
34
+ return match ? (match[1] ?? "") : null;
35
+ }
36
+
37
+ /** Reads the directive body. An unrecognised word is ignored, never fatal. */
38
+ export function parseTableDirective(body: string): TableDirective {
39
+ const directive: TableDirective = { static: false, sort: null };
40
+ for (const term of body.split(/\s+/)) {
41
+ if (term === "") continue;
42
+ if (term === "static") {
43
+ directive.static = true;
44
+ continue;
45
+ }
46
+ const sort = /^sort=(.+)\.(asc|desc)$/.exec(term);
47
+ if (sort?.[1]) directive.sort = { id: sort[1], desc: sort[2] === "desc" };
48
+ }
49
+ return directive;
50
+ }
51
+
52
+ /** A column id from a header cell: what the `sort=` directive names. */
53
+ export function columnSlug(header: string, taken: Set<string>): string {
54
+ const base =
55
+ header
56
+ .toLowerCase()
57
+ .replace(/[^a-z0-9]+/g, "-")
58
+ .replace(/^-|-$/g, "") || "col";
59
+ if (!taken.has(base)) return base;
60
+ // Two columns headed the same is a bad table, not an error. Number them.
61
+ let n = 2;
62
+ while (taken.has(`${base}-${n}`)) n++;
63
+ return `${base}-${n}`;
64
+ }
65
+
66
+ // --- The remark half -------------------------------------------------------
67
+
68
+ interface Node {
69
+ type: string;
70
+ value?: string;
71
+ data?: { hProperties?: Record<string, string> };
72
+ children?: Node[];
73
+ }
74
+
75
+ /**
76
+ * Attaches a `table:` comment to the table it introduces. remark leaves the
77
+ * comment as an `html` node and react-markdown drops it, so without this the
78
+ * directive would be invisible to the component that has to obey it.
79
+ *
80
+ * "Introduces" means the node immediately before, at the same level - which
81
+ * is the only place an author would think to write it.
82
+ */
83
+ export function remarkTableDirective() {
84
+ return (tree: Node): void => {
85
+ const walk = (node: Node): void => {
86
+ const children = node.children;
87
+ if (!children) return;
88
+ for (let i = 0; i < children.length; i++) {
89
+ const child = children[i];
90
+ if (!child) continue;
91
+ walk(child);
92
+ if (child.type !== "table") continue;
93
+ const previous = children[i - 1];
94
+ if (!previous || previous.type !== "html") continue;
95
+ const body = parseTableComment(previous.value ?? "");
96
+ if (body === null) continue;
97
+ child.data = child.data ?? {};
98
+ child.data.hProperties = {
99
+ ...child.data.hProperties,
100
+ [TABLE_DIRECTIVE_ATTR]: body,
101
+ };
102
+ }
103
+ };
104
+ walk(tree);
105
+ };
106
+ }
@@ -0,0 +1,120 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { describe, expect, it } from "vitest";
3
+ import { STORE_KINDS } from "../catalog";
4
+ import {
5
+ STORE_KIND_GLYPH,
6
+ TECH_MARKS,
7
+ TECH_WITHOUT_GLYPH,
8
+ techGlyph,
9
+ techKey,
10
+ } from "./tech";
11
+
12
+ /**
13
+ * The names extract-project can write, read off its own source: every
14
+ * `{"Name", <seen>}` marker in the technologies table. Reading the Go file
15
+ * rather than copying the list is the point - a marker added there and
16
+ * forgotten here is exactly what this test exists to catch.
17
+ */
18
+ function extractedTechnologies(): string[] {
19
+ const source = readFileSync(
20
+ new URL("../../plugins/extract-project/extract.go", import.meta.url),
21
+ "utf8",
22
+ );
23
+ const body = source.slice(source.indexOf("func technologies("));
24
+ return [...body.matchAll(/^\s*\{"([^"]+)", /gm)].map((m) => m[1] ?? "");
25
+ }
26
+
27
+ describe("techKey", () => {
28
+ it("folds case and punctuation", () => {
29
+ expect(techKey("Node.js")).toBe("nodejs");
30
+ expect(techKey("NodeJS")).toBe("nodejs");
31
+ expect(techKey("Apache Kafka")).toBe("apachekafka");
32
+ expect(techKey("Spring Boot")).toBe("springboot");
33
+ });
34
+
35
+ it("keeps what makes C++ and C# different languages from C", () => {
36
+ expect(techKey("C++")).toBe("c++");
37
+ expect(techKey("C#")).toBe("c#");
38
+ expect(techKey("C")).toBe("c");
39
+ });
40
+ });
41
+
42
+ describe("techGlyph", () => {
43
+ it("answers the same mark for every spelling of one brand", () => {
44
+ const postgres = techGlyph("PostgreSQL");
45
+ expect(postgres?.title).toBe("PostgreSQL");
46
+ for (const spelling of ["postgres", "Postgres", "postgresql", "pg", "psql"]) {
47
+ expect(techGlyph(spelling), spelling).toEqual(postgres);
48
+ }
49
+ expect(techGlyph("nodejs")?.title).toBe("Node.js");
50
+ expect(techGlyph("Kafka")?.title).toBe("Apache Kafka");
51
+ expect(techGlyph("k8s")?.title).toBe("Kubernetes");
52
+ });
53
+
54
+ it("answers null for a word with no mark", () => {
55
+ expect(techGlyph("River")).toBeNull();
56
+ expect(techGlyph("")).toBeNull();
57
+ expect(techGlyph("something nobody ships")).toBeNull();
58
+ });
59
+
60
+ it("draws a real path for every mark", () => {
61
+ for (const mark of TECH_MARKS) {
62
+ expect(mark.path, mark.title).toMatch(/^[Mm]/);
63
+ expect(mark.names[0]).toBe(mark.title);
64
+ }
65
+ });
66
+
67
+ it("gives no name to two marks", () => {
68
+ const seen = new Map<string, string>();
69
+ for (const mark of TECH_MARKS) {
70
+ // An alias that folds to the title's own key is redundant, not a clash.
71
+ for (const key of new Set(mark.names.map(techKey))) {
72
+ const name = mark.names.find((n) => techKey(n) === key);
73
+ expect(
74
+ seen.get(key),
75
+ `"${name}" names both ${seen.get(key)} and ${mark.title}`,
76
+ ).toBeUndefined();
77
+ seen.set(key, mark.title);
78
+ }
79
+ }
80
+ });
81
+ });
82
+
83
+ describe("store kind glyphs", () => {
84
+ it("decides for every store kind, glyph or none", () => {
85
+ for (const kind of STORE_KINDS) {
86
+ expect(kind in STORE_KIND_GLYPH).toBe(true);
87
+ }
88
+ });
89
+
90
+ it("draws the kinds that have a mark and leaves the rest a word", () => {
91
+ expect(STORE_KIND_GLYPH.postgres?.title).toBe("PostgreSQL");
92
+ expect(STORE_KIND_GLYPH.redis?.title).toBe("Redis");
93
+ expect(STORE_KIND_GLYPH.s3).toBeNull();
94
+ expect(STORE_KIND_GLYPH.other).toBeNull();
95
+ });
96
+ });
97
+
98
+ describe("extract-project markers", () => {
99
+ const markers = extractedTechnologies();
100
+
101
+ it("are read off the Go source", () => {
102
+ expect(markers).toContain("Go");
103
+ expect(markers).toContain("Kafka");
104
+ expect(markers.length).toBeGreaterThan(10);
105
+ });
106
+
107
+ it("each have a glyph or are named as having none", () => {
108
+ for (const name of markers) {
109
+ const decided = techGlyph(name) !== null || TECH_WITHOUT_GLYPH.includes(name);
110
+ expect(decided, `${name} has neither a glyph nor a place in TECH_WITHOUT_GLYPH`).toBe(true);
111
+ }
112
+ });
113
+
114
+ it("are not listed as having none when they have one", () => {
115
+ for (const name of TECH_WITHOUT_GLYPH) {
116
+ expect(markers, `${name} is not a name extract-project writes`).toContain(name);
117
+ expect(techGlyph(name), `${name} has a glyph after all`).toBeNull();
118
+ }
119
+ });
120
+ });
@@ -0,0 +1,421 @@
1
+ // A technology's mark, looked up by whatever the catalog calls it.
2
+ //
3
+ // Two vocabularies name a technology in the catalog and both land here. A
4
+ // store says what it is with a StoreKind - `postgres`, `redis` - and a service
5
+ // carries the names an extractor read off its manifests - `Go`, `Kafka`,
6
+ // `PostgreSQL`. Tomorrow's extractor will spell the same brand a third way,
7
+ // so the table is not keyed by a spelling: every mark lists the names it is
8
+ // known by, and a lookup folds case and punctuation before it compares, so
9
+ // `Postgres`, `postgresql`, `PostgreSQL` and `pg` are one entry.
10
+ //
11
+ // The glyphs come from simple-icons: one filled path per brand, drawn on a
12
+ // 24x24 box. They are painted from currentColor like every other icon in the
13
+ // app, never in the brand's own colour - a red Redis mark beside a grey
14
+ // database glyph would say Redis is the loudest thing on the row, and the row's
15
+ // loudest thing is the event. See ../components/TechIcon for how one is drawn.
16
+ //
17
+ // The table is deliberately wider than what any extractor writes today. A new
18
+ // stack lands as a new marker name in an extractor, and the mark for it should
19
+ // already be here rather than be one more thing that PR has to remember. What
20
+ // is NOT here is anything simple-icons does not carry - S3, gRPC, Protobuf,
21
+ // River, Watermill - because a made-up glyph is a lie about what the brand
22
+ // looks like. Those stay a word, which is what they were before.
23
+
24
+ import {
25
+ siAngular,
26
+ siAnsible,
27
+ siApachecassandra,
28
+ siApachecouchdb,
29
+ siApachekafka,
30
+ siApachepulsar,
31
+ siArgo,
32
+ siAuth0,
33
+ siBun,
34
+ siC,
35
+ siCelery,
36
+ siCilium,
37
+ siClickhouse,
38
+ siClojure,
39
+ siCloudflare,
40
+ siCockroachlabs,
41
+ siConsul,
42
+ siCouchbase,
43
+ siCplusplus,
44
+ siCypress,
45
+ siDart,
46
+ siDatadog,
47
+ siDeno,
48
+ siDjango,
49
+ siDocker,
50
+ siDotnet,
51
+ siDrizzle,
52
+ siDuckdb,
53
+ siElasticsearch,
54
+ siElectron,
55
+ siElixir,
56
+ siEnvoyproxy,
57
+ siErlang,
58
+ siEtcd,
59
+ siExpress,
60
+ siFastapi,
61
+ siFastify,
62
+ siFirebase,
63
+ siFlask,
64
+ siFlutter,
65
+ siGin,
66
+ siGit,
67
+ siGithubactions,
68
+ siGitlab,
69
+ siGo,
70
+ siGooglebigquery,
71
+ siGooglecloud,
72
+ siGooglecloudspanner,
73
+ siGradle,
74
+ siGrafana,
75
+ siGraphql,
76
+ siHaskell,
77
+ siHelm,
78
+ siHibernate,
79
+ siHono,
80
+ siHuggingface,
81
+ siInfluxdb,
82
+ siIstio,
83
+ siJaeger,
84
+ siJavascript,
85
+ siJenkins,
86
+ siJest,
87
+ siKeycloak,
88
+ siKotlin,
89
+ siKtor,
90
+ siKubernetes,
91
+ siLangchain,
92
+ siLaravel,
93
+ siLinkerd,
94
+ siLua,
95
+ siMariadb,
96
+ siMeilisearch,
97
+ siMinio,
98
+ siMongodb,
99
+ siMqtt,
100
+ siMysql,
101
+ siNatsdotio,
102
+ siNeo4j,
103
+ siNeon,
104
+ siNestjs,
105
+ siNetlify,
106
+ siNextdotjs,
107
+ siNginx,
108
+ siNodedotjs,
109
+ siNomad,
110
+ siNpm,
111
+ siOllama,
112
+ siOpenapiinitiative,
113
+ siOpenjdk,
114
+ siOpensearch,
115
+ siOpentelemetry,
116
+ siPhoenixframework,
117
+ siPhp,
118
+ siPlanetscale,
119
+ siPnpm,
120
+ siPoetry,
121
+ siPostgresql,
122
+ siPrisma,
123
+ siPrometheus,
124
+ siPulumi,
125
+ siPytest,
126
+ siPython,
127
+ siPytorch,
128
+ siQuarkus,
129
+ siRabbitmq,
130
+ siReact,
131
+ siRedis,
132
+ siRuby,
133
+ siRubyonrails,
134
+ siRust,
135
+ siScala,
136
+ siScylladb,
137
+ siSentry,
138
+ siSequelize,
139
+ siSnowflake,
140
+ siSpring,
141
+ siSpringboot,
142
+ siSqlalchemy,
143
+ siSqlite,
144
+ siStripe,
145
+ siSupabase,
146
+ siSvelte,
147
+ siSwift,
148
+ siSymfony,
149
+ siTailwindcss,
150
+ siTauri,
151
+ siTemporal,
152
+ siTensorflow,
153
+ siTerraform,
154
+ siTidb,
155
+ siTimescale,
156
+ siTraefikproxy,
157
+ siTurso,
158
+ siTypeorm,
159
+ siTypescript,
160
+ siUv,
161
+ siVault,
162
+ siVercel,
163
+ siVictoriametrics,
164
+ siVite,
165
+ siVitess,
166
+ siVitest,
167
+ siVuedotjs,
168
+ siWebassembly,
169
+ siWebpack,
170
+ siYarn,
171
+ siZig,
172
+ } from "simple-icons";
173
+ import type { StoreKind } from "../catalog";
174
+
175
+ export interface TechGlyph {
176
+ /** The brand's own name, for a title attribute. */
177
+ title: string;
178
+ /** SVG path data on a 24x24 box, filled. */
179
+ path: string;
180
+ }
181
+
182
+ /** One brand: its glyph and every name it answers to. */
183
+ export interface TechMark extends TechGlyph {
184
+ /** The brand's title plus its aliases, as written; folded by `techKey`. */
185
+ names: readonly string[];
186
+ }
187
+
188
+ /**
189
+ * How a name is compared: case dropped, everything that is not a letter, a
190
+ * digit, `+` or `#` dropped. "Node.js" and "nodejs" and "NodeJS" are one key;
191
+ * "C++" and "C#" keep the characters that make them a different language
192
+ * from "C".
193
+ */
194
+ export function techKey(name: string): string {
195
+ return name.toLowerCase().replace(/[^a-z0-9+#]/g, "");
196
+ }
197
+
198
+ function mark(
199
+ icon: { title: string; path: string },
200
+ ...aliases: string[]
201
+ ): TechMark {
202
+ return { title: icon.title, path: icon.path, names: [icon.title, ...aliases] };
203
+ }
204
+
205
+ /**
206
+ * Every mark the app can draw, grouped the way a reader would list a stack.
207
+ * Aliases are the spellings an extractor, a manifest or a person is likely to
208
+ * use; the brand's own title is always one of them.
209
+ */
210
+ export const TECH_MARKS: readonly TechMark[] = [
211
+ // Languages and runtimes.
212
+ mark(siGo, "golang"),
213
+ mark(siTypescript, "ts"),
214
+ mark(siJavascript, "js"),
215
+ mark(siNodedotjs, "node"),
216
+ mark(siDeno),
217
+ mark(siBun),
218
+ mark(siRust),
219
+ // simple-icons dropped Oracle's Java cup; OpenJDK's is the mark the language
220
+ // is known by everywhere the trademark is not.
221
+ mark(siOpenjdk, "Java", "JDK", "JVM"),
222
+ mark(siKotlin),
223
+ mark(siScala),
224
+ mark(siPython),
225
+ mark(siRuby),
226
+ mark(siPhp),
227
+ mark(siC),
228
+ mark(siCplusplus, "cpp"),
229
+ mark(siDotnet, "dotnet", "C#", "csharp", "ASP.NET"),
230
+ mark(siSwift),
231
+ mark(siDart),
232
+ mark(siElixir),
233
+ mark(siErlang),
234
+ mark(siHaskell),
235
+ mark(siClojure),
236
+ mark(siLua),
237
+ mark(siZig),
238
+ mark(siWebassembly, "wasm"),
239
+
240
+ // Frameworks and libraries.
241
+ mark(siGin, "gin-gonic"),
242
+ mark(siDjango),
243
+ mark(siFastapi),
244
+ mark(siFlask),
245
+ mark(siCelery),
246
+ mark(siSpring),
247
+ mark(siSpringboot),
248
+ mark(siQuarkus),
249
+ mark(siKtor),
250
+ mark(siRubyonrails, "Rails"),
251
+ mark(siLaravel),
252
+ mark(siSymfony),
253
+ mark(siPhoenixframework, "Phoenix"),
254
+ mark(siNestjs),
255
+ mark(siExpress, "expressjs"),
256
+ mark(siFastify),
257
+ mark(siHono),
258
+ mark(siNextdotjs, "nextjs"),
259
+ mark(siReact),
260
+ mark(siVuedotjs, "vue"),
261
+ mark(siAngular),
262
+ mark(siSvelte, "SvelteKit"),
263
+ mark(siFlutter),
264
+ mark(siElectron),
265
+ mark(siTauri),
266
+ mark(siGraphql),
267
+ mark(siOpenapiinitiative, "OpenAPI", "Swagger"),
268
+ mark(siTemporal),
269
+ mark(siLangchain),
270
+ mark(siPytorch),
271
+ mark(siTensorflow),
272
+ mark(siOllama),
273
+ mark(siHuggingface),
274
+
275
+ // ORMs and data access.
276
+ mark(siPrisma),
277
+ mark(siSqlalchemy),
278
+ mark(siHibernate),
279
+ mark(siDrizzle, "Drizzle ORM"),
280
+ mark(siTypeorm),
281
+ mark(siSequelize),
282
+
283
+ // Stores.
284
+ mark(siPostgresql, "Postgres", "pg", "psql"),
285
+ mark(siMysql),
286
+ mark(siMariadb),
287
+ mark(siSqlite),
288
+ mark(siRedis),
289
+ mark(siMongodb, "Mongo"),
290
+ mark(siClickhouse),
291
+ mark(siApachecassandra, "Cassandra"),
292
+ mark(siScylladb, "Scylla"),
293
+ mark(siElasticsearch, "Elastic"),
294
+ mark(siOpensearch),
295
+ mark(siCockroachlabs, "CockroachDB", "Cockroach"),
296
+ mark(siTidb),
297
+ mark(siVitess),
298
+ mark(siNeo4j),
299
+ mark(siInfluxdb),
300
+ mark(siTimescale, "TimescaleDB"),
301
+ mark(siCouchbase),
302
+ mark(siApachecouchdb, "CouchDB"),
303
+ mark(siEtcd),
304
+ mark(siMinio),
305
+ mark(siSupabase),
306
+ mark(siFirebase, "Firestore"),
307
+ mark(siDuckdb),
308
+ mark(siSnowflake),
309
+ mark(siGooglebigquery, "BigQuery"),
310
+ mark(siGooglecloudspanner, "Spanner"),
311
+ mark(siMeilisearch),
312
+ mark(siPlanetscale),
313
+ mark(siNeon),
314
+ mark(siTurso),
315
+
316
+ // Messaging.
317
+ mark(siApachekafka, "Kafka"),
318
+ mark(siNatsdotio, "NATS", "JetStream"),
319
+ mark(siRabbitmq, "AMQP"),
320
+ mark(siApachepulsar, "Pulsar"),
321
+ mark(siMqtt),
322
+
323
+ // Infrastructure and delivery.
324
+ mark(siDocker, "Docker Compose"),
325
+ mark(siKubernetes, "k8s"),
326
+ mark(siHelm),
327
+ mark(siTerraform),
328
+ mark(siPulumi),
329
+ mark(siAnsible),
330
+ mark(siNomad),
331
+ mark(siConsul),
332
+ mark(siVault),
333
+ mark(siNginx),
334
+ mark(siEnvoyproxy, "Envoy"),
335
+ mark(siIstio),
336
+ mark(siLinkerd),
337
+ mark(siCilium),
338
+ mark(siTraefikproxy, "Traefik"),
339
+ mark(siCloudflare),
340
+ mark(siGooglecloud, "GCP"),
341
+ mark(siVercel),
342
+ mark(siNetlify),
343
+ mark(siGit),
344
+ mark(siGithubactions),
345
+ mark(siGitlab, "GitLab CI"),
346
+ mark(siJenkins),
347
+ mark(siArgo, "Argo CD", "ArgoCD"),
348
+
349
+ // Observability.
350
+ mark(siOpentelemetry, "otel"),
351
+ mark(siPrometheus),
352
+ mark(siGrafana),
353
+ mark(siJaeger),
354
+ mark(siVictoriametrics),
355
+ mark(siSentry),
356
+ mark(siDatadog),
357
+
358
+ // Identity and payments.
359
+ mark(siKeycloak),
360
+ mark(siAuth0),
361
+ mark(siStripe),
362
+
363
+ // Build and test tooling.
364
+ mark(siVite),
365
+ mark(siWebpack),
366
+ mark(siTailwindcss, "Tailwind"),
367
+ mark(siNpm),
368
+ mark(siPnpm),
369
+ mark(siYarn),
370
+ mark(siGradle),
371
+ mark(siPoetry),
372
+ mark(siUv),
373
+ mark(siPytest),
374
+ mark(siJest),
375
+ mark(siVitest),
376
+ mark(siCypress),
377
+ ];
378
+
379
+ const BY_KEY: ReadonlyMap<string, TechGlyph> = (() => {
380
+ const map = new Map<string, TechGlyph>();
381
+ for (const { names, title, path } of TECH_MARKS) {
382
+ const glyph = { title, path };
383
+ for (const name of names) {
384
+ map.set(techKey(name), glyph);
385
+ }
386
+ }
387
+ return map;
388
+ })();
389
+
390
+ /**
391
+ * The mark for a technology, or null when it is a word only. The name is
392
+ * folded by `techKey` first, so a caller passes whatever it has.
393
+ */
394
+ export function techGlyph(name: string): TechGlyph | null {
395
+ return BY_KEY.get(techKey(name)) ?? null;
396
+ }
397
+
398
+ /**
399
+ * Marker names extract-project can write that deliberately have no mark:
400
+ * simple-icons carries none for them. The test holds every marker in the Go
401
+ * source to either a glyph or a place here, so a new stack in the extractor
402
+ * is decided, not forgotten.
403
+ */
404
+ export const TECH_WITHOUT_GLYPH: readonly string[] = ["River", "Watermill"];
405
+
406
+ /**
407
+ * By store kind. `null` is a kind that has no mark, and is listed rather than
408
+ * left out so that adding a kind to the catalog fails the test until someone
409
+ * has decided what it looks like.
410
+ */
411
+ export const STORE_KIND_GLYPH: Record<StoreKind, TechGlyph | null> = {
412
+ postgres: techGlyph("postgres"),
413
+ mysql: techGlyph("mysql"),
414
+ sqlite: techGlyph("sqlite"),
415
+ redis: techGlyph("redis"),
416
+ mongodb: techGlyph("mongodb"),
417
+ clickhouse: techGlyph("clickhouse"),
418
+ // simple-icons was asked to drop Amazon's marks, S3's among them.
419
+ s3: null,
420
+ other: null,
421
+ };
@@ -0,0 +1,67 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { catalog } from "../testing/estate";
3
+ import { bindTerms } from "./terms";
4
+
5
+ const bound = bindTerms(catalog);
6
+
7
+ const namesOf = (termId: string) =>
8
+ (bound.byTerm.get(termId) ?? []).map((t) => `${t.kind}:${t.name}`);
9
+
10
+ describe("bindTerms", () => {
11
+ it("pairs a word with the aggregate, the entity and the value object it names", () => {
12
+ expect(namesOf("auth.session")).toContain("entity:Session");
13
+ expect(namesOf("auth.token")).toContain("vo:Token");
14
+ // The value object is called email.Address in the code and Email address
15
+ // in the glossary; the slug is what the two agree on.
16
+ expect(namesOf("auth.email-address")).toContain("vo:email.Address");
17
+ });
18
+
19
+ it("pairs a word with the command or query that runs it", () => {
20
+ expect(namesOf("auth.login")).toContain("command:Login");
21
+ expect(namesOf("auth.validate")).toContain("query:Validate");
22
+ });
23
+
24
+ it("pairs a word with a lifecycle state, which has no page of its own", () => {
25
+ const locked = bound.byTerm.get("auth.locked") ?? [];
26
+ const state = locked.find((t) => t.kind === "state");
27
+
28
+ expect(state?.name).toBe("locked");
29
+ expect(state?.path).toMatch(/#bb-lifecycle$/);
30
+ });
31
+
32
+ it("answers from the other end too", () => {
33
+ const session = catalog.contexts
34
+ .flatMap((c) => c.services)
35
+ .flatMap((s) => s.aggregates)
36
+ .find((a) => a.id === "auth.auth.session");
37
+ if (!session) throw new Error("fixture has no session aggregate");
38
+
39
+ expect(bound.byTarget.get(session.id)?.name).toBe("Session");
40
+ });
41
+
42
+ // The rule is exact, inside one context, and that is the whole rule. A
43
+ // matcher loose enough to pair Register with registerUser is loose enough to
44
+ // pair Line with Lineage, and a wrong pairing is worse than none because the
45
+ // reader believes it.
46
+ it("says nothing about a word that names nothing", () => {
47
+ for (const word of ["auth.bus", "auth.outbox", "auth.refusal"]) {
48
+ expect(bound.byTerm.get(word)).toBeUndefined();
49
+ }
50
+ });
51
+
52
+ it("never pairs across a context boundary", () => {
53
+ for (const [termId, targets] of bound.byTerm) {
54
+ const context = termId.slice(0, termId.indexOf("."));
55
+ for (const target of targets) {
56
+ expect(target.id.startsWith(`${context}.`), `${termId} -> ${target.id}`).toBe(true);
57
+ }
58
+ }
59
+ });
60
+
61
+ it("is empty for a catalog with no glossary", () => {
62
+ const bare = bindTerms({ ...catalog, terms: [] });
63
+
64
+ expect(bare.byTerm.size).toBe(0);
65
+ expect(bare.byTarget.size).toBe(0);
66
+ });
67
+ });