@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.
- 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 +27 -10
- package/scripts/local-api.test.mjs +85 -2
- package/scripts/manifest.mjs +3 -2
- package/scripts/package-smoke.mjs +24 -3
- 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 +17 -9
- 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,379 +0,0 @@
|
|
|
1
|
-
package main
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"go/ast"
|
|
5
|
-
"go/token"
|
|
6
|
-
"reflect"
|
|
7
|
-
"sort"
|
|
8
|
-
"strconv"
|
|
9
|
-
|
|
10
|
-
"github.com/shortlink-org/portolan/internal/goscan"
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
const (
|
|
14
|
-
natsPkg = "github.com/nats-io/nats.go"
|
|
15
|
-
jsPkg = "github.com/nats-io/nats.go/jetstream"
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
// structType is a struct as the reader needs it: what type each field has, so
|
|
19
|
-
// that `b.conn` is known to be a connection, and what a field defaults to
|
|
20
|
-
// when its tag says, so that a subject read off config resolves.
|
|
21
|
-
type structType struct {
|
|
22
|
-
key string
|
|
23
|
-
fields map[string]string
|
|
24
|
-
defaults map[string]string
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// function is one declared function or method: its parameters by name and
|
|
28
|
-
// type, what it returns, and what its body assigns to which name.
|
|
29
|
-
type function struct {
|
|
30
|
-
key string
|
|
31
|
-
name string
|
|
32
|
-
receiver string
|
|
33
|
-
file *goscan.File
|
|
34
|
-
decl *ast.FuncDecl
|
|
35
|
-
params []string
|
|
36
|
-
types map[string]string
|
|
37
|
-
results []string
|
|
38
|
-
assigned map[string]assignment
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// assignment is the last thing a local name was given: the expression, and
|
|
42
|
-
// which of its values when the expression yields several.
|
|
43
|
-
type assignment struct {
|
|
44
|
-
expr ast.Expr
|
|
45
|
-
index int
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// scanner is the tree, and the shapes in it a nats call is read against.
|
|
49
|
-
type scanner struct {
|
|
50
|
-
*goscan.Tree
|
|
51
|
-
structs map[string]*structType
|
|
52
|
-
interfaces map[string][]string
|
|
53
|
-
functions map[string]*function
|
|
54
|
-
methods map[string][]*function
|
|
55
|
-
byName map[string][]*function
|
|
56
|
-
// typing is the locals whose type is being worked out right now, so a
|
|
57
|
-
// name shadowed by an expression of itself - `js := js.Sub()` in an
|
|
58
|
-
// inner block - ends rather than recurses.
|
|
59
|
-
typing map[string]bool
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
func newScanner(tree *goscan.Tree) *scanner {
|
|
63
|
-
return &scanner{
|
|
64
|
-
Tree: tree,
|
|
65
|
-
structs: map[string]*structType{},
|
|
66
|
-
interfaces: map[string][]string{},
|
|
67
|
-
functions: map[string]*function{},
|
|
68
|
-
methods: map[string][]*function{},
|
|
69
|
-
byName: map[string][]*function{},
|
|
70
|
-
typing: map[string]bool{},
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
func (s *scanner) index() {
|
|
75
|
-
for _, file := range s.Files {
|
|
76
|
-
for _, decl := range file.Node.Decls {
|
|
77
|
-
switch d := decl.(type) {
|
|
78
|
-
case *ast.GenDecl:
|
|
79
|
-
if d.Tok != token.TYPE {
|
|
80
|
-
continue
|
|
81
|
-
}
|
|
82
|
-
for _, raw := range d.Specs {
|
|
83
|
-
s.indexType(file, raw.(*ast.TypeSpec))
|
|
84
|
-
}
|
|
85
|
-
case *ast.FuncDecl:
|
|
86
|
-
s.indexFunction(file, d)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
func (s *scanner) indexType(file *goscan.File, spec *ast.TypeSpec) {
|
|
93
|
-
key := file.Pkg + "." + spec.Name.Name
|
|
94
|
-
switch body := spec.Type.(type) {
|
|
95
|
-
case *ast.StructType:
|
|
96
|
-
st := &structType{key: key, fields: map[string]string{}, defaults: map[string]string{}}
|
|
97
|
-
for _, field := range body.Fields.List {
|
|
98
|
-
typeKey := s.TypeKey(field.Type, file)
|
|
99
|
-
def := ""
|
|
100
|
-
if field.Tag != nil {
|
|
101
|
-
tag, _ := strconv.Unquote(field.Tag.Value)
|
|
102
|
-
def = reflect.StructTag(tag).Get("default")
|
|
103
|
-
}
|
|
104
|
-
for _, name := range field.Names {
|
|
105
|
-
st.fields[name.Name] = typeKey
|
|
106
|
-
if def != "" {
|
|
107
|
-
st.defaults[name.Name] = def
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
s.structs[key] = st
|
|
112
|
-
case *ast.InterfaceType:
|
|
113
|
-
// Embedded interfaces are not followed: the port a service writes for
|
|
114
|
-
// its bus names its methods itself.
|
|
115
|
-
var names []string
|
|
116
|
-
for _, method := range body.Methods.List {
|
|
117
|
-
for _, name := range method.Names {
|
|
118
|
-
names = append(names, name.Name)
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
sort.Strings(names)
|
|
122
|
-
s.interfaces[key] = names
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
func (s *scanner) indexFunction(file *goscan.File, decl *ast.FuncDecl) {
|
|
127
|
-
key := file.Pkg + "." + decl.Name.Name
|
|
128
|
-
receiver := ""
|
|
129
|
-
if decl.Recv != nil && len(decl.Recv.List) > 0 {
|
|
130
|
-
receiver = s.TypeKey(decl.Recv.List[0].Type, file)
|
|
131
|
-
key = receiver + "." + decl.Name.Name
|
|
132
|
-
}
|
|
133
|
-
fn := &function{key: key, name: decl.Name.Name, receiver: receiver, file: file, decl: decl, types: map[string]string{}}
|
|
134
|
-
if decl.Recv != nil {
|
|
135
|
-
for _, field := range decl.Recv.List {
|
|
136
|
-
for _, name := range field.Names {
|
|
137
|
-
fn.types[name.Name] = receiver
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
if decl.Type.Params != nil {
|
|
142
|
-
for _, field := range decl.Type.Params.List {
|
|
143
|
-
typeKey := s.TypeKey(field.Type, file)
|
|
144
|
-
for _, name := range field.Names {
|
|
145
|
-
fn.params = append(fn.params, name.Name)
|
|
146
|
-
fn.types[name.Name] = typeKey
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
if decl.Type.Results != nil {
|
|
151
|
-
for _, field := range decl.Type.Results.List {
|
|
152
|
-
typeKey := s.TypeKey(field.Type, file)
|
|
153
|
-
if len(field.Names) == 0 {
|
|
154
|
-
fn.results = append(fn.results, typeKey)
|
|
155
|
-
}
|
|
156
|
-
for range field.Names {
|
|
157
|
-
fn.results = append(fn.results, typeKey)
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
s.functions[key] = fn
|
|
162
|
-
if receiver != "" {
|
|
163
|
-
s.methods[receiver] = append(s.methods[receiver], fn)
|
|
164
|
-
s.byName[fn.name] = append(s.byName[fn.name], fn)
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// implements is whether a receiver type has every method an interface asks
|
|
169
|
-
// for, by name. Names are what a port is: a type with the right names is
|
|
170
|
-
// what the assembly hands over, and the compiler holds the signatures.
|
|
171
|
-
func (s *scanner) implements(receiver, iface string) bool {
|
|
172
|
-
want := s.interfaces[iface]
|
|
173
|
-
if len(want) == 0 {
|
|
174
|
-
return false
|
|
175
|
-
}
|
|
176
|
-
have := map[string]bool{}
|
|
177
|
-
for _, fn := range s.methods[receiver] {
|
|
178
|
-
have[fn.name] = true
|
|
179
|
-
}
|
|
180
|
-
for _, name := range want {
|
|
181
|
-
if !have[name] {
|
|
182
|
-
return false
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
return true
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// assignedTo is the last expression a local name was given in the function,
|
|
189
|
-
// read once per function.
|
|
190
|
-
func (s *scanner) assignedTo(fn *function, name string) (assignment, bool) {
|
|
191
|
-
if fn.assigned == nil {
|
|
192
|
-
fn.assigned = map[string]assignment{}
|
|
193
|
-
if fn.decl.Body != nil {
|
|
194
|
-
ast.Inspect(fn.decl.Body, func(node ast.Node) bool {
|
|
195
|
-
switch stmt := node.(type) {
|
|
196
|
-
case *ast.AssignStmt:
|
|
197
|
-
record(fn.assigned, stmt.Lhs, stmt.Rhs)
|
|
198
|
-
case *ast.ValueSpec:
|
|
199
|
-
var lhs []ast.Expr
|
|
200
|
-
for _, ident := range stmt.Names {
|
|
201
|
-
lhs = append(lhs, ident)
|
|
202
|
-
}
|
|
203
|
-
record(fn.assigned, lhs, stmt.Values)
|
|
204
|
-
}
|
|
205
|
-
return true
|
|
206
|
-
})
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
found, ok := fn.assigned[name]
|
|
210
|
-
return found, ok
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
func record(into map[string]assignment, lhs, rhs []ast.Expr) {
|
|
214
|
-
if len(rhs) == 0 {
|
|
215
|
-
return
|
|
216
|
-
}
|
|
217
|
-
for i, target := range lhs {
|
|
218
|
-
ident, ok := target.(*ast.Ident)
|
|
219
|
-
if !ok || ident.Name == "_" {
|
|
220
|
-
continue
|
|
221
|
-
}
|
|
222
|
-
if len(rhs) == 1 && len(lhs) > 1 {
|
|
223
|
-
into[ident.Name] = assignment{expr: rhs[0], index: i}
|
|
224
|
-
} else if i < len(rhs) {
|
|
225
|
-
into[ident.Name] = assignment{expr: rhs[i]}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// typeOf is the type key of an expression, as far as declarations say: a
|
|
231
|
-
// parameter or receiver by its declared type, a local by what it was
|
|
232
|
-
// assigned, a field by its struct, a call by what the callee returns.
|
|
233
|
-
func (s *scanner) typeOf(expr ast.Expr, fn *function) string {
|
|
234
|
-
switch value := goscan.Unwrap(expr).(type) {
|
|
235
|
-
case *ast.Ident:
|
|
236
|
-
if kind := fn.types[value.Name]; kind != "" {
|
|
237
|
-
return kind
|
|
238
|
-
}
|
|
239
|
-
key := fn.key + ":" + value.Name
|
|
240
|
-
if s.typing[key] {
|
|
241
|
-
return ""
|
|
242
|
-
}
|
|
243
|
-
s.typing[key] = true
|
|
244
|
-
defer delete(s.typing, key)
|
|
245
|
-
if given, ok := s.assignedTo(fn, value.Name); ok {
|
|
246
|
-
if call, isCall := goscan.Unwrap(given.expr).(*ast.CallExpr); isCall {
|
|
247
|
-
results := s.resultsOf(call, fn)
|
|
248
|
-
if given.index < len(results) {
|
|
249
|
-
return results[given.index]
|
|
250
|
-
}
|
|
251
|
-
return ""
|
|
252
|
-
}
|
|
253
|
-
if given.index == 0 {
|
|
254
|
-
return s.typeOf(given.expr, fn)
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
case *ast.CompositeLit:
|
|
258
|
-
return s.TypeKey(value.Type, fn.file)
|
|
259
|
-
case *ast.SelectorExpr:
|
|
260
|
-
if st := s.structs[s.typeOf(value.X, fn)]; st != nil {
|
|
261
|
-
return st.fields[value.Sel.Name]
|
|
262
|
-
}
|
|
263
|
-
case *ast.CallExpr:
|
|
264
|
-
if results := s.resultsOf(value, fn); len(results) > 0 {
|
|
265
|
-
return results[0]
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
return ""
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// knownResults is what the nats.go constructors hand back, since their
|
|
272
|
-
// declarations are not in the tree.
|
|
273
|
-
var knownResults = map[string][]string{
|
|
274
|
-
natsPkg + ".Connect": {natsPkg + ".Conn", "error"},
|
|
275
|
-
natsPkg + ".Conn.JetStream": {natsPkg + ".JetStreamContext", "error"},
|
|
276
|
-
jsPkg + ".New": {jsPkg + ".JetStream", "error"},
|
|
277
|
-
jsPkg + ".NewWithAPIPrefix": {jsPkg + ".JetStream", "error"},
|
|
278
|
-
jsPkg + ".NewWithDomain": {jsPkg + ".JetStream", "error"},
|
|
279
|
-
jsPkg + ".JetStream.Stream": {jsPkg + ".Stream", "error"},
|
|
280
|
-
jsPkg + ".JetStream.CreateStream": {jsPkg + ".Stream", "error"},
|
|
281
|
-
jsPkg + ".JetStream.UpdateStream": {jsPkg + ".Stream", "error"},
|
|
282
|
-
jsPkg + ".JetStream.CreateOrUpdateStream": {jsPkg + ".Stream", "error"},
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// resultsOf is what a call returns: the callee's declared results when it is
|
|
286
|
-
// in the tree, the table above when it is nats.go's.
|
|
287
|
-
func (s *scanner) resultsOf(call *ast.CallExpr, fn *function) []string {
|
|
288
|
-
for _, target := range s.callees(call, fn) {
|
|
289
|
-
return target.results
|
|
290
|
-
}
|
|
291
|
-
if key := s.externalKey(call, fn); key != "" {
|
|
292
|
-
return knownResults[key]
|
|
293
|
-
}
|
|
294
|
-
return nil
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// externalKey names a call on something declared outside the tree: a
|
|
298
|
-
// package function by import path, a method by the type of what it is
|
|
299
|
-
// called on.
|
|
300
|
-
func (s *scanner) externalKey(call *ast.CallExpr, fn *function) string {
|
|
301
|
-
sel, ok := call.Fun.(*ast.SelectorExpr)
|
|
302
|
-
if !ok {
|
|
303
|
-
return ""
|
|
304
|
-
}
|
|
305
|
-
if base, ok := sel.X.(*ast.Ident); ok {
|
|
306
|
-
if imported := fn.file.Imports[base.Name]; imported != "" && fn.types[base.Name] == "" {
|
|
307
|
-
if _, local := s.assignedTo(fn, base.Name); !local {
|
|
308
|
-
return imported + "." + sel.Sel.Name
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
if recv := s.typeOf(sel.X, fn); recv != "" {
|
|
313
|
-
return recv + "." + sel.Sel.Name
|
|
314
|
-
}
|
|
315
|
-
return ""
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// callees is every function in the tree a call may reach: the one named,
|
|
319
|
-
// when it is a plain function or a method on a known type; every
|
|
320
|
-
// implementation, when it is a method on an interface the tree declares.
|
|
321
|
-
func (s *scanner) callees(call *ast.CallExpr, fn *function) []*function {
|
|
322
|
-
switch callee := call.Fun.(type) {
|
|
323
|
-
case *ast.Ident:
|
|
324
|
-
if target := s.functions[fn.file.Pkg+"."+callee.Name]; target != nil {
|
|
325
|
-
return []*function{target}
|
|
326
|
-
}
|
|
327
|
-
case *ast.SelectorExpr:
|
|
328
|
-
if base, ok := callee.X.(*ast.Ident); ok && fn.types[base.Name] == "" {
|
|
329
|
-
if imported := fn.file.Imports[base.Name]; imported != "" {
|
|
330
|
-
if _, local := s.assignedTo(fn, base.Name); !local {
|
|
331
|
-
if target := s.functions[imported+"."+callee.Sel.Name]; target != nil {
|
|
332
|
-
return []*function{target}
|
|
333
|
-
}
|
|
334
|
-
return nil
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
recv := s.typeOf(callee.X, fn)
|
|
339
|
-
if recv == "" {
|
|
340
|
-
return nil
|
|
341
|
-
}
|
|
342
|
-
if target := s.functions[recv+"."+callee.Sel.Name]; target != nil {
|
|
343
|
-
return []*function{target}
|
|
344
|
-
}
|
|
345
|
-
if s.interfaces[recv] != nil {
|
|
346
|
-
var out []*function
|
|
347
|
-
for _, candidate := range s.byName[callee.Sel.Name] {
|
|
348
|
-
if s.implements(candidate.receiver, recv) {
|
|
349
|
-
out = append(out, candidate)
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
sort.Slice(out, func(i, j int) bool { return out[i].key < out[j].key })
|
|
353
|
-
return out
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
return nil
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
// paramIndex is which parameter a name is, or -1.
|
|
360
|
-
func paramIndex(fn *function, name string) int {
|
|
361
|
-
for i, param := range fn.params {
|
|
362
|
-
if param == name {
|
|
363
|
-
return i
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
return -1
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// sortedFunctions is every function with a body, in a fixed order.
|
|
370
|
-
func (s *scanner) sortedFunctions() []*function {
|
|
371
|
-
out := make([]*function, 0, len(s.functions))
|
|
372
|
-
for _, fn := range s.functions {
|
|
373
|
-
if fn.decl.Body != nil {
|
|
374
|
-
out = append(out, fn)
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
sort.Slice(out, func(i, j int) bool { return out[i].key < out[j].key })
|
|
378
|
-
return out
|
|
379
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
// Package main is portolan-extract-go-nats: nats.go and JetStream calls in a
|
|
2
|
-
// Go repository in, the subjects the service listens on and publishes to out.
|
|
3
|
-
package main
|
|
4
|
-
|
|
5
|
-
import (
|
|
6
|
-
"fmt"
|
|
7
|
-
"io"
|
|
8
|
-
"os"
|
|
9
|
-
"path/filepath"
|
|
10
|
-
|
|
11
|
-
"github.com/shortlink-org/portolan/internal/goscan"
|
|
12
|
-
"github.com/shortlink-org/portolan/plugin"
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
type Options struct {
|
|
16
|
-
Context string `json:"context"`
|
|
17
|
-
Service string `json:"service"`
|
|
18
|
-
Out string `json:"out,omitempty"`
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
func main() {
|
|
22
|
-
if err := run(os.Stdin, os.Stdout); err != nil {
|
|
23
|
-
fmt.Fprintln(os.Stderr, "portolan-extract-go-nats:", err)
|
|
24
|
-
os.Exit(1)
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
func run(stdin io.Reader, stdout io.Writer) error {
|
|
29
|
-
return plugin.Serve(stdin, stdout, descriptor(), func(req plugin.Request, opts Options) (plugin.Response, error) {
|
|
30
|
-
if req.Input.Root == "" {
|
|
31
|
-
return plugin.Response{}, fmt.Errorf("no input root: an extractor has nothing to read")
|
|
32
|
-
}
|
|
33
|
-
if opts.Context == "" {
|
|
34
|
-
opts.Context = goscan.Slug(filepath.Base(req.Input.Root))
|
|
35
|
-
}
|
|
36
|
-
if opts.Service == "" {
|
|
37
|
-
opts.Service = goscan.Slug(filepath.Base(req.Input.Root))
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return extract(req.Input, opts)
|
|
41
|
-
})
|
|
42
|
-
}
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
package main
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"go/ast"
|
|
5
|
-
"go/token"
|
|
6
|
-
"strconv"
|
|
7
|
-
|
|
8
|
-
"github.com/shortlink-org/portolan/internal/goscan"
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
// hops is how far up the callers a subject is followed. One hop is the port:
|
|
12
|
-
// the adapter takes the subject as a parameter and the assembly passes a
|
|
13
|
-
// constant. Two is an assembly that itself was handed the subject. Further
|
|
14
|
-
// than that is not a declaration any more.
|
|
15
|
-
const hops = 2
|
|
16
|
-
|
|
17
|
-
// resolved is one string an expression was found to be, where it was
|
|
18
|
-
// written, and - when it came through a wrapper that also names the message -
|
|
19
|
-
// what the message is called.
|
|
20
|
-
type resolved struct {
|
|
21
|
-
value string
|
|
22
|
-
at goscan.Source
|
|
23
|
-
name string
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// resolve is the strings an expression can be worth: a literal; a constant,
|
|
27
|
-
// the tree's own or an imported one; a config field's default; a call to a
|
|
28
|
-
// function whose body is one return; a parameter, by what every caller
|
|
29
|
-
// passes for it.
|
|
30
|
-
func (s *scanner) resolve(expr ast.Expr, fn *function, depth int, visiting map[string]bool) []resolved {
|
|
31
|
-
at := s.At(expr.Pos())
|
|
32
|
-
switch value := goscan.Unwrap(expr).(type) {
|
|
33
|
-
case *ast.BasicLit:
|
|
34
|
-
if value.Kind == token.STRING {
|
|
35
|
-
text, _ := strconv.Unquote(value.Value)
|
|
36
|
-
return []resolved{{value: text, at: at}}
|
|
37
|
-
}
|
|
38
|
-
case *ast.Ident:
|
|
39
|
-
if index := paramIndex(fn, value.Name); index >= 0 {
|
|
40
|
-
return s.fromCallers(fn, index, depth, visiting)
|
|
41
|
-
}
|
|
42
|
-
key := fn.key + ":" + value.Name
|
|
43
|
-
if visiting[key] {
|
|
44
|
-
return nil
|
|
45
|
-
}
|
|
46
|
-
visiting[key] = true
|
|
47
|
-
defer delete(visiting, key)
|
|
48
|
-
if given, ok := s.assignedTo(fn, value.Name); ok {
|
|
49
|
-
if given.index == 0 {
|
|
50
|
-
return s.resolve(given.expr, fn, depth, visiting)
|
|
51
|
-
}
|
|
52
|
-
return nil
|
|
53
|
-
}
|
|
54
|
-
if text := s.StringOf(value, fn.file, nil); text != "" {
|
|
55
|
-
return []resolved{{value: text, at: at}}
|
|
56
|
-
}
|
|
57
|
-
case *ast.SelectorExpr:
|
|
58
|
-
if text := s.StringOf(value, fn.file, nil); text != "" {
|
|
59
|
-
return []resolved{{value: text, at: at}}
|
|
60
|
-
}
|
|
61
|
-
if st := s.structs[s.typeOf(value.X, fn)]; st != nil {
|
|
62
|
-
if def := st.defaults[value.Sel.Name]; def != "" {
|
|
63
|
-
return []resolved{{value: def, at: at}}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
case *ast.CallExpr:
|
|
67
|
-
var out []resolved
|
|
68
|
-
for _, target := range s.callees(value, fn) {
|
|
69
|
-
if ret := singleReturn(target); ret != nil {
|
|
70
|
-
key := "call:" + target.key
|
|
71
|
-
if visiting[key] {
|
|
72
|
-
continue
|
|
73
|
-
}
|
|
74
|
-
visiting[key] = true
|
|
75
|
-
out = append(out, s.resolve(ret, target, depth, visiting)...)
|
|
76
|
-
delete(visiting, key)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return out
|
|
80
|
-
}
|
|
81
|
-
return nil
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// fromCallers is what a parameter is worth: whatever each call site passes
|
|
85
|
-
// for it, resolved there. A call site that also passes a literal or constant
|
|
86
|
-
// for the one other string parameter of the same function is taken to name
|
|
87
|
-
// the message - the shape of a bus port, Subscribe(subject, name, handler).
|
|
88
|
-
func (s *scanner) fromCallers(fn *function, index, depth int, visiting map[string]bool) []resolved {
|
|
89
|
-
if depth >= hops {
|
|
90
|
-
return nil
|
|
91
|
-
}
|
|
92
|
-
key := fn.key + "#" + strconv.Itoa(index)
|
|
93
|
-
if visiting[key] {
|
|
94
|
-
return nil
|
|
95
|
-
}
|
|
96
|
-
visiting[key] = true
|
|
97
|
-
defer delete(visiting, key)
|
|
98
|
-
|
|
99
|
-
nameIndex := s.companionString(fn, index)
|
|
100
|
-
var out []resolved
|
|
101
|
-
for _, caller := range s.sortedFunctions() {
|
|
102
|
-
ast.Inspect(caller.decl.Body, func(node ast.Node) bool {
|
|
103
|
-
call, ok := node.(*ast.CallExpr)
|
|
104
|
-
if !ok || index >= len(call.Args) || !s.reaches(call, caller, fn) {
|
|
105
|
-
return true
|
|
106
|
-
}
|
|
107
|
-
found := s.resolve(call.Args[index], caller, depth+1, visiting)
|
|
108
|
-
if nameIndex >= 0 && nameIndex < len(call.Args) {
|
|
109
|
-
names := s.resolve(call.Args[nameIndex], caller, depth+1, visiting)
|
|
110
|
-
if len(names) == 1 {
|
|
111
|
-
for i := range found {
|
|
112
|
-
found[i].name = names[0].value
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
out = append(out, found...)
|
|
117
|
-
return true
|
|
118
|
-
})
|
|
119
|
-
}
|
|
120
|
-
return out
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// reaches is whether a call lands on fn: directly, or through an interface
|
|
124
|
-
// fn's receiver satisfies.
|
|
125
|
-
func (s *scanner) reaches(call *ast.CallExpr, caller, fn *function) bool {
|
|
126
|
-
for _, target := range s.callees(call, caller) {
|
|
127
|
-
if target == fn {
|
|
128
|
-
return true
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return false
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// companionString is the one string parameter beside the subject, or -1
|
|
135
|
-
// when there is none or more than one.
|
|
136
|
-
func (s *scanner) companionString(fn *function, subject int) int {
|
|
137
|
-
found := -1
|
|
138
|
-
for i, param := range fn.params {
|
|
139
|
-
if i == subject || fn.types[param] != "string" {
|
|
140
|
-
continue
|
|
141
|
-
}
|
|
142
|
-
if found >= 0 {
|
|
143
|
-
return -1
|
|
144
|
-
}
|
|
145
|
-
found = i
|
|
146
|
-
}
|
|
147
|
-
return found
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// singleReturn is the expression a function is, when its whole body is
|
|
151
|
-
// `return x`: the Name() of an event, the Topic() of a message.
|
|
152
|
-
func singleReturn(fn *function) ast.Expr {
|
|
153
|
-
if fn.decl.Body == nil || len(fn.decl.Body.List) != 1 {
|
|
154
|
-
return nil
|
|
155
|
-
}
|
|
156
|
-
ret, ok := fn.decl.Body.List[0].(*ast.ReturnStmt)
|
|
157
|
-
if !ok || len(ret.Results) != 1 {
|
|
158
|
-
return nil
|
|
159
|
-
}
|
|
160
|
-
return ret.Results[0]
|
|
161
|
-
}
|