@shortlink-org/portolan 0.1.0 → 0.2.1

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 (381) hide show
  1. package/README.md +69 -205
  2. package/cli/init.mjs +285 -0
  3. package/cli/init.test.mjs +158 -0
  4. package/cli/portolan.mjs +37 -73
  5. package/index.html +19 -0
  6. package/package.json +5 -10
  7. package/plugins/README.md +66 -27
  8. package/plugins/portolan-go.wasm +0 -0
  9. package/portolan.json +52 -73
  10. package/public/landing/cats/bug-hunter.webp +0 -0
  11. package/public/landing/cats/compass-nap.webp +0 -0
  12. package/public/landing/cats/diagrammer.webp +0 -0
  13. package/public/landing/cats/docs-reader.webp +0 -0
  14. package/public/landing/cats/laptop.webp +0 -0
  15. package/public/landing/cats/map-inspector.webp +0 -0
  16. package/public/landing/cats/server-break.webp +0 -0
  17. package/public/landing/cats/star-mapper.webp +0 -0
  18. package/public/landing/cats/system-builder.webp +0 -0
  19. package/public/landing/cats/thread-tangle.webp +0 -0
  20. package/public/og.png +0 -0
  21. package/public/readme-header.webp +0 -0
  22. package/schema/portolan.schema.json +180 -0
  23. package/scripts/builtin-plugins.mjs +14 -0
  24. package/scripts/delivery-presets.mjs +353 -0
  25. package/scripts/gen.mjs +37 -4
  26. package/scripts/history.mjs +126 -0
  27. package/scripts/history.test.mjs +110 -0
  28. package/scripts/host-plugins/fetch-bsr.mjs +351 -0
  29. package/{plugins/fetch-bsr/options.schema.json → scripts/host-plugins/fetch-bsr.options.json} +4 -0
  30. package/scripts/host-plugins/fetch-bsr.test.mjs +212 -0
  31. package/scripts/host-plugins/fetch-csr.mjs +386 -0
  32. package/scripts/host-plugins/fetch-csr.test.mjs +178 -0
  33. package/scripts/host-plugins/fetch-git.mjs +379 -0
  34. package/scripts/host-plugins/fetch-git.test.mjs +210 -0
  35. package/scripts/local-api.mjs +27 -10
  36. package/scripts/local-api.test.mjs +85 -2
  37. package/scripts/manifest.mjs +3 -2
  38. package/scripts/package-smoke.mjs +24 -3
  39. package/scripts/plugin-host.mjs +77 -18
  40. package/scripts/plugin-host.test.mjs +50 -1
  41. package/scripts/plugin-wasm-worker.mjs +6 -3
  42. package/scripts/run-builtin.mjs +6 -26
  43. package/scripts/schema.mjs +6 -1
  44. package/src/app/App.tsx +24 -429
  45. package/src/app/Breadcrumbs.test.ts +7 -0
  46. package/src/app/Breadcrumbs.tsx +15 -2
  47. package/src/app/CatalogApp.tsx +436 -0
  48. package/src/app/Sidebar.tsx +0 -1
  49. package/src/chat/ChatPanel.tsx +98 -41
  50. package/src/chat/Composer.tsx +4 -2
  51. package/src/chat/Conversation.tsx +79 -15
  52. package/src/chat/Header.tsx +43 -9
  53. package/src/chat/Starter.tsx +64 -3
  54. package/src/chat/Steps.tsx +1 -1
  55. package/src/chat/flags.test.ts +51 -14
  56. package/src/chat/flags.ts +8 -2
  57. package/src/chat/page-context.test.ts +51 -0
  58. package/src/chat/page-context.ts +128 -0
  59. package/src/chat/prompt.test.ts +49 -1
  60. package/src/chat/prompt.ts +42 -1
  61. package/src/chat/tools.ts +7 -2
  62. package/src/chat/transport.ts +16 -4
  63. package/src/components/ProblemRow.tsx +182 -0
  64. package/src/data.ts +20 -5
  65. package/src/er/ErCanvas.tsx +1 -1
  66. package/src/graph/DependencyGraph.tsx +10 -1
  67. package/src/graph/FocusedEventGraph.tsx +1 -1
  68. package/src/graph/GraphToolbar.tsx +2 -4
  69. package/src/index.css +220 -2
  70. package/src/landing/DraggableReveal.tsx +168 -0
  71. package/src/landing/EstateGraph.tsx +28 -0
  72. package/src/landing/FlowPlayback.tsx +282 -0
  73. package/src/landing/HeroMap.tsx +128 -0
  74. package/src/landing/LandingPage.tsx +757 -0
  75. package/src/landing/ProductFrame.tsx +68 -0
  76. package/src/landing/ProductTour.tsx +371 -0
  77. package/src/landing/catalog.ts +25 -0
  78. package/src/landing/motion.tsx +52 -0
  79. package/src/lib/all-problems.ts +28 -0
  80. package/src/lib/local-api.ts +35 -1
  81. package/src/lib/setup-info.test.ts +8 -0
  82. package/src/lib/setup-info.ts +3 -2
  83. package/src/lib/source-code.ts +2 -1
  84. package/src/likec4/C4View.tsx +5 -0
  85. package/src/likec4/InteractiveView.tsx +5 -1
  86. package/src/map/ContextMapGraph.tsx +47 -20
  87. package/src/pages/ContextMap.tsx +5 -1
  88. package/src/pages/FlowDetail.tsx +24 -7
  89. package/src/pages/Overview.tsx +68 -12
  90. package/src/pages/Problems.tsx +6 -193
  91. package/src/pages/Settings.tsx +133 -108
  92. package/src/pages/settings/DeliverySettings.tsx +229 -0
  93. package/src/pages/settings/PreferencesSettings.tsx +101 -0
  94. package/src/routes.test.ts +20 -0
  95. package/src/routes.ts +13 -1
  96. package/vite.config.ts +17 -9
  97. package/catalog/enum_test.go +0 -46
  98. package/catalog/model.go +0 -932
  99. package/catalog/roundtrip_test.go +0 -185
  100. package/catalog/via_test.go +0 -38
  101. package/go.mod +0 -14
  102. package/go.sum +0 -14
  103. package/internal/commands/cargo.go +0 -154
  104. package/internal/commands/commands.go +0 -143
  105. package/internal/commands/commands_test.go +0 -323
  106. package/internal/commands/gradle.go +0 -77
  107. package/internal/commands/justfile.go +0 -82
  108. package/internal/commands/makefile.go +0 -106
  109. package/internal/commands/maven.go +0 -93
  110. package/internal/commands/packagejson.go +0 -159
  111. package/internal/commands/pyproject.go +0 -169
  112. package/internal/commands/taskfile.go +0 -101
  113. package/internal/commands/testdata/estate/.cargo/config.toml +0 -7
  114. package/internal/commands/testdata/estate/Makefile +0 -33
  115. package/internal/commands/testdata/estate/Taskfile.yml +0 -21
  116. package/internal/commands/testdata/estate/build.gradle.kts +0 -21
  117. package/internal/commands/testdata/estate/justfile +0 -20
  118. package/internal/commands/testdata/estate/package.json +0 -13
  119. package/internal/commands/testdata/estate/pom.xml +0 -29
  120. package/internal/commands/testdata/estate/pyproject.toml +0 -27
  121. package/internal/commands/testdata/estate/xtask/src/main.rs +0 -27
  122. package/internal/commands/testdata/golden/commands.json +0 -305
  123. package/internal/gohttp/analyze.go +0 -2500
  124. package/internal/gohttp/endpoints.go +0 -1067
  125. package/internal/gohttp/roots.go +0 -320
  126. package/internal/gohttp/typed.go +0 -143
  127. package/internal/goscan/constants.go +0 -85
  128. package/internal/goscan/goscan_test.go +0 -227
  129. package/internal/goscan/names.go +0 -52
  130. package/internal/goscan/parse_test.go +0 -11
  131. package/internal/goscan/source.go +0 -36
  132. package/internal/goscan/tree.go +0 -155
  133. package/internal/goscan/types.go +0 -99
  134. package/internal/wsdl/ids.go +0 -127
  135. package/internal/wsdl/ids_test.go +0 -21
  136. package/internal/wsdl/model.go +0 -62
  137. package/internal/wsdl/parse.go +0 -920
  138. package/internal/wsdl/parse_test.go +0 -133
  139. package/plugin/describe.go +0 -107
  140. package/plugin/describe_test.go +0 -114
  141. package/plugin/protocol.go +0 -117
  142. package/plugin/schematest/schematest.go +0 -126
  143. package/plugins/extract-adr/describe.go +0 -19
  144. package/plugins/extract-adr/describe_test.go +0 -11
  145. package/plugins/extract-adr/extract.go +0 -153
  146. package/plugins/extract-adr/extract_test.go +0 -350
  147. package/plugins/extract-adr/history.go +0 -99
  148. package/plugins/extract-adr/main.go +0 -65
  149. package/plugins/extract-adr/parse.go +0 -642
  150. package/plugins/extract-adr/parse_test.go +0 -405
  151. package/plugins/extract-asyncapi/describe.go +0 -19
  152. package/plugins/extract-asyncapi/describe_test.go +0 -11
  153. package/plugins/extract-asyncapi/extract.go +0 -315
  154. package/plugins/extract-asyncapi/extract_test.go +0 -197
  155. package/plugins/extract-asyncapi/main.go +0 -48
  156. package/plugins/extract-asyncapi/spec.go +0 -151
  157. package/plugins/extract-commands/describe.go +0 -19
  158. package/plugins/extract-commands/describe_test.go +0 -11
  159. package/plugins/extract-commands/extract.go +0 -79
  160. package/plugins/extract-commands/extract_test.go +0 -92
  161. package/plugins/extract-commands/main.go +0 -55
  162. package/plugins/extract-csr/avro.go +0 -258
  163. package/plugins/extract-csr/describe.go +0 -19
  164. package/plugins/extract-csr/describe_test.go +0 -11
  165. package/plugins/extract-csr/extract.go +0 -338
  166. package/plugins/extract-csr/extract_test.go +0 -374
  167. package/plugins/extract-csr/jsonschema.go +0 -343
  168. package/plugins/extract-csr/lock.go +0 -25
  169. package/plugins/extract-csr/main.go +0 -84
  170. package/plugins/extract-csr/subject.go +0 -102
  171. package/plugins/extract-flows/describe.go +0 -19
  172. package/plugins/extract-flows/describe_test.go +0 -11
  173. package/plugins/extract-flows/extract.go +0 -91
  174. package/plugins/extract-flows/main.go +0 -45
  175. package/plugins/extract-flows/parse.go +0 -593
  176. package/plugins/extract-flows/parse_test.go +0 -204
  177. package/plugins/extract-glossary/describe.go +0 -19
  178. package/plugins/extract-glossary/describe_test.go +0 -11
  179. package/plugins/extract-glossary/extract.go +0 -115
  180. package/plugins/extract-glossary/extract_test.go +0 -220
  181. package/plugins/extract-glossary/main.go +0 -59
  182. package/plugins/extract-glossary/parse.go +0 -214
  183. package/plugins/extract-glossary/parse_test.go +0 -203
  184. package/plugins/extract-go/aggregate.go +0 -214
  185. package/plugins/extract-go/client.go +0 -409
  186. package/plugins/extract-go/client_test.go +0 -266
  187. package/plugins/extract-go/describe.go +0 -19
  188. package/plugins/extract-go/describe_test.go +0 -11
  189. package/plugins/extract-go/enum.go +0 -195
  190. package/plugins/extract-go/enum_test.go +0 -82
  191. package/plugins/extract-go/event.go +0 -99
  192. package/plugins/extract-go/extract.go +0 -191
  193. package/plugins/extract-go/extract_test.go +0 -261
  194. package/plugins/extract-go/flow.go +0 -1441
  195. package/plugins/extract-go/flow_test.go +0 -609
  196. package/plugins/extract-go/httpclient.go +0 -174
  197. package/plugins/extract-go/httpclient_test.go +0 -296
  198. package/plugins/extract-go/ids.go +0 -92
  199. package/plugins/extract-go/layout.go +0 -225
  200. package/plugins/extract-go/layout_test.go +0 -125
  201. package/plugins/extract-go/lifecycle.go +0 -324
  202. package/plugins/extract-go/lifecycle_test.go +0 -108
  203. package/plugins/extract-go/main.go +0 -79
  204. package/plugins/extract-go/operation.go +0 -157
  205. package/plugins/extract-go/source.go +0 -316
  206. package/plugins/extract-go/transport.go +0 -321
  207. package/plugins/extract-go/transport_test.go +0 -145
  208. package/plugins/extract-go/wiring.go +0 -434
  209. package/plugins/extract-go-nats/describe.go +0 -19
  210. package/plugins/extract-go-nats/describe_test.go +0 -11
  211. package/plugins/extract-go-nats/extract.go +0 -177
  212. package/plugins/extract-go-nats/extract_test.go +0 -389
  213. package/plugins/extract-go-nats/index.go +0 -379
  214. package/plugins/extract-go-nats/main.go +0 -42
  215. package/plugins/extract-go-nats/resolve.go +0 -161
  216. package/plugins/extract-go-nats/sites.go +0 -224
  217. package/plugins/extract-graphql/describe.go +0 -19
  218. package/plugins/extract-graphql/describe_test.go +0 -11
  219. package/plugins/extract-graphql/extract.go +0 -433
  220. package/plugins/extract-graphql/extract_test.go +0 -256
  221. package/plugins/extract-graphql/ids.go +0 -49
  222. package/plugins/extract-graphql/lex.go +0 -237
  223. package/plugins/extract-graphql/main.go +0 -51
  224. package/plugins/extract-graphql/parse.go +0 -621
  225. package/plugins/extract-graphql/parse_test.go +0 -122
  226. package/plugins/extract-http-clients/describe.go +0 -19
  227. package/plugins/extract-http-clients/describe_test.go +0 -11
  228. package/plugins/extract-http-clients/extract.go +0 -705
  229. package/plugins/extract-http-clients/extract_test.go +0 -1263
  230. package/plugins/extract-http-clients/main.go +0 -42
  231. package/plugins/extract-openapi/describe.go +0 -19
  232. package/plugins/extract-openapi/describe_test.go +0 -11
  233. package/plugins/extract-openapi/discover.go +0 -243
  234. package/plugins/extract-openapi/extract.go +0 -526
  235. package/plugins/extract-openapi/extract_test.go +0 -545
  236. package/plugins/extract-openapi/main.go +0 -75
  237. package/plugins/extract-openapi/spec.go +0 -350
  238. package/plugins/extract-project/describe.go +0 -19
  239. package/plugins/extract-project/describe_test.go +0 -11
  240. package/plugins/extract-project/extract.go +0 -221
  241. package/plugins/extract-project/extract_test.go +0 -109
  242. package/plugins/extract-project/main.go +0 -41
  243. package/plugins/extract-proto/ast.go +0 -125
  244. package/plugins/extract-proto/consumes.go +0 -77
  245. package/plugins/extract-proto/describe.go +0 -19
  246. package/plugins/extract-proto/extract.go +0 -293
  247. package/plugins/extract-proto/extract_test.go +0 -459
  248. package/plugins/extract-proto/ids.go +0 -89
  249. package/plugins/extract-proto/ids_test.go +0 -57
  250. package/plugins/extract-proto/lex.go +0 -285
  251. package/plugins/extract-proto/main.go +0 -100
  252. package/plugins/extract-proto/module.go +0 -120
  253. package/plugins/extract-proto/parse.go +0 -720
  254. package/plugins/extract-proto/parse_test.go +0 -307
  255. package/plugins/extract-proto/provides.go +0 -236
  256. package/plugins/extract-proto/resolve.go +0 -222
  257. package/plugins/extract-proto/resolve_test.go +0 -119
  258. package/plugins/extract-redis/describe.go +0 -19
  259. package/plugins/extract-redis/describe_test.go +0 -11
  260. package/plugins/extract-redis/extract.go +0 -183
  261. package/plugins/extract-redis/extract_test.go +0 -168
  262. package/plugins/extract-redis/keyspaces.go +0 -469
  263. package/plugins/extract-redis/main.go +0 -44
  264. package/plugins/extract-river/describe.go +0 -19
  265. package/plugins/extract-river/describe_test.go +0 -11
  266. package/plugins/extract-river/extract.go +0 -507
  267. package/plugins/extract-river/extract_test.go +0 -132
  268. package/plugins/extract-river/main.go +0 -42
  269. package/plugins/extract-sql/ddl.go +0 -893
  270. package/plugins/extract-sql/ddl_test.go +0 -401
  271. package/plugins/extract-sql/describe.go +0 -19
  272. package/plugins/extract-sql/describe_test.go +0 -11
  273. package/plugins/extract-sql/layout.go +0 -221
  274. package/plugins/extract-sql/layout_test.go +0 -55
  275. package/plugins/extract-sql/lineage.go +0 -107
  276. package/plugins/extract-sql/main.go +0 -141
  277. package/plugins/extract-sql/maps.go +0 -564
  278. package/plugins/extract-sql/maps_java.go +0 -117
  279. package/plugins/extract-sql/maps_rust.go +0 -333
  280. package/plugins/extract-sql/maps_rust_test.go +0 -70
  281. package/plugins/extract-sql/maps_test.go +0 -204
  282. package/plugins/extract-sql/maps_ts.go +0 -398
  283. package/plugins/extract-sql/maps_ts_test.go +0 -136
  284. package/plugins/extract-sql/projection.go +0 -70
  285. package/plugins/extract-sql/projection_test.go +0 -50
  286. package/plugins/extract-sql/store.go +0 -420
  287. package/plugins/extract-sql/store_test.go +0 -233
  288. package/plugins/extract-sql/view.go +0 -295
  289. package/plugins/extract-watermill/describe.go +0 -19
  290. package/plugins/extract-watermill/describe_test.go +0 -11
  291. package/plugins/extract-watermill/extract.go +0 -1228
  292. package/plugins/extract-watermill/extract_test.go +0 -234
  293. package/plugins/extract-watermill/main.go +0 -41
  294. package/plugins/extract-wsdl/describe.go +0 -19
  295. package/plugins/extract-wsdl/describe_test.go +0 -11
  296. package/plugins/extract-wsdl/extract.go +0 -148
  297. package/plugins/extract-wsdl/extract_test.go +0 -45
  298. package/plugins/extract-wsdl/main.go +0 -53
  299. package/plugins/fetch-bsr/auth.go +0 -114
  300. package/plugins/fetch-bsr/bsr.go +0 -240
  301. package/plugins/fetch-bsr/cache.go +0 -66
  302. package/plugins/fetch-bsr/describe.go +0 -19
  303. package/plugins/fetch-bsr/fetch.go +0 -192
  304. package/plugins/fetch-bsr/fetch_test.go +0 -465
  305. package/plugins/fetch-bsr/lock.go +0 -71
  306. package/plugins/fetch-bsr/main.go +0 -117
  307. package/plugins/fetch-csr/auth.go +0 -95
  308. package/plugins/fetch-csr/cache.go +0 -69
  309. package/plugins/fetch-csr/describe.go +0 -19
  310. package/plugins/fetch-csr/describe_test.go +0 -11
  311. package/plugins/fetch-csr/fetch.go +0 -254
  312. package/plugins/fetch-csr/fetch_test.go +0 -494
  313. package/plugins/fetch-csr/lock.go +0 -95
  314. package/plugins/fetch-csr/main.go +0 -122
  315. package/plugins/fetch-csr/registry.go +0 -209
  316. package/plugins/fetch-git/cache.go +0 -65
  317. package/plugins/fetch-git/describe.go +0 -19
  318. package/plugins/fetch-git/describe_test.go +0 -11
  319. package/plugins/fetch-git/fetch.go +0 -181
  320. package/plugins/fetch-git/fetch_test.go +0 -332
  321. package/plugins/fetch-git/git.go +0 -169
  322. package/plugins/fetch-git/lock.go +0 -72
  323. package/plugins/fetch-git/main.go +0 -127
  324. package/plugins/fetch-git/offline.go +0 -39
  325. package/plugins/fetch-git/pin.go +0 -90
  326. package/plugins/fetch-git/pin_test.go +0 -74
  327. package/plugins/gen-backstage/describe.go +0 -17
  328. package/plugins/gen-backstage/main.go +0 -22
  329. package/plugins/gen-backstage/plugin.go +0 -473
  330. package/plugins/gen-backstage/plugin_test.go +0 -145
  331. package/plugins/gen-backstage.wasm +0 -0
  332. package/plugins/gen-markdown/adr.go +0 -162
  333. package/plugins/gen-markdown/aggregate.go +0 -362
  334. package/plugins/gen-markdown/canonical.go +0 -93
  335. package/plugins/gen-markdown/context.go +0 -90
  336. package/plugins/gen-markdown/coverage_test.go +0 -89
  337. package/plugins/gen-markdown/describe.go +0 -19
  338. package/plugins/gen-markdown/describe_test.go +0 -11
  339. package/plugins/gen-markdown/external.go +0 -71
  340. package/plugins/gen-markdown/flow.go +0 -277
  341. package/plugins/gen-markdown/glossary.go +0 -76
  342. package/plugins/gen-markdown/glossary_test.go +0 -148
  343. package/plugins/gen-markdown/llms.go +0 -302
  344. package/plugins/gen-markdown/main.go +0 -22
  345. package/plugins/gen-markdown/markdown.go +0 -254
  346. package/plugins/gen-markdown/markdown_test.go +0 -100
  347. package/plugins/gen-markdown/module.go +0 -107
  348. package/plugins/gen-markdown/plugin.go +0 -39
  349. package/plugins/gen-markdown/quality_test.go +0 -176
  350. package/plugins/gen-markdown/redis_test.go +0 -38
  351. package/plugins/gen-markdown/render.go +0 -344
  352. package/plugins/gen-markdown/render_test.go +0 -186
  353. package/plugins/gen-markdown/service.go +0 -456
  354. package/plugins/gen-markdown/source.go +0 -177
  355. package/plugins/gen-markdown/store.go +0 -201
  356. package/plugins/gen-markdown.wasm +0 -0
  357. package/plugins/gen-mermaid/describe.go +0 -17
  358. package/plugins/gen-mermaid/main.go +0 -22
  359. package/plugins/gen-mermaid/plugin.go +0 -104
  360. package/plugins/gen-mermaid/plugin_test.go +0 -33
  361. package/plugins/gen-mermaid.wasm +0 -0
  362. package/plugins/openapi/ids.go +0 -261
  363. package/plugins/openapi/ids_test.go +0 -98
  364. package/plugins/verify-codeowners/describe.go +0 -19
  365. package/plugins/verify-codeowners/describe_test.go +0 -11
  366. package/plugins/verify-codeowners/main.go +0 -75
  367. package/plugins/verify-codeowners/match.go +0 -85
  368. package/plugins/verify-codeowners/match_test.go +0 -47
  369. package/plugins/verify-codeowners/owners.go +0 -164
  370. package/plugins/verify-codeowners/owners_test.go +0 -225
  371. package/plugins/verify-codeowners/parse.go +0 -90
  372. package/plugins/verify-codeowners/parse_test.go +0 -62
  373. package/plugins/verify-otel/describe.go +0 -19
  374. package/plugins/verify-otel/describe_test.go +0 -11
  375. package/plugins/verify-otel/main.go +0 -53
  376. package/plugins/verify-otel/match.go +0 -336
  377. package/plugins/verify-otel/otlp.go +0 -200
  378. package/plugins/verify-otel/verify.go +0 -734
  379. package/plugins/verify-otel/verify_test.go +0 -460
  380. /package/{plugins/fetch-csr/options.schema.json → scripts/host-plugins/fetch-csr.options.json} +0 -0
  381. /package/{plugins/fetch-git/options.schema.json → scripts/host-plugins/fetch-git.options.json} +0 -0
@@ -1,227 +0,0 @@
1
- package goscan
2
-
3
- import (
4
- "go/ast"
5
- "os"
6
- "path/filepath"
7
- "reflect"
8
- "strings"
9
- "testing"
10
- )
11
-
12
- func write(t *testing.T, root, name, contents string) {
13
- t.Helper()
14
- full := filepath.Join(root, name)
15
- if err := os.MkdirAll(filepath.Dir(full), 0o755); err != nil {
16
- t.Fatal(err)
17
- }
18
- if err := os.WriteFile(full, []byte(contents), 0o644); err != nil {
19
- t.Fatal(err)
20
- }
21
- }
22
-
23
- func tree(t *testing.T) *Tree {
24
- t.Helper()
25
- root := t.TempDir()
26
- write(t, root, "go.mod", "module example.com/m\n\ngo 1.22\n")
27
- write(t, root, "main.go", `package main
28
-
29
- import (
30
- other "example.com/m/sub"
31
- "example.com/m/vendor/lib"
32
- )
33
-
34
- const (
35
- A = "a"
36
- B = A
37
- C = other.D
38
- Inherited
39
- Self1 = Self2
40
- Self2 = Self1
41
- Foreign = lib.Default
42
- Number = 3
43
- )
44
-
45
- type Args struct {
46
- ID string `+"`json:\"id\"`"+`
47
- Secret string `+"`json:\"-\"`"+`
48
- Plain int
49
- hidden bool
50
- }
51
- `)
52
- write(t, root, "sub/b.go", "package sub\n\nconst D = \"d\"\n")
53
- write(t, root, "sub/b_test.go", "package sub\n\nconst Test = \"never\"\n")
54
- write(t, root, "sub/gen.gen.go", "package sub\n\nconst Generated = \"never\"\n")
55
- write(t, root, "vendor/lib/lib.go", "package lib\n\nconst Default = \"never\"\n")
56
- write(t, root, ".hidden/h.go", "package hidden\n\nconst Hidden = \"never\"\n")
57
- write(t, root, "node_modules/x/x.go", "package x\n\nconst X = \"never\"\n")
58
-
59
- out, err := Read(root)
60
- if err != nil {
61
- t.Fatal(err)
62
- }
63
- return out
64
- }
65
-
66
- func TestReadKeepsTheSourceAndLeavesTheRest(t *testing.T) {
67
- out := tree(t)
68
-
69
- var names []string
70
- for _, file := range out.Files {
71
- names = append(names, file.Name+" "+file.Pkg)
72
- }
73
- want := []string{"main.go example.com/m", "sub/b.go example.com/m/sub"}
74
- if !reflect.DeepEqual(names, want) {
75
- t.Errorf("files: got %v, want %v", names, want)
76
- }
77
- if out.Module != "example.com/m" {
78
- t.Errorf("module: got %q", out.Module)
79
- }
80
- for _, key := range []string{"example.com/m/sub.Test", "example.com/m/sub.Generated", "example.com/m/vendor/lib.Default", "example.com/m/.hidden.Hidden"} {
81
- if _, found := out.Constants[key]; found {
82
- t.Errorf("%s was read", key)
83
- }
84
- }
85
- }
86
-
87
- func TestImportsAreByLocalName(t *testing.T) {
88
- out := tree(t)
89
- got := out.Files[0].Imports
90
- want := map[string]string{"other": "example.com/m/sub", "lib": "example.com/m/vendor/lib"}
91
- if !reflect.DeepEqual(got, want) {
92
- t.Errorf("imports: got %v, want %v", got, want)
93
- }
94
- }
95
-
96
- func TestADottedImportSegmentIsKnownByItsPackageName(t *testing.T) {
97
- root := t.TempDir()
98
- write(t, root, "go.mod", "module example.com/m\n")
99
- write(t, root, "main.go", "package main\n\nimport (\n\t\"github.com/nats-io/nats.go\"\n\t\"gopkg.in/yaml.v3\"\n\t\"github.com/nats-io/nats.go/jetstream\"\n)\n")
100
- out, err := Read(root)
101
- if err != nil {
102
- t.Fatal(err)
103
- }
104
- got := out.Files[0].Imports
105
- want := map[string]string{
106
- "nats.go": "github.com/nats-io/nats.go",
107
- "nats": "github.com/nats-io/nats.go",
108
- "yaml.v3": "gopkg.in/yaml.v3",
109
- "yaml": "gopkg.in/yaml.v3",
110
- "jetstream": "github.com/nats-io/nats.go/jetstream",
111
- }
112
- if !reflect.DeepEqual(got, want) {
113
- t.Errorf("imports: got %v, want %v", got, want)
114
- }
115
- }
116
-
117
- func TestConstantsResolveThroughEachOther(t *testing.T) {
118
- out := tree(t)
119
- cases := map[string]string{
120
- "example.com/m.A": "a",
121
- "example.com/m.B": "a",
122
- "example.com/m.C": "d",
123
- "example.com/m.Inherited": "d",
124
- "example.com/m.Self1": "",
125
- "example.com/m.Foreign": "",
126
- "example.com/m.Number": "",
127
- "example.com/m.Missing": "",
128
- }
129
- for key, want := range cases {
130
- if got := out.ConstantString(key, nil); got != want {
131
- t.Errorf("%s: got %q, want %q", key, got, want)
132
- }
133
- }
134
- }
135
-
136
- func TestForeignAnswersWhatTheTreeCannot(t *testing.T) {
137
- out := tree(t)
138
- out.Foreign = func(importPath, name string) (string, bool) {
139
- if importPath == "example.com/m/vendor/lib" && name == "Default" {
140
- return "default", true
141
- }
142
- return "", false
143
- }
144
- if got := out.ConstantString("example.com/m.Foreign", nil); got != "default" {
145
- t.Errorf("got %q, want %q", got, "default")
146
- }
147
- }
148
-
149
- func TestTypeKey(t *testing.T) {
150
- out := tree(t)
151
- file := out.Files[0]
152
- parse := func(src string) ast.Expr {
153
- expr, err := parseExpr(src)
154
- if err != nil {
155
- t.Fatal(err)
156
- }
157
- return expr
158
- }
159
- cases := map[string]string{
160
- "Args": "example.com/m.Args",
161
- "*Args": "example.com/m.Args",
162
- "string": "string",
163
- "other.Thing": "example.com/m/sub.Thing",
164
- "[]other.Thing": "[]example.com/m/sub.Thing",
165
- "map[string]Args": "map[string]example.com/m.Args",
166
- "interface{ M() }": "interface",
167
- "func()": "",
168
- "a.b.C": "",
169
- }
170
- for src, want := range cases {
171
- if got := out.TypeKey(parse(src), file); got != want {
172
- t.Errorf("%s: got %q, want %q", src, got, want)
173
- }
174
- }
175
- if got := out.TypeKey(nil, file); got != "" {
176
- t.Errorf("nil: got %q", got)
177
- }
178
- }
179
-
180
- func TestFieldsOfFollowTheJSONTag(t *testing.T) {
181
- out := tree(t)
182
- var body *ast.StructType
183
- ast.Inspect(out.Files[0].Node, func(node ast.Node) bool {
184
- if spec, ok := node.(*ast.TypeSpec); ok && spec.Name.Name == "Args" {
185
- body = spec.Type.(*ast.StructType)
186
- }
187
- return body == nil
188
- })
189
- got := out.FieldsOf(body)
190
- want := []string{"id string", "Plain int", "hidden bool"}
191
- if !reflect.DeepEqual(got, want) {
192
- t.Errorf("got %v, want %v", got, want)
193
- }
194
- }
195
-
196
- func TestAtIsRelativeToTheRoot(t *testing.T) {
197
- out := tree(t)
198
- file := out.Files[1]
199
- at := out.At(file.Node.Decls[0].Pos())
200
- if at.String() != "sub/b.go:3" {
201
- t.Errorf("got %q", at.String())
202
- }
203
- if (Source{File: "x.go"}).String() != "x.go" {
204
- t.Error("a source with no line prints its line")
205
- }
206
- }
207
-
208
- func TestNames(t *testing.T) {
209
- if got := LastSegment("example.com/m.Args"); got != "Args" {
210
- t.Errorf("LastSegment: %q", got)
211
- }
212
- if got := LastSegment("plain"); got != "plain" {
213
- t.Errorf("LastSegment plain: %q", got)
214
- }
215
- if got := Slug(" Send Welcome_Mail!! "); got != "send-welcome-mail" {
216
- t.Errorf("Slug: %q", got)
217
- }
218
- if got := Title("send-welcome_mail.v1"); got != "Send Welcome Mail V1" {
219
- t.Errorf("Title: %q", got)
220
- }
221
- if got := FirstNonEmpty(" ", "", "x", "y"); got != "x" {
222
- t.Errorf("FirstNonEmpty: %q", got)
223
- }
224
- if got := strings.TrimSpace(FirstNonEmpty(" ", "")); got != "" {
225
- t.Errorf("FirstNonEmpty empty: %q", got)
226
- }
227
- }
@@ -1,52 +0,0 @@
1
- package goscan
2
-
3
- import "strings"
4
-
5
- // LastSegment is what follows the last dot: the name off a type key, the
6
- // event off a wire name.
7
- func LastSegment(value string) string {
8
- if at := strings.LastIndex(value, "."); at >= 0 {
9
- return value[at+1:]
10
- }
11
- return value
12
- }
13
-
14
- // Slug is a value as an identifier in a URL or a catalog id: lower case,
15
- // runs of anything else collapsed to one dash, none at the ends.
16
- func Slug(value string) string {
17
- value = strings.ToLower(strings.TrimSpace(value))
18
- var out strings.Builder
19
- dash := false
20
- for _, r := range value {
21
- if r >= 'a' && r <= 'z' || r >= '0' && r <= '9' {
22
- out.WriteRune(r)
23
- dash = false
24
- } else if out.Len() > 0 && !dash {
25
- out.WriteByte('-')
26
- dash = true
27
- }
28
- }
29
- return strings.TrimSuffix(out.String(), "-")
30
- }
31
-
32
- // Title is a slug or an identifier as words: split on dash, underscore and
33
- // dot, each capitalised.
34
- func Title(value string) string {
35
- parts := strings.FieldsFunc(value, func(r rune) bool { return r == '-' || r == '_' || r == '.' })
36
- for i := range parts {
37
- if parts[i] != "" {
38
- parts[i] = strings.ToUpper(parts[i][:1]) + parts[i][1:]
39
- }
40
- }
41
- return strings.Join(parts, " ")
42
- }
43
-
44
- // FirstNonEmpty is the first value that is more than whitespace.
45
- func FirstNonEmpty(values ...string) string {
46
- for _, value := range values {
47
- if strings.TrimSpace(value) != "" {
48
- return value
49
- }
50
- }
51
- return ""
52
- }
@@ -1,11 +0,0 @@
1
- package goscan
2
-
3
- import (
4
- "go/ast"
5
- "go/parser"
6
- )
7
-
8
- // parseExpr is go/parser's, named here so a test reads as a table.
9
- func parseExpr(src string) (ast.Expr, error) {
10
- return parser.ParseExpr(src)
11
- }
@@ -1,36 +0,0 @@
1
- package goscan
2
-
3
- import (
4
- "fmt"
5
- "go/ast"
6
- )
7
-
8
- // Source is a place in the tree, the way the catalog cites one: the file
9
- // relative to the root, and the line when there is one.
10
- type Source struct {
11
- File string
12
- Line int
13
- }
14
-
15
- func (s Source) String() string {
16
- if s.Line == 0 {
17
- return s.File
18
- }
19
- return fmt.Sprintf("%s:%d", s.File, s.Line)
20
- }
21
-
22
- // File is one parsed file: its path under the root, the import path of its
23
- // package, its imports by local name, and the syntax.
24
- type File struct {
25
- Name string
26
- Pkg string
27
- Imports map[string]string
28
- Node *ast.File
29
- }
30
-
31
- // ConstExpr is a constant as it was declared: the expression, and the file it
32
- // is in, since the expression's names mean what that file's imports say.
33
- type ConstExpr struct {
34
- Expr ast.Expr
35
- File *File
36
- }
@@ -1,155 +0,0 @@
1
- // Package goscan reads a Go source tree the way the extractors need it: every
2
- // non-test, non-generated file parsed once, each with the import path of its
3
- // package and its imports by local name, and the string constants of the tree
4
- // indexed so that a topic, a queue or a subject named by a constant resolves to
5
- // the literal behind it.
6
- //
7
- // It is the part of a Go extractor that has nothing to do with what the
8
- // extractor is looking for. River and Watermill read the tree this way, and the
9
- // next Go extractor should not have to copy it a third time.
10
- package goscan
11
-
12
- import (
13
- "fmt"
14
- "go/ast"
15
- "go/parser"
16
- "go/token"
17
- "io/fs"
18
- "os"
19
- "path"
20
- "path/filepath"
21
- "sort"
22
- "strconv"
23
- "strings"
24
- )
25
-
26
- // Tree is one Go module's source, read once.
27
- type Tree struct {
28
- Root string
29
- Module string
30
- Fset *token.FileSet
31
- // Files in path order, so that whatever is read off them comes out in the
32
- // same order every run.
33
- Files []*File
34
- // Constants is every constant of the tree by "<import path>.<Name>", as
35
- // the expression that declared it, so a constant defined through another
36
- // is followed rather than copied.
37
- Constants map[string]ConstExpr
38
- // Foreign is what an identifier from a package outside the tree is worth,
39
- // when the extractor knows: river.QueueDefault is "default", and nothing
40
- // in the tree says so. Nil when there is nothing to say.
41
- Foreign func(importPath, name string) (string, bool)
42
- }
43
-
44
- // Read parses the tree under root. Test files, generated files, vendored
45
- // code and dot-directories are left out: they are not what the service
46
- // says about itself.
47
- func Read(root string) (*Tree, error) {
48
- t := &Tree{Root: root, Module: ModulePath(root), Fset: token.NewFileSet(), Constants: map[string]ConstExpr{}}
49
-
50
- var names []string
51
- err := filepath.WalkDir(root, func(name string, entry fs.DirEntry, err error) error {
52
- if err != nil {
53
- return err
54
- }
55
- if entry.IsDir() {
56
- if name != root && strings.HasPrefix(entry.Name(), ".") {
57
- return filepath.SkipDir
58
- }
59
- switch entry.Name() {
60
- case ".git", ".portolan", "node_modules", "vendor":
61
- if name != root {
62
- return filepath.SkipDir
63
- }
64
- }
65
- return nil
66
- }
67
- base := entry.Name()
68
- if !strings.HasSuffix(base, ".go") || strings.HasSuffix(base, "_test.go") || strings.HasSuffix(base, ".gen.go") || strings.HasSuffix(base, "_generated.go") {
69
- return nil
70
- }
71
- names = append(names, name)
72
- return nil
73
- })
74
- if err != nil {
75
- return nil, err
76
- }
77
- sort.Strings(names)
78
-
79
- for _, name := range names {
80
- node, err := parser.ParseFile(t.Fset, name, nil, parser.ParseComments)
81
- if err != nil {
82
- return nil, fmt.Errorf("parse %s: %w", name, err)
83
- }
84
- rel, _ := filepath.Rel(root, name)
85
- t.Files = append(t.Files, &File{
86
- Name: filepath.ToSlash(rel),
87
- Pkg: t.PackagePath(filepath.Dir(name)),
88
- Imports: ImportsOf(node),
89
- Node: node,
90
- })
91
- }
92
- t.indexConstants()
93
-
94
- return t, nil
95
- }
96
-
97
- // PackagePath is the import path of the package in dir: the module path
98
- // with the directory under it.
99
- func (t *Tree) PackagePath(dir string) string {
100
- rel, err := filepath.Rel(t.Root, dir)
101
- if err != nil || rel == "." {
102
- return t.Module
103
- }
104
- return strings.TrimSuffix(t.Module, "/") + "/" + filepath.ToSlash(rel)
105
- }
106
-
107
- // At is where a node is, relative to the root.
108
- func (t *Tree) At(pos token.Pos) Source {
109
- position := t.Fset.Position(pos)
110
- rel, err := filepath.Rel(t.Root, position.Filename)
111
- if err != nil {
112
- rel = position.Filename
113
- }
114
- return Source{File: filepath.ToSlash(rel), Line: position.Line}
115
- }
116
-
117
- // ModulePath is what go.mod under root calls the module; the cleaned root
118
- // when there is no go.mod to ask.
119
- func ModulePath(root string) string {
120
- data, err := os.ReadFile(filepath.Join(root, "go.mod"))
121
- if err == nil {
122
- for _, line := range strings.Split(string(data), "\n") {
123
- if value, ok := strings.CutPrefix(strings.TrimSpace(line), "module "); ok {
124
- return strings.TrimSpace(value)
125
- }
126
- }
127
- }
128
- return filepath.ToSlash(filepath.Clean(root))
129
- }
130
-
131
- // ImportsOf is a file's imports by the name the file uses for them: the alias
132
- // when there is one, the last path segment when there is not. Blank and dot
133
- // imports keep the segment, since nothing in the file refers to them by name.
134
- //
135
- // A segment with a dot in it - `nats.go`, `yaml.v3` - is not a Go identifier,
136
- // and the package behind it is called by what comes before the dot; that name
137
- // is recorded too, since it is the one the file uses.
138
- func ImportsOf(node *ast.File) map[string]string {
139
- out := map[string]string{}
140
- for _, spec := range node.Imports {
141
- value, err := strconv.Unquote(spec.Path.Value)
142
- if err != nil {
143
- continue
144
- }
145
- name := path.Base(value)
146
- if spec.Name != nil && spec.Name.Name != "_" && spec.Name.Name != "." {
147
- name = spec.Name.Name
148
- }
149
- out[name] = value
150
- if short, _, dotted := strings.Cut(name, "."); dotted && short != "" {
151
- out[short] = value
152
- }
153
- }
154
- return out
155
- }
@@ -1,99 +0,0 @@
1
- package goscan
2
-
3
- import (
4
- "bytes"
5
- "go/ast"
6
- "go/printer"
7
- "reflect"
8
- "strconv"
9
- "strings"
10
- )
11
-
12
- // Unwrap takes the parentheses, the address-of and the pointer off an
13
- // expression, down to the thing itself.
14
- func Unwrap(expr ast.Expr) ast.Expr {
15
- for {
16
- switch value := expr.(type) {
17
- case *ast.ParenExpr:
18
- expr = value.X
19
- case *ast.UnaryExpr:
20
- expr = value.X
21
- case *ast.StarExpr:
22
- expr = value.X
23
- default:
24
- return expr
25
- }
26
- }
27
- }
28
-
29
- // TypeKey names a type the way the tree indexes types: "<import path>.<Name>"
30
- // for a named type, whether written bare or through an import; the builtin's
31
- // own name; "[]T" and "map[K]V" over their parts; "interface" for any
32
- // interface literal. Empty for a type this reader does not name.
33
- func (t *Tree) TypeKey(expr ast.Expr, file *File) string {
34
- if expr == nil {
35
- return ""
36
- }
37
- switch value := Unwrap(expr).(type) {
38
- case *ast.Ident:
39
- if IsBuiltin(value.Name) {
40
- return value.Name
41
- }
42
- return file.Pkg + "." + value.Name
43
- case *ast.SelectorExpr:
44
- if base, ok := value.X.(*ast.Ident); ok {
45
- return file.Imports[base.Name] + "." + value.Sel.Name
46
- }
47
- case *ast.ArrayType:
48
- return "[]" + t.TypeKey(value.Elt, file)
49
- case *ast.MapType:
50
- return "map[" + t.TypeKey(value.Key, file) + "]" + t.TypeKey(value.Value, file)
51
- case *ast.InterfaceType:
52
- return "interface"
53
- }
54
- return ""
55
- }
56
-
57
- // IsBuiltin is whether a bare identifier is one of the language's own types.
58
- func IsBuiltin(name string) bool {
59
- switch name {
60
- case "string", "bool", "byte", "rune", "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "float32", "float64", "error", "any":
61
- return true
62
- }
63
- return false
64
- }
65
-
66
- // FieldsOf lists a struct's named fields as "name type", the name being what
67
- // the json tag says when it says anything, and a field tagged "-" left out:
68
- // the fields as they travel, not as the code calls them.
69
- func (t *Tree) FieldsOf(body *ast.StructType) []string {
70
- var out []string
71
- for _, field := range body.Fields.List {
72
- if len(field.Names) == 0 {
73
- continue
74
- }
75
- typeName := t.PrintNode(field.Type)
76
- for _, ident := range field.Names {
77
- name := ident.Name
78
- if field.Tag != nil {
79
- tagText, _ := strconv.Unquote(field.Tag.Value)
80
- jsonName := strings.Split(reflect.StructTag(tagText).Get("json"), ",")[0]
81
- if jsonName == "-" {
82
- continue
83
- }
84
- if jsonName != "" {
85
- name = jsonName
86
- }
87
- }
88
- out = append(out, name+" "+typeName)
89
- }
90
- }
91
- return out
92
- }
93
-
94
- // PrintNode is a node as source text.
95
- func (t *Tree) PrintNode(node ast.Node) string {
96
- var out bytes.Buffer
97
- _ = printer.Fprint(&out, t.Fset, node)
98
- return out.String()
99
- }