@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,545 @@
1
+ package main
2
+
3
+ import (
4
+ "encoding/json"
5
+ "os"
6
+ "path/filepath"
7
+ "strings"
8
+ "testing"
9
+
10
+ "github.com/shortlink-org/portolan/catalog"
11
+ "github.com/shortlink-org/portolan/plugin"
12
+ "gopkg.in/yaml.v3"
13
+ )
14
+
15
+ func fragment(t *testing.T) catalog.Catalog {
16
+ t.Helper()
17
+
18
+ resp, err := extract(
19
+ plugin.Input{Root: "testdata", Commit: "abc1234", GeneratedAt: "2026-01-01T00:00:00Z"},
20
+ Options{Context: "billing", Service: "invoices", Spec: "openapi.yaml"},
21
+ )
22
+ if err != nil {
23
+ t.Fatal(err)
24
+ }
25
+ if len(resp.Files) != 1 {
26
+ t.Fatalf("expected one fragment, got %d files", len(resp.Files))
27
+ }
28
+
29
+ var out catalog.Catalog
30
+ if err := json.Unmarshal([]byte(resp.Files[0].Contents), &out); err != nil {
31
+ t.Fatal(err)
32
+ }
33
+
34
+ return out
35
+ }
36
+
37
+ func testDocument(t *testing.T, source string) *document {
38
+ t.Helper()
39
+ var root yaml.Node
40
+ if err := yaml.Unmarshal([]byte(source), &root); err != nil {
41
+ t.Fatal(err)
42
+ }
43
+ node := root.Content[0]
44
+ return &document{root: node, path: "test.yaml", cache: map[string]*document{}}
45
+ }
46
+
47
+ func provided(t *testing.T) []catalog.RpcService {
48
+ t.Helper()
49
+
50
+ return fragment(t).Contexts[0].Services[0].Provides
51
+ }
52
+
53
+ // A method is an object now, and every assertion below is about the names.
54
+ func names(methods []catalog.RpcMethod) []string {
55
+ out := make([]string, 0, len(methods))
56
+ for _, method := range methods {
57
+ out = append(out, method.Name)
58
+ }
59
+
60
+ return out
61
+ }
62
+
63
+ // Tags organise operations within one OpenAPI contract. They must not split a
64
+ // document into duplicate interfaces with duplicate message inventories.
65
+ func TestTagsStayWithinOneService(t *testing.T) {
66
+ provides := provided(t)
67
+ if len(provides) != 1 {
68
+ t.Fatalf("provides = %d, want one contract", len(provides))
69
+ }
70
+ if provides[0].ID != "billing.v2" {
71
+ t.Errorf("interface = %q", provides[0].ID)
72
+ }
73
+ if got := strings.Join(names(provides[0].Methods), ","); got != "raiseInvoice,GET /v2/health" {
74
+ t.Errorf("methods = %q", got)
75
+ }
76
+ }
77
+
78
+ func TestSharedSchemaIsNotRepeatedAcrossTags(t *testing.T) {
79
+ doc := testDocument(t, `
80
+ openapi: 3.0.3
81
+ info: {title: shared, version: 1.0.0}
82
+ paths:
83
+ /orders:
84
+ get:
85
+ tags: [orders]
86
+ operationId: listOrders
87
+ responses:
88
+ '200':
89
+ content:
90
+ application/json:
91
+ schema: {$ref: '#/components/schemas/Result'}
92
+ /refunds:
93
+ get:
94
+ tags: [refunds]
95
+ operationId: listRefunds
96
+ responses:
97
+ '200':
98
+ content:
99
+ application/json:
100
+ schema: {$ref: '#/components/schemas/Result'}
101
+ components:
102
+ schemas:
103
+ Result: {type: object}
104
+ `)
105
+
106
+ services := rpcServices(doc, "shared.v1", "test.yaml", &plugin.Builder{})
107
+ if len(services) != 1 || len(services[0].Methods) != 2 || len(services[0].Messages) != 1 {
108
+ t.Fatalf("contract = %+v", services)
109
+ }
110
+ }
111
+
112
+ // The id is the document's own title and major version, so it survives a patch
113
+ // release without every id in the catalog changing.
114
+ func TestApiIDFromTitleAndMajorVersion(t *testing.T) {
115
+ for _, p := range provided(t) {
116
+ if !strings.HasPrefix(p.ID, "billing.v2") {
117
+ t.Errorf("unexpected id %q", p.ID)
118
+ }
119
+ }
120
+ }
121
+
122
+ // A shared response is how a spec says "the same error body as everywhere
123
+ // else". Not following it would document the endpoint as returning nothing
124
+ // when it fails.
125
+ func TestFollowsRefsThroughSharedResponses(t *testing.T) {
126
+ var names []string
127
+ for _, p := range provided(t) {
128
+ if p.ID != "billing.v2" {
129
+ continue
130
+ }
131
+ for _, message := range p.Messages {
132
+ names = append(names, message.Name)
133
+ }
134
+ }
135
+
136
+ // Line arrives through RaiseRequest, Error through the shared BadRequest.
137
+ want := "RaiseRequest,Invoice,Error,Line"
138
+ if strings.Join(names, ",") != want {
139
+ t.Errorf("messages = %v, want %s", names, want)
140
+ }
141
+ }
142
+
143
+ func TestFieldTypesAndOptionality(t *testing.T) {
144
+ var request *catalog.RpcMessage
145
+ for _, p := range provided(t) {
146
+ for i := range p.Messages {
147
+ if p.Messages[i].Name == "RaiseRequest" {
148
+ request = &p.Messages[i]
149
+ }
150
+ }
151
+ }
152
+ if request == nil {
153
+ t.Fatal("no RaiseRequest message")
154
+ }
155
+
156
+ fields := map[string]catalog.Field{}
157
+ for _, field := range request.Fields {
158
+ fields[field.Name] = field
159
+ }
160
+
161
+ if got := fields["customerId"].Type; got != "string (uuid)" {
162
+ t.Errorf("format belongs in the type, got %q", got)
163
+ }
164
+ if got := fields["customerId"].Doc; got != "Who is being billed." {
165
+ t.Errorf("a required field carries its description alone, got %q", got)
166
+ }
167
+ if got := fields["lines"].Type; got != "[]Line" {
168
+ t.Errorf("an array of refs, got %q", got)
169
+ }
170
+ // Which fields must be sent is the first thing a caller needs, and the
171
+ // catalog has nowhere else to put it.
172
+ if got := fields["lines"].Doc; !strings.HasPrefix(got, "Optional.") {
173
+ t.Errorf("an optional field should say so, got %q", got)
174
+ }
175
+ }
176
+
177
+ func TestComposedSchemasMapsEnumsAndNullableTypes(t *testing.T) {
178
+ doc := testDocument(t, `
179
+ components:
180
+ schemas:
181
+ Base:
182
+ type: object
183
+ required: [id]
184
+ properties:
185
+ id: {type: string, format: uuid}
186
+ Account:
187
+ allOf:
188
+ - $ref: '#/components/schemas/Base'
189
+ - type: object
190
+ required: [labels]
191
+ properties:
192
+ labels:
193
+ type: object
194
+ additionalProperties: {type: string}
195
+ state:
196
+ type: string
197
+ enum: [active, disabled]
198
+ contact:
199
+ nullable: true
200
+ oneOf:
201
+ - {type: string, format: email}
202
+ - {type: string, format: phone}
203
+ `)
204
+ account := child(doc.root, "components", "schemas", "Account")
205
+ fields := map[string]catalog.Field{}
206
+ for _, field := range schemaFields(doc, account) {
207
+ fields[field.Name] = field
208
+ }
209
+
210
+ if fields["id"].Type != "string (uuid)" || strings.HasPrefix(fields["id"].Doc, "Optional.") {
211
+ t.Errorf("allOf required field = %+v", fields["id"])
212
+ }
213
+ if fields["labels"].Type != "map[string]string" || strings.HasPrefix(fields["labels"].Doc, "Optional.") {
214
+ t.Errorf("map field = %+v", fields["labels"])
215
+ }
216
+ if fields["state"].Type != "string enum(active | disabled)" || !strings.HasPrefix(fields["state"].Doc, "Optional.") {
217
+ t.Errorf("enum field = %+v", fields["state"])
218
+ }
219
+ if fields["contact"].Type != "string (email) | string (phone) | null" {
220
+ t.Errorf("oneOf nullable field type = %q", fields["contact"].Type)
221
+ }
222
+ }
223
+
224
+ func TestDiscriminatorKeepsPolymorphicMessagesVisible(t *testing.T) {
225
+ doc := testDocument(t, `
226
+ openapi: 3.1.0
227
+ info: {title: animals, version: 1.0.0}
228
+ paths:
229
+ /pets/{id}:
230
+ get:
231
+ operationId: getPet
232
+ responses:
233
+ '200':
234
+ content:
235
+ application/json:
236
+ schema: {$ref: '#/components/schemas/Pet'}
237
+ components:
238
+ schemas:
239
+ Pet:
240
+ oneOf:
241
+ - {$ref: '#/components/schemas/Cat'}
242
+ - {$ref: '#/components/schemas/Dog'}
243
+ discriminator:
244
+ propertyName: kind
245
+ mapping:
246
+ feline: '#/components/schemas/Cat'
247
+ Cat:
248
+ type: object
249
+ required: [kind, lives]
250
+ properties:
251
+ kind: {type: string}
252
+ lives: {type: integer}
253
+ Dog:
254
+ type: object
255
+ required: [kind, good]
256
+ properties:
257
+ kind: {type: string}
258
+ good: {type: boolean}
259
+ `)
260
+ services := rpcServices(doc, "animals.v1", "test.yaml", &plugin.Builder{})
261
+ if len(services) != 1 || len(services[0].Methods) != 1 {
262
+ t.Fatalf("services = %+v", services)
263
+ }
264
+ if got := services[0].Methods[0].Response; got != "Pet" {
265
+ t.Fatalf("response = %q, want Pet", got)
266
+ }
267
+
268
+ byName := map[string]catalog.RpcMessage{}
269
+ for _, message := range services[0].Messages {
270
+ byName[message.Name] = message
271
+ }
272
+ pet, ok := byName["Pet"]
273
+ if !ok || pet.Discriminator == nil {
274
+ t.Fatalf("Pet discriminator is missing: %+v", pet)
275
+ }
276
+ if pet.Discriminator.Property != "kind" {
277
+ t.Errorf("property = %q", pet.Discriminator.Property)
278
+ }
279
+ if len(pet.Discriminator.Variants) != 2 {
280
+ t.Fatalf("variants = %+v", pet.Discriminator.Variants)
281
+ }
282
+ if got := pet.Discriminator.Variants[0]; got.Value != "feline" || got.Message != "Cat" {
283
+ t.Errorf("mapped variant = %+v", got)
284
+ }
285
+ if got := pet.Discriminator.Variants[1]; got.Value != "Dog" || got.Message != "Dog" {
286
+ t.Errorf("implicit variant = %+v", got)
287
+ }
288
+ if _, ok := byName["Cat"]; !ok {
289
+ t.Error("Cat concrete message is missing")
290
+ }
291
+ if _, ok := byName["Dog"]; !ok {
292
+ t.Error("Dog concrete message is missing")
293
+ }
294
+ }
295
+
296
+ func TestRelativeExternalSchemaRefsAreLoaded(t *testing.T) {
297
+ dir := t.TempDir()
298
+ common := filepath.Join(dir, "common.yaml")
299
+ root := filepath.Join(dir, "openapi.yaml")
300
+ if err := os.WriteFile(common, []byte(`components:
301
+ schemas:
302
+ External:
303
+ type: object
304
+ required: [code]
305
+ properties:
306
+ code: {type: integer, format: int64}
307
+ `), 0o600); err != nil {
308
+ t.Fatal(err)
309
+ }
310
+ if err := os.WriteFile(root, []byte(`openapi: 3.1.0
311
+ info: {title: external, version: 1.0.0}
312
+ paths:
313
+ /external:
314
+ get:
315
+ operationId: getExternal
316
+ responses:
317
+ '200':
318
+ content:
319
+ application/json:
320
+ schema: {$ref: './common.yaml#/components/schemas/External'}
321
+ `), 0o600); err != nil {
322
+ t.Fatal(err)
323
+ }
324
+ doc, err := load(root)
325
+ if err != nil {
326
+ t.Fatal(err)
327
+ }
328
+ services := rpcServices(doc, "external.v1", root, &plugin.Builder{})
329
+ if len(services) != 1 || len(services[0].Messages) != 1 {
330
+ t.Fatalf("services = %+v", services)
331
+ }
332
+ message := services[0].Messages[0]
333
+ if message.Name != "External" || len(message.Fields) != 1 || message.Fields[0].Type != "integer (int64)" {
334
+ t.Errorf("external message = %+v", message)
335
+ }
336
+ }
337
+
338
+ // The fragment describes what the service answers and nothing else; the name
339
+ // and readme belong to whichever source knows them.
340
+ func TestFragmentClaimsNothingItDoesNotKnow(t *testing.T) {
341
+ service := fragment(t).Contexts[0].Services[0]
342
+
343
+ if service.Name != "" || service.Readme != "" || service.Repo != "" {
344
+ t.Errorf("the api fragment should not name the service: %+v", service)
345
+ }
346
+ if len(service.Aggregates) != 0 {
347
+ t.Error("the api fragment should carry no aggregates")
348
+ }
349
+ }
350
+
351
+ // What the operation sends and answers with. The document names both whenever
352
+ // the body is a $ref; a success with no body at all is answered by its status,
353
+ // because 204 is a real answer and an empty string reads as an unread one.
354
+ func TestShapesOnEitherSide(t *testing.T) {
355
+ byName := map[string]catalog.RpcMethod{}
356
+ for _, p := range provided(t) {
357
+ for _, method := range p.Methods {
358
+ byName[method.Name] = method
359
+ }
360
+ }
361
+
362
+ raise, ok := byName["raiseInvoice"]
363
+ if !ok {
364
+ t.Fatal("no raiseInvoice")
365
+ }
366
+ if raise.Request != "RaiseRequest" || raise.Response != "Invoice" {
367
+ t.Errorf("raiseInvoice sends %q and returns %q", raise.Request, raise.Response)
368
+ }
369
+
370
+ health, ok := byName["GET /v2/health"]
371
+ if !ok {
372
+ t.Fatal("no health operation")
373
+ }
374
+ if health.Request != "" || health.Response != "200" {
375
+ t.Errorf("health sends %q and returns %q", health.Request, health.Response)
376
+ }
377
+ }
378
+
379
+ // The same document, read as a copy vendored from outside the estate: the
380
+ // fragment carries no context and no service, only the external and what it
381
+ // answers on, under the id the manifest gave it.
382
+ func TestExternalCarriesNoService(t *testing.T) {
383
+ resp, err := extract(
384
+ plugin.Input{Root: "testdata", Commit: "abc1234", GeneratedAt: "2026-01-01T00:00:00Z"},
385
+ Options{External: "psp", ExternalName: "PSP", ExternalURL: "https://psp.example/docs", API: "psp.v1", Spec: "openapi.yaml"},
386
+ )
387
+ if err != nil {
388
+ t.Fatal(err)
389
+ }
390
+ var out catalog.Catalog
391
+ if err := json.Unmarshal([]byte(resp.Files[0].Contents), &out); err != nil {
392
+ t.Fatal(err)
393
+ }
394
+ if len(out.Contexts) != 0 {
395
+ t.Errorf("an external's fragment names %d contexts", len(out.Contexts))
396
+ }
397
+ if len(out.Externals) != 1 {
398
+ t.Fatalf("externals = %+v", out.Externals)
399
+ }
400
+ ext := out.Externals[0]
401
+ if ext.ID != "psp" || ext.Slug != "psp" || ext.Name != "PSP" || ext.URL != "https://psp.example/docs" {
402
+ t.Errorf("external = %+v", ext)
403
+ }
404
+ var ids []string
405
+ for _, p := range ext.Provides {
406
+ ids = append(ids, p.ID)
407
+ }
408
+ if strings.Join(ids, ",") != "psp.v1" {
409
+ t.Errorf("interfaces = %v", ids)
410
+ }
411
+
412
+ // A dotted id would put the external inside a context nobody declared.
413
+ if _, err := extract(plugin.Input{Root: "testdata"}, Options{External: "shop.psp"}); err == nil {
414
+ t.Error("an external with a dot in its id was accepted")
415
+ }
416
+ }
417
+
418
+ // A Swagger 2.0 document keeps its schemas under definitions, sends its body
419
+ // as a parameter and puts the response schema straight on the response. A
420
+ // generator that still writes 2.0 - swag, for one - documents a service
421
+ // exactly as well as one that writes 3.
422
+ func TestSwagger2DefinitionsAndBodyParameters(t *testing.T) {
423
+ resp, err := extract(
424
+ plugin.Input{Root: "testdata/swagger2", Commit: "abc1234", GeneratedAt: "2026-01-01T00:00:00Z"},
425
+ Options{Context: "avia", Service: "aviasupp", Spec: "swagger.yaml"},
426
+ )
427
+ if err != nil {
428
+ t.Fatal(err)
429
+ }
430
+ var out catalog.Catalog
431
+ if err := json.Unmarshal([]byte(resp.Files[0].Contents), &out); err != nil {
432
+ t.Fatal(err)
433
+ }
434
+
435
+ byName := map[string]catalog.RpcMethod{}
436
+ shapes := map[string][]string{}
437
+ for _, p := range out.Contexts[0].Services[0].Provides {
438
+ for _, method := range p.Methods {
439
+ byName[method.Name] = method
440
+ }
441
+ for _, message := range p.Messages {
442
+ var fields []string
443
+ for _, field := range message.Fields {
444
+ fields = append(fields, field.Name+" "+field.Type)
445
+ }
446
+ shapes[message.Name] = fields
447
+ }
448
+ }
449
+
450
+ book, ok := byName["POST /book"]
451
+ if !ok {
452
+ t.Fatalf("no POST /book among %v", byName)
453
+ }
454
+ if book.Request != "book.Request" || book.Response != "book.Response" {
455
+ t.Errorf("book sends %q and returns %q", book.Request, book.Response)
456
+ }
457
+
458
+ // The body parameter is inherited from the path item, and a list of a
459
+ // definition is that definition with brackets.
460
+ search, ok := byName["search"]
461
+ if !ok {
462
+ t.Fatalf("no search among %v", byName)
463
+ }
464
+ if search.Request != "search.Request" || search.Response != "search.Offer[]" {
465
+ t.Errorf("search sends %q and returns %q", search.Request, search.Response)
466
+ }
467
+
468
+ if got := strings.Join(shapes["book.Request"], ", "); got != "offer_id string, passengers []book.Passenger" {
469
+ t.Errorf("book.Request = %q", got)
470
+ }
471
+ if _, ok := shapes["book.Passenger"]; !ok {
472
+ t.Errorf("book.Passenger, reached through book.Request, is not among the messages: %v", shapes)
473
+ }
474
+ if _, ok := shapes["search.Offer"]; !ok {
475
+ t.Errorf("search.Offer, the response item, is not among the messages: %v", shapes)
476
+ }
477
+ }
478
+
479
+ // Nothing named: the tree says which documents this service implements and
480
+ // which it calls. A server generated from a document means provides; a client
481
+ // generated from one means a system outside the estate, named by the
482
+ // document's own title, unless the manifest says the api is one of ours. A
483
+ // document with neither beside it is reported and left alone.
484
+ func TestATreeSaysWhatIsImplementedAndWhatIsCalled(t *testing.T) {
485
+ read := func(opts Options) (catalog.Catalog, plugin.Response) {
486
+ t.Helper()
487
+ opts.Context, opts.Service = "avia", "aviasupp"
488
+ resp, err := extract(plugin.Input{Root: "testdata/discover", Commit: "abc1234", GeneratedAt: "2026-01-01T00:00:00Z"}, opts)
489
+ if err != nil {
490
+ t.Fatal(err)
491
+ }
492
+ var out catalog.Catalog
493
+ if err := json.Unmarshal([]byte(resp.Files[0].Contents), &out); err != nil {
494
+ t.Fatal(err)
495
+ }
496
+ return out, resp
497
+ }
498
+
499
+ out, resp := read(Options{Peers: map[string]string{"partner-api.v2": "shop.partner"}})
500
+
501
+ var provided []string
502
+ for _, p := range out.Contexts[0].Services[0].Provides {
503
+ provided = append(provided, p.ID+" from "+p.Source)
504
+ }
505
+ if strings.Join(provided, ", ") != "aviasupp.v1 from testdata/discover/docs/swagger.yaml" {
506
+ t.Errorf("provides = %v", provided)
507
+ }
508
+
509
+ if len(out.Externals) != 1 {
510
+ t.Fatalf("externals = %+v", out.Externals)
511
+ }
512
+ acme := out.Externals[0]
513
+ if acme.ID != "acme-flights" || acme.Slug != "acme-flights" || acme.Name != "Acme Flights API" || acme.Summary != "Flights and ancillaries from Acme." || acme.URL != "https://developer.acme.example/flights" {
514
+ t.Errorf("external = %+v", acme)
515
+ }
516
+ if len(acme.Provides) != 1 || acme.Provides[0].ID != "acme-flights-api.v1" {
517
+ t.Errorf("acme provides %+v", acme.Provides)
518
+ }
519
+
520
+ warned := func(substring string) bool {
521
+ for _, w := range resp.Warnings() {
522
+ if strings.Contains(w.Message, substring) {
523
+ return true
524
+ }
525
+ }
526
+ return false
527
+ }
528
+ if !warned("found testdata/discover/internal/stray/openapi.yaml, and nothing beside it says") {
529
+ t.Errorf("the stray document was not reported; warnings = %+v", resp.Warnings())
530
+ }
531
+ if !warned("nameless/client/openapi.yaml is called from here and its document has no title") {
532
+ t.Errorf("the nameless document was not reported; warnings = %+v", resp.Warnings())
533
+ }
534
+
535
+ // The manifest may name the system itself; and a called document whose
536
+ // api no peers line claims is a system outside the estate too.
537
+ out, _ = read(Options{Externals: map[string]string{"acme-flights-api.v1": "acme"}})
538
+ var ids []string
539
+ for _, e := range out.Externals {
540
+ ids = append(ids, e.ID)
541
+ }
542
+ if strings.Join(ids, ",") != "acme,partner" {
543
+ t.Errorf("externals = %v", ids)
544
+ }
545
+ }
@@ -0,0 +1,75 @@
1
+ // Package main is portolan-extract-openapi: an OpenAPI document in, a catalog
2
+ // fragment out.
3
+ //
4
+ // It describes one aspect of a service - what it answers - and nothing else.
5
+ // The aggregates come from a different extractor reading a different part of
6
+ // the tree, and the two meet in the merge. Neither knows the other exists,
7
+ // which is the whole reason each of them stays small.
8
+ package main
9
+
10
+ import (
11
+ "fmt"
12
+ "io"
13
+ "os"
14
+
15
+ "github.com/shortlink-org/portolan/plugin"
16
+ )
17
+
18
+ // Options are what the manifest tells the extractor: the things an OpenAPI
19
+ // document does not say about the estate it belongs to.
20
+ type Options struct {
21
+ Context string `json:"context"`
22
+ Service string `json:"service"`
23
+
24
+ // Spec is the document, relative to the input root. Left out, the
25
+ // extractor walks the tree for every document and reads what sits beside
26
+ // each one: a server generated from it means this service implements it,
27
+ // a client generated from it means this service calls it, and a called
28
+ // document names a system outside the estate unless `peers` says the api
29
+ // is one of ours.
30
+ Spec string `json:"spec,omitempty"`
31
+
32
+ // Peers says which called documents are ours, as the api id to the
33
+ // service that implements it: {"auth.v1": "auth.auth"}. A called document
34
+ // whose api is named here is that service's to describe, and is skipped.
35
+ Peers map[string]string `json:"peers,omitempty"`
36
+
37
+ // Externals names a called document's system when the name its title
38
+ // would give is not the one wanted, as the api id to the external's bare
39
+ // id: {"stripe.v1": "stripe"}.
40
+ Externals map[string]string `json:"externals,omitempty"`
41
+
42
+ // API prefixes the ids of the rpc services this produces. Left out, it is
43
+ // built from the document's title and major version - `auth` 1.0.0 gives
44
+ // `auth.v1`, and a tag called `users` gives `auth.v1.Users`.
45
+ API string `json:"api,omitempty"`
46
+
47
+ // External names a system outside the estate the document belongs to,
48
+ // when it is not one of ours: the copy vendored beside an adapter, read
49
+ // for what the third party answers on. Set, the fragment carries no
50
+ // context and no service, only the external, and `context` and `service`
51
+ // are not read.
52
+ External string `json:"external,omitempty"`
53
+ ExternalName string `json:"externalName,omitempty"`
54
+ ExternalSummary string `json:"externalSummary,omitempty"`
55
+ ExternalURL string `json:"externalUrl,omitempty"`
56
+
57
+ Out string `json:"out,omitempty"`
58
+ }
59
+
60
+ func main() {
61
+ if err := run(os.Stdin, os.Stdout); err != nil {
62
+ fmt.Fprintln(os.Stderr, "portolan-extract-openapi:", err)
63
+ os.Exit(1)
64
+ }
65
+ }
66
+
67
+ func run(stdin io.Reader, stdout io.Writer) error {
68
+ return plugin.Serve(stdin, stdout, descriptor(), func(req plugin.Request, opts Options) (plugin.Response, error) {
69
+ if req.Input.Root == "" {
70
+ return plugin.Response{}, fmt.Errorf("no input root: an extractor has nothing to read")
71
+ }
72
+
73
+ return extract(req.Input, opts)
74
+ })
75
+ }
@@ -0,0 +1,62 @@
1
+ {
2
+ "type": "object",
3
+ "additionalProperties": false,
4
+ "properties": {
5
+ "context": {
6
+ "type": "string",
7
+ "description": "Slug of the bounded context that owns the service this document belongs to. Defaults to the name of the input directory.",
8
+ "examples": ["auth"]
9
+ },
10
+ "service": {
11
+ "type": "string",
12
+ "description": "Slug of the service the document describes. Defaults to the name of the input directory.",
13
+ "examples": ["auth"]
14
+ },
15
+ "spec": {
16
+ "type": "string",
17
+ "description": "The OpenAPI document, relative to the input root. Left out, the extractor walks the tree for every document and reads what sits beside each: a server generated from it means this service implements it, a client generated from it means this service calls it, and a called document names a system outside the estate unless peers says the api is one of ours.",
18
+ "examples": ["internal/infrastructure/transport/http/gen/openapi.yaml"]
19
+ },
20
+ "peers": {
21
+ "type": "object",
22
+ "additionalProperties": { "type": "string" },
23
+ "description": "Which called documents are ours, as the api id to the service that implements it. A called document whose api is named here is that service's to describe, and is skipped rather than read as a system outside the estate.",
24
+ "examples": [{ "auth.v1": "auth.auth" }]
25
+ },
26
+ "externals": {
27
+ "type": "object",
28
+ "additionalProperties": { "type": "string" },
29
+ "description": "What a called document's system is called when the name its title would give is not the one wanted, as the api id to the external's bare id. Left out, a document titled \"Stripe API\" makes the external stripe.",
30
+ "examples": [{ "stripe.v1": "stripe" }]
31
+ },
32
+ "api": {
33
+ "type": "string",
34
+ "description": "Prefix for the ids of the rpc services this produces. Left out, it is the document's own x-portolan-api when it carries one, and otherwise built from its title and major version: auth 1.0.0 gives auth.v1, and a tag called users gives auth.v1.Users.",
35
+ "examples": ["auth.v1"]
36
+ },
37
+ "external": {
38
+ "type": "string",
39
+ "description": "Id of a system outside the estate the document belongs to, when it is not one of ours: a copy vendored beside the adapter that calls it, read for what the third party answers on. A bare name with no dot, the same one the caller's extractor is given under externals. Set, the fragment carries the external and no service, and context and service are not read.",
40
+ "examples": ["stripe"]
41
+ },
42
+ "externalName": {
43
+ "type": "string",
44
+ "description": "What the external is called on the page.",
45
+ "examples": ["Stripe"]
46
+ },
47
+ "externalSummary": {
48
+ "type": "string",
49
+ "description": "A sentence or two on what the estate uses it for."
50
+ },
51
+ "externalUrl": {
52
+ "type": "string",
53
+ "description": "Where the third party documents itself, for a reader who needs more than the vendored copy.",
54
+ "examples": ["https://docs.stripe.com/api"]
55
+ },
56
+ "out": {
57
+ "type": "string",
58
+ "description": "Name of the fragment file, inside the step's output directory.",
59
+ "default": "api.json"
60
+ }
61
+ }
62
+ }