@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,53 @@
1
+ # Host
2
+
3
+ The side of portolan that runs. `npm run gen` reads the manifest, runs every
4
+ plugin it names, stamps and writes what comes back, merges the sources into
5
+ one estate and validates the union. Nothing here draws anything.
6
+
7
+ ## What it does
8
+
9
+ - Refuses a `portolan.json` that does not match `schema/portolan.schema.json`,
10
+ the schema `npm run schema` composes out of what every declared plugin says
11
+ it can be told.
12
+ - Runs three phases in order, extract, verify, generate, and hands each
13
+ plugin one JSON message: the input root, output directory and stamp for an
14
+ extractor, the merged catalog for a verifier or a generator, the step's
15
+ options unread. The output path lets a fragment point at a companion file
16
+ returned in the same response without letting the plugin write it itself.
17
+ - Stamps a fragment from the last commit that touched its input, never from a
18
+ clock, so a committed fragment changes exactly when its subject does
19
+ (portolan.0002).
20
+ - Writes the files a plugin named, refuses a name that climbs out of the
21
+ step's output directory, keeps a listing per step of what it wrote, and
22
+ deletes what stopped being generated (portolan.0001).
23
+ - Merges every source the manifest's globs find and validates the union with
24
+ the code the site runs: `src/merge.ts`, `src/catalog.ts`, `src/enrich.ts`.
25
+ - In `--check` mode writes nothing and fails on the first file that differs
26
+ from disk. Either way it leaves `.portolan/build-report.json` for the
27
+ Settings page.
28
+
29
+ ## What it does not do
30
+
31
+ - Know what any plugin can be told: options pass through, and the schema is
32
+ the plugins' answer, not the host's.
33
+ - Read a plugin's stdout for anything but the one message, or its stderr for
34
+ anything but notes; a warning is kept beside the step in the build report.
35
+ - Draw the C4 model: `gen-likec4.mjs` writes `likec4/` from the same merged
36
+ catalog, and the site draws.
37
+
38
+ ## Files
39
+
40
+ - `gen.mjs`, the three phases; `plugin-host.mjs` and
41
+ `plugin-wasm-worker.mjs`, one plugin run as a process or a wasm module;
42
+ `manifest.mjs`, the manifest read and checked; `catalog-sources.mjs`, the
43
+ merge; `output-path.mjs`, the one refusal of an unsafe name;
44
+ `build-report.mjs`, what the Settings page reads.
45
+ - `schema.mjs`, the manifest schema composed; `gen-likec4.mjs`, the C4 model;
46
+ `diff.mjs`, what a branch changes about the architecture; `forge-comment.mjs`,
47
+ that report put on the pull request as one comment kept current;
48
+ `forge-release.mjs`, the same report as one section of a release's notes;
49
+ `forge.mjs`, what those two share - which forge the CI is, and how to talk
50
+ to it; `vendor-lock.mjs`,
51
+ the commit a fetched copy is of; `site-docs.mjs`, generated documentation
52
+ put into the built site; `local-api.mjs`, what the dev server answers the
53
+ site with.
@@ -0,0 +1,60 @@
1
+ // The last generator run, for the Settings page.
2
+ //
3
+ // Unlike catalog fragments this is deliberately not committed: elapsed time
4
+ // and the wall clock are observations of one run, not reproducible catalog
5
+ // facts. Vite reduces this file again before it reaches the browser.
6
+
7
+ import { readFileSync } from "node:fs";
8
+ import { join } from "node:path";
9
+
10
+ import { writeOutputFile } from "./output-path.mjs";
11
+
12
+ export const BUILD_REPORT_DIR = ".portolan";
13
+ export const BUILD_REPORT_NAME = "build-report.json";
14
+
15
+ export function createBuildReport({
16
+ mode,
17
+ manifestSha256,
18
+ now = Date.now(),
19
+ }) {
20
+ return {
21
+ version: 1,
22
+ mode,
23
+ manifestSha256,
24
+ status: "running",
25
+ startedAt: new Date(now).toISOString(),
26
+ finishedAt: "",
27
+ durationMs: 0,
28
+ steps: [],
29
+ };
30
+ }
31
+
32
+ export function addBuildStep(report, step) {
33
+ report.steps.push({ ordinal: report.steps.length, ...step });
34
+ }
35
+
36
+ export function finishBuildReport(report, status, now = Date.now()) {
37
+ report.status = status;
38
+ report.finishedAt = new Date(now).toISOString();
39
+ report.durationMs = Math.max(0, now - Date.parse(report.startedAt));
40
+ return report;
41
+ }
42
+
43
+ export function writeBuildReport(
44
+ report,
45
+ out = BUILD_REPORT_DIR,
46
+ name = BUILD_REPORT_NAME,
47
+ ) {
48
+ writeOutputFile(out, name, `${JSON.stringify(report, null, 2)}\n`);
49
+ }
50
+
51
+ export function readBuildReport(
52
+ out = BUILD_REPORT_DIR,
53
+ name = BUILD_REPORT_NAME,
54
+ ) {
55
+ try {
56
+ return JSON.parse(readFileSync(join(out, name), "utf8"));
57
+ } catch {
58
+ return null;
59
+ }
60
+ }
@@ -0,0 +1,44 @@
1
+ import { mkdtempSync, readFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { describe, expect, it } from "vitest";
5
+ import {
6
+ addBuildStep,
7
+ createBuildReport,
8
+ finishBuildReport,
9
+ writeBuildReport,
10
+ } from "./build-report.mjs";
11
+
12
+ describe("build report", () => {
13
+ it("records one run without making it a generated catalog artifact", () => {
14
+ const report = createBuildReport({
15
+ mode: "check",
16
+ manifestSha256: "abc",
17
+ now: Date.parse("2026-09-05T00:00:00Z"),
18
+ });
19
+ addBuildStep(report, {
20
+ phase: "extract",
21
+ plugin: "domain",
22
+ input: "services/auth",
23
+ output: "services/auth/portolan",
24
+ status: "up-to-date",
25
+ durationMs: 42,
26
+ fileCount: 1,
27
+ changedCount: 0,
28
+ files: ["services/auth/portolan/domain.json"],
29
+ });
30
+ finishBuildReport(
31
+ report,
32
+ "ok",
33
+ Date.parse("2026-09-05T00:00:01Z"),
34
+ );
35
+
36
+ expect(report.durationMs).toBe(1000);
37
+ expect(report.steps[0]?.ordinal).toBe(0);
38
+
39
+ const dir = mkdtempSync(join(tmpdir(), "portolan-report-"));
40
+ writeBuildReport(report, dir);
41
+ expect(JSON.parse(readFileSync(join(dir, "build-report.json"), "utf8")))
42
+ .toEqual(report);
43
+ });
44
+ });
@@ -0,0 +1,49 @@
1
+ // Resolves the plugins shipped with Portolan.
2
+ //
3
+ // A user manifest names built-ins by name and does not repeat how this npm
4
+ // package happens to run them. Custom plugins may still be declared in the
5
+ // manifest with `process` or `wasm`; those declarations always win.
6
+
7
+ import { readFileSync } from "node:fs";
8
+ import { dirname, resolve } from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+
11
+ export const INSTALL_ROOT = process.env.PORTOLAN_INSTALL_ROOT
12
+ ? resolve(process.env.PORTOLAN_INSTALL_ROOT)
13
+ : resolve(dirname(fileURLToPath(import.meta.url)), "..");
14
+
15
+ let definitions;
16
+
17
+ function shippedDefinitions() {
18
+ if (definitions) return definitions;
19
+ const manifest = JSON.parse(readFileSync(resolve(INSTALL_ROOT, "portolan.json"), "utf8"));
20
+ definitions = new Map((manifest.plugins ?? []).map((plugin) => [plugin.name, plugin]));
21
+ return definitions;
22
+ }
23
+
24
+ export function builtinPluginNames() {
25
+ return new Set(shippedDefinitions().keys());
26
+ }
27
+
28
+ /** Return a runnable built-in definition, or null when the package has none. */
29
+ export function builtinPlugin(name) {
30
+ const declared = shippedDefinitions().get(name);
31
+ if (!declared) return null;
32
+
33
+ if (declared.wasm) {
34
+ const value = declared.wasm.url;
35
+ const url = value.startsWith("file://")
36
+ ? `file://${resolve(INSTALL_ROOT, value.slice("file://".length))}`
37
+ : value;
38
+ return { ...declared, builtin: true, wasm: { ...declared.wasm, url } };
39
+ }
40
+
41
+ return {
42
+ name,
43
+ builtin: true,
44
+ process: {
45
+ command: process.execPath,
46
+ args: [resolve(INSTALL_ROOT, "scripts/run-builtin.mjs"), name],
47
+ },
48
+ };
49
+ }
@@ -0,0 +1,67 @@
1
+ // Reads every catalog source the manifest names, merges them, and validates
2
+ // the union.
3
+ //
4
+ // Shared by the generator runner and the LikeC4 generator so the two cannot
5
+ // disagree about what the estate is. Merging before validating is the point:
6
+ // referential integrity holds over the union, and a fragment naming a peer it
7
+ // does not own is normal rather than broken.
8
+
9
+ import { readFileSync } from "node:fs";
10
+ import { glob } from "node:fs/promises";
11
+ import { normalize } from "node:path";
12
+
13
+ import { validateCatalog } from "../src/catalog.ts";
14
+ import { filterCatalogForProfile } from "../src/catalog-profile.ts";
15
+ import { enrichCatalog } from "../src/enrich.ts";
16
+ import { mergeCatalogs } from "../src/merge.ts";
17
+
18
+ /**
19
+ * `exclude` names source files to leave out, as the manifest would spell
20
+ * them. It exists for the verify phase: a step that writes a fragment from
21
+ * what it observed must be shown the catalog WITHOUT its own last output, or
22
+ * what it wrote last time would count as what it saw this time.
23
+ */
24
+ export async function loadCatalog(manifestPath = "portolan.json", { exclude = [], profile } = {}) {
25
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
26
+ const excluded = new Set(exclude.map((path) => normalize(path)));
27
+ const selected = profile
28
+ ? (manifest.catalogs ?? []).find((candidate) => candidate.id === profile)
29
+ : null;
30
+ if (profile && !selected) {
31
+ throw new Error(`${manifestPath}: unknown catalog profile ${JSON.stringify(profile)}`);
32
+ }
33
+ const patterns = selected?.sources ?? manifest.sources ?? [];
34
+
35
+ const paths = [];
36
+ for await (const path of glob(patterns)) {
37
+ if (!excluded.has(normalize(path))) paths.push(path);
38
+ }
39
+
40
+ if (paths.length === 0) {
41
+ throw new Error(
42
+ `${manifestPath}: no catalog matched ${JSON.stringify(patterns)}`,
43
+ );
44
+ }
45
+
46
+ const merged = mergeCatalogs(
47
+ paths.map((path) => ({
48
+ path,
49
+ catalog: JSON.parse(readFileSync(path, "utf8")),
50
+ })),
51
+ );
52
+
53
+ // The edges the flows imply are added before validation, the same way the
54
+ // app does it, so a generator draws the same estate the reader sees.
55
+ const scoped = selected
56
+ ? filterCatalogForProfile(merged.catalog, selected)
57
+ : merged.catalog;
58
+ const enriched = enrichCatalog(scoped);
59
+
60
+ try {
61
+ validateCatalog(enriched.catalog);
62
+ } catch (cause) {
63
+ throw new Error(`the merged catalog is not valid: ${cause.message}`);
64
+ }
65
+
66
+ return { manifest, ...merged, catalog: enriched.catalog, derived: enriched.derived };
67
+ }
@@ -0,0 +1,315 @@
1
+ // What a branch changes about the architecture.
2
+ //
3
+ // node scripts/diff.mjs against origin/main, or main
4
+ // node scripts/diff.mjs <ref> against any commit, tag or branch
5
+ // --format markdown|json|sarif markdown is what a pull request renders
6
+ // --output <file> instead of stdout; the directory is made
7
+ // --site <url> --head <branch> markdown ends with a link into the site's
8
+ // Changes page for the same pair, so a
9
+ // reviewer can go from the list to the diff
10
+ //
11
+ // `gen:check` proves the documentation follows from the catalog; it says
12
+ // nothing about what a change DOES. The diff it leaves a reviewer with is a
13
+ // hundred markdown pages, which is a shape nobody reads and everybody
14
+ // approves. This prints the other thing: the events, endpoints, transitions
15
+ // and owners that are not what they were.
16
+ //
17
+ // The catalog at the base ref is not rebuilt. Every source a plugin writes is
18
+ // COMMITTED - that is the whole point of `gen:check` - so the estate as it
19
+ // stood at any commit is a handful of `git show`s away, and nothing here needs
20
+ // a checkout, a worktree, a toolchain, or the extractors to run twice. The
21
+ // working tree's side is read the way the app reads it.
22
+
23
+ import { execFileSync } from "node:child_process";
24
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
25
+ import { dirname } from "node:path";
26
+
27
+ import { validateCatalog } from "../src/catalog.ts";
28
+ import { enrichCatalog } from "../src/enrich.ts";
29
+ import { mergeCatalogs } from "../src/merge.ts";
30
+ import { diffCatalogs, SEVERITIES } from "../src/lib/catalog-diff.ts";
31
+ import { loadCatalog } from "./catalog-sources.mjs";
32
+
33
+ const HEADINGS = {
34
+ breaking: "Breaking",
35
+ addition: "Added",
36
+ change: "Changed",
37
+ };
38
+
39
+ async function main() {
40
+ const options = parseArgs(process.argv.slice(2));
41
+ const ref = options.ref || defaultBase();
42
+ const before = catalogAt(ref);
43
+ const { catalog: after, sources } = await loadCatalog("portolan.json");
44
+ const changes = diffCatalogs(before, after);
45
+ const output = renderFormat(options.format, ref, changes, {
46
+ site: options.site,
47
+ head: options.head || currentBranch(),
48
+ files: sources.map(({ path }) => ({ path, text: readFileSync(path, "utf8") })),
49
+ });
50
+ if (options.output) {
51
+ mkdirSync(dirname(options.output), { recursive: true });
52
+ writeFileSync(options.output, output);
53
+ console.log(`architecture diff: ${options.format} → ${options.output}`);
54
+ } else {
55
+ process.stdout.write(output);
56
+ }
57
+
58
+ // Zero either way. This describes a change; it does not judge one, and a
59
+ // non-zero exit would make every pull request that touches the estate look
60
+ // like a failure.
61
+ }
62
+
63
+ export function parseArgs(args) {
64
+ const options = { ref: "", format: "markdown", output: "", site: "", head: "" };
65
+ const valued = ["--format", "--output", "--site", "--head"];
66
+ for (let i = 0; i < args.length; i++) {
67
+ const arg = args[i];
68
+ const spelled = valued.find((name) => arg === name || arg.startsWith(name + "="));
69
+ if (spelled) {
70
+ const value = arg === spelled ? args[++i] : arg.slice(spelled.length + 1);
71
+ if (!value) throw new Error(`${spelled} needs a value`);
72
+ options[spelled.slice(2)] = value;
73
+ } else if (arg.startsWith("-")) {
74
+ throw new Error(`unknown option ${arg}`);
75
+ } else if (options.ref) {
76
+ throw new Error(`more than one base ref: ${options.ref}, ${arg}`);
77
+ } else {
78
+ options.ref = arg;
79
+ }
80
+ }
81
+ if (!["markdown", "json", "sarif"].includes(options.format)) {
82
+ throw new Error(`unknown diff format ${options.format}; use markdown, json or sarif`);
83
+ }
84
+ return options;
85
+ }
86
+
87
+ /**
88
+ * `extra` is what a format may use beyond the changes: `site` and `head` for
89
+ * the markdown's link into the Changes page, `files` (path and text of every
90
+ * working-tree source) for SARIF to anchor a finding to the fragment that
91
+ * declares the id it names.
92
+ */
93
+ export function renderFormat(format, ref, changes, extra = {}) {
94
+ if (format === "json") return renderJson(ref, changes);
95
+ if (format === "sarif") return renderSarif(ref, changes, extra.files ?? []);
96
+ return render(ref, changes, extra);
97
+ }
98
+
99
+ /** The branch checked out, or "" when HEAD is detached, as a PR checkout is. */
100
+ function currentBranch() {
101
+ try {
102
+ const name = git(["rev-parse", "--abbrev-ref", "HEAD"]);
103
+
104
+ return name === "HEAD" ? "" : name;
105
+ } catch {
106
+ return "";
107
+ }
108
+ }
109
+
110
+ /**
111
+ * The Changes page for the same pair: the base as the site spells a branch,
112
+ * without the remote, and the head only when it is known - a detached
113
+ * checkout has no name, and the page can ask.
114
+ */
115
+ export function changesHref(site, ref, head) {
116
+ if (!site) return "";
117
+ const base = ref.replace(/^origin\//, "");
118
+ const query = new URLSearchParams({ base });
119
+ if (head) query.set("head", head);
120
+
121
+ return site.replace(/\/$/, "") + "/changes?" + query.toString();
122
+ }
123
+
124
+ /**
125
+ * Where to compare against when nobody said: the trunk as the remote has it,
126
+ * because a local `main` that has not been fetched for a week would report a
127
+ * week of somebody else's work as this branch's.
128
+ */
129
+ function defaultBase() {
130
+ for (const ref of ["origin/main", "main"]) {
131
+ try {
132
+ execFileSync("git", ["rev-parse", "--verify", "--quiet", ref], { stdio: "ignore" });
133
+
134
+ return ref;
135
+ } catch {
136
+ // Not a ref in this repository.
137
+ }
138
+ }
139
+
140
+ throw new Error("no origin/main or main to compare against; name a ref");
141
+ }
142
+
143
+ /** The merged, enriched, validated catalog as it stood at `ref`. */
144
+ function catalogAt(ref) {
145
+ const manifest = JSON.parse(git(["show", ref + ":portolan.json"]));
146
+ const patterns = (manifest.sources ?? []).map(globToRegExp);
147
+
148
+ const paths = git(["ls-tree", "-r", "--name-only", ref])
149
+ .split("\n")
150
+ .filter((path) => patterns.some((re) => re.test(path)));
151
+
152
+ if (paths.length === 0) {
153
+ throw new Error(ref + " holds no catalog sources matching " + JSON.stringify(manifest.sources));
154
+ }
155
+
156
+ const merged = mergeCatalogs(
157
+ paths.map((path) => ({ path, catalog: JSON.parse(git(["show", ref + ":" + path])) })),
158
+ );
159
+
160
+ // Enriched before it is compared, exactly as the app and the generators see
161
+ // it, so a derived edge is compared with a derived edge rather than with a
162
+ // difference in how the two sides were built.
163
+ const { catalog } = enrichCatalog(merged.catalog);
164
+ try {
165
+ validateCatalog(catalog);
166
+ } catch (cause) {
167
+ throw new Error("the catalog at " + ref + " is not valid: " + cause.message);
168
+ }
169
+
170
+ return catalog;
171
+ }
172
+
173
+ function git(args) {
174
+ return execFileSync("git", args, {
175
+ encoding: "utf8",
176
+ maxBuffer: 64 * 1024 * 1024,
177
+ }).trimEnd();
178
+ }
179
+
180
+ /**
181
+ * A manifest glob as a regular expression.
182
+ *
183
+ * A star stops at a slash and two stars do not, which is what the manifest's
184
+ * patterns mean and what `fs.glob` gives the working tree's side. Anchored at
185
+ * both ends: a source pattern names a whole path.
186
+ */
187
+ export function globToRegExp(pattern) {
188
+ let out = "";
189
+ for (let i = 0; i < pattern.length; i++) {
190
+ const c = pattern[i];
191
+ if (c === "*") {
192
+ if (pattern[i + 1] === "*") {
193
+ out += ".*";
194
+ i++;
195
+ } else {
196
+ out += "[^/]*";
197
+ }
198
+
199
+ continue;
200
+ }
201
+ out += /[a-zA-Z0-9/_-]/.test(c) ? c : "\\" + c;
202
+ }
203
+
204
+ return new RegExp("^" + out + "$");
205
+ }
206
+
207
+ /** The report, as markdown, because that is what a pull request renders. */
208
+ export function render(ref, changes, { site = "", head = "" } = {}) {
209
+ if (changes.length === 0) {
210
+ return "No architectural change against `" + ref + "`.\n";
211
+ }
212
+
213
+ const lines = [
214
+ "### Architecture, against `" + ref + "`",
215
+ "",
216
+ changes.length + " change" + (changes.length === 1 ? "" : "s") + ".",
217
+ "",
218
+ ];
219
+
220
+ for (const severity of SEVERITIES) {
221
+ const of = changes.filter((change) => change.severity === severity);
222
+ if (of.length === 0) continue;
223
+
224
+ lines.push("**" + HEADINGS[severity] + "** (" + of.length + ")", "");
225
+ for (const change of of) lines.push("- " + change.summary);
226
+ lines.push("");
227
+ }
228
+
229
+ // The list says what moved; the page shows it in the estate, with the
230
+ // diagrams and the pages around it, so the link is the reviewer's way on.
231
+ const href = changesHref(site, ref, head);
232
+ if (href) lines.push("[Open in Changes](" + href + ")", "");
233
+
234
+ return lines.join("\n");
235
+ }
236
+
237
+ /**
238
+ * Where a change is declared: the first working-tree source whose text holds
239
+ * `"id": "<where>"`, and the line it is on. A change with no such source - a
240
+ * removal, whose id is only on the base side; a catalog-level fact - is
241
+ * anchored at the manifest, because code scanning shows nothing without a
242
+ * location, and the manifest is the one file every estate has.
243
+ */
244
+ export function locate(where, files) {
245
+ const id = where.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
246
+ const re = new RegExp('"id"\\s*:\\s*"' + id + '"');
247
+ for (const { path, text } of files) {
248
+ const at = text.search(re);
249
+ if (at === -1) continue;
250
+
251
+ return { uri: path, line: text.slice(0, at).split("\n").length };
252
+ }
253
+
254
+ return { uri: "portolan.json", line: 1 };
255
+ }
256
+
257
+ function counts(changes) {
258
+ return Object.fromEntries(SEVERITIES.map((severity) => [severity, changes.filter((change) => change.severity === severity).length]));
259
+ }
260
+
261
+ /** Stable machine output for CI, bots and downstream reports. */
262
+ export function renderJson(ref, changes) {
263
+ return `${JSON.stringify({ version: 1, base: ref, counts: counts(changes), changes }, null, 2)}\n`;
264
+ }
265
+
266
+ /**
267
+ * SARIF 2.1.0: breaking changes are errors; everything else remains
268
+ * reviewable. Every result carries a location, because a code scanning
269
+ * upload shows a result without one to nobody.
270
+ */
271
+ export function renderSarif(ref, changes, files = []) {
272
+ const kinds = [...new Set(changes.map((change) => change.kind))].sort();
273
+ const rules = kinds.map((kind) => ({
274
+ id: kind,
275
+ name: kind.replace(/[^a-zA-Z0-9]+/g, "_"),
276
+ shortDescription: { text: `Portolan architecture change: ${kind}` },
277
+ helpUri: "https://github.com/shortlink-org/portolan",
278
+ }));
279
+ const level = { breaking: "error", change: "warning", addition: "note" };
280
+ const sarif = {
281
+ version: "2.1.0",
282
+ $schema: "https://json.schemastore.org/sarif-2.1.0.json",
283
+ runs: [{
284
+ tool: { driver: { name: "Portolan", informationUri: "https://github.com/shortlink-org/portolan", rules } },
285
+ automationDetails: { id: `architecture-diff/${ref}` },
286
+ results: changes.map((change) => {
287
+ const at = locate(change.where, files);
288
+
289
+ return {
290
+ ruleId: change.kind,
291
+ level: level[change.severity],
292
+ message: { text: change.summary },
293
+ locations: [{
294
+ physicalLocation: {
295
+ artifactLocation: { uri: at.uri, uriBaseId: "%SRCROOT%" },
296
+ region: { startLine: at.line, startColumn: 1 },
297
+ },
298
+ }],
299
+ properties: { severity: change.severity, where: change.where, base: ref },
300
+ };
301
+ }),
302
+ }],
303
+ };
304
+ return `${JSON.stringify(sarif, null, 2)}\n`;
305
+ }
306
+
307
+ // Only when run, not when imported: the tests below this reach for the two
308
+ // pieces with logic in them, and a module that ran a git command on import
309
+ // would be a module they could not reach at all.
310
+ if (import.meta.main) {
311
+ main().catch((cause) => {
312
+ console.error("diff: " + cause.message);
313
+ process.exit(1);
314
+ });
315
+ }