@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,224 @@
1
+ package main
2
+
3
+ import (
4
+ "go/ast"
5
+
6
+ "github.com/shortlink-org/portolan/catalog"
7
+ "github.com/shortlink-org/portolan/internal/goscan"
8
+ )
9
+
10
+ // natsCall is one method of nats.go the reader knows: which way messages go,
11
+ // and where in the arguments the subject is - directly, inside a *nats.Msg,
12
+ // or inside a consumer config.
13
+ type natsCall struct {
14
+ direction catalog.ChannelDirection
15
+ api string
16
+ subject int
17
+ message int
18
+ config int
19
+ queue int
20
+ durable int
21
+ }
22
+
23
+ func core(direction catalog.ChannelDirection, subject, queue int) natsCall {
24
+ return natsCall{direction: direction, api: "NATS", subject: subject, message: -1, config: -1, queue: queue, durable: -1}
25
+ }
26
+
27
+ func coreMsg(direction catalog.ChannelDirection, message int) natsCall {
28
+ return natsCall{direction: direction, api: "NATS", subject: -1, message: message, config: -1, queue: -1, durable: -1}
29
+ }
30
+
31
+ func stream(direction catalog.ChannelDirection, subject, queue, durable int) natsCall {
32
+ return natsCall{direction: direction, api: "JetStream", subject: subject, message: -1, config: -1, queue: queue, durable: durable}
33
+ }
34
+
35
+ func streamMsg(message int) natsCall {
36
+ return natsCall{direction: catalog.ChannelSend, api: "JetStream", subject: -1, message: message, config: -1, queue: -1, durable: -1}
37
+ }
38
+
39
+ func consumer(config int) natsCall {
40
+ return natsCall{direction: catalog.ChannelReceive, api: "JetStream", subject: -1, message: -1, config: config, queue: -1, durable: -1}
41
+ }
42
+
43
+ // natsCalls is the surface read, by the type a method is called on. The
44
+ // type is what decides: a service's own bus port has a Subscribe too, and
45
+ // it is not this one.
46
+ var natsCalls = map[string]map[string]natsCall{
47
+ natsPkg + ".Conn": {
48
+ "Subscribe": core(catalog.ChannelReceive, 0, -1),
49
+ "SubscribeSync": core(catalog.ChannelReceive, 0, -1),
50
+ "ChanSubscribe": core(catalog.ChannelReceive, 0, -1),
51
+ "QueueSubscribe": core(catalog.ChannelReceive, 0, 1),
52
+ "QueueSubscribeSync": core(catalog.ChannelReceive, 0, 1),
53
+ "ChanQueueSubscribe": core(catalog.ChannelReceive, 0, 1),
54
+ "Publish": core(catalog.ChannelSend, 0, -1),
55
+ "Request": core(catalog.ChannelSend, 0, -1),
56
+ "PublishMsg": coreMsg(catalog.ChannelSend, 0),
57
+ "RequestMsg": coreMsg(catalog.ChannelSend, 0),
58
+ },
59
+ natsPkg + ".JetStreamContext": {
60
+ "Subscribe": stream(catalog.ChannelReceive, 0, -1, -1),
61
+ "SubscribeSync": stream(catalog.ChannelReceive, 0, -1, -1),
62
+ "ChanSubscribe": stream(catalog.ChannelReceive, 0, -1, -1),
63
+ "QueueSubscribe": stream(catalog.ChannelReceive, 0, 1, -1),
64
+ "QueueSubscribeSync": stream(catalog.ChannelReceive, 0, 1, -1),
65
+ "ChanQueueSubscribe": stream(catalog.ChannelReceive, 0, 1, -1),
66
+ "PullSubscribe": stream(catalog.ChannelReceive, 0, -1, 1),
67
+ "Publish": stream(catalog.ChannelSend, 0, -1, -1),
68
+ "PublishAsync": stream(catalog.ChannelSend, 0, -1, -1),
69
+ "PublishMsg": streamMsg(0),
70
+ "PublishMsgAsync": streamMsg(0),
71
+ },
72
+ jsPkg + ".JetStream": {
73
+ "Publish": stream(catalog.ChannelSend, 1, -1, -1),
74
+ "PublishAsync": stream(catalog.ChannelSend, 1, -1, -1),
75
+ "PublishMsg": streamMsg(1),
76
+ "PublishMsgAsync": streamMsg(1),
77
+ "CreateOrUpdateConsumer": consumer(2),
78
+ "CreateConsumer": consumer(2),
79
+ "UpdateConsumer": consumer(2),
80
+ "OrderedConsumer": consumer(2),
81
+ },
82
+ jsPkg + ".Stream": {
83
+ "CreateOrUpdateConsumer": consumer(1),
84
+ "CreateConsumer": consumer(1),
85
+ "UpdateConsumer": consumer(1),
86
+ "OrderedConsumer": consumer(1),
87
+ },
88
+ }
89
+
90
+ // site is one nats.go call as found: where, which way, and the expressions
91
+ // that name the subject, the queue group and the durable consumer - still
92
+ // expressions, since what they are worth may be decided by a caller.
93
+ type site struct {
94
+ fn *function
95
+ method string
96
+ direction catalog.ChannelDirection
97
+ api string
98
+ configured bool
99
+ subjects []ast.Expr
100
+ queue ast.Expr
101
+ durable ast.Expr
102
+ at goscan.Source
103
+ }
104
+
105
+ // sites is every nats.go call in the tree, in source order.
106
+ func (s *scanner) sites() []site {
107
+ var out []site
108
+ for _, fn := range s.sortedFunctions() {
109
+ ast.Inspect(fn.decl.Body, func(node ast.Node) bool {
110
+ call, ok := node.(*ast.CallExpr)
111
+ if !ok {
112
+ return true
113
+ }
114
+ sel, ok := call.Fun.(*ast.SelectorExpr)
115
+ if !ok {
116
+ return true
117
+ }
118
+ spec, known := natsCalls[s.typeOf(sel.X, fn)][sel.Sel.Name]
119
+ if !known {
120
+ return true
121
+ }
122
+ out = append(out, s.site(fn, call, sel.Sel.Name, spec))
123
+ return true
124
+ })
125
+ }
126
+ return out
127
+ }
128
+
129
+ func (s *scanner) site(fn *function, call *ast.CallExpr, method string, spec natsCall) site {
130
+ found := site{fn: fn, method: method, direction: spec.direction, api: spec.api, at: s.At(call.Pos())}
131
+ arg := func(index int) ast.Expr {
132
+ if index >= 0 && index < len(call.Args) {
133
+ return call.Args[index]
134
+ }
135
+ return nil
136
+ }
137
+ if subject := arg(spec.subject); subject != nil {
138
+ found.subjects = []ast.Expr{subject}
139
+ }
140
+ if message := arg(spec.message); message != nil {
141
+ if subject := s.messageSubject(message, fn, map[string]bool{}); subject != nil {
142
+ found.subjects = []ast.Expr{subject}
143
+ }
144
+ }
145
+ if config := arg(spec.config); config != nil {
146
+ found.configured = true
147
+ found.subjects, found.durable = s.consumerConfig(config, fn)
148
+ }
149
+ found.queue = arg(spec.queue)
150
+ if found.durable == nil {
151
+ found.durable = arg(spec.durable)
152
+ }
153
+ // The legacy API takes the durable name as an option.
154
+ for _, option := range call.Args {
155
+ if optionCall, ok := option.(*ast.CallExpr); ok && s.externalKey(optionCall, fn) == natsPkg+".Durable" && len(optionCall.Args) == 1 {
156
+ found.durable = optionCall.Args[0]
157
+ }
158
+ }
159
+ return found
160
+ }
161
+
162
+ // messageSubject is the subject a *nats.Msg was built with: nats.NewMsg(x),
163
+ // &nats.Msg{Subject: x}, or a local that was given one of those.
164
+ func (s *scanner) messageSubject(expr ast.Expr, fn *function, seen map[string]bool) ast.Expr {
165
+ switch value := goscan.Unwrap(expr).(type) {
166
+ case *ast.CallExpr:
167
+ if s.externalKey(value, fn) == natsPkg+".NewMsg" && len(value.Args) == 1 {
168
+ return value.Args[0]
169
+ }
170
+ case *ast.CompositeLit:
171
+ if s.TypeKey(value.Type, fn.file) == natsPkg+".Msg" {
172
+ return field(value, "Subject")
173
+ }
174
+ case *ast.Ident:
175
+ if seen[value.Name] {
176
+ return nil
177
+ }
178
+ seen[value.Name] = true
179
+ if given, ok := s.assignedTo(fn, value.Name); ok && given.index == 0 {
180
+ return s.messageSubject(given.expr, fn, seen)
181
+ }
182
+ }
183
+ return nil
184
+ }
185
+
186
+ // consumerConfig is what a JetStream consumer config filters on and is
187
+ // called: FilterSubject, or each of FilterSubjects, and Durable.
188
+ func (s *scanner) consumerConfig(expr ast.Expr, fn *function) (subjects []ast.Expr, durable ast.Expr) {
189
+ lit, ok := goscan.Unwrap(expr).(*ast.CompositeLit)
190
+ if !ok {
191
+ if ident, isIdent := goscan.Unwrap(expr).(*ast.Ident); isIdent {
192
+ if given, found := s.assignedTo(fn, ident.Name); found && given.index == 0 {
193
+ lit, ok = goscan.Unwrap(given.expr).(*ast.CompositeLit)
194
+ }
195
+ }
196
+ }
197
+ if !ok {
198
+ return nil, nil
199
+ }
200
+ if single := field(lit, "FilterSubject"); single != nil {
201
+ subjects = append(subjects, single)
202
+ }
203
+ if many, isList := goscan.Unwrap(field(lit, "FilterSubjects")).(*ast.CompositeLit); isList {
204
+ subjects = append(subjects, many.Elts...)
205
+ }
206
+ return subjects, field(lit, "Durable")
207
+ }
208
+
209
+ // field is the value a composite literal gives a named field, or nil.
210
+ func field(lit *ast.CompositeLit, name string) ast.Expr {
211
+ if lit == nil {
212
+ return nil
213
+ }
214
+ for _, raw := range lit.Elts {
215
+ pair, ok := raw.(*ast.KeyValueExpr)
216
+ if !ok {
217
+ continue
218
+ }
219
+ if key, ok := pair.Key.(*ast.Ident); ok && key.Name == name {
220
+ return pair.Value
221
+ }
222
+ }
223
+ return nil
224
+ }
@@ -0,0 +1,19 @@
1
+ package main
2
+
3
+ import (
4
+ _ "embed"
5
+
6
+ "github.com/shortlink-org/portolan/plugin"
7
+ )
8
+
9
+ //go:embed options.schema.json
10
+ var optionsSchema []byte
11
+
12
+ func descriptor() plugin.Descriptor {
13
+ return plugin.Descriptor{
14
+ Name: "extract-graphql",
15
+ Summary: "Reads a GraphQL schema and answers with the interfaces a service provides, one per schema module.",
16
+ Phases: []string{plugin.PhaseExtract},
17
+ Options: optionsSchema,
18
+ }
19
+ }
@@ -0,0 +1,11 @@
1
+ package main
2
+
3
+ import (
4
+ "testing"
5
+
6
+ "github.com/shortlink-org/portolan/plugin/schematest"
7
+ )
8
+
9
+ func TestOptionsSchemaMatchesStruct(t *testing.T) {
10
+ schematest.Check(t, optionsSchema, Options{})
11
+ }
@@ -0,0 +1,433 @@
1
+ package main
2
+
3
+ // The schema in, the interfaces a service provides out.
4
+ //
5
+ // A GraphQL schema says three things a catalog wants: what a client may ask
6
+ // for, what comes back, and which of those answers keep arriving. The first
7
+ // two are what every other interface in this estate already carries - methods
8
+ // with a request and a response - and the third is what `Streaming` is for: a
9
+ // subscription is a server stream, and drawing it as a call would be a lie
10
+ // about how the two ends are coupled.
11
+ //
12
+ // What it deliberately does not say is who answers underneath. A BFF's whole
13
+ // job is to fan out to other services, and the schema is silent about that on
14
+ // purpose - the resolvers know, and the extractor that reads the resolvers is
15
+ // the one that reports the calls.
16
+
17
+ import (
18
+ "encoding/json"
19
+ "fmt"
20
+ "io/fs"
21
+ "os"
22
+ "path/filepath"
23
+ "sort"
24
+ "strings"
25
+
26
+ "github.com/shortlink-org/portolan/catalog"
27
+ "github.com/shortlink-org/portolan/plugin"
28
+ )
29
+
30
+ // operations are the three root operation types, in the order a reader meets
31
+ // them: ask, change, keep listening.
32
+ var operations = []string{"query", "mutation", "subscription"}
33
+
34
+ func extract(in plugin.Input, opts Options) (plugin.Response, error) {
35
+ b := &plugin.Builder{}
36
+ root := in.Root
37
+
38
+ if opts.Context == "" {
39
+ opts.Context = filepath.Base(root)
40
+ }
41
+ if opts.Service == "" {
42
+ opts.Service = filepath.Base(root)
43
+ }
44
+ api := opts.API
45
+ if api == "" {
46
+ api = opts.Service + ".v1"
47
+ }
48
+
49
+ files, err := findSchema(root, opts.Schema)
50
+ if err != nil {
51
+ return plugin.Response{}, err
52
+ }
53
+
54
+ doc := newDocument()
55
+ for _, file := range files {
56
+ source, err := os.ReadFile(file)
57
+ if err != nil {
58
+ return plugin.Response{}, err
59
+ }
60
+ if err := parseInto(doc, string(source), filepath.ToSlash(file), moduleOf(root, file)); err != nil {
61
+ return plugin.Response{}, err
62
+ }
63
+ }
64
+
65
+ provides := rpcServices(doc, api, b)
66
+ if len(provides) == 0 {
67
+ b.Warn(opts.Context+"."+opts.Service, strings.Join(relAll(files), ", ")+" declares no root fields; nothing answers over this schema")
68
+ }
69
+
70
+ fragment := catalog.Catalog{
71
+ GeneratedAt: in.GeneratedAt,
72
+ Commit: in.Commit,
73
+ Contexts: []catalog.BoundedContext{{
74
+ ID: opts.Context,
75
+ Slug: opts.Context,
76
+ // Named by whichever source knows the name. A schema says what the
77
+ // service answers, not what the service is called.
78
+ Services: []catalog.Service{{
79
+ ID: opts.Context + "." + opts.Service,
80
+ Slug: opts.Service,
81
+ Provides: provides,
82
+ Consumes: []catalog.RpcCall{},
83
+ Aggregates: []catalog.Aggregate{},
84
+ }},
85
+ }},
86
+ Defs: map[string]catalog.TypeDef{},
87
+ Flows: []catalog.Flow{},
88
+ Adrs: []catalog.Adr{},
89
+ }
90
+
91
+ encoded, err := json.MarshalIndent(fragment, "", " ")
92
+ if err != nil {
93
+ return plugin.Response{}, err
94
+ }
95
+
96
+ b.File(firstNonEmpty(opts.Out, "graphql.json"), string(encoded)+"\n")
97
+
98
+ return b.Response(), nil
99
+ }
100
+
101
+ // rpcServices groups the root fields by the module that declared them.
102
+ //
103
+ // A tag is how an OpenAPI author says "these endpoints belong together"; a
104
+ // schema module - one directory, one `schema.graphql` - is how a GraphQL
105
+ // author says it, and it has the advantage of being a file, so the interface
106
+ // can point at something a reader can open. A schema written in one file has
107
+ // one group, named by the api itself, exactly as an untagged document is.
108
+ func rpcServices(doc *document, api string, b *plugin.Builder) []catalog.RpcService {
109
+ type group struct {
110
+ methods []catalog.RpcMethod
111
+ // extra are the argument shapes invented for this interface. Nobody
112
+ // declared them, so they are carried here rather than looked up.
113
+ extra []catalog.RpcMessage
114
+ queue []string
115
+ seen map[string]bool
116
+ source string
117
+ }
118
+
119
+ groups := map[string]*group{}
120
+ var order []string
121
+
122
+ for _, operation := range operations {
123
+ rootName := doc.root(operation)
124
+ rootType := doc.types[rootName]
125
+ if rootType == nil {
126
+ continue
127
+ }
128
+
129
+ for _, field := range rootType.fields {
130
+ id := interfaceID(api, field.module)
131
+ g, ok := groups[id]
132
+ if !ok {
133
+ g = &group{seen: map[string]bool{}, source: field.file}
134
+ groups[id] = g
135
+ order = append(order, id)
136
+ }
137
+ if g.source != field.file {
138
+ // One module, two files. The interface can only point at one
139
+ // of them, and a reader following it to the wrong half would
140
+ // not know it had.
141
+ b.Warn(id, "root fields come from both "+g.source+" and "+field.file+"; the interface points at the first")
142
+ }
143
+
144
+ method := catalog.RpcMethod{
145
+ Name: methodName(rootName, field.name),
146
+ Doc: field.doc,
147
+ Response: field.typ.name,
148
+ Deprecated: field.deprecated,
149
+ }
150
+ if field.deprecated && field.reason != "" {
151
+ method.Doc = strings.TrimSpace(method.Doc + "\n\nDeprecated: " + field.reason)
152
+ }
153
+ if operation == "subscription" {
154
+ method.Streaming = catalog.StreamingServer
155
+ }
156
+
157
+ request, invented := requestOf(doc, rootName, field)
158
+ method.Request = request
159
+ if invented != nil {
160
+ g.extra = append(g.extra, *invented)
161
+ } else {
162
+ enqueue(doc, g.seen, &g.queue, request)
163
+ }
164
+ for _, arg := range field.args {
165
+ enqueue(doc, g.seen, &g.queue, arg.typ.name)
166
+ }
167
+ enqueue(doc, g.seen, &g.queue, field.typ.name)
168
+
169
+ g.methods = append(g.methods, method)
170
+ }
171
+ }
172
+
173
+ sort.Strings(order)
174
+
175
+ out := make([]catalog.RpcService, 0, len(order))
176
+ for _, id := range order {
177
+ g := groups[id]
178
+ out = append(out, catalog.RpcService{
179
+ ID: id,
180
+ Methods: g.methods,
181
+ Source: g.source,
182
+ Messages: append(g.extra, messages(doc, g.seen, g.queue)...),
183
+ })
184
+ }
185
+
186
+ return out
187
+ }
188
+
189
+ // requestOf names what a field is given.
190
+ //
191
+ // A field whose whole input is one input object is already named by the
192
+ // schema, and inventing a second name for it would be noise. A field with
193
+ // loose arguments has no name for them, so one is made and the arguments
194
+ // become its fields.
195
+ func requestOf(doc *document, rootName string, field fieldDef) (string, *catalog.RpcMessage) {
196
+ if len(field.args) == 0 {
197
+ return "", nil
198
+ }
199
+ if len(field.args) == 1 {
200
+ if t := doc.types[field.args[0].typ.name]; t != nil && t.kind == kindInput && !field.args[0].typ.list {
201
+ return t.name, nil
202
+ }
203
+ }
204
+
205
+ message := catalog.RpcMessage{Name: argsMessage(rootName, field.name)}
206
+ for _, arg := range field.args {
207
+ message.Fields = append(message.Fields, catalog.Field{
208
+ Name: arg.name,
209
+ Type: spell(doc, arg.typ),
210
+ Doc: optional(arg.doc, arg.typ),
211
+ })
212
+ }
213
+
214
+ return message.Name, &message
215
+ }
216
+
217
+ func enqueue(doc *document, seen map[string]bool, queue *[]string, name string) {
218
+ t := doc.types[name]
219
+ if t == nil || seen[name] {
220
+ return
221
+ }
222
+ switch t.kind {
223
+ case kindObject, kindInput, kindInterface, kindUnion:
224
+ seen[name] = true
225
+ *queue = append(*queue, name)
226
+ }
227
+ }
228
+
229
+ // messages turns every type the group's fields reach into a named shape.
230
+ //
231
+ // The list grows while it is walked - a response names a type, that type names
232
+ // another - for the same reason the OpenAPI extractor's does: a reader who has
233
+ // to follow three links to find out what came back has been given a worse
234
+ // document than the schema.
235
+ func messages(doc *document, seen map[string]bool, queue []string) []catalog.RpcMessage {
236
+ out := []catalog.RpcMessage{}
237
+
238
+ for i := 0; i < len(queue); i++ {
239
+ t := doc.types[queue[i]]
240
+ if t == nil {
241
+ continue
242
+ }
243
+
244
+ message := catalog.RpcMessage{Name: t.name, Fields: []catalog.Field{}}
245
+ for _, field := range t.fields {
246
+ prose := optional(field.doc, field.typ)
247
+ if field.deprecated {
248
+ prose = strings.TrimSpace(prose + "\n\nDeprecated: " + field.reason)
249
+ }
250
+ message.Fields = append(message.Fields, catalog.Field{
251
+ Name: field.name,
252
+ Type: spell(doc, field.typ),
253
+ Doc: prose,
254
+ })
255
+ enqueue(doc, seen, &queue, field.typ.name)
256
+ for _, arg := range field.args {
257
+ enqueue(doc, seen, &queue, arg.typ.name)
258
+ }
259
+ }
260
+ if d := discriminator(doc, t); d != nil {
261
+ message.Discriminator = d
262
+ for _, variant := range d.Variants {
263
+ enqueue(doc, seen, &queue, variant.Message)
264
+ }
265
+ }
266
+ out = append(out, message)
267
+ }
268
+
269
+ return out
270
+ }
271
+
272
+ // discriminator is how a polymorphic answer says which shape it is. GraphQL
273
+ // has one answer for both of its ways of being polymorphic, and it is the same
274
+ // field a client would select: `__typename`.
275
+ func discriminator(doc *document, t *typeDef) *catalog.RpcDiscriminator {
276
+ var members []string
277
+ switch t.kind {
278
+ case kindUnion:
279
+ members = t.members
280
+ case kindInterface:
281
+ for _, name := range doc.order {
282
+ other := doc.types[name]
283
+ if other.kind == kindObject && contains(other.implements, t.name) {
284
+ members = append(members, other.name)
285
+ }
286
+ }
287
+ }
288
+ if len(members) == 0 {
289
+ return nil
290
+ }
291
+
292
+ variants := make([]catalog.RpcVariant, 0, len(members))
293
+ for _, member := range members {
294
+ variants = append(variants, catalog.RpcVariant{Value: member, Message: member})
295
+ }
296
+
297
+ return &catalog.RpcDiscriminator{Property: "__typename", Variants: variants}
298
+ }
299
+
300
+ // spell renders a field's type. An enum carries its values along with its
301
+ // name, the way an OpenAPI enum does, because a status whose values are three
302
+ // clicks away is a status nobody reads.
303
+ func spell(doc *document, ref typeRef) string {
304
+ spelled := ref.spell()
305
+ if t := doc.types[ref.name]; t != nil && t.kind == kindEnum && len(t.values) > 0 {
306
+ spelled += " enum(" + strings.Join(t.values, " | ") + ")"
307
+ }
308
+
309
+ return spelled
310
+ }
311
+
312
+ // optional says in prose what `!` says in the schema, because that is where
313
+ // the rest of the catalog says it.
314
+ func optional(doc string, ref typeRef) string {
315
+ if ref.nonNull {
316
+ return doc
317
+ }
318
+
319
+ return strings.TrimSpace("Optional. " + doc)
320
+ }
321
+
322
+ // findSchema locates the documents. Told where they are - a file or a
323
+ // directory - it reads there; otherwise it searches, because a service with
324
+ // its schema in the conventional place should not have to say so.
325
+ func findSchema(root, declared string) ([]string, error) {
326
+ if declared != "" {
327
+ at := filepath.Join(root, filepath.FromSlash(declared))
328
+ info, err := os.Stat(at)
329
+ if err != nil {
330
+ return nil, err
331
+ }
332
+ if !info.IsDir() {
333
+ return []string{at}, nil
334
+ }
335
+
336
+ return walkSchema(at)
337
+ }
338
+
339
+ found, err := walkSchema(root)
340
+ if err != nil {
341
+ return nil, err
342
+ }
343
+ if len(found) == 0 {
344
+ return nil, fmt.Errorf("no graphql schema under %s, and none named in the options", root)
345
+ }
346
+
347
+ return found, nil
348
+ }
349
+
350
+ func walkSchema(dir string) ([]string, error) {
351
+ var found []string
352
+ err := filepath.WalkDir(dir, func(p string, entry fs.DirEntry, err error) error {
353
+ if err != nil {
354
+ return err
355
+ }
356
+ if entry.IsDir() {
357
+ switch entry.Name() {
358
+ case "node_modules", "dist", "vendor", ".git":
359
+ return filepath.SkipDir
360
+ }
361
+
362
+ return nil
363
+ }
364
+ switch filepath.Ext(entry.Name()) {
365
+ case ".graphql", ".graphqls", ".gql":
366
+ // The generator writes the whole schema out again beside the
367
+ // modules it read - `schema.generated.graphqls` - and reading that
368
+ // copy would give the estate a module nobody wrote, holding every
369
+ // field twice.
370
+ if !strings.Contains(entry.Name(), ".generated.") {
371
+ found = append(found, p)
372
+ }
373
+ }
374
+
375
+ return nil
376
+ })
377
+ if err != nil {
378
+ return nil, err
379
+ }
380
+ sort.Strings(found)
381
+
382
+ return found, nil
383
+ }
384
+
385
+ // moduleOf is what a file is called for the purpose of grouping. A schema
386
+ // written as `basket/schema.graphql` is the basket module; one written as
387
+ // `basket.graphql` is the same module said another way.
388
+ func moduleOf(root, file string) string {
389
+ rel, err := filepath.Rel(root, file)
390
+ if err != nil {
391
+ rel = file
392
+ }
393
+ name := strings.TrimSuffix(filepath.Base(rel), filepath.Ext(rel))
394
+ if name != "schema" && name != "index" {
395
+ return name
396
+ }
397
+
398
+ parent := filepath.Base(filepath.Dir(rel))
399
+ if parent == "." || parent == string(filepath.Separator) {
400
+ return ""
401
+ }
402
+
403
+ return parent
404
+ }
405
+
406
+ func relAll(files []string) []string {
407
+ out := make([]string, 0, len(files))
408
+ for _, file := range files {
409
+ out = append(out, filepath.ToSlash(file))
410
+ }
411
+
412
+ return out
413
+ }
414
+
415
+ func contains(values []string, want string) bool {
416
+ for _, value := range values {
417
+ if value == want {
418
+ return true
419
+ }
420
+ }
421
+
422
+ return false
423
+ }
424
+
425
+ func firstNonEmpty(values ...string) string {
426
+ for _, value := range values {
427
+ if strings.TrimSpace(value) != "" {
428
+ return value
429
+ }
430
+ }
431
+
432
+ return ""
433
+ }