@shortlink-org/portolan 0.1.0 → 0.2.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.
- package/README.md +69 -205
- package/cli/init.mjs +285 -0
- package/cli/init.test.mjs +158 -0
- package/cli/portolan.mjs +37 -73
- package/index.html +19 -0
- package/package.json +5 -10
- package/plugins/README.md +66 -27
- package/plugins/portolan-go.wasm +0 -0
- package/portolan.json +52 -73
- package/public/landing/cats/bug-hunter.webp +0 -0
- package/public/landing/cats/compass-nap.webp +0 -0
- package/public/landing/cats/diagrammer.webp +0 -0
- package/public/landing/cats/docs-reader.webp +0 -0
- package/public/landing/cats/laptop.webp +0 -0
- package/public/landing/cats/map-inspector.webp +0 -0
- package/public/landing/cats/server-break.webp +0 -0
- package/public/landing/cats/star-mapper.webp +0 -0
- package/public/landing/cats/system-builder.webp +0 -0
- package/public/landing/cats/thread-tangle.webp +0 -0
- package/public/og.png +0 -0
- package/public/readme-header.webp +0 -0
- package/schema/portolan.schema.json +180 -0
- package/scripts/builtin-plugins.mjs +14 -0
- package/scripts/delivery-presets.mjs +353 -0
- package/scripts/gen.mjs +37 -4
- package/scripts/history.mjs +126 -0
- package/scripts/history.test.mjs +110 -0
- package/scripts/host-plugins/fetch-bsr.mjs +351 -0
- package/{plugins/fetch-bsr/options.schema.json → scripts/host-plugins/fetch-bsr.options.json} +4 -0
- package/scripts/host-plugins/fetch-bsr.test.mjs +212 -0
- package/scripts/host-plugins/fetch-csr.mjs +386 -0
- package/scripts/host-plugins/fetch-csr.test.mjs +178 -0
- package/scripts/host-plugins/fetch-git.mjs +379 -0
- package/scripts/host-plugins/fetch-git.test.mjs +210 -0
- package/scripts/local-api.mjs +22 -4
- package/scripts/local-api.test.mjs +84 -2
- package/scripts/manifest.mjs +3 -2
- package/scripts/package-smoke.mjs +6 -2
- package/scripts/plugin-host.mjs +77 -18
- package/scripts/plugin-host.test.mjs +50 -1
- package/scripts/plugin-wasm-worker.mjs +6 -3
- package/scripts/run-builtin.mjs +6 -26
- package/scripts/schema.mjs +6 -1
- package/src/app/App.tsx +24 -429
- package/src/app/Breadcrumbs.test.ts +7 -0
- package/src/app/Breadcrumbs.tsx +15 -2
- package/src/app/CatalogApp.tsx +436 -0
- package/src/app/Sidebar.tsx +0 -1
- package/src/chat/ChatPanel.tsx +98 -41
- package/src/chat/Composer.tsx +4 -2
- package/src/chat/Conversation.tsx +79 -15
- package/src/chat/Header.tsx +43 -9
- package/src/chat/Starter.tsx +64 -3
- package/src/chat/Steps.tsx +1 -1
- package/src/chat/flags.test.ts +51 -14
- package/src/chat/flags.ts +8 -2
- package/src/chat/page-context.test.ts +51 -0
- package/src/chat/page-context.ts +128 -0
- package/src/chat/prompt.test.ts +49 -1
- package/src/chat/prompt.ts +42 -1
- package/src/chat/tools.ts +7 -2
- package/src/chat/transport.ts +16 -4
- package/src/components/ProblemRow.tsx +182 -0
- package/src/data.ts +20 -5
- package/src/er/ErCanvas.tsx +1 -1
- package/src/graph/DependencyGraph.tsx +10 -1
- package/src/graph/FocusedEventGraph.tsx +1 -1
- package/src/graph/GraphToolbar.tsx +2 -4
- package/src/index.css +220 -2
- package/src/landing/DraggableReveal.tsx +168 -0
- package/src/landing/EstateGraph.tsx +28 -0
- package/src/landing/FlowPlayback.tsx +282 -0
- package/src/landing/HeroMap.tsx +128 -0
- package/src/landing/LandingPage.tsx +757 -0
- package/src/landing/ProductFrame.tsx +68 -0
- package/src/landing/ProductTour.tsx +371 -0
- package/src/landing/catalog.ts +25 -0
- package/src/landing/motion.tsx +52 -0
- package/src/lib/all-problems.ts +28 -0
- package/src/lib/local-api.ts +35 -1
- package/src/lib/setup-info.test.ts +8 -0
- package/src/lib/setup-info.ts +3 -2
- package/src/lib/source-code.ts +2 -1
- package/src/likec4/C4View.tsx +5 -0
- package/src/likec4/InteractiveView.tsx +5 -1
- package/src/map/ContextMapGraph.tsx +47 -20
- package/src/pages/ContextMap.tsx +5 -1
- package/src/pages/FlowDetail.tsx +24 -7
- package/src/pages/Overview.tsx +68 -12
- package/src/pages/Problems.tsx +6 -193
- package/src/pages/Settings.tsx +133 -108
- package/src/pages/settings/DeliverySettings.tsx +229 -0
- package/src/pages/settings/PreferencesSettings.tsx +101 -0
- package/src/routes.test.ts +20 -0
- package/src/routes.ts +13 -1
- package/vite.config.ts +12 -8
- package/catalog/enum_test.go +0 -46
- package/catalog/model.go +0 -932
- package/catalog/roundtrip_test.go +0 -185
- package/catalog/via_test.go +0 -38
- package/go.mod +0 -14
- package/go.sum +0 -14
- package/internal/commands/cargo.go +0 -154
- package/internal/commands/commands.go +0 -143
- package/internal/commands/commands_test.go +0 -323
- package/internal/commands/gradle.go +0 -77
- package/internal/commands/justfile.go +0 -82
- package/internal/commands/makefile.go +0 -106
- package/internal/commands/maven.go +0 -93
- package/internal/commands/packagejson.go +0 -159
- package/internal/commands/pyproject.go +0 -169
- package/internal/commands/taskfile.go +0 -101
- package/internal/commands/testdata/estate/.cargo/config.toml +0 -7
- package/internal/commands/testdata/estate/Makefile +0 -33
- package/internal/commands/testdata/estate/Taskfile.yml +0 -21
- package/internal/commands/testdata/estate/build.gradle.kts +0 -21
- package/internal/commands/testdata/estate/justfile +0 -20
- package/internal/commands/testdata/estate/package.json +0 -13
- package/internal/commands/testdata/estate/pom.xml +0 -29
- package/internal/commands/testdata/estate/pyproject.toml +0 -27
- package/internal/commands/testdata/estate/xtask/src/main.rs +0 -27
- package/internal/commands/testdata/golden/commands.json +0 -305
- package/internal/gohttp/analyze.go +0 -2500
- package/internal/gohttp/endpoints.go +0 -1067
- package/internal/gohttp/roots.go +0 -320
- package/internal/gohttp/typed.go +0 -143
- package/internal/goscan/constants.go +0 -85
- package/internal/goscan/goscan_test.go +0 -227
- package/internal/goscan/names.go +0 -52
- package/internal/goscan/parse_test.go +0 -11
- package/internal/goscan/source.go +0 -36
- package/internal/goscan/tree.go +0 -155
- package/internal/goscan/types.go +0 -99
- package/internal/wsdl/ids.go +0 -127
- package/internal/wsdl/ids_test.go +0 -21
- package/internal/wsdl/model.go +0 -62
- package/internal/wsdl/parse.go +0 -920
- package/internal/wsdl/parse_test.go +0 -133
- package/plugin/describe.go +0 -107
- package/plugin/describe_test.go +0 -114
- package/plugin/protocol.go +0 -117
- package/plugin/schematest/schematest.go +0 -126
- package/plugins/extract-adr/describe.go +0 -19
- package/plugins/extract-adr/describe_test.go +0 -11
- package/plugins/extract-adr/extract.go +0 -153
- package/plugins/extract-adr/extract_test.go +0 -350
- package/plugins/extract-adr/history.go +0 -99
- package/plugins/extract-adr/main.go +0 -65
- package/plugins/extract-adr/parse.go +0 -642
- package/plugins/extract-adr/parse_test.go +0 -405
- package/plugins/extract-asyncapi/describe.go +0 -19
- package/plugins/extract-asyncapi/describe_test.go +0 -11
- package/plugins/extract-asyncapi/extract.go +0 -315
- package/plugins/extract-asyncapi/extract_test.go +0 -197
- package/plugins/extract-asyncapi/main.go +0 -48
- package/plugins/extract-asyncapi/spec.go +0 -151
- package/plugins/extract-commands/describe.go +0 -19
- package/plugins/extract-commands/describe_test.go +0 -11
- package/plugins/extract-commands/extract.go +0 -79
- package/plugins/extract-commands/extract_test.go +0 -92
- package/plugins/extract-commands/main.go +0 -55
- package/plugins/extract-csr/avro.go +0 -258
- package/plugins/extract-csr/describe.go +0 -19
- package/plugins/extract-csr/describe_test.go +0 -11
- package/plugins/extract-csr/extract.go +0 -338
- package/plugins/extract-csr/extract_test.go +0 -374
- package/plugins/extract-csr/jsonschema.go +0 -343
- package/plugins/extract-csr/lock.go +0 -25
- package/plugins/extract-csr/main.go +0 -84
- package/plugins/extract-csr/subject.go +0 -102
- package/plugins/extract-flows/describe.go +0 -19
- package/plugins/extract-flows/describe_test.go +0 -11
- package/plugins/extract-flows/extract.go +0 -91
- package/plugins/extract-flows/main.go +0 -45
- package/plugins/extract-flows/parse.go +0 -593
- package/plugins/extract-flows/parse_test.go +0 -204
- package/plugins/extract-glossary/describe.go +0 -19
- package/plugins/extract-glossary/describe_test.go +0 -11
- package/plugins/extract-glossary/extract.go +0 -115
- package/plugins/extract-glossary/extract_test.go +0 -220
- package/plugins/extract-glossary/main.go +0 -59
- package/plugins/extract-glossary/parse.go +0 -214
- package/plugins/extract-glossary/parse_test.go +0 -203
- package/plugins/extract-go/aggregate.go +0 -214
- package/plugins/extract-go/client.go +0 -409
- package/plugins/extract-go/client_test.go +0 -266
- package/plugins/extract-go/describe.go +0 -19
- package/plugins/extract-go/describe_test.go +0 -11
- package/plugins/extract-go/enum.go +0 -195
- package/plugins/extract-go/enum_test.go +0 -82
- package/plugins/extract-go/event.go +0 -99
- package/plugins/extract-go/extract.go +0 -191
- package/plugins/extract-go/extract_test.go +0 -261
- package/plugins/extract-go/flow.go +0 -1441
- package/plugins/extract-go/flow_test.go +0 -609
- package/plugins/extract-go/httpclient.go +0 -174
- package/plugins/extract-go/httpclient_test.go +0 -296
- package/plugins/extract-go/ids.go +0 -92
- package/plugins/extract-go/layout.go +0 -225
- package/plugins/extract-go/layout_test.go +0 -125
- package/plugins/extract-go/lifecycle.go +0 -324
- package/plugins/extract-go/lifecycle_test.go +0 -108
- package/plugins/extract-go/main.go +0 -79
- package/plugins/extract-go/operation.go +0 -157
- package/plugins/extract-go/source.go +0 -316
- package/plugins/extract-go/transport.go +0 -321
- package/plugins/extract-go/transport_test.go +0 -145
- package/plugins/extract-go/wiring.go +0 -434
- package/plugins/extract-go-nats/describe.go +0 -19
- package/plugins/extract-go-nats/describe_test.go +0 -11
- package/plugins/extract-go-nats/extract.go +0 -177
- package/plugins/extract-go-nats/extract_test.go +0 -389
- package/plugins/extract-go-nats/index.go +0 -379
- package/plugins/extract-go-nats/main.go +0 -42
- package/plugins/extract-go-nats/resolve.go +0 -161
- package/plugins/extract-go-nats/sites.go +0 -224
- package/plugins/extract-graphql/describe.go +0 -19
- package/plugins/extract-graphql/describe_test.go +0 -11
- package/plugins/extract-graphql/extract.go +0 -433
- package/plugins/extract-graphql/extract_test.go +0 -256
- package/plugins/extract-graphql/ids.go +0 -49
- package/plugins/extract-graphql/lex.go +0 -237
- package/plugins/extract-graphql/main.go +0 -51
- package/plugins/extract-graphql/parse.go +0 -621
- package/plugins/extract-graphql/parse_test.go +0 -122
- package/plugins/extract-http-clients/describe.go +0 -19
- package/plugins/extract-http-clients/describe_test.go +0 -11
- package/plugins/extract-http-clients/extract.go +0 -705
- package/plugins/extract-http-clients/extract_test.go +0 -1263
- package/plugins/extract-http-clients/main.go +0 -42
- package/plugins/extract-openapi/describe.go +0 -19
- package/plugins/extract-openapi/describe_test.go +0 -11
- package/plugins/extract-openapi/discover.go +0 -243
- package/plugins/extract-openapi/extract.go +0 -526
- package/plugins/extract-openapi/extract_test.go +0 -545
- package/plugins/extract-openapi/main.go +0 -75
- package/plugins/extract-openapi/spec.go +0 -350
- package/plugins/extract-project/describe.go +0 -19
- package/plugins/extract-project/describe_test.go +0 -11
- package/plugins/extract-project/extract.go +0 -221
- package/plugins/extract-project/extract_test.go +0 -109
- package/plugins/extract-project/main.go +0 -41
- package/plugins/extract-proto/ast.go +0 -125
- package/plugins/extract-proto/consumes.go +0 -77
- package/plugins/extract-proto/describe.go +0 -19
- package/plugins/extract-proto/extract.go +0 -293
- package/plugins/extract-proto/extract_test.go +0 -459
- package/plugins/extract-proto/ids.go +0 -89
- package/plugins/extract-proto/ids_test.go +0 -57
- package/plugins/extract-proto/lex.go +0 -285
- package/plugins/extract-proto/main.go +0 -100
- package/plugins/extract-proto/module.go +0 -120
- package/plugins/extract-proto/parse.go +0 -720
- package/plugins/extract-proto/parse_test.go +0 -307
- package/plugins/extract-proto/provides.go +0 -236
- package/plugins/extract-proto/resolve.go +0 -222
- package/plugins/extract-proto/resolve_test.go +0 -119
- package/plugins/extract-redis/describe.go +0 -19
- package/plugins/extract-redis/describe_test.go +0 -11
- package/plugins/extract-redis/extract.go +0 -183
- package/plugins/extract-redis/extract_test.go +0 -168
- package/plugins/extract-redis/keyspaces.go +0 -469
- package/plugins/extract-redis/main.go +0 -44
- package/plugins/extract-river/describe.go +0 -19
- package/plugins/extract-river/describe_test.go +0 -11
- package/plugins/extract-river/extract.go +0 -507
- package/plugins/extract-river/extract_test.go +0 -132
- package/plugins/extract-river/main.go +0 -42
- package/plugins/extract-sql/ddl.go +0 -893
- package/plugins/extract-sql/ddl_test.go +0 -401
- package/plugins/extract-sql/describe.go +0 -19
- package/plugins/extract-sql/describe_test.go +0 -11
- package/plugins/extract-sql/layout.go +0 -221
- package/plugins/extract-sql/layout_test.go +0 -55
- package/plugins/extract-sql/lineage.go +0 -107
- package/plugins/extract-sql/main.go +0 -141
- package/plugins/extract-sql/maps.go +0 -564
- package/plugins/extract-sql/maps_java.go +0 -117
- package/plugins/extract-sql/maps_rust.go +0 -333
- package/plugins/extract-sql/maps_rust_test.go +0 -70
- package/plugins/extract-sql/maps_test.go +0 -204
- package/plugins/extract-sql/maps_ts.go +0 -398
- package/plugins/extract-sql/maps_ts_test.go +0 -136
- package/plugins/extract-sql/projection.go +0 -70
- package/plugins/extract-sql/projection_test.go +0 -50
- package/plugins/extract-sql/store.go +0 -420
- package/plugins/extract-sql/store_test.go +0 -233
- package/plugins/extract-sql/view.go +0 -295
- package/plugins/extract-watermill/describe.go +0 -19
- package/plugins/extract-watermill/describe_test.go +0 -11
- package/plugins/extract-watermill/extract.go +0 -1228
- package/plugins/extract-watermill/extract_test.go +0 -234
- package/plugins/extract-watermill/main.go +0 -41
- package/plugins/extract-wsdl/describe.go +0 -19
- package/plugins/extract-wsdl/describe_test.go +0 -11
- package/plugins/extract-wsdl/extract.go +0 -148
- package/plugins/extract-wsdl/extract_test.go +0 -45
- package/plugins/extract-wsdl/main.go +0 -53
- package/plugins/fetch-bsr/auth.go +0 -114
- package/plugins/fetch-bsr/bsr.go +0 -240
- package/plugins/fetch-bsr/cache.go +0 -66
- package/plugins/fetch-bsr/describe.go +0 -19
- package/plugins/fetch-bsr/fetch.go +0 -192
- package/plugins/fetch-bsr/fetch_test.go +0 -465
- package/plugins/fetch-bsr/lock.go +0 -71
- package/plugins/fetch-bsr/main.go +0 -117
- package/plugins/fetch-csr/auth.go +0 -95
- package/plugins/fetch-csr/cache.go +0 -69
- package/plugins/fetch-csr/describe.go +0 -19
- package/plugins/fetch-csr/describe_test.go +0 -11
- package/plugins/fetch-csr/fetch.go +0 -254
- package/plugins/fetch-csr/fetch_test.go +0 -494
- package/plugins/fetch-csr/lock.go +0 -95
- package/plugins/fetch-csr/main.go +0 -122
- package/plugins/fetch-csr/registry.go +0 -209
- package/plugins/fetch-git/cache.go +0 -65
- package/plugins/fetch-git/describe.go +0 -19
- package/plugins/fetch-git/describe_test.go +0 -11
- package/plugins/fetch-git/fetch.go +0 -181
- package/plugins/fetch-git/fetch_test.go +0 -332
- package/plugins/fetch-git/git.go +0 -169
- package/plugins/fetch-git/lock.go +0 -72
- package/plugins/fetch-git/main.go +0 -127
- package/plugins/fetch-git/offline.go +0 -39
- package/plugins/fetch-git/pin.go +0 -90
- package/plugins/fetch-git/pin_test.go +0 -74
- package/plugins/gen-backstage/describe.go +0 -17
- package/plugins/gen-backstage/main.go +0 -22
- package/plugins/gen-backstage/plugin.go +0 -473
- package/plugins/gen-backstage/plugin_test.go +0 -145
- package/plugins/gen-backstage.wasm +0 -0
- package/plugins/gen-markdown/adr.go +0 -162
- package/plugins/gen-markdown/aggregate.go +0 -362
- package/plugins/gen-markdown/canonical.go +0 -93
- package/plugins/gen-markdown/context.go +0 -90
- package/plugins/gen-markdown/coverage_test.go +0 -89
- package/plugins/gen-markdown/describe.go +0 -19
- package/plugins/gen-markdown/describe_test.go +0 -11
- package/plugins/gen-markdown/external.go +0 -71
- package/plugins/gen-markdown/flow.go +0 -277
- package/plugins/gen-markdown/glossary.go +0 -76
- package/plugins/gen-markdown/glossary_test.go +0 -148
- package/plugins/gen-markdown/llms.go +0 -302
- package/plugins/gen-markdown/main.go +0 -22
- package/plugins/gen-markdown/markdown.go +0 -254
- package/plugins/gen-markdown/markdown_test.go +0 -100
- package/plugins/gen-markdown/module.go +0 -107
- package/plugins/gen-markdown/plugin.go +0 -39
- package/plugins/gen-markdown/quality_test.go +0 -176
- package/plugins/gen-markdown/redis_test.go +0 -38
- package/plugins/gen-markdown/render.go +0 -344
- package/plugins/gen-markdown/render_test.go +0 -186
- package/plugins/gen-markdown/service.go +0 -456
- package/plugins/gen-markdown/source.go +0 -177
- package/plugins/gen-markdown/store.go +0 -201
- package/plugins/gen-markdown.wasm +0 -0
- package/plugins/gen-mermaid/describe.go +0 -17
- package/plugins/gen-mermaid/main.go +0 -22
- package/plugins/gen-mermaid/plugin.go +0 -104
- package/plugins/gen-mermaid/plugin_test.go +0 -33
- package/plugins/gen-mermaid.wasm +0 -0
- package/plugins/openapi/ids.go +0 -261
- package/plugins/openapi/ids_test.go +0 -98
- package/plugins/verify-codeowners/describe.go +0 -19
- package/plugins/verify-codeowners/describe_test.go +0 -11
- package/plugins/verify-codeowners/main.go +0 -75
- package/plugins/verify-codeowners/match.go +0 -85
- package/plugins/verify-codeowners/match_test.go +0 -47
- package/plugins/verify-codeowners/owners.go +0 -164
- package/plugins/verify-codeowners/owners_test.go +0 -225
- package/plugins/verify-codeowners/parse.go +0 -90
- package/plugins/verify-codeowners/parse_test.go +0 -62
- package/plugins/verify-otel/describe.go +0 -19
- package/plugins/verify-otel/describe_test.go +0 -11
- package/plugins/verify-otel/main.go +0 -53
- package/plugins/verify-otel/match.go +0 -336
- package/plugins/verify-otel/otlp.go +0 -200
- package/plugins/verify-otel/verify.go +0 -734
- package/plugins/verify-otel/verify_test.go +0 -460
- /package/{plugins/fetch-csr/options.schema.json → scripts/host-plugins/fetch-csr.options.json} +0 -0
- /package/{plugins/fetch-git/options.schema.json → scripts/host-plugins/fetch-git.options.json} +0 -0
|
@@ -1,434 +0,0 @@
|
|
|
1
|
-
package main
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"go/ast"
|
|
5
|
-
"go/types"
|
|
6
|
-
"strings"
|
|
7
|
-
)
|
|
8
|
-
|
|
9
|
-
// portBindings reads internal/di/provider for the one thing a use case cannot
|
|
10
|
-
// say about itself: which other use case fills a port it declares.
|
|
11
|
-
//
|
|
12
|
-
// A use case states its need as an interface of its own - login.Authenticator -
|
|
13
|
-
// precisely so that it does not import the package that satisfies it. The
|
|
14
|
-
// binding therefore exists nowhere in either of them; it exists in assembly,
|
|
15
|
-
// as a provider whose result is the port and whose parameter is the use case:
|
|
16
|
-
//
|
|
17
|
-
// func ProvideAuthenticator(uc *authenticate.UseCase) login.Authenticator
|
|
18
|
-
//
|
|
19
|
-
// Result and parameter are both written in the signature, so for a port filled
|
|
20
|
-
// by one use case this reads the declaration and never the body.
|
|
21
|
-
//
|
|
22
|
-
// A port can also be filled by several use cases at once - one per method,
|
|
23
|
-
// with an adapter in between:
|
|
24
|
-
//
|
|
25
|
-
// func ProvideLockout(check *check.UseCase, failed *record_failure.UseCase, ...) authenticate.Lockout {
|
|
26
|
-
// return lockoutAdapter{check: check, failed: failed, ...}
|
|
27
|
-
// }
|
|
28
|
-
// func (l lockoutAdapter) Failed(ctx context.Context, id string) error {
|
|
29
|
-
// return l.failed.Handle(ctx, ...)
|
|
30
|
-
// }
|
|
31
|
-
//
|
|
32
|
-
// The signature alone cannot say which method reaches which use case, so
|
|
33
|
-
// these are read off the adapter: the struct the provider returns, and which
|
|
34
|
-
// field's Handle each of its methods calls. Such a binding is keyed by port
|
|
35
|
-
// and method, "user/authenticate.Lockout.Failed", beside the port-level key
|
|
36
|
-
// the single-use-case case produces. An adapter this cannot read falls back to
|
|
37
|
-
// the first use case in the signature, which is the reading it always had.
|
|
38
|
-
//
|
|
39
|
-
// A provider that builds its port out of something else is not a binding
|
|
40
|
-
// between use cases and does not appear here.
|
|
41
|
-
func portBindings(root string, layouts ...sourceLayout) map[string]string {
|
|
42
|
-
out := map[string]string{}
|
|
43
|
-
|
|
44
|
-
packages := goPackageDirs(root, "internal")
|
|
45
|
-
if len(layouts) > 0 {
|
|
46
|
-
packages = layouts[0].packages
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
for _, dir := range packages {
|
|
50
|
-
pkg, err := parsePkg(root, dir)
|
|
51
|
-
if err != nil {
|
|
52
|
-
continue
|
|
53
|
-
}
|
|
54
|
-
for _, file := range pkg.files {
|
|
55
|
-
useCases := useCaseImports(file, layouts...)
|
|
56
|
-
if len(useCases) == 0 {
|
|
57
|
-
continue
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
for _, decl := range file.Decls {
|
|
61
|
-
fn, ok := decl.(*ast.FuncDecl)
|
|
62
|
-
if !ok || fn.Recv != nil || fn.Type.Results == nil {
|
|
63
|
-
continue
|
|
64
|
-
}
|
|
65
|
-
if len(fn.Type.Results.List) != 1 {
|
|
66
|
-
continue
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
port, ok := portName(fn.Type.Results.List[0].Type, useCases)
|
|
70
|
-
if !ok {
|
|
71
|
-
continue
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
var bound []string
|
|
75
|
-
for _, param := range params(fn) {
|
|
76
|
-
if useCase, ok := useCaseParam(param, useCases); ok {
|
|
77
|
-
bound = append(bound, useCase)
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
if len(bound) == 0 {
|
|
81
|
-
continue
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if len(bound) > 1 {
|
|
85
|
-
perMethod := methodBindings(file, fn, useCases)
|
|
86
|
-
for method, useCase := range perMethod {
|
|
87
|
-
out[port+"."+method] = useCase
|
|
88
|
-
}
|
|
89
|
-
if len(perMethod) > 0 {
|
|
90
|
-
continue
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
out[port] = bound[0]
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return out
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// methodBindings reads which use case each method of a provider's adapter
|
|
103
|
-
// reaches: the struct the provider returns, its fields' types, and the field
|
|
104
|
-
// whose Handle each method calls. Empty when any of those cannot be read.
|
|
105
|
-
func methodBindings(file *ast.File, provider *ast.FuncDecl, useCases map[string]string) map[string]string {
|
|
106
|
-
adapter := returnedType(provider)
|
|
107
|
-
if adapter == "" {
|
|
108
|
-
return nil
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
fields := adapterFields(file, adapter)
|
|
112
|
-
out := map[string]string{}
|
|
113
|
-
|
|
114
|
-
for method, field := range handleCalls(file, adapter) {
|
|
115
|
-
if useCase, ok := useCaseParam(fields[field], useCases); ok {
|
|
116
|
-
out[method] = useCase
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return out
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// returnedType names the struct a provider returns as a composite literal,
|
|
124
|
-
// `return lockoutAdapter{...}` or `return &lockoutAdapter{...}`. Anything else
|
|
125
|
-
// - a call, a variable - is not read.
|
|
126
|
-
func returnedType(fn *ast.FuncDecl) string {
|
|
127
|
-
if fn.Body == nil {
|
|
128
|
-
return ""
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
name := ""
|
|
132
|
-
ast.Inspect(fn.Body, func(n ast.Node) bool {
|
|
133
|
-
ret, ok := n.(*ast.ReturnStmt)
|
|
134
|
-
if !ok || len(ret.Results) != 1 || name != "" {
|
|
135
|
-
return true
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
expr := ret.Results[0]
|
|
139
|
-
if unary, ok := expr.(*ast.UnaryExpr); ok {
|
|
140
|
-
expr = unary.X
|
|
141
|
-
}
|
|
142
|
-
if lit, ok := expr.(*ast.CompositeLit); ok {
|
|
143
|
-
if ident, ok := lit.Type.(*ast.Ident); ok {
|
|
144
|
-
name = ident.Name
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return true
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
return name
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// adapterFields reads the field types of a struct declared in the file.
|
|
155
|
-
func adapterFields(file *ast.File, typeName string) map[string]ast.Expr {
|
|
156
|
-
out := map[string]ast.Expr{}
|
|
157
|
-
|
|
158
|
-
for _, decl := range file.Decls {
|
|
159
|
-
gen, ok := decl.(*ast.GenDecl)
|
|
160
|
-
if !ok {
|
|
161
|
-
continue
|
|
162
|
-
}
|
|
163
|
-
for _, spec := range gen.Specs {
|
|
164
|
-
ts, ok := spec.(*ast.TypeSpec)
|
|
165
|
-
if !ok || ts.Name.Name != typeName {
|
|
166
|
-
continue
|
|
167
|
-
}
|
|
168
|
-
st, ok := ts.Type.(*ast.StructType)
|
|
169
|
-
if !ok {
|
|
170
|
-
continue
|
|
171
|
-
}
|
|
172
|
-
for _, field := range st.Fields.List {
|
|
173
|
-
for _, name := range field.Names {
|
|
174
|
-
out[name.Name] = field.Type
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return out
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// handleCalls reads, for every method on typeName in the file, the field whose
|
|
184
|
-
// Handle it calls: `l.failed.Handle(ctx, ...)` gives Failed -> "failed". A
|
|
185
|
-
// method that calls Handle on two fields is read as the first; none here does.
|
|
186
|
-
func handleCalls(file *ast.File, typeName string) map[string]string {
|
|
187
|
-
out := map[string]string{}
|
|
188
|
-
|
|
189
|
-
for _, decl := range file.Decls {
|
|
190
|
-
fn, ok := decl.(*ast.FuncDecl)
|
|
191
|
-
if !ok || fn.Recv == nil || fn.Body == nil || receiverTypeName(fn) != typeName {
|
|
192
|
-
continue
|
|
193
|
-
}
|
|
194
|
-
recv := receiverIdent(fn)
|
|
195
|
-
if recv == "" {
|
|
196
|
-
continue
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
ast.Inspect(fn.Body, func(n ast.Node) bool {
|
|
200
|
-
call, ok := n.(*ast.CallExpr)
|
|
201
|
-
if !ok {
|
|
202
|
-
return true
|
|
203
|
-
}
|
|
204
|
-
sel, ok := call.Fun.(*ast.SelectorExpr)
|
|
205
|
-
if !ok || sel.Sel.Name != "Handle" {
|
|
206
|
-
return true
|
|
207
|
-
}
|
|
208
|
-
field, ok := sel.X.(*ast.SelectorExpr)
|
|
209
|
-
if !ok {
|
|
210
|
-
return true
|
|
211
|
-
}
|
|
212
|
-
base, ok := field.X.(*ast.Ident)
|
|
213
|
-
if !ok || base.Name != recv {
|
|
214
|
-
return true
|
|
215
|
-
}
|
|
216
|
-
if _, seen := out[fn.Name.Name]; !seen {
|
|
217
|
-
out[fn.Name.Name] = field.Sel.Name
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return true
|
|
221
|
-
})
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return out
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// receiverTypeName reads `lockoutAdapter` off `(l lockoutAdapter)` and
|
|
228
|
-
// `(l *lockoutAdapter)` alike.
|
|
229
|
-
func receiverTypeName(fn *ast.FuncDecl) string {
|
|
230
|
-
if fn.Recv == nil || len(fn.Recv.List) == 0 {
|
|
231
|
-
return ""
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
expr := fn.Recv.List[0].Type
|
|
235
|
-
if star, ok := expr.(*ast.StarExpr); ok {
|
|
236
|
-
expr = star.X
|
|
237
|
-
}
|
|
238
|
-
if ident, ok := expr.(*ast.Ident); ok {
|
|
239
|
-
return ident.Name
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return ""
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// portName turns the result type `login.Authenticator` into the key the use
|
|
246
|
-
// case's own field carries: "session/login.Authenticator". The field is written
|
|
247
|
-
// unqualified there - it is declared in that package - so the use case has to
|
|
248
|
-
// be part of the key or two ports of the same name would collide.
|
|
249
|
-
func portName(expr ast.Expr, useCases map[string]string) (string, bool) {
|
|
250
|
-
selector, name, found := strings.Cut(types.ExprString(expr), ".")
|
|
251
|
-
if !found {
|
|
252
|
-
return "", false
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
useCase, known := useCases[selector]
|
|
256
|
-
if !known {
|
|
257
|
-
return "", false
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return useCase + "." + name, true
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// useCaseParam reads `*authenticate.UseCase` back to "user/authenticate".
|
|
264
|
-
func useCaseParam(expr ast.Expr, useCases map[string]string) (string, bool) {
|
|
265
|
-
selector, name, found := strings.Cut(strings.TrimPrefix(types.ExprString(expr), "*"), ".")
|
|
266
|
-
if !found || name != "UseCase" {
|
|
267
|
-
return "", false
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
useCase, known := useCases[selector]
|
|
271
|
-
|
|
272
|
-
return useCase, known
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// adapterDecl is a provider whose result is a port of a use case and whose
|
|
276
|
-
// parameters are not another use case: whatever it builds the port out of,
|
|
277
|
-
// the flow reader will have to follow.
|
|
278
|
-
type adapterDecl struct {
|
|
279
|
-
pkg *pkg
|
|
280
|
-
fn *ast.FuncDecl
|
|
281
|
-
imports map[string]string
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// adapterBindings reads the same directory for the other kind of binding: a
|
|
285
|
-
// port filled by an adapter over something that is not a use case - a
|
|
286
|
-
// generated client, say. What that something is, and what the adapter does
|
|
287
|
-
// with it, is left to the reader that follows it; here the declaration is
|
|
288
|
-
// enough to know which provider to follow.
|
|
289
|
-
func adapterBindings(root string, layouts ...sourceLayout) map[string]adapterDecl {
|
|
290
|
-
out := map[string]adapterDecl{}
|
|
291
|
-
packages := goPackageDirs(root, "internal")
|
|
292
|
-
if len(layouts) > 0 {
|
|
293
|
-
packages = layouts[0].packages
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
for _, dir := range packages {
|
|
297
|
-
pkg, err := parsePkg(root, dir)
|
|
298
|
-
if err != nil {
|
|
299
|
-
continue
|
|
300
|
-
}
|
|
301
|
-
for _, file := range pkg.files {
|
|
302
|
-
useCases := useCaseImports(file, layouts...)
|
|
303
|
-
if len(useCases) == 0 {
|
|
304
|
-
continue
|
|
305
|
-
}
|
|
306
|
-
imports := map[string]string{}
|
|
307
|
-
for _, spec := range file.Imports {
|
|
308
|
-
importPath := strings.Trim(spec.Path.Value, `"`)
|
|
309
|
-
name := importPath[strings.LastIndex(importPath, "/")+1:]
|
|
310
|
-
if spec.Name != nil {
|
|
311
|
-
name = spec.Name.Name
|
|
312
|
-
}
|
|
313
|
-
imports[name] = importPath
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
for _, decl := range file.Decls {
|
|
317
|
-
fn, ok := decl.(*ast.FuncDecl)
|
|
318
|
-
if !ok || fn.Recv != nil || fn.Type.Results == nil || len(fn.Type.Results.List) != 1 {
|
|
319
|
-
continue
|
|
320
|
-
}
|
|
321
|
-
port, ok := portName(fn.Type.Results.List[0].Type, useCases)
|
|
322
|
-
if !ok {
|
|
323
|
-
continue
|
|
324
|
-
}
|
|
325
|
-
bound := false
|
|
326
|
-
for _, param := range params(fn) {
|
|
327
|
-
if _, ok := useCaseParam(param, useCases); ok {
|
|
328
|
-
bound = true
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
if bound {
|
|
332
|
-
continue
|
|
333
|
-
}
|
|
334
|
-
out[port] = adapterDecl{pkg: pkg, fn: fn, imports: imports}
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return out
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// wireBoundPorts reads direct Wire bindings from a use case's local interface
|
|
343
|
-
// to a concrete adapter:
|
|
344
|
-
//
|
|
345
|
-
// wire.Bind(new(register.PasswordHasher), new(*password.Hasher))
|
|
346
|
-
//
|
|
347
|
-
// Unlike a provider function, this binding has no body to follow. It still
|
|
348
|
-
// proves that the port is deliberate local work rather than a missing domain
|
|
349
|
-
// or use-case binding, so the flow reader can omit the call without warning.
|
|
350
|
-
func wireBoundPorts(root string, layouts ...sourceLayout) map[string]bool {
|
|
351
|
-
out := map[string]bool{}
|
|
352
|
-
packages := goPackageDirs(root, "internal")
|
|
353
|
-
if len(layouts) > 0 {
|
|
354
|
-
packages = layouts[0].packages
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
for _, dir := range packages {
|
|
358
|
-
pkg, err := parsePkg(root, dir)
|
|
359
|
-
if err != nil {
|
|
360
|
-
continue
|
|
361
|
-
}
|
|
362
|
-
for _, file := range pkg.files {
|
|
363
|
-
useCases := useCaseImports(file, layouts...)
|
|
364
|
-
if len(useCases) == 0 {
|
|
365
|
-
continue
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
wireNames := map[string]bool{}
|
|
369
|
-
for _, spec := range file.Imports {
|
|
370
|
-
if strings.Trim(spec.Path.Value, `"`) != "github.com/google/wire" {
|
|
371
|
-
continue
|
|
372
|
-
}
|
|
373
|
-
name := "wire"
|
|
374
|
-
if spec.Name != nil {
|
|
375
|
-
name = spec.Name.Name
|
|
376
|
-
}
|
|
377
|
-
wireNames[name] = true
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
ast.Inspect(file, func(node ast.Node) bool {
|
|
381
|
-
call, ok := node.(*ast.CallExpr)
|
|
382
|
-
if !ok || len(call.Args) < 2 {
|
|
383
|
-
return true
|
|
384
|
-
}
|
|
385
|
-
sel, ok := call.Fun.(*ast.SelectorExpr)
|
|
386
|
-
if !ok || sel.Sel.Name != "Bind" {
|
|
387
|
-
return true
|
|
388
|
-
}
|
|
389
|
-
owner, ok := sel.X.(*ast.Ident)
|
|
390
|
-
if !ok || !wireNames[owner.Name] {
|
|
391
|
-
return true
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
bound, ok := newArgument(call.Args[0])
|
|
395
|
-
if !ok {
|
|
396
|
-
return true
|
|
397
|
-
}
|
|
398
|
-
if port, ok := portName(bound, useCases); ok {
|
|
399
|
-
out[port] = true
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
return true
|
|
403
|
-
})
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
return out
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
func newArgument(expr ast.Expr) (ast.Expr, bool) {
|
|
411
|
-
call, ok := expr.(*ast.CallExpr)
|
|
412
|
-
if !ok || len(call.Args) != 1 {
|
|
413
|
-
return nil, false
|
|
414
|
-
}
|
|
415
|
-
name, ok := call.Fun.(*ast.Ident)
|
|
416
|
-
if !ok || name.Name != "new" {
|
|
417
|
-
return nil, false
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
return call.Args[0], true
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
func params(fn *ast.FuncDecl) []ast.Expr {
|
|
424
|
-
if fn.Type.Params == nil {
|
|
425
|
-
return nil
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
var out []ast.Expr
|
|
429
|
-
for _, param := range fn.Type.Params.List {
|
|
430
|
-
out = append(out, param.Type)
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
return out
|
|
434
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
package main
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
_ "embed"
|
|
5
|
-
|
|
6
|
-
"github.com/shortlink-org/portolan/plugin"
|
|
7
|
-
)
|
|
8
|
-
|
|
9
|
-
//go:embed options.schema.json
|
|
10
|
-
var optionsSchema []byte
|
|
11
|
-
|
|
12
|
-
func descriptor() plugin.Descriptor {
|
|
13
|
-
return plugin.Descriptor{
|
|
14
|
-
Name: "extract-go-nats",
|
|
15
|
-
Summary: "Reads nats.go and JetStream calls, through the port that wraps them, into the subjects a service listens on and publishes to.",
|
|
16
|
-
Phases: []string{plugin.PhaseExtract},
|
|
17
|
-
Options: optionsSchema,
|
|
18
|
-
}
|
|
19
|
-
}
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
package main
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"encoding/json"
|
|
5
|
-
"go/ast"
|
|
6
|
-
"sort"
|
|
7
|
-
"strings"
|
|
8
|
-
|
|
9
|
-
"github.com/shortlink-org/portolan/catalog"
|
|
10
|
-
"github.com/shortlink-org/portolan/internal/goscan"
|
|
11
|
-
"github.com/shortlink-org/portolan/plugin"
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
func extract(in plugin.Input, opts Options) (plugin.Response, error) {
|
|
15
|
-
b := &plugin.Builder{}
|
|
16
|
-
tree, err := goscan.Read(in.Root)
|
|
17
|
-
if err != nil {
|
|
18
|
-
return plugin.Response{}, err
|
|
19
|
-
}
|
|
20
|
-
s := newScanner(tree)
|
|
21
|
-
s.index()
|
|
22
|
-
|
|
23
|
-
sites := s.sites()
|
|
24
|
-
if len(sites) == 0 {
|
|
25
|
-
b.Warn(in.Root, "no nats.go or JetStream call was found")
|
|
26
|
-
}
|
|
27
|
-
channels := s.catalog(sites, b)
|
|
28
|
-
|
|
29
|
-
serviceID := opts.Context + "." + opts.Service
|
|
30
|
-
fragment := catalog.Catalog{
|
|
31
|
-
GeneratedAt: in.GeneratedAt,
|
|
32
|
-
Commit: in.Commit,
|
|
33
|
-
Contexts: []catalog.BoundedContext{{
|
|
34
|
-
ID: opts.Context,
|
|
35
|
-
Slug: opts.Context,
|
|
36
|
-
Services: []catalog.Service{{
|
|
37
|
-
ID: serviceID,
|
|
38
|
-
Slug: opts.Service,
|
|
39
|
-
Provides: []catalog.RpcService{},
|
|
40
|
-
Consumes: []catalog.RpcCall{},
|
|
41
|
-
Aggregates: []catalog.Aggregate{},
|
|
42
|
-
Channels: channels,
|
|
43
|
-
}},
|
|
44
|
-
}},
|
|
45
|
-
Defs: map[string]catalog.TypeDef{},
|
|
46
|
-
Flows: []catalog.Flow{},
|
|
47
|
-
Adrs: []catalog.Adr{},
|
|
48
|
-
}
|
|
49
|
-
encoded, err := json.MarshalIndent(fragment, "", " ")
|
|
50
|
-
if err != nil {
|
|
51
|
-
return plugin.Response{}, err
|
|
52
|
-
}
|
|
53
|
-
b.File(goscan.FirstNonEmpty(opts.Out, "nats.json"), string(encoded)+"\n")
|
|
54
|
-
return b.Response(), nil
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// channelState is one subject as the sites describe it, gathered before it
|
|
58
|
-
// is written out: which way messages go from where, and what they are
|
|
59
|
-
// called when a port said.
|
|
60
|
-
type channelState struct {
|
|
61
|
-
address string
|
|
62
|
-
api string
|
|
63
|
-
sources []string
|
|
64
|
-
notes map[string]bool
|
|
65
|
-
messages map[string]catalog.ChannelMessage
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// catalog turns the sites into channels. A site whose subject cannot be
|
|
69
|
-
// followed to a string is a warning at the call, not a channel with a hole
|
|
70
|
-
// in it.
|
|
71
|
-
func (s *scanner) catalog(sites []site, b *plugin.Builder) []catalog.Channel {
|
|
72
|
-
states := map[string]*channelState{}
|
|
73
|
-
for _, found := range sites {
|
|
74
|
-
if len(found.subjects) == 0 {
|
|
75
|
-
why := "the message was not built with nats.NewMsg or &nats.Msg{Subject: ...} in this function"
|
|
76
|
-
if found.configured {
|
|
77
|
-
why = "a consumer with no filter subject reads whatever its stream holds"
|
|
78
|
-
}
|
|
79
|
-
b.Warn(found.at.String(), found.method+" names no subject this reader can see: "+why)
|
|
80
|
-
continue
|
|
81
|
-
}
|
|
82
|
-
for _, subject := range found.subjects {
|
|
83
|
-
values := s.resolve(subject, found.fn, 0, map[string]bool{})
|
|
84
|
-
if len(values) == 0 {
|
|
85
|
-
b.Warn(found.at.String(), "subject of "+found.method+" could not be resolved to a literal, a constant, a config default or a caller's argument")
|
|
86
|
-
continue
|
|
87
|
-
}
|
|
88
|
-
for _, value := range values {
|
|
89
|
-
state := states[value.value]
|
|
90
|
-
if state == nil {
|
|
91
|
-
state = &channelState{address: value.value, api: found.api, notes: map[string]bool{}, messages: map[string]catalog.ChannelMessage{}}
|
|
92
|
-
states[value.value] = state
|
|
93
|
-
}
|
|
94
|
-
state.sources = append(state.sources, value.at.String())
|
|
95
|
-
state.notes[s.note(found)] = true
|
|
96
|
-
if value.name != "" {
|
|
97
|
-
state.messages[string(found.direction)+" "+value.name] = catalog.ChannelMessage{Name: value.name, Title: value.name, Direction: found.direction}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
addresses := make([]string, 0, len(states))
|
|
104
|
-
for address := range states {
|
|
105
|
-
addresses = append(addresses, address)
|
|
106
|
-
}
|
|
107
|
-
sort.Strings(addresses)
|
|
108
|
-
out := make([]catalog.Channel, 0, len(addresses))
|
|
109
|
-
for _, address := range addresses {
|
|
110
|
-
state := states[address]
|
|
111
|
-
sort.Strings(state.sources)
|
|
112
|
-
notes := make([]string, 0, len(state.notes))
|
|
113
|
-
for note := range state.notes {
|
|
114
|
-
notes = append(notes, note)
|
|
115
|
-
}
|
|
116
|
-
sort.Strings(notes)
|
|
117
|
-
keys := make([]string, 0, len(state.messages))
|
|
118
|
-
for key := range state.messages {
|
|
119
|
-
keys = append(keys, key)
|
|
120
|
-
}
|
|
121
|
-
sort.Strings(keys)
|
|
122
|
-
messages := make([]catalog.ChannelMessage, 0, len(keys))
|
|
123
|
-
for _, key := range keys {
|
|
124
|
-
messages = append(messages, state.messages[key])
|
|
125
|
-
}
|
|
126
|
-
out = append(out, catalog.Channel{
|
|
127
|
-
Address: address,
|
|
128
|
-
Kind: catalog.ChannelKindEvent,
|
|
129
|
-
Title: state.api + " subject",
|
|
130
|
-
Doc: "Read through " + natsPkg + ". " + strings.Join(notes, " "),
|
|
131
|
-
Messages: messages,
|
|
132
|
-
Source: state.sources[0],
|
|
133
|
-
})
|
|
134
|
-
}
|
|
135
|
-
return out
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// note is one sentence on a site: which way, from where, and what JetStream
|
|
139
|
-
// was told about the consumer.
|
|
140
|
-
func (s *scanner) note(found site) string {
|
|
141
|
-
verb := "Subscribed"
|
|
142
|
-
if found.direction == catalog.ChannelSend {
|
|
143
|
-
verb = "Published"
|
|
144
|
-
}
|
|
145
|
-
text := verb + " by `" + goscan.LastSegment(found.fn.receiver) + dot(found.fn.receiver) + found.fn.name + "`"
|
|
146
|
-
if found.api == "JetStream" {
|
|
147
|
-
text += " over JetStream"
|
|
148
|
-
}
|
|
149
|
-
if durable := s.literal(found.durable, found.fn); durable != "" {
|
|
150
|
-
text += ", durable consumer `" + durable + "`"
|
|
151
|
-
}
|
|
152
|
-
if queue := s.literal(found.queue, found.fn); queue != "" {
|
|
153
|
-
text += ", queue group `" + queue + "`"
|
|
154
|
-
}
|
|
155
|
-
return text + "."
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
func dot(receiver string) string {
|
|
159
|
-
if receiver == "" {
|
|
160
|
-
return ""
|
|
161
|
-
}
|
|
162
|
-
return "."
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// literal is a string an expression is worth without leaving the function:
|
|
166
|
-
// a durable name or queue group is documentation, and following it up the
|
|
167
|
-
// callers would be more than it is worth.
|
|
168
|
-
func (s *scanner) literal(expr ast.Expr, fn *function) string {
|
|
169
|
-
if expr == nil {
|
|
170
|
-
return ""
|
|
171
|
-
}
|
|
172
|
-
values := s.resolve(expr, fn, hops, map[string]bool{})
|
|
173
|
-
if len(values) != 1 {
|
|
174
|
-
return ""
|
|
175
|
-
}
|
|
176
|
-
return values[0].value
|
|
177
|
-
}
|