@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,564 @@
1
+ package main
2
+
3
+ import (
4
+ "go/ast"
5
+ "go/parser"
6
+ "go/token"
7
+ "os"
8
+ "path"
9
+ "path/filepath"
10
+ "regexp"
11
+ "strconv"
12
+ "strings"
13
+
14
+ "github.com/pgplex/pgparser/nodes"
15
+ pgsql "github.com/pgplex/pgparser/parser"
16
+
17
+ "github.com/shortlink-org/portolan/plugin"
18
+ )
19
+
20
+ // Which domain field a column carries.
21
+ //
22
+ // This is the fact that makes a schema readable next to a model rather than
23
+ // beside it, and it is the one thing here that cannot be read off the layout.
24
+ // Column names do not carry it: `password_hash` is not `Password` by any rule
25
+ // that is not a guess, and a rule that guesses would be wrong quietly.
26
+ //
27
+ // What does carry it is the statement that writes the row:
28
+ //
29
+ // `INSERT INTO users (id, email, password_hash, created_at, version)
30
+ // VALUES ($1, $2, $3, $4, 1)`,
31
+ // u.ID, u.Email.String(), u.Password.String(), u.CreatedAt)
32
+ //
33
+ // Five columns, four arguments. The alignment is through the placeholders, not
34
+ // through the column order: `version` is written as a literal, and counting
35
+ // positions would have mapped it to a field it has nothing to do with.
36
+ //
37
+ // The rule is all-or-nothing per column. Either the chain from column to `$N`
38
+ // to argument to field is unambiguous, or the column gets no `maps` at all -
39
+ // a blank is a reader looking the column up themselves, and a wrong one is a
40
+ // reader believing something untrue.
41
+ func readMaps(root, repositoryDir, aggregate string, b *plugin.Builder) map[string]map[string]string {
42
+ out := map[string]map[string]string{}
43
+
44
+ dir := mapSourceDir(root, repositoryDir, aggregate)
45
+ entries, err := os.ReadDir(filepath.Join(root, filepath.FromSlash(dir)))
46
+ if err != nil {
47
+ return out
48
+ }
49
+
50
+ // The root type is the one the aggregate's package is named after, which is
51
+ // the same rule the domain extractor used to pick it.
52
+ root_ := title(aggregate)
53
+ fset := token.NewFileSet()
54
+
55
+ files := make([]*ast.File, 0, len(entries))
56
+
57
+ for _, entry := range entries {
58
+ name := entry.Name()
59
+ if entry.IsDir() || !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
60
+ continue
61
+ }
62
+
63
+ file, err := parser.ParseFile(fset, filepath.Join(root, filepath.FromSlash(dir), name), nil, parser.SkipObjectResolution)
64
+ if err != nil {
65
+ continue
66
+ }
67
+ files = append(files, file)
68
+ }
69
+
70
+ // A statement is routinely assembled from a shared column list rather than
71
+ // written whole, so the package's string constants are collected before
72
+ // anything is read and folded into the literals that name them.
73
+ constants := stringConstants(files)
74
+
75
+ for _, file := range files {
76
+ packages := importNames(file)
77
+
78
+ // One walk per declaration rather than one per file, because which
79
+ // identifier is the aggregate changes at every function: in Save it
80
+ // is the parameter typed as the root, and inside the loop over its
81
+ // lines the same shape of expression on the loop variable is a line's
82
+ // field, not the aggregate's.
83
+ for _, decl := range file.Decls {
84
+ fn, ok := decl.(*ast.FuncDecl)
85
+ if !ok || fn.Body == nil {
86
+ continue
87
+ }
88
+ s := scope{packages: packages, roots: rootParams(fn, root_), aliases: rangeAliases(fn)}
89
+
90
+ ast.Inspect(fn.Body, func(node ast.Node) bool {
91
+ call, ok := node.(*ast.CallExpr)
92
+ if !ok {
93
+ return true
94
+ }
95
+
96
+ table, sql, columns, values, args := readInsert(call, constants)
97
+ if table == "" {
98
+ return true
99
+ }
100
+
101
+ mapped := out[table]
102
+ if mapped == nil {
103
+ mapped = map[string]string{}
104
+ out[table] = mapped
105
+ }
106
+
107
+ // The parser records that a value IS a placeholder but not which
108
+ // one - ParamRef.Number comes back zero - so the numbers are read
109
+ // off the text and paired with the placeholders in order. If the
110
+ // two do not agree on how many there are, nothing is mapped:
111
+ // mapping by position from a disagreement is how a column ends up
112
+ // confidently pointing at the wrong field.
113
+ numbers := placeholderNumbers(sql)
114
+ if numbers == nil || countParams(values) != len(numbers) {
115
+ if countParams(values) > 0 {
116
+ b.Warn(table, "the insert into "+table+" has placeholders this reader cannot number; its columns are left unmapped")
117
+ }
118
+
119
+ return true
120
+ }
121
+
122
+ seen := 0
123
+ for i, column := range columns {
124
+ if i >= len(values) {
125
+ break
126
+ }
127
+
128
+ if _, ok := values[i].(*nodes.ParamRef); !ok {
129
+ // A literal, a default, an expression: written by the
130
+ // statement rather than carried from the aggregate.
131
+ continue
132
+ }
133
+
134
+ number := numbers[seen]
135
+ seen++
136
+
137
+ if number < 1 || number > len(args) {
138
+ b.Warn(table, "the insert refers to $"+itoa(number)+" but the call passes "+itoa(len(args))+" values; "+column+" is left unmapped")
139
+
140
+ continue
141
+ }
142
+
143
+ field := fieldOf(args[number-1], s)
144
+ if field == "" {
145
+ continue
146
+ }
147
+ mapped[column] = root_ + "." + field
148
+ }
149
+
150
+ return true
151
+ })
152
+ }
153
+ }
154
+
155
+ return out
156
+ }
157
+
158
+ // scope is what fieldOf needs to know about the code around an argument that
159
+ // the argument itself does not say: which bare names are packages, and which
160
+ // one is the aggregate.
161
+ type scope struct {
162
+ // packages are the names the file's imports bind. `time.Now()` and
163
+ // `q.ID()` are the same shape of expression, and this is what tells them
164
+ // apart without a type checker.
165
+ packages map[string]bool
166
+ // roots are the parameters of the enclosing function typed as the
167
+ // aggregate's root. Nil when it has none, in which case any bare name is
168
+ // taken for the aggregate, as it always was; a function that names the
169
+ // root can only mean the root by it.
170
+ roots map[string]bool
171
+ // aliases are the variables of the enclosing function's range loops and
172
+ // what each one ranges over: `for _, l := range q.Lines()` makes l stand
173
+ // for one of q.Lines(), so l.SKU() is Lines.SKU - a field of the
174
+ // elements of a field, which is what a child table's column carries.
175
+ aliases map[string]ast.Expr
176
+ }
177
+
178
+ // without is the scope with one alias forgotten, which is what following
179
+ // that alias reads the rest of the expression in: an alias cannot stand for
180
+ // itself, however the loop was written.
181
+ func (s scope) without(alias string) scope {
182
+ rest := make(map[string]ast.Expr, len(s.aliases))
183
+ for name, expr := range s.aliases {
184
+ if name != alias {
185
+ rest[name] = expr
186
+ }
187
+ }
188
+ s.aliases = rest
189
+
190
+ return s
191
+ }
192
+
193
+ // rangeAliases reads every range loop of fn: the value variable, and the
194
+ // expression it walks.
195
+ func rangeAliases(fn *ast.FuncDecl) map[string]ast.Expr {
196
+ var aliases map[string]ast.Expr
197
+ ast.Inspect(fn.Body, func(node ast.Node) bool {
198
+ loop, ok := node.(*ast.RangeStmt)
199
+ if !ok {
200
+ return true
201
+ }
202
+ value, ok := loop.Value.(*ast.Ident)
203
+ if !ok || value.Name == "_" {
204
+ return true
205
+ }
206
+ if aliases == nil {
207
+ aliases = map[string]ast.Expr{}
208
+ }
209
+ aliases[value.Name] = loop.X
210
+
211
+ return true
212
+ })
213
+
214
+ return aliases
215
+ }
216
+
217
+ // receiver says whether a bare identifier stands for the aggregate.
218
+ func (s scope) receiver(ident *ast.Ident) bool {
219
+ if s.packages[ident.Name] {
220
+ return false
221
+ }
222
+
223
+ return s.roots == nil || s.roots[ident.Name]
224
+ }
225
+
226
+ // importNames reads what the file calls each package it imports: the alias
227
+ // when there is one, the last path element otherwise. The last element is a
228
+ // guess only for a package whose directory is not its name, and a package like
229
+ // that used as a receiver would have to be a variable of the same name to be
230
+ // wrong.
231
+ func importNames(file *ast.File) map[string]bool {
232
+ names := map[string]bool{}
233
+ for _, spec := range file.Imports {
234
+ name := ""
235
+ if spec.Name != nil {
236
+ name = spec.Name.Name
237
+ } else {
238
+ name = path.Base(unquote(spec.Path.Value))
239
+ }
240
+ if name == "" || name == "_" || name == "." {
241
+ continue
242
+ }
243
+ names[name] = true
244
+ }
245
+
246
+ return names
247
+ }
248
+
249
+ // rootParams names the parameters of fn whose type is the aggregate's root:
250
+ // `u *user.User` when the root is User, whether the type is a pointer, is
251
+ // qualified by its package or is written bare. Nil when there is none.
252
+ func rootParams(fn *ast.FuncDecl, root string) map[string]bool {
253
+ var roots map[string]bool
254
+ if fn.Type.Params == nil {
255
+ return nil
256
+ }
257
+ for _, param := range fn.Type.Params.List {
258
+ if !typeNamed(param.Type, root) {
259
+ continue
260
+ }
261
+ for _, name := range param.Names {
262
+ if roots == nil {
263
+ roots = map[string]bool{}
264
+ }
265
+ roots[name.Name] = true
266
+ }
267
+ }
268
+
269
+ return roots
270
+ }
271
+
272
+ func typeNamed(expr ast.Expr, name string) bool {
273
+ switch t := expr.(type) {
274
+ case *ast.StarExpr:
275
+ return typeNamed(t.X, name)
276
+ case *ast.SelectorExpr:
277
+ return t.Sel.Name == name
278
+ case *ast.Ident:
279
+ return t.Name == name
280
+ }
281
+
282
+ return false
283
+ }
284
+
285
+ // readInsert pulls the parts out of a call whose argument is an INSERT: the
286
+ // table, its column list, the values written into it, and the arguments the
287
+ // placeholders stand for.
288
+ func readInsert(call *ast.CallExpr, constants map[string]string) (string, string, []string, []nodes.Node, []ast.Expr) {
289
+ for i, arg := range call.Args {
290
+ sql, ok := stringValue(arg, constants)
291
+ if !ok || !strings.Contains(strings.ToUpper(sql), "INSERT INTO") {
292
+ continue
293
+ }
294
+
295
+ tree, err := pgsql.Parse(sql)
296
+ if err != nil || len(tree.Items) == 0 {
297
+ return "", "", nil, nil, nil
298
+ }
299
+
300
+ insert, ok := tree.Items[0].(*nodes.InsertStmt)
301
+ if !ok || insert.Relation == nil {
302
+ return "", "", nil, nil, nil
303
+ }
304
+
305
+ var columns []string
306
+ for _, item := range items(insert.Cols) {
307
+ if target, ok := item.(*nodes.ResTarget); ok {
308
+ columns = append(columns, target.Name)
309
+ }
310
+ }
311
+
312
+ return relationName(insert.Relation), sql, columns, insertValues(insert), call.Args[i+1:]
313
+ }
314
+
315
+ return "", "", nil, nil, nil
316
+ }
317
+
318
+ // stringConstants collects the package's string constants, which is where a
319
+ // column list usually lives when a statement is not written whole.
320
+ func stringConstants(files []*ast.File) map[string]string {
321
+ out := map[string]string{}
322
+
323
+ for _, file := range files {
324
+ for _, decl := range file.Decls {
325
+ gen, ok := decl.(*ast.GenDecl)
326
+ if !ok || gen.Tok != token.CONST {
327
+ continue
328
+ }
329
+
330
+ for _, spec := range gen.Specs {
331
+ value, ok := spec.(*ast.ValueSpec)
332
+ if !ok {
333
+ continue
334
+ }
335
+ for i, name := range value.Names {
336
+ if i >= len(value.Values) {
337
+ break
338
+ }
339
+ if literal, ok := value.Values[i].(*ast.BasicLit); ok && literal.Kind == token.STRING {
340
+ out[name.Name] = unquote(literal.Value)
341
+ }
342
+ }
343
+ }
344
+ }
345
+ }
346
+
347
+ return out
348
+ }
349
+
350
+ // stringValue folds an expression down to the string it is, following the
351
+ // concatenation and the constants a statement is commonly built from. Anything
352
+ // it cannot fold answers false, and the statement is left alone rather than
353
+ // read half-resolved.
354
+ func stringValue(expr ast.Expr, constants map[string]string) (string, bool) {
355
+ switch value := expr.(type) {
356
+ case *ast.BasicLit:
357
+ if value.Kind != token.STRING {
358
+ return "", false
359
+ }
360
+
361
+ return unquote(value.Value), true
362
+
363
+ case *ast.Ident:
364
+ text, known := constants[value.Name]
365
+
366
+ return text, known
367
+
368
+ case *ast.ParenExpr:
369
+ return stringValue(value.X, constants)
370
+
371
+ case *ast.BinaryExpr:
372
+ if value.Op != token.ADD {
373
+ return "", false
374
+ }
375
+ left, ok := stringValue(value.X, constants)
376
+ if !ok {
377
+ return "", false
378
+ }
379
+ right, ok := stringValue(value.Y, constants)
380
+ if !ok {
381
+ return "", false
382
+ }
383
+
384
+ return left + right, true
385
+ }
386
+
387
+ return "", false
388
+ }
389
+
390
+ // placeholderNumbers reads $1, $2 ... out of the values clause, in the order
391
+ // they are written.
392
+ //
393
+ // It exists because the grammar port keeps a placeholder as a node with no
394
+ // number on it. Taking the order of the nodes as the order of the arguments
395
+ // would be right for every statement written in ascending order and wrong,
396
+ // silently, for the one that is not.
397
+ func placeholderNumbers(sql string) []int {
398
+ upper := strings.ToUpper(sql)
399
+
400
+ at := strings.LastIndex(upper, "VALUES")
401
+ if at < 0 {
402
+ return nil
403
+ }
404
+
405
+ clause := sql[at:]
406
+ if end := strings.Index(strings.ToUpper(clause), "RETURNING"); end >= 0 {
407
+ clause = clause[:end]
408
+ }
409
+ if end := strings.Index(strings.ToUpper(clause), "ON CONFLICT"); end >= 0 {
410
+ clause = clause[:end]
411
+ }
412
+
413
+ var out []int
414
+ for _, match := range placeholder.FindAllStringSubmatch(clause, -1) {
415
+ number, err := strconv.Atoi(match[1])
416
+ if err != nil {
417
+ return nil
418
+ }
419
+ out = append(out, number)
420
+ }
421
+
422
+ return out
423
+ }
424
+
425
+ var placeholder = regexp.MustCompile(`\$(\d+)`)
426
+
427
+ func countParams(values []nodes.Node) int {
428
+ n := 0
429
+ for _, value := range values {
430
+ if _, ok := value.(*nodes.ParamRef); ok {
431
+ n++
432
+ }
433
+ }
434
+
435
+ return n
436
+ }
437
+
438
+ // insertValues is the single VALUES row of an insert. An insert from a SELECT,
439
+ // or one writing more than one row, is not read: the first has no per-column
440
+ // argument to find and the second would need every row to agree.
441
+ func insertValues(insert *nodes.InsertStmt) []nodes.Node {
442
+ source, ok := insert.SelectStmt.(*nodes.SelectStmt)
443
+ if !ok {
444
+ return nil
445
+ }
446
+
447
+ rows := items(source.ValuesLists)
448
+ if len(rows) != 1 {
449
+ return nil
450
+ }
451
+
452
+ row, ok := rows[0].(*nodes.List)
453
+ if !ok {
454
+ return nil
455
+ }
456
+
457
+ return row.Items
458
+ }
459
+
460
+ // fieldOf reads the field an argument came from: `u.ID` is ID, and
461
+ // `u.Email.String()` is Email, because what the column carries is the value
462
+ // object, not the conversion applied to it on the way out. An aggregate that
463
+ // keeps its fields unexported hands them out through getters, and `q.ID()` is
464
+ // ID by the same reading: a method with no arguments on the aggregate itself
465
+ // is the field it is named after, in whatever case the domain spells it.
466
+ //
467
+ // The first selector standing on the aggregate wins. Anything with no such
468
+ // selector - a local variable, a function of several fields, a literal -
469
+ // answers empty, and the column stays unmapped.
470
+ func fieldOf(arg ast.Expr, s scope) string {
471
+ for {
472
+ switch expr := arg.(type) {
473
+ case *ast.CallExpr:
474
+ // Three shapes hide the field in different places, and they look
475
+ // alike. `u.Email.String()` and `q.Total().AmountMinor()` read it
476
+ // off their receiver, which is itself a selector or a call on
477
+ // one; `q.ID()` reads it off the aggregate, with nothing to pass;
478
+ // `pgtype.Text(u.Email)` takes it as an argument. What tells the
479
+ // last from the second without a type checker is the file's
480
+ // imports: a call with no arguments on a package name is a
481
+ // function, and on anything else a getter.
482
+ if method, ok := expr.Fun.(*ast.SelectorExpr); ok {
483
+ switch on := method.X.(type) {
484
+ case *ast.SelectorExpr, *ast.CallExpr:
485
+ arg = expr.Fun
486
+
487
+ continue
488
+ case *ast.Ident:
489
+ if len(expr.Args) == 0 && !s.packages[on.Name] {
490
+ arg = expr.Fun
491
+
492
+ continue
493
+ }
494
+ }
495
+ }
496
+
497
+ // Otherwise the value came through the call, and only an argument
498
+ // of exactly one says which field: a function of two has no single
499
+ // field to name, and one of none has no field at all.
500
+ if len(expr.Args) != 1 {
501
+ return ""
502
+ }
503
+ arg = expr.Args[0]
504
+ case *ast.SelectorExpr:
505
+ if ident, ok := expr.X.(*ast.Ident); ok {
506
+ if over, ok := s.aliases[ident.Name]; ok {
507
+ head := fieldOf(over, s.without(ident.Name))
508
+ if head == "" {
509
+ return ""
510
+ }
511
+
512
+ return head + "." + expr.Sel.Name
513
+ }
514
+ if !s.receiver(ident) {
515
+ return ""
516
+ }
517
+
518
+ return expr.Sel.Name
519
+ }
520
+ arg = expr.X
521
+ case *ast.UnaryExpr:
522
+ arg = expr.X
523
+ case *ast.ParenExpr:
524
+ arg = expr.X
525
+ default:
526
+ return ""
527
+ }
528
+ }
529
+ }
530
+
531
+ // unquote handles both spellings a Go string literal comes in. The statements
532
+ // here are raw-quoted because they span lines, but a short one need not be.
533
+ // title is the type a package is named after: user becomes User,
534
+ // price_list becomes PriceList.
535
+ func title(name string) string {
536
+ var b strings.Builder
537
+ for _, word := range strings.FieldsFunc(name, func(r rune) bool { return r == '_' || r == '-' }) {
538
+ runes := []rune(word)
539
+ if runes[0] >= 'a' && runes[0] <= 'z' {
540
+ runes[0] = runes[0] - 'a' + 'A'
541
+ }
542
+ b.WriteString(string(runes))
543
+ }
544
+
545
+ return b.String()
546
+ }
547
+
548
+ func itoa(n int) string { return strconv.Itoa(n) }
549
+
550
+ func unquote(literal string) string {
551
+ if len(literal) >= 2 {
552
+ if literal[0] == '`' || literal[0] == '"' {
553
+ return literal[1 : len(literal)-1]
554
+ }
555
+ }
556
+
557
+ return literal
558
+ }
559
+
560
+ // slug is the id form of a package name: price_list becomes price-list, the
561
+ // way every extractor spells an aggregate.
562
+ func slug(name string) string {
563
+ return strings.ReplaceAll(name, "_", "-")
564
+ }
@@ -0,0 +1,117 @@
1
+ package main
2
+
3
+ // The same fact read out of a repository written in Java, where JPA already
4
+ // writes it down: an entity says which table it is and each field says which
5
+ // column it is.
6
+ //
7
+ // @Entity
8
+ // @Table(name = "payments")
9
+ // class PaymentEntity {
10
+ // @Column(name = "order_id", nullable = false)
11
+ // private String orderId;
12
+ //
13
+ // So this is the one language where the mapping is not read off the statements
14
+ // that write the rows - there are none to read, Spring Data writes them - but
15
+ // off the annotations that decide what those statements will say. A field with
16
+ // no @Column is still mapped: JPA derives the column from the field name, and
17
+ // the derivation is the same snake_case every Spring Boot project defaults to.
18
+ //
19
+ // The domain object is the entity's own name without the suffix the row shape
20
+ // carries: PostingEntity holds Posting, and a column of the postings table maps
21
+ // to `Posting.account` rather than to the aggregate root it hangs off.
22
+
23
+ import (
24
+ "os"
25
+ "path"
26
+ "path/filepath"
27
+ "regexp"
28
+ "strings"
29
+
30
+ "github.com/shortlink-org/portolan/plugin"
31
+ )
32
+
33
+ var (
34
+ javaEntity = regexp.MustCompile(`(?s)@Entity\b.*?@Table\s*\(\s*name\s*=\s*"([^"]+)"[^)]*\).*?(?:class|record)\s+(\w+)`)
35
+ javaColumn = regexp.MustCompile(`@Column\s*\(([^)]*)\)\s*(?:@[\w.]+\s*(?:\([^)]*\)\s*)?)*(?:private|protected|public)?\s*(?:final\s+)?[\w.<>\[\], ]+\s+(\w+)\s*[;=]`)
36
+ javaField = regexp.MustCompile(`(?m)^\s*(?:private|protected|public)\s+(?:final\s+)?[\w.<>\[\], ]+\s+(\w+)\s*;`)
37
+ javaName = regexp.MustCompile(`name\s*=\s*"([^"]+)"`)
38
+ )
39
+
40
+ func readMapsJava(root, repositoryDir, aggregate string, b *plugin.Builder) map[string]map[string]string {
41
+ out := map[string]map[string]string{}
42
+ dir := mapSourceDir(root, repositoryDir, aggregate)
43
+
44
+ entries, err := os.ReadDir(filepath.Join(root, filepath.FromSlash(dir)))
45
+ if err != nil {
46
+ return out
47
+ }
48
+
49
+ for _, entry := range entries {
50
+ name := entry.Name()
51
+ if entry.IsDir() || !strings.HasSuffix(name, ".java") {
52
+ continue
53
+ }
54
+
55
+ source, err := os.ReadFile(filepath.Join(root, filepath.FromSlash(dir), name))
56
+ if err != nil {
57
+ b.Warn(dir, path.Join(dir, name)+" could not be read: "+err.Error())
58
+
59
+ continue
60
+ }
61
+ text := string(source)
62
+
63
+ found := javaEntity.FindStringSubmatch(text)
64
+ if found == nil {
65
+ continue
66
+ }
67
+ table, block := found[1], strings.TrimSuffix(found[2], "Entity")
68
+
69
+ columns := map[string]string{}
70
+ // The annotated ones first: what the annotation says wins over what the
71
+ // name would have been derived to.
72
+ annotated := map[string]bool{}
73
+ for _, match := range javaColumn.FindAllStringSubmatch(text, -1) {
74
+ field := match[2]
75
+ column := field
76
+ if named := javaName.FindStringSubmatch(match[1]); named != nil {
77
+ column = named[1]
78
+ } else {
79
+ column = snake(field)
80
+ }
81
+ columns[column] = block + "." + field
82
+ annotated[field] = true
83
+ }
84
+ for _, match := range javaField.FindAllStringSubmatch(text, -1) {
85
+ field := match[1]
86
+ if annotated[field] {
87
+ continue
88
+ }
89
+ columns[snake(field)] = block + "." + field
90
+ }
91
+
92
+ if len(columns) > 0 {
93
+ out[table] = columns
94
+ }
95
+ }
96
+
97
+ return out
98
+ }
99
+
100
+ // snake is the column name JPA derives from a field when nothing says
101
+ // otherwise: orderId becomes order_id.
102
+ func snake(field string) string {
103
+ var b strings.Builder
104
+ for i, r := range field {
105
+ if r >= 'A' && r <= 'Z' {
106
+ if i > 0 {
107
+ b.WriteByte('_')
108
+ }
109
+ b.WriteRune(r - 'A' + 'a')
110
+
111
+ continue
112
+ }
113
+ b.WriteRune(r)
114
+ }
115
+
116
+ return b.String()
117
+ }