@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,126 @@
1
+ {
2
+ "type": "object",
3
+ "additionalProperties": false,
4
+ "properties": {
5
+ "context": {
6
+ "type": "string",
7
+ "description": "Slug of the bounded context this service belongs to. Defaults to the name of the input directory.",
8
+ "examples": ["shop"]
9
+ },
10
+ "contextName": {
11
+ "type": "string",
12
+ "description": "What the context is called on the page. Defaults to the slug, titled."
13
+ },
14
+ "contextSummary": {
15
+ "type": "string",
16
+ "description": "A sentence or two on what the context is responsible for."
17
+ },
18
+ "classification": {
19
+ "enum": ["core", "supporting", "generic"],
20
+ "description": "Whether the context is core to the business, supports it, or is generic and could be bought."
21
+ },
22
+ "service": {
23
+ "type": "string",
24
+ "description": "Slug of the service. Defaults to the name of the input directory.",
25
+ "examples": ["billing"]
26
+ },
27
+ "serviceName": {
28
+ "type": "string",
29
+ "description": "What the service is called on the page. Defaults to the title of its README, and failing that to the slug, titled."
30
+ },
31
+ "repo": {
32
+ "type": "string",
33
+ "description": "Where the source lives. Defaults to the repository url in pyproject.toml.",
34
+ "examples": ["github.com/shortlink-org/portolan"]
35
+ },
36
+ "store": {
37
+ "type": "string",
38
+ "description": "Slug of the database this service keeps its state in. Defaults from the kind of DATABASES['default'] when that setting is statically readable. The models are read as its schema, and a call into the ORM lands on its lane.",
39
+ "examples": ["pg"]
40
+ },
41
+ "storeName": {
42
+ "type": "string",
43
+ "description": "What the database is called on the page. Defaults to the service, titled, and the word database."
44
+ },
45
+ "storeKind": {
46
+ "enum": ["postgres", "mysql", "sqlite", "redis", "mongodb", "clickhouse", "s3", "other"],
47
+ "description": "Which database the models are the schema of. Read off DATABASES['default']['ENGINE'] in the settings module when left out; given here, it wins, and a disagreement with the settings is reported. It picks the column types a field becomes; only postgres has a mapping, and a kind without one keeps the field's own name and says so."
48
+ },
49
+ "apps": {
50
+ "type": "array",
51
+ "items": { "type": "string" },
52
+ "description": "The Django applications to read, as import packages, for a project that keeps them somewhere a models module would not be found. Every package holding one is read when this is left out.",
53
+ "examples": [["billing.invoices"]]
54
+ },
55
+ "aggregates": {
56
+ "type": "object",
57
+ "additionalProperties": { "type": "string" },
58
+ "description": "Which model is the root of an application's aggregate, as the application to the model. Only needed where the application is not named after its root - `invoices` finds `Invoice` on its own.",
59
+ "examples": [{ "invoices": "Invoice" }]
60
+ },
61
+ "peers": {
62
+ "type": "object",
63
+ "additionalProperties": { "type": "string" },
64
+ "description": "Which service answers for what this one calls, as the api id of the document vendored beside the client to the callee's service id. A client with no line here is called as unknown and its steps stay unresolved.",
65
+ "examples": [{ "pricing.v1": "shop.pricing" }]
66
+ },
67
+ "events": {
68
+ "type": "object",
69
+ "additionalProperties": { "type": "string" },
70
+ "description": "Which aggregate another service's events belong to, as the module a receiver imports the signal from to the aggregate id, so a policy reacting to a foreign event resolves.",
71
+ "examples": [{ "payments.events": "payments.ledger.payment" }]
72
+ },
73
+ "flowWrappers": {
74
+ "type": "object",
75
+ "additionalProperties": {
76
+ "type": "object",
77
+ "additionalProperties": false,
78
+ "properties": {
79
+ "label": {
80
+ "type": "string",
81
+ "description": "Business-facing label shown instead of expanding the wrapper's implementation. Defaults to the callable name, titled."
82
+ },
83
+ "target": {
84
+ "type": "string",
85
+ "description": "Service id the wrapper calls. Omit for a semantic operation inside this service."
86
+ },
87
+ "technical": {
88
+ "type": "boolean",
89
+ "default": false,
90
+ "description": "Collapse every call to this wrapper in one flow into one counted step."
91
+ }
92
+ }
93
+ },
94
+ "description": "Project callables that form a meaningful flow boundary, keyed as module.function or module.Class.method. Their internals are replaced by one semantic step; technical wrappers are also deduplicated per flow.",
95
+ "examples": [{
96
+ "util.logger.send_log": { "label": "Record application log", "technical": true },
97
+ "mailer.client.send": { "label": "Send email", "target": "messaging.mailer" }
98
+ }]
99
+ },
100
+ "source": {
101
+ "type": "string",
102
+ "description": "The directory the applications are looked for in, relative to the input root.",
103
+ "default": "."
104
+ },
105
+ "settings": {
106
+ "type": "string",
107
+ "description": "The Django settings module Celery is configured from, as an import spells it, so an enqueue lands on the queue the routes give it. Defaults to what manage.py sets DJANGO_SETTINGS_MODULE to.",
108
+ "examples": ["config.settings"]
109
+ },
110
+ "out": {
111
+ "type": "string",
112
+ "description": "Name of the fragment file, inside the step's output directory.",
113
+ "default": "domain.json"
114
+ },
115
+ "storesOut": {
116
+ "type": "string",
117
+ "description": "Name of the fragment holding the database the models describe, inside the step's output directory. Written when store is set or inferred from DATABASES['default'].",
118
+ "default": "stores.json"
119
+ },
120
+ "openapiOut": {
121
+ "type": "string",
122
+ "description": "Name of the inferred OpenAPI 3.1 document, inside the step's output directory. Written when URLConf exposes HTTP operations.",
123
+ "default": "openapi.inferred.yaml"
124
+ }
125
+ }
126
+ }
@@ -0,0 +1,214 @@
1
+ """Django URLConf, read without importing the project.
2
+
3
+ The runtime route table is assembled from ``path``/``re_path``, nested
4
+ ``include`` calls and DRF routers. Importing it would execute settings and
5
+ application code, so this module follows the same declarations through the
6
+ AST instead. The result is deliberately the wire fact only: target view,
7
+ HTTP path and the URLConf line that declared it.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import ast
13
+ import re
14
+ from dataclasses import dataclass
15
+ from typing import Dict, List, Optional, Set, Tuple
16
+
17
+ from celery_conf import follow, settings_module_name, str_value
18
+ from source import Module, Project, const_str, dotted, keyword
19
+
20
+
21
+ @dataclass(frozen=True)
22
+ class Route:
23
+ module: str
24
+ view: str
25
+ path: str
26
+ source: str
27
+ name: str = ""
28
+ router: bool = False
29
+ basename: str = ""
30
+ parameters: Tuple[Tuple[str, str], ...] = ()
31
+
32
+
33
+ @dataclass
34
+ class Routes:
35
+ root: Optional[Module]
36
+ entries: List[Route]
37
+ runtime_schema: str = ""
38
+
39
+ def for_view(self, module: str, view: str) -> List[Route]:
40
+ return [route for route in self.entries if route.module == module and route.view == view]
41
+
42
+
43
+ def read(project: Project, settings: str = "") -> Routes:
44
+ root = root_urlconf(project, settings)
45
+ if root is None:
46
+ return Routes(None, [])
47
+ entries: List[Route] = []
48
+ runtime_schema = ""
49
+ visit(project, root, "", (), entries, set())
50
+ for node in ast.walk(root.tree):
51
+ if isinstance(node, ast.Call) and dotted(node.func).split(".")[-1] in ("get_schema_view", "SpectacularAPIView"):
52
+ runtime_schema = root.where(node)
53
+ break
54
+ return Routes(root, entries, runtime_schema)
55
+
56
+
57
+ def root_urlconf(project: Project, settings: str = "") -> Optional[Module]:
58
+ settings_name = settings or settings_module_name(project)
59
+ module = project.module(settings_name) if settings_name else None
60
+ if module is not None:
61
+ for node in module.tree.body:
62
+ if not isinstance(node, (ast.Assign, ast.AnnAssign)):
63
+ continue
64
+ targets = node.targets if isinstance(node, ast.Assign) else [node.target]
65
+ if not any(isinstance(target, ast.Name) and target.id == "ROOT_URLCONF" for target in targets):
66
+ continue
67
+ value = node.value
68
+ name = str_value(follow(value, module), module)
69
+ if name and project.module(name) is not None:
70
+ return project.module(name)
71
+ package = settings_name.rsplit(".", 1)[0] if "." in settings_name else ""
72
+ if package and project.module(package + ".urls") is not None:
73
+ return project.module(package + ".urls")
74
+
75
+ # Conventional fallback for small projects whose settings are assembled
76
+ # dynamically: prefer a URLConf beside manage.py's package, otherwise the
77
+ # only non-application URLConf in the tree.
78
+ candidates = [m for m in project.modules.values() if m.dotted.endswith(".urls") or m.dotted == "urls"]
79
+ return candidates[0] if len(candidates) == 1 else None
80
+
81
+
82
+ def visit(project: Project, module: Module, prefix: str, prefix_parameters: Tuple[Tuple[str, str], ...], out: List[Route], seen: Set[Tuple[str, str]]) -> None:
83
+ key = (module.dotted, prefix)
84
+ if key in seen:
85
+ return
86
+ seen.add(key)
87
+
88
+ for node in ast.walk(module.tree):
89
+ if not isinstance(node, ast.Call) or dotted(node.func).split(".")[-1] not in ("path", "re_path", "url"):
90
+ continue
91
+ if len(node.args) < 2:
92
+ continue
93
+ # An empty string is a route too: `path("", include("invoices.urls"))`
94
+ # mounts an application at the root, and `path("", index)` is the
95
+ # root itself. Only a pattern that is not a literal is skipped.
96
+ first = node.args[0]
97
+ if not (isinstance(first, ast.Constant) and isinstance(first.value, str)):
98
+ continue
99
+ fragment = first.value
100
+ regex = dotted(node.func).split(".")[-1] != "path"
101
+ path = join_path(prefix, fragment, regex)
102
+ parameters = prefix_parameters + route_parameters(fragment, regex)
103
+ target = node.args[1]
104
+ if isinstance(target, ast.Call) and dotted(target.func).split(".")[-1] == "include":
105
+ included = include_module(project, module, target)
106
+ if included is not None:
107
+ visit(project, included, path, parameters, out, seen)
108
+ continue
109
+ resolved = view_target(project, module, target)
110
+ if resolved is None:
111
+ continue
112
+ target_module, view = resolved
113
+ out.append(Route(target_module, view, path, module.where(node), const_str(keyword(node, "name")), parameters=parameters))
114
+
115
+ # ``urlpatterns = router.urls`` contributes routes without a path() call.
116
+ # Each registration is mounted at every prefix by which this URLConf was
117
+ # reached from the root.
118
+ for node in ast.walk(module.tree):
119
+ if not isinstance(node, ast.Call) or dotted(node.func).split(".")[-1] != "register" or len(node.args) < 2:
120
+ continue
121
+ route_prefix = const_str(node.args[0]).strip("^/$")
122
+ resolved = view_target(project, module, node.args[1])
123
+ if not route_prefix or resolved is None:
124
+ continue
125
+ target_module, view = resolved
126
+ basename = const_str(keyword(node, "basename")) or route_prefix.replace("/", "_")
127
+ out.append(Route(target_module, view, join_path(prefix, route_prefix + "/"), module.where(node), router=True, basename=basename, parameters=prefix_parameters))
128
+
129
+
130
+ def route_parameters(fragment: str, regex: bool = False) -> Tuple[Tuple[str, str], ...]:
131
+ if regex:
132
+ return tuple((match.group(1), "str") for match in re.finditer(r"\(\?P<([A-Za-z_][A-Za-z0-9_]*)>[^)]+\)", fragment))
133
+ return tuple(
134
+ (match.group(2), match.group(1) or "str")
135
+ for match in re.finditer(r"<(?:(str|int|slug|uuid|path):)?([A-Za-z_][A-Za-z0-9_]*)>", fragment)
136
+ )
137
+
138
+
139
+ def include_module(project: Project, module: Module, call: ast.Call) -> Optional[Module]:
140
+ if not call.args:
141
+ return None
142
+ value = call.args[0]
143
+ if isinstance(value, (ast.Tuple, ast.List)) and value.elts:
144
+ value = value.elts[0]
145
+ name = const_str(value)
146
+ if name:
147
+ return project.module(name)
148
+ resolved = imported_name(project, module, dotted(value))
149
+ return project.module(resolved) if resolved else None
150
+
151
+
152
+ def view_target(project: Project, module: Module, node: ast.AST) -> Optional[Tuple[str, str]]:
153
+ # Decorators and ``SomeView().as_view()`` wrap the same target. Peeling
154
+ # calls is safe here because only names are read; nothing is executed.
155
+ while isinstance(node, ast.Call):
156
+ name = dotted(node.func)
157
+ if name.endswith(".as_view"):
158
+ node = node.func.value # type: ignore[union-attr]
159
+ continue
160
+ if node.args and name.split(".")[-1] in ("csrf_exempt", "login_required", "permission_required"):
161
+ node = node.args[0]
162
+ continue
163
+ if isinstance(node.func, ast.Attribute) and node.func.attr == "as_view":
164
+ node = node.func.value
165
+ continue
166
+ break
167
+ name = dotted(node)
168
+ if not name:
169
+ return None
170
+ parts = name.split(".")
171
+ resolved = imported_name(project, module, name)
172
+ if resolved:
173
+ parts = resolved.split(".")
174
+ for end in range(len(parts) - 1, 0, -1):
175
+ target_module = ".".join(parts[:end])
176
+ if project.module(target_module) is not None:
177
+ return target_module, ".".join(parts[end:])
178
+ if len(parts) == 1:
179
+ return module.dotted, parts[0]
180
+ return None
181
+
182
+
183
+ def imported_name(project: Project, module: Module, name: str) -> str:
184
+ parts = name.split(".")
185
+ imported = module.imports.get(parts[0])
186
+ if imported is None:
187
+ return name if project.module(".".join(parts[:-1])) is not None else ""
188
+ base = imported.module
189
+ if imported.name != "*":
190
+ base = ".".join(part for part in (base, imported.name) if part)
191
+ rest = parts[1:]
192
+ # ``from avia.views import booking`` names the submodule
193
+ # ``avia.views.booking``; ``from .views import View`` names the class in
194
+ # ``app.views``. Prefer the longest prefix that is an actual module.
195
+ candidates = []
196
+ combined = [part for part in base.split(".") if part] + rest
197
+ for end in range(len(combined), 0, -1):
198
+ prefix = ".".join(combined[:end])
199
+ if project.module(prefix) is not None:
200
+ candidates.append(prefix + ("." + ".".join(combined[end:]) if combined[end:] else ""))
201
+ return candidates[0] if candidates else ".".join(combined)
202
+
203
+
204
+ def join_path(prefix: str, fragment: str, regex: bool = False) -> str:
205
+ value = fragment
206
+ if regex:
207
+ value = value.removeprefix("^").removesuffix("$")
208
+ value = re.sub(r"\(\?P<([A-Za-z_][A-Za-z0-9_]*)>[^)]+\)", r"{\1}", value)
209
+ value = value.replace("\\/", "/")
210
+ value = re.sub(r"\\[AbZ]", "", value)
211
+ value = re.sub(r"<(?:(?:str|int|slug|uuid|path):)?([A-Za-z_][A-Za-z0-9_]*)>", r"{\1}", value)
212
+ joined = "/".join(part.strip("/") for part in (prefix, value) if part.strip("/"))
213
+ trailing = value.endswith("/")
214
+ return "/" + joined + ("/" if trailing and joined else "")
@@ -0,0 +1,198 @@
1
+ import os
2
+ import sys
3
+ import tempfile
4
+ import unittest
5
+
6
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
7
+ sys.path.insert(1, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "pyplugin"))
8
+
9
+ import apps # noqa: E402
10
+ import routing # noqa: E402
11
+ import serializers # noqa: E402
12
+ import transport # noqa: E402
13
+ from extract import http_contracts, openapi_document, routed_applications # noqa: E402
14
+ from protocol import Builder # noqa: E402
15
+ from source import Project # noqa: E402
16
+
17
+
18
+ class StaticRoutes(unittest.TestCase):
19
+ def setUp(self):
20
+ self.holder = tempfile.TemporaryDirectory(prefix="portolan-django-routes-")
21
+ root = self.holder.name
22
+ files = {
23
+ "manage.py": 'os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")\n',
24
+ "config/settings.py": 'ROOT_URLCONF = "config.urls"\n',
25
+ "config/urls.py": '''
26
+ from django.urls import include, path
27
+ from drf_yasg.views import get_schema_view
28
+ schema_view = get_schema_view()
29
+ urlpatterns = [
30
+ path("api/v2/", include("orders.urls")),
31
+ path("health/", include("health.urls")),
32
+ path("", include("home.urls")),
33
+ path("swagger/", schema_view.with_ui("swagger")),
34
+ ]
35
+ ''',
36
+ "home/urls.py": '''
37
+ from django.urls import path
38
+ from .views import Home
39
+ urlpatterns = [path("", Home.as_view()), path("about/", Home.as_view())]
40
+ ''',
41
+ "home/views.py": '''
42
+ from rest_framework.views import APIView
43
+ class Home(APIView):
44
+ def get(self, request):
45
+ return None
46
+ ''',
47
+ "health/urls.py": '''
48
+ from django.urls import path
49
+ from .views import Ready
50
+ urlpatterns = [path("ready/", Ready.as_view())]
51
+ ''',
52
+ "health/views.py": '''
53
+ from rest_framework.views import APIView
54
+ class Ready(APIView):
55
+ def get(self, request):
56
+ return None
57
+ ''',
58
+ "orders/models.py": '''
59
+ from django.db import models
60
+ class Order(models.Model):
61
+ active = models.BooleanField(default=True)
62
+ ''',
63
+ "orders/serializers.py": '''
64
+ from rest_framework import serializers
65
+ from .models import Order
66
+ class OrderSerializer(serializers.ModelSerializer):
67
+ class Meta:
68
+ model = Order
69
+ fields = ("active",)
70
+ ''',
71
+ "orders/views.py": '''
72
+ from rest_framework import generics, viewsets
73
+ from rest_framework.views import APIView
74
+ from .models import Order
75
+ from .serializers import OrderSerializer
76
+
77
+ class OrderList(generics.ListCreateAPIView):
78
+ queryset = Order.objects.filter(active=True)
79
+ serializer_class = OrderSerializer
80
+
81
+ class OrderDetail(APIView):
82
+ def get(self, request):
83
+ """Read an order."""
84
+ pass
85
+ def delete(self, request):
86
+ pass
87
+
88
+ class OrderViewSet(viewsets.ModelViewSet):
89
+ serializer_class = OrderSerializer
90
+
91
+ class Health:
92
+ def get(request):
93
+ pass
94
+
95
+ class Maintenance:
96
+ @classmethod
97
+ def fetch(cls, request):
98
+ return None
99
+ ''',
100
+ "orders/urls.py": '''
101
+ from django.urls import path, re_path
102
+ from rest_framework.routers import DefaultRouter
103
+ from .views import Health, Maintenance, OrderDetail, OrderList, OrderViewSet
104
+
105
+ router = DefaultRouter()
106
+ router.register("orders", OrderViewSet, basename="order")
107
+ urlpatterns = [
108
+ path("manual/", OrderList.as_view(), name="order-list"),
109
+ path("manual/<uuid:pk>/", OrderDetail.as_view(), name="order-detail"),
110
+ re_path(r"^health/(?P<region>[^/]+)/$", Health.get),
111
+ path("maintenance/fetch", Maintenance.fetch),
112
+ ] + router.urls
113
+ ''',
114
+ }
115
+ for name, contents in files.items():
116
+ path = os.path.join(root, name)
117
+ directory = os.path.dirname(path)
118
+ if directory:
119
+ os.makedirs(directory, exist_ok=True)
120
+ with open(path, "w", encoding="utf-8") as handle:
121
+ handle.write(contents)
122
+ self.project = Project(root, root, lambda path: os.path.relpath(path, root).replace(os.sep, "/"))
123
+
124
+ def tearDown(self):
125
+ self.holder.cleanup()
126
+
127
+ def test_nested_includes_direct_views_regexes_and_runtime_swagger(self):
128
+ routes = routing.read(self.project)
129
+ self.assertEqual(routes.root.dotted, "config.urls")
130
+ self.assertEqual(routes.runtime_schema, "config/urls.py:4")
131
+ paths = {(route.view, route.path) for route in routes.entries}
132
+ self.assertIn(("OrderList", "/api/v2/manual/"), paths)
133
+ self.assertIn(("OrderDetail", "/api/v2/manual/{pk}/"), paths)
134
+ self.assertIn(("Health.get", "/api/v2/health/{region}/"), paths)
135
+ self.assertIn(("OrderViewSet", "/api/v2/orders/"), paths)
136
+ self.assertIn(("Ready", "/health/ready/"), paths)
137
+ # A root mount is the commonest way to include an application, and the
138
+ # empty prefix must not be read as "no route".
139
+ self.assertIn(("Home", "/"), paths)
140
+ self.assertIn(("Home", "/about/"), paths)
141
+ detail = next(route for route in routes.entries if route.view == "OrderDetail")
142
+ self.assertEqual(dict(detail.parameters), {"pk": "uuid"})
143
+
144
+ def test_drf_generic_and_router_methods_become_http_operations(self):
145
+ routes = routing.read(self.project)
146
+ app = apps.discover(self.project, ["orders"])[0]
147
+ endpoints = transport.read_endpoints(app, Builder(), routes)
148
+ http = {(item.verb, item.path) for item in endpoints}
149
+ self.assertIn(("GET", "/api/v2/manual/"), http)
150
+ self.assertIn(("POST", "/api/v2/manual/"), http)
151
+ self.assertIn(("GET", "/api/v2/manual/{pk}/"), http)
152
+ self.assertIn(("DELETE", "/api/v2/manual/{pk}/"), http)
153
+ self.assertIn(("GET", "/api/v2/orders/"), http)
154
+ self.assertIn(("POST", "/api/v2/orders/"), http)
155
+ self.assertIn(("GET", "/api/v2/orders/{id}/"), http)
156
+ self.assertIn(("PATCH", "/api/v2/orders/{id}/"), http)
157
+ self.assertIn(("GET", "/api/v2/health/{region}/"), http)
158
+ flow_only = next(item for item in endpoints if item.view == "Maintenance" and item.action == "fetch")
159
+ self.assertEqual((flow_only.verb, flow_only.path), ("", "/api/v2/maintenance/fetch"))
160
+ detail = next(item for item in endpoints if item.verb == "GET" and item.path.endswith("manual/{pk}/"))
161
+ self.assertEqual(detail.path_parameters, {"pk": "uuid"})
162
+ spec = openapi_document([(app, item) for item in endpoints], "Orders", Builder())
163
+ parameter = spec["paths"]["/api/v2/manual/{pk}/"]["get"]["parameters"][0]
164
+ self.assertEqual(parameter["schema"], {"type": "string", "format": "uuid"})
165
+
166
+ def test_queryset_and_serializer_metadata_resolve_the_inherited_action_model(self):
167
+ routes = routing.read(self.project)
168
+ app = apps.discover(self.project, ["orders"])[0]
169
+ endpoints = transport.read_endpoints(app, Builder(), routes)
170
+ registry = serializers.read(self.project, [app])
171
+ list_endpoint = next(item for item in endpoints if item.view == "OrderList" and item.action == "list")
172
+ create_endpoint = next(item for item in endpoints if item.view == "OrderViewSet" and item.action == "create")
173
+ self.assertEqual(registry.model_for_endpoint(list_endpoint).name, "Order")
174
+ self.assertEqual(registry.model_for_endpoint(create_endpoint).name, "Order")
175
+
176
+ def test_stateless_routed_app_still_contributes_an_http_interface(self):
177
+ routes = routing.read(self.project)
178
+ model_apps = apps.discover(self.project, [])
179
+ endpoint_apps = routed_applications(self.project, model_apps, routes)
180
+ self.assertEqual([app.dotted for app in endpoint_apps], ["health", "home", "orders"])
181
+ endpoints = []
182
+ for app in endpoint_apps:
183
+ endpoints += [(app, endpoint) for endpoint in transport.read_endpoints(app, Builder(), routes)]
184
+ contracts = http_contracts(endpoints, "shop.billing", "billing/portolan/openapi.inferred.yaml")
185
+ health = [contract for contract in contracts if contract["id"] == "shop.billing.health"][0]
186
+ self.assertEqual(health["methods"], [{"name": "health_ready_get", "http": {"method": "GET", "path": "/health/ready/"}}])
187
+ home = [contract for contract in contracts if contract["id"] == "shop.billing.home"][0]
188
+ self.assertEqual(
189
+ home["methods"],
190
+ [
191
+ {"name": "about_get", "http": {"method": "GET", "path": "/about/"}},
192
+ {"name": "home_get", "http": {"method": "GET", "path": "/"}},
193
+ ],
194
+ )
195
+
196
+
197
+ if __name__ == "__main__":
198
+ unittest.main()