@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,459 @@
1
+ package main
2
+
3
+ // The mapping: protos in a tree, a catalog fragment out.
4
+ //
5
+ // Shaped like plugins/extract-openapi/extract_test.go, which is the house style
6
+ // for an extractor test - one behaviour per test, and a whole-fragment golden
7
+ // underneath so an unintended field change is a diff rather than an assertion
8
+ // nobody thought to write.
9
+
10
+ import (
11
+ "encoding/json"
12
+ "flag"
13
+ "os"
14
+ "strings"
15
+ "testing"
16
+
17
+ "github.com/shortlink-org/portolan/catalog"
18
+ "github.com/shortlink-org/portolan/plugin"
19
+ )
20
+
21
+ var update = flag.Bool("update", false, "rewrite the golden fragment instead of comparing against it")
22
+
23
+ const goldenPath = "testdata/golden/proto.json"
24
+
25
+ func options() Options {
26
+ return Options{
27
+ Context: "shop",
28
+ Service: "oms",
29
+ Paths: []string{"proto"},
30
+ Vendored: []string{"internal/infrastructure/pricing"},
31
+ Peers: map[string]string{"pricing.v1": "shop.pricing"},
32
+ Out: "proto.json",
33
+ }
34
+ }
35
+
36
+ func input() plugin.Input {
37
+ // The stamp comes from the host, which derives it from git. A plugin that
38
+ // read a clock would write a different file every run.
39
+ return plugin.Input{
40
+ Root: "testdata/estate",
41
+ Commit: "abc1234",
42
+ GeneratedAt: "2024-01-01T00:00:00Z",
43
+ }
44
+ }
45
+
46
+ func response(t *testing.T) plugin.Response {
47
+ t.Helper()
48
+
49
+ resp, err := extract(input(), options())
50
+ if err != nil {
51
+ t.Fatal(err)
52
+ }
53
+
54
+ return resp
55
+ }
56
+
57
+ func fragment(t *testing.T) catalog.Catalog {
58
+ t.Helper()
59
+
60
+ resp := response(t)
61
+ if len(resp.Files) != 1 || resp.Files[0].Name != "proto.json" {
62
+ t.Fatalf("files: %+v", resp.Files)
63
+ }
64
+
65
+ var out catalog.Catalog
66
+ if err := json.Unmarshal([]byte(resp.Files[0].Contents), &out); err != nil {
67
+ t.Fatal(err)
68
+ }
69
+
70
+ return out
71
+ }
72
+
73
+ func service(t *testing.T) catalog.Service {
74
+ t.Helper()
75
+
76
+ return fragment(t).Contexts[0].Services[0]
77
+ }
78
+
79
+ // A proto service is an interface, named by its package and its own name -
80
+ // already the spelling RpcService.id documents.
81
+ func TestProtoServiceBecomesAnInterface(t *testing.T) {
82
+ provides := service(t).Provides
83
+
84
+ if len(provides) != 1 {
85
+ t.Fatalf("provides: %+v", provides)
86
+ }
87
+ orders := provides[0]
88
+ if orders.ID != "shop.v1.Orders" {
89
+ t.Errorf("interface id: %q", orders.ID)
90
+ }
91
+ if orders.Source != "testdata/estate/proto/shop/v1/orders.proto:16" {
92
+ t.Errorf("source must name the file and the line: %q", orders.Source)
93
+ }
94
+ if orders.Module != "buf.build/acme/shop" {
95
+ t.Errorf("the interface does not name the module it came from: %q", orders.Module)
96
+ }
97
+ }
98
+
99
+ // The shapes on either side and how the method streams: the whole reason
100
+ // RpcService.methods stopped being a list of strings.
101
+ func TestMethodsCarryShapesAndStreaming(t *testing.T) {
102
+ methods := map[string]catalog.RpcMethod{}
103
+ for _, m := range service(t).Provides[0].Methods {
104
+ methods[m.Name] = m
105
+ }
106
+
107
+ place := methods["PlaceOrder"]
108
+ if place.Request != "PlaceOrderRequest" || place.Response != "PlaceOrderResponse" {
109
+ t.Errorf("PlaceOrder: %q -> %q", place.Request, place.Response)
110
+ }
111
+ if place.Streaming != "" {
112
+ t.Errorf("a unary method must not claim to stream: %q", place.Streaming)
113
+ }
114
+ if place.Doc == "" {
115
+ t.Error("the comment above a method did not reach the catalog")
116
+ }
117
+
118
+ if got := methods["WatchOrder"].Streaming; got != catalog.StreamingServer {
119
+ t.Errorf("WatchOrder streams %q", got)
120
+ }
121
+ if got := methods["ImportOrders"].Streaming; got != catalog.StreamingClient {
122
+ t.Errorf("ImportOrders streams %q", got)
123
+ }
124
+ if got := methods["Sync"].Streaming; got != catalog.StreamingBidi {
125
+ t.Errorf("Sync streams %q", got)
126
+ }
127
+ if !methods["CancelOrder"].Deprecated {
128
+ t.Error("a deprecated method is not marked deprecated")
129
+ }
130
+ }
131
+
132
+ // Reachable messages, not every message in the file: a reader wants what the
133
+ // methods actually move.
134
+ func TestMessagesAreReachedTransitively(t *testing.T) {
135
+ names := map[string]bool{}
136
+ for _, m := range service(t).Provides[0].Messages {
137
+ names[m.Name] = true
138
+ }
139
+
140
+ for _, want := range []string{"PlaceOrderRequest", "PlaceOrderResponse", "Order", "LineItem"} {
141
+ if !names[want] {
142
+ t.Errorf("%s is moved by a method but is not listed", want)
143
+ }
144
+ }
145
+ // Money is reached through PlaceOrderRequest.total, two hops from a method.
146
+ if !names["Money"] {
147
+ t.Error("a message reached through another message was not followed")
148
+ }
149
+ }
150
+
151
+ // A type the author put in ANOTHER file is shared: an import is their own
152
+ // signal that it is not local to this message.
153
+ func TestImportedTypesBecomeDefs(t *testing.T) {
154
+ frag := fragment(t)
155
+
156
+ if _, ok := frag.Defs["Money"]; !ok {
157
+ t.Fatalf("Money was not promoted to a shared type: %v", frag.Defs)
158
+ }
159
+ // The key is BARE, not fully qualified - see src/merge.ts on why.
160
+ for key := range frag.Defs {
161
+ if strings.Contains(key, ".") {
162
+ t.Errorf("a def key is fully qualified: %q", key)
163
+ }
164
+ }
165
+
166
+ var total *catalog.Field
167
+ for _, msg := range frag.Contexts[0].Services[0].Provides[0].Messages {
168
+ if msg.Name != "PlaceOrderRequest" {
169
+ continue
170
+ }
171
+ for i := range msg.Fields {
172
+ if msg.Fields[i].Name == "total" {
173
+ total = &msg.Fields[i]
174
+ }
175
+ }
176
+ }
177
+ if total == nil {
178
+ t.Fatal("no total field")
179
+ }
180
+ if total.Ref != "Money" {
181
+ t.Errorf("the field does not point at the shared type: %+v", total)
182
+ }
183
+ // A type local to the file it is used in is NOT shared.
184
+ if _, ok := frag.Defs["LineItem"]; ok {
185
+ t.Error("a type local to its own file was promoted to a shared type")
186
+ }
187
+ }
188
+
189
+ // Types as written, because a reader comparing the page against the file it
190
+ // came from should recognise what they are looking at.
191
+ func TestFieldTypesAreRenderedTheWayTheCatalogRendersThem(t *testing.T) {
192
+ byName := map[string]string{}
193
+ for _, msg := range service(t).Provides[0].Messages {
194
+ if msg.Name != "PlaceOrderRequest" {
195
+ continue
196
+ }
197
+ for _, f := range msg.Fields {
198
+ byName[f.Name] = f.Type
199
+ }
200
+ }
201
+
202
+ want := map[string]string{
203
+ "customer_id": "string",
204
+ "items": "[]LineItem",
205
+ "coupon": "string",
206
+ "metadata": "map[string]string",
207
+ "total": "Money",
208
+ }
209
+ for name, typ := range want {
210
+ if byName[name] != typ {
211
+ t.Errorf("%s: %q, want %q", name, byName[name], typ)
212
+ }
213
+ }
214
+ }
215
+
216
+ // A vendored copy is a statement about what this service intends to call.
217
+ func TestVendoredProtosBecomeCalls(t *testing.T) {
218
+ consumes := service(t).Consumes
219
+
220
+ if len(consumes) != 2 {
221
+ t.Fatalf("consumes: %+v", consumes)
222
+ }
223
+ quote := consumes[0]
224
+ if quote.ID != "pricing.v1.Pricing/GetQuote" {
225
+ t.Errorf("call id: %q", quote.ID)
226
+ }
227
+ // The id is exactly the key buildIndex builds rpcProviderByMethod by, which
228
+ // is what makes a call and a provided method meet with no other machinery.
229
+ if quote.Peer != "shop.pricing" {
230
+ t.Errorf("a mapped peer was not resolved: %q", quote.Peer)
231
+ }
232
+ if !strings.Contains(quote.Note, "narrowed copy") {
233
+ t.Errorf("the header comment of the vendored copy did not reach the note: %q", quote.Note)
234
+ }
235
+ }
236
+
237
+ // THE INVARIANT MOST LIKELY TO BE HELPFULLY BROKEN LATER.
238
+ //
239
+ // Reading a .proto proves the call was WRITTEN DOWN, which is what `declared`
240
+ // means. `verified` in the shipped catalog means a test exercises the call end
241
+ // to end, and no extractor can know that: verification is a property of the
242
+ // union, and every extractor runs before one exists.
243
+ func TestNoCallIsEverVerified(t *testing.T) {
244
+ for _, call := range service(t).Consumes {
245
+ if call.Status != catalog.StatusDeclared {
246
+ t.Errorf("%s is %q; an extractor may only declare", call.ID, call.Status)
247
+ }
248
+ }
249
+ }
250
+
251
+ // Without a peer mapping the raw package name survives, because guessing a
252
+ // service id from a proto package would be inventing an edge.
253
+ func TestUnmappedPeerKeepsTheRawPackageName(t *testing.T) {
254
+ opts := options()
255
+ opts.Peers = nil
256
+
257
+ resp, err := extract(input(), opts)
258
+ if err != nil {
259
+ t.Fatal(err)
260
+ }
261
+
262
+ var frag catalog.Catalog
263
+ if err := json.Unmarshal([]byte(resp.Files[0].Contents), &frag); err != nil {
264
+ t.Fatal(err)
265
+ }
266
+ call := frag.Contexts[0].Services[0].Consumes[0]
267
+ if call.Peer != "pricing.v1" {
268
+ t.Errorf("peer: %q, want the raw package name", call.Peer)
269
+ }
270
+ if !warned(resp, "no peer is mapped") {
271
+ t.Error("an unmapped peer was resolved silently")
272
+ }
273
+ }
274
+
275
+ // A module the estate publishes has an owner; the lock beside it says which
276
+ // commit it was built from.
277
+ func TestOwnedModuleIsDescribed(t *testing.T) {
278
+ modules := fragment(t).Modules
279
+
280
+ var shop *catalog.ProtoModule
281
+ for i := range modules {
282
+ if modules[i].ID == "buf.build/acme/shop" {
283
+ shop = &modules[i]
284
+ }
285
+ }
286
+ if shop == nil {
287
+ t.Fatalf("modules: %+v", modules)
288
+ }
289
+
290
+ if shop.Slug != "acme-shop" || shop.Name != "acme/shop" || shop.Registry != "buf.build" {
291
+ t.Errorf("module identity: %+v", shop)
292
+ }
293
+ if shop.Owner != "shop.oms" {
294
+ t.Errorf("a module this service publishes has no owner: %q", shop.Owner)
295
+ }
296
+ if shop.Commit == "" || shop.Digest == "" {
297
+ t.Errorf("the lock's commit and digest did not reach the module: %+v", shop)
298
+ }
299
+ if len(shop.Packages) != 1 || shop.Packages[0] != "shop.v1" {
300
+ t.Errorf("packages: %v", shop.Packages)
301
+ }
302
+ if len(shop.Files) != 2 || shop.Files[0] != "shop/v1/money.proto" {
303
+ t.Errorf("files must be module-relative and sorted: %v", shop.Files)
304
+ }
305
+ }
306
+
307
+ // A vendored module is published by somebody else. Owner is left empty rather
308
+ // than guessed - a publisher outside the estate is the ordinary case.
309
+ func TestVendoredModuleHasNoOwner(t *testing.T) {
310
+ for _, m := range fragment(t).Modules {
311
+ if m.ID == "buf.build/acme/shop" {
312
+ continue
313
+ }
314
+ if m.Owner != "" {
315
+ t.Errorf("a vendored module claims an owner: %+v", m)
316
+ }
317
+ if !strings.HasPrefix(m.ID, "local:") {
318
+ t.Errorf("an unpinned directory should be listed as local: %q", m.ID)
319
+ }
320
+ }
321
+ }
322
+
323
+ // A narrowed copy imports files nobody vendored beside it - `pricing.proto`
324
+ // here imports a `money.proto` that is not in the tree, and its `Quote.total`
325
+ // names a type nothing declares.
326
+ //
327
+ // A compiler refuses to produce anything for that input. This must read every
328
+ // service and method that IS present, which is the whole reason the parser is
329
+ // tolerant rather than correct.
330
+ func TestNarrowedCopyIsStillFullyRead(t *testing.T) {
331
+ consumes := service(t).Consumes
332
+
333
+ if len(consumes) != 2 {
334
+ t.Fatalf("a copy with an unresolvable import was not fully read: %+v", consumes)
335
+ }
336
+ for _, call := range consumes {
337
+ if call.Source == "" || call.Peer == "" {
338
+ t.Errorf("a call from a narrowed copy is incomplete: %+v", call)
339
+ }
340
+ }
341
+ }
342
+
343
+ // The fragment claims only what this extractor knows. The name, repo, readme
344
+ // and aggregates belong to other extractors reading other files, and a fragment
345
+ // that filled them in would be inventing.
346
+ func TestFragmentClaimsNothingItDoesNotKnow(t *testing.T) {
347
+ svc := service(t)
348
+
349
+ if svc.Name != "" || svc.Repo != "" || svc.Readme != "" || svc.Path != "" {
350
+ t.Errorf("the fragment named the service: %+v", svc)
351
+ }
352
+ if len(svc.Aggregates) != 0 {
353
+ t.Errorf("the fragment invented aggregates: %+v", svc.Aggregates)
354
+ }
355
+ if len(fragment(t).Flows) != 0 || len(fragment(t).Adrs) != 0 {
356
+ t.Error("the fragment invented flows or decisions")
357
+ }
358
+ }
359
+
360
+ // The fragment is committed and compared by gen:check. A map iterated in Go's
361
+ // order would rewrite the file every run and turn every build into a diff.
362
+ func TestOutputIsByteIdentical(t *testing.T) {
363
+ first, err := extract(input(), options())
364
+ if err != nil {
365
+ t.Fatal(err)
366
+ }
367
+ for i := 0; i < 5; i++ {
368
+ again, err := extract(input(), options())
369
+ if err != nil {
370
+ t.Fatal(err)
371
+ }
372
+ if again.Files[0].Contents != first.Files[0].Contents {
373
+ t.Fatal("two runs over the same tree produced different fragments")
374
+ }
375
+ }
376
+ }
377
+
378
+ // The whole fragment, so a field that changes shape shows up as a diff rather
379
+ // than slipping past every assertion above.
380
+ func TestGoldenFragment(t *testing.T) {
381
+ got := response(t).Files[0].Contents
382
+
383
+ if *update {
384
+ if err := os.WriteFile(goldenPath, []byte(got), 0o644); err != nil {
385
+ t.Fatal(err)
386
+ }
387
+ t.Log("golden fragment rewritten")
388
+
389
+ return
390
+ }
391
+
392
+ want, err := os.ReadFile(goldenPath)
393
+ if err != nil {
394
+ t.Fatalf("reading the golden fragment: %v (run `go test ./plugins/extract-proto -update`)", err)
395
+ }
396
+ if string(want) != got {
397
+ t.Errorf("the fragment differs from the golden file\n%s", firstDifference(string(want), got))
398
+ }
399
+ }
400
+
401
+ func warned(resp plugin.Response, substring string) bool {
402
+ for _, d := range resp.Warnings() {
403
+ if strings.Contains(d.Message, substring) {
404
+ return true
405
+ }
406
+ }
407
+
408
+ return false
409
+ }
410
+
411
+ func firstDifference(want, got string) string {
412
+ a := strings.Split(want, "\n")
413
+ b := strings.Split(got, "\n")
414
+ for i := 0; i < len(a) && i < len(b); i++ {
415
+ if a[i] != b[i] {
416
+ return "line " + itoa(i+1) + ":\n want: " + a[i] + "\n got: " + b[i]
417
+ }
418
+ }
419
+
420
+ return "want " + itoa(len(a)) + " lines, got " + itoa(len(b))
421
+ }
422
+
423
+ func itoa(n int) string {
424
+ return strings.TrimSpace(strings.Replace(strings.Repeat(" ", 0)+string(rune(0)), string(rune(0)), fmtInt(n), 1))
425
+ }
426
+
427
+ func fmtInt(n int) string {
428
+ if n == 0 {
429
+ return "0"
430
+ }
431
+ var digits []byte
432
+ for n > 0 {
433
+ digits = append([]byte{byte('0' + n%10)}, digits...)
434
+ n /= 10
435
+ }
436
+
437
+ return string(digits)
438
+ }
439
+
440
+ // An enum a field names is listed beside the messages, values and numbers
441
+ // in declaration order. Only the ones reached: a set no method moves is
442
+ // not what the interface says.
443
+ func TestEnumsAreReachedThroughFields(t *testing.T) {
444
+ byName := map[string]catalog.RpcEnum{}
445
+ for _, e := range service(t).Provides[0].Enums {
446
+ byName[e.Name] = e
447
+ }
448
+
449
+ channel, ok := byName["Channel"]
450
+ if !ok {
451
+ t.Fatalf("Order.channel names Channel, which is not listed: %v", byName)
452
+ }
453
+ if status, ok := byName["Status"]; !ok || status.Doc != "How far along an order is." || status.Values[1].Doc != "The shop has it." {
454
+ t.Errorf("Status, reached through Order.status, lost its docs: %+v", status)
455
+ }
456
+ if len(channel.Values) != 2 || channel.Values[1].Name != "CHANNEL_WEB" || channel.Values[1].Number != 1 {
457
+ t.Errorf("values = %+v", channel.Values)
458
+ }
459
+ }
@@ -0,0 +1,89 @@
1
+ package main
2
+
3
+ // The id and slug rules, written once.
4
+ //
5
+ // Every other extractor keeps these in one file for the same reason: the ids
6
+ // are the join between fragments that never see each other, and a rule spelled
7
+ // twice is a rule that drifts. `plugins/extract-go/ids.go` is the precedent.
8
+
9
+ import (
10
+ "regexp"
11
+ "strings"
12
+ )
13
+
14
+ // interfaceID is what a service in a .proto is called across the catalog:
15
+ // its proto package and its name. `shop.v1.Orders`.
16
+ //
17
+ // This is already the spelling `RpcService.id` documents, so a proto read here
18
+ // lands beside interfaces every other extractor names the same way.
19
+ func interfaceID(pkg, service string) string {
20
+ if pkg == "" {
21
+ return service
22
+ }
23
+
24
+ return pkg + "." + service
25
+ }
26
+
27
+ // callID is one method of one interface: `shop.v1.Orders/PlaceOrder`.
28
+ //
29
+ // The same string `buildIndex` keys `rpcProviderByMethod` by, which is what
30
+ // makes a consumed call and a provided method meet with no other machinery.
31
+ func callID(iface, method string) string {
32
+ return iface + "/" + method
33
+ }
34
+
35
+ // moduleID is the module's registry-global name, or a local stand-in.
36
+ //
37
+ // A module never published still needs an id, because the interfaces read out
38
+ // of it have to say where they came from. `local:` prefixes it so nobody
39
+ // mistakes the path for a module someone could go and fetch.
40
+ func localModuleID(dir string) string {
41
+ return localPrefix + strings.Trim(dir, "/")
42
+ }
43
+
44
+ var notSlug = regexp.MustCompile(`[^a-z0-9]+`)
45
+
46
+ const localPrefix = "local:"
47
+
48
+ // moduleName is the module as a reader says it: `acme/shop` for a published
49
+ // module, and the whole path for a local one.
50
+ //
51
+ // A published module drops its registry host, because it is the same for every
52
+ // module in almost every estate and repeating it would say nothing. A local id
53
+ // drops NOTHING - its path is not `host/owner/name`, and trimming its first
54
+ // segment would turn `internal/infrastructure/pricing` into a directory that
55
+ // does not exist.
56
+ func moduleName(id string) string {
57
+ if strings.HasPrefix(id, localPrefix) {
58
+ return strings.TrimPrefix(id, localPrefix)
59
+ }
60
+ if parts := strings.Split(id, "/"); len(parts) > 2 {
61
+ return strings.Join(parts[1:], "/")
62
+ }
63
+
64
+ return id
65
+ }
66
+
67
+ // moduleSlug is what the URL uses. `buf.build/acme/shop` gives `acme-shop`,
68
+ // `local:internal/infrastructure/pricing` gives
69
+ // `internal-infrastructure-pricing`.
70
+ //
71
+ // Should two registries ever host the same owner and name, the validator
72
+ // refuses the catalog rather than letting two entities share an address.
73
+ func moduleSlug(id string) string {
74
+ slug := notSlug.ReplaceAllString(strings.ToLower(moduleName(id)), "-")
75
+
76
+ return strings.Trim(slug, "-")
77
+ }
78
+
79
+ // registryOf is the host a module was published to, empty for a local set.
80
+ func registryOf(id string) string {
81
+ if strings.HasPrefix(id, localPrefix) {
82
+ return ""
83
+ }
84
+ if parts := strings.Split(id, "/"); len(parts) > 2 {
85
+ return parts[0]
86
+ }
87
+
88
+ return ""
89
+ }
@@ -0,0 +1,57 @@
1
+ package main
2
+
3
+ // The id rules, which are the join between fragments that never see each other.
4
+
5
+ import "testing"
6
+
7
+ func TestModuleIdentity(t *testing.T) {
8
+ cases := []struct{ id, name, slug, registry string }{
9
+ {"buf.build/acme/shop", "acme/shop", "acme-shop", "buf.build"},
10
+ {"buf.build/acme/shop-events", "acme/shop-events", "acme-shop-events", "buf.build"},
11
+ // A local id is a path, not `host/owner/name`. Trimming its first
12
+ // segment would name a directory that does not exist.
13
+ {"local:internal/infrastructure/pricing", "internal/infrastructure/pricing", "internal-infrastructure-pricing", ""},
14
+ {"local:proto", "proto", "proto", ""},
15
+ }
16
+
17
+ for _, c := range cases {
18
+ if got := moduleName(c.id); got != c.name {
19
+ t.Errorf("%s name: %q, want %q", c.id, got, c.name)
20
+ }
21
+ if got := moduleSlug(c.id); got != c.slug {
22
+ t.Errorf("%s slug: %q, want %q", c.id, got, c.slug)
23
+ }
24
+ if got := registryOf(c.id); got != c.registry {
25
+ t.Errorf("%s registry: %q, want %q", c.id, got, c.registry)
26
+ }
27
+ }
28
+ }
29
+
30
+ // A slug goes in a URL segment, so it may never carry a dot or a slash -
31
+ // src/routes.test.ts holds every catalog path to that.
32
+ func TestSlugIsUrlSafe(t *testing.T) {
33
+ for _, id := range []string{"buf.build/acme/shop.v1", "local:proto/shop/v1"} {
34
+ slug := moduleSlug(id)
35
+ for _, bad := range []rune{'.', '/', ':', ' '} {
36
+ for _, r := range slug {
37
+ if r == bad {
38
+ t.Errorf("%s gives slug %q, which cannot go in a URL segment", id, slug)
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+
45
+ // The ids the catalog joins on, spelled the way RpcService.id documents.
46
+ func TestInterfaceAndCallIds(t *testing.T) {
47
+ if got := interfaceID("shop.v1", "Orders"); got != "shop.v1.Orders" {
48
+ t.Errorf("interface id: %q", got)
49
+ }
50
+ if got := callID("shop.v1.Orders", "PlaceOrder"); got != "shop.v1.Orders/PlaceOrder" {
51
+ t.Errorf("call id: %q", got)
52
+ }
53
+ // A proto with no package still has to produce something findable.
54
+ if got := interfaceID("", "Orders"); got != "Orders" {
55
+ t.Errorf("interface id with no package: %q", got)
56
+ }
57
+ }