@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,185 +0,0 @@
|
|
|
1
|
-
package catalog
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"encoding/json"
|
|
5
|
-
"fmt"
|
|
6
|
-
"os"
|
|
7
|
-
"path/filepath"
|
|
8
|
-
"sort"
|
|
9
|
-
"testing"
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
// TestRoundTrip is what holds this package to src/catalog.ts.
|
|
13
|
-
//
|
|
14
|
-
// Every real catalog in the repository is unmarshalled into these structs and
|
|
15
|
-
// marshalled straight back out. Anything the mirror does not know about is
|
|
16
|
-
// dropped on the way in and missing on the way out, so a field added to the
|
|
17
|
-
// TypeScript and forgotten here fails as a named path rather than as a blank
|
|
18
|
-
// section in somebody's generated documentation.
|
|
19
|
-
//
|
|
20
|
-
// The comparison is semantic: key order differs by construction, and an
|
|
21
|
-
// optional list that was written as [] is the same fact as one left out.
|
|
22
|
-
func TestRoundTrip(t *testing.T) {
|
|
23
|
-
files, err := filepath.Glob("../data/*.json")
|
|
24
|
-
if err != nil {
|
|
25
|
-
t.Fatal(err)
|
|
26
|
-
}
|
|
27
|
-
if len(files) == 0 {
|
|
28
|
-
t.Fatal("no catalogs under ../data - this test proves nothing without one")
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
for _, path := range files {
|
|
32
|
-
t.Run(filepath.Base(path), func(t *testing.T) {
|
|
33
|
-
raw, err := os.ReadFile(path)
|
|
34
|
-
if err != nil {
|
|
35
|
-
t.Fatal(err)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
var before any
|
|
39
|
-
if err := json.Unmarshal(raw, &before); err != nil {
|
|
40
|
-
t.Fatalf("source is not JSON: %v", err)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
var parsed Catalog
|
|
44
|
-
if err := json.Unmarshal(raw, &parsed); err != nil {
|
|
45
|
-
t.Fatalf("catalog does not fit the mirror: %v", err)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
out, err := json.Marshal(&parsed)
|
|
49
|
-
if err != nil {
|
|
50
|
-
t.Fatalf("mirror does not marshal: %v", err)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
var after any
|
|
54
|
-
if err := json.Unmarshal(out, &after); err != nil {
|
|
55
|
-
t.Fatal(err)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
diffs := compare("catalog", normalize(before), normalize(after))
|
|
59
|
-
if len(diffs) == 0 {
|
|
60
|
-
return
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
shown := diffs
|
|
64
|
-
if len(shown) > 20 {
|
|
65
|
-
shown = shown[:20]
|
|
66
|
-
}
|
|
67
|
-
for _, d := range shown {
|
|
68
|
-
t.Error(d)
|
|
69
|
-
}
|
|
70
|
-
if len(diffs) > len(shown) {
|
|
71
|
-
t.Errorf("... and %d more", len(diffs)-len(shown))
|
|
72
|
-
}
|
|
73
|
-
})
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// normalize drops keys whose value carries no information. An optional list
|
|
78
|
-
// written as [] and one left out entirely say the same thing, and holding the
|
|
79
|
-
// mirror to which of the two it produces would test encoding/json rather than
|
|
80
|
-
// the shape.
|
|
81
|
-
func normalize(v any) any {
|
|
82
|
-
switch t := v.(type) {
|
|
83
|
-
case map[string]any:
|
|
84
|
-
out := make(map[string]any, len(t))
|
|
85
|
-
for k, item := range t {
|
|
86
|
-
switch inner := item.(type) {
|
|
87
|
-
case []any:
|
|
88
|
-
if len(inner) == 0 {
|
|
89
|
-
continue
|
|
90
|
-
}
|
|
91
|
-
case map[string]any:
|
|
92
|
-
if len(inner) == 0 {
|
|
93
|
-
continue
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
out[k] = normalize(item)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return out
|
|
100
|
-
case []any:
|
|
101
|
-
out := make([]any, len(t))
|
|
102
|
-
for i, item := range t {
|
|
103
|
-
out[i] = normalize(item)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return out
|
|
107
|
-
default:
|
|
108
|
-
return v
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// compare walks both trees together and names every place they part, as a path
|
|
113
|
-
// a reader can find in the file.
|
|
114
|
-
func compare(path string, before, after any) []string {
|
|
115
|
-
switch b := before.(type) {
|
|
116
|
-
case map[string]any:
|
|
117
|
-
a, ok := after.(map[string]any)
|
|
118
|
-
if !ok {
|
|
119
|
-
return []string{fmt.Sprintf("%s: object in the source, %T after the round trip", path, after)}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
var diffs []string
|
|
123
|
-
for _, key := range sortedKeys(b, a) {
|
|
124
|
-
bv, inSource := b[key]
|
|
125
|
-
av, inMirror := a[key]
|
|
126
|
-
switch {
|
|
127
|
-
case inSource && !inMirror:
|
|
128
|
-
diffs = append(diffs, fmt.Sprintf("%s.%s: dropped by the mirror (%s)", path, key, brief(bv)))
|
|
129
|
-
case !inSource && inMirror:
|
|
130
|
-
diffs = append(diffs, fmt.Sprintf("%s.%s: invented by the mirror (%s)", path, key, brief(av)))
|
|
131
|
-
default:
|
|
132
|
-
diffs = append(diffs, compare(path+"."+key, bv, av)...)
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return diffs
|
|
137
|
-
case []any:
|
|
138
|
-
a, ok := after.([]any)
|
|
139
|
-
if !ok {
|
|
140
|
-
return []string{fmt.Sprintf("%s: list in the source, %T after the round trip", path, after)}
|
|
141
|
-
}
|
|
142
|
-
if len(b) != len(a) {
|
|
143
|
-
return []string{fmt.Sprintf("%s: %d entries in the source, %d after the round trip", path, len(b), len(a))}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
var diffs []string
|
|
147
|
-
for i := range b {
|
|
148
|
-
diffs = append(diffs, compare(fmt.Sprintf("%s[%d]", path, i), b[i], a[i])...)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return diffs
|
|
152
|
-
default:
|
|
153
|
-
if before != after {
|
|
154
|
-
return []string{fmt.Sprintf("%s: %s became %s", path, brief(before), brief(after))}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return nil
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
func sortedKeys(maps ...map[string]any) []string {
|
|
162
|
-
seen := map[string]bool{}
|
|
163
|
-
for _, m := range maps {
|
|
164
|
-
for k := range m {
|
|
165
|
-
seen[k] = true
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
keys := make([]string, 0, len(seen))
|
|
170
|
-
for k := range seen {
|
|
171
|
-
keys = append(keys, k)
|
|
172
|
-
}
|
|
173
|
-
sort.Strings(keys)
|
|
174
|
-
|
|
175
|
-
return keys
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
func brief(v any) string {
|
|
179
|
-
s := fmt.Sprintf("%v", v)
|
|
180
|
-
if len(s) > 60 {
|
|
181
|
-
return s[:57] + "..."
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return s
|
|
185
|
-
}
|
package/catalog/via_test.go
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
package catalog
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"encoding/json"
|
|
5
|
-
"testing"
|
|
6
|
-
)
|
|
7
|
-
|
|
8
|
-
// TestEdgeViaRoundTrip pins the one field no committed catalog carries: `via`
|
|
9
|
-
// is written by the host after the merge, so the roundtrip over data/*.json
|
|
10
|
-
// never sees it, and the mirror would drop it silently on the way to a
|
|
11
|
-
// generator.
|
|
12
|
-
func TestEdgeViaRoundTrip(t *testing.T) {
|
|
13
|
-
in := `{"service":"payments.ledger","status":"declared","via":{"flow":"order-accepted","step":"a3"}}`
|
|
14
|
-
|
|
15
|
-
var c EventConsumer
|
|
16
|
-
if err := json.Unmarshal([]byte(in), &c); err != nil {
|
|
17
|
-
t.Fatal(err)
|
|
18
|
-
}
|
|
19
|
-
if c.Via == nil || c.Via.Flow != "order-accepted" || c.Via.Step != "a3" {
|
|
20
|
-
t.Fatalf("via not read: %+v", c.Via)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
out, err := json.Marshal(&c)
|
|
24
|
-
if err != nil {
|
|
25
|
-
t.Fatal(err)
|
|
26
|
-
}
|
|
27
|
-
if string(out) != in {
|
|
28
|
-
t.Fatalf("round trip changed the consumer:\n got %s\nwant %s", out, in)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
var call RpcCall
|
|
32
|
-
if err := json.Unmarshal([]byte(`{"id":"x/Y","peer":"p","status":"declared","source":"s"}`), &call); err != nil {
|
|
33
|
-
t.Fatal(err)
|
|
34
|
-
}
|
|
35
|
-
if call.Via != nil {
|
|
36
|
-
t.Fatalf("a call without via must round-trip without one: %+v", call.Via)
|
|
37
|
-
}
|
|
38
|
-
}
|
package/go.mod
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
module github.com/shortlink-org/portolan
|
|
2
|
-
|
|
3
|
-
go 1.27.0
|
|
4
|
-
|
|
5
|
-
require (
|
|
6
|
-
github.com/pgplex/pgparser v0.2.0
|
|
7
|
-
golang.org/x/tools v0.49.0
|
|
8
|
-
gopkg.in/yaml.v3 v3.0.1
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
require (
|
|
12
|
-
golang.org/x/mod v0.39.0 // indirect
|
|
13
|
-
golang.org/x/sync v0.22.0 // indirect
|
|
14
|
-
)
|
package/go.sum
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
|
2
|
-
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
|
3
|
-
github.com/pgplex/pgparser v0.2.0 h1:BB7I/Mrwetiw07PTq/AlXcKfajlCwoJfwB7KZ7V9irI=
|
|
4
|
-
github.com/pgplex/pgparser v0.2.0/go.mod h1:DWhK7oZJn/16KTFeOQ+mk78+sRnEYya1XPghIoP9NFU=
|
|
5
|
-
golang.org/x/mod v0.39.0 h1:UF5zwQdCRRUpHfyPwr7d4UrGiVeldIsogtzWVnczL74=
|
|
6
|
-
golang.org/x/mod v0.39.0/go.mod h1:bvIbwjQ0HUFFf5AKukeeYQG4ZBUG9yxQbR9aEweIwYY=
|
|
7
|
-
golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
|
|
8
|
-
golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
|
9
|
-
golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI=
|
|
10
|
-
golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo=
|
|
11
|
-
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
|
12
|
-
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
13
|
-
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|
14
|
-
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
package commands
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"os"
|
|
5
|
-
"path/filepath"
|
|
6
|
-
"regexp"
|
|
7
|
-
"slices"
|
|
8
|
-
"strings"
|
|
9
|
-
|
|
10
|
-
"github.com/shortlink-org/portolan/catalog"
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
var cargoAliasTable = regexp.MustCompile(`(?m)^\[alias\]\s*$`)
|
|
14
|
-
var xtaskArm = regexp.MustCompile(`(?m)^[ \t]*(?:Some\()?"[a-z][a-z0-9-]*"\)?[ \t]*(?:\|[ \t]*(?:Some\()?"[a-z][a-z0-9-]*"\)?[ \t]*)*=>`)
|
|
15
|
-
var xtaskLiteral = regexp.MustCompile(`"([a-z][a-z0-9-]*)"`)
|
|
16
|
-
var xtaskVariant = regexp.MustCompile(`^[ \t]*([A-Z][A-Za-z0-9]*)\s*(?:\{[^}]*\}|\([^)]*\))?\s*,?\s*$`)
|
|
17
|
-
var xtaskEnum = regexp.MustCompile(`(?s)#\[derive\([^)]*Subcommand[^)]*\)\][^{]*\benum\s+\w+\s*\{(.*?)\n\}`)
|
|
18
|
-
|
|
19
|
-
// readCargoAliases lists the aliases a checkout gives cargo in
|
|
20
|
-
// `.cargo/config.toml`. An alias is the one place a Cargo project declares a
|
|
21
|
-
// command of its own - `cargo xtask`, `cargo gen` - and its expansion is the
|
|
22
|
-
// body. When an alias runs the `xtask` package, that package's subcommands
|
|
23
|
-
// are listed under it as well, because `cargo xtask` on its own does nothing.
|
|
24
|
-
func readCargoAliases(root, file, src string) []catalog.Command {
|
|
25
|
-
loc := cargoAliasTable.FindStringIndex(src)
|
|
26
|
-
if loc == nil {
|
|
27
|
-
return nil
|
|
28
|
-
}
|
|
29
|
-
lines := strings.Split(src, "\n")
|
|
30
|
-
start := strings.Count(src[:loc[0]], "\n") + 1
|
|
31
|
-
|
|
32
|
-
var out []catalog.Command
|
|
33
|
-
for i := start; i < len(lines); i++ {
|
|
34
|
-
text := strings.TrimSpace(lines[i])
|
|
35
|
-
if tomlHeader.MatchString(text) {
|
|
36
|
-
break
|
|
37
|
-
}
|
|
38
|
-
m := tomlKey.FindStringSubmatch(text)
|
|
39
|
-
if m == nil {
|
|
40
|
-
continue
|
|
41
|
-
}
|
|
42
|
-
name := strings.Trim(m[1], `"`)
|
|
43
|
-
if !typeable(name) {
|
|
44
|
-
continue
|
|
45
|
-
}
|
|
46
|
-
body, _ := tomlTask(strings.TrimSpace(m[2]))
|
|
47
|
-
out = append(out, catalog.Command{Runner: "cargo", Name: name, Run: "cargo " + name, Body: body, Source: at(file, i+1)})
|
|
48
|
-
|
|
49
|
-
if pkg := runsPackage(body); pkg != "" {
|
|
50
|
-
out = append(out, readXtask(root, name, pkg)...)
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return out
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// runsPackage is the package an alias expansion runs, when it is `run
|
|
58
|
-
// --package <name>` or `run -p <name>` - the xtask convention - and the
|
|
59
|
-
// alias leaves the subcommand to the caller. `gen = "run -p xtask -- gen"`
|
|
60
|
-
// names one subcommand already, and is listed as the one command it is.
|
|
61
|
-
func runsPackage(expansion string) string {
|
|
62
|
-
fields := strings.Fields(expansion)
|
|
63
|
-
if len(fields) == 0 || fields[0] != "run" {
|
|
64
|
-
return ""
|
|
65
|
-
}
|
|
66
|
-
if i := slices.Index(fields, "--"); i >= 0 && i+1 < len(fields) {
|
|
67
|
-
return ""
|
|
68
|
-
}
|
|
69
|
-
for i, f := range fields {
|
|
70
|
-
if (f == "--package" || f == "-p") && i+1 < len(fields) {
|
|
71
|
-
return fields[i+1]
|
|
72
|
-
}
|
|
73
|
-
if rest, ok := strings.CutPrefix(f, "--package="); ok {
|
|
74
|
-
return rest
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return ""
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// readXtask lists the subcommands of an xtask-style package by reading its
|
|
82
|
-
// main.rs for the two shapes they are written in: a match on the first
|
|
83
|
-
// argument (`"dist" => ...`, `Some("dist") => ...`), and a clap enum
|
|
84
|
-
// deriving Subcommand, whose variants are the commands in kebab-case. A
|
|
85
|
-
// `///` comment over a variant, or its `about`, is the doc.
|
|
86
|
-
func readXtask(root, alias, pkg string) []catalog.Command {
|
|
87
|
-
for _, candidate := range []string{filepath.Join(pkg, "src", "main.rs"), filepath.Join("xtask", "src", "main.rs")} {
|
|
88
|
-
raw, err := os.ReadFile(filepath.Join(root, candidate))
|
|
89
|
-
if err != nil {
|
|
90
|
-
continue
|
|
91
|
-
}
|
|
92
|
-
src := string(raw)
|
|
93
|
-
file := filepath.ToSlash(filepath.Join(root, candidate))
|
|
94
|
-
var out []catalog.Command
|
|
95
|
-
seen := map[string]bool{}
|
|
96
|
-
add := func(name, doc string, line int) {
|
|
97
|
-
if seen[name] || !typeable(name) {
|
|
98
|
-
return
|
|
99
|
-
}
|
|
100
|
-
seen[name] = true
|
|
101
|
-
out = append(out, catalog.Command{Runner: "cargo", Name: alias + " " + name, Run: "cargo " + alias + " " + name, Doc: doc, Source: at(file, line)})
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if e := xtaskEnum.FindStringSubmatchIndex(src); e != nil {
|
|
105
|
-
body := src[e[2]:e[3]]
|
|
106
|
-
lines := strings.Split(body, "\n")
|
|
107
|
-
base := strings.Count(src[:e[2]], "\n") + 1
|
|
108
|
-
for i, line := range lines {
|
|
109
|
-
m := xtaskVariant.FindStringSubmatch(line)
|
|
110
|
-
if m == nil {
|
|
111
|
-
continue
|
|
112
|
-
}
|
|
113
|
-
doc := commentAbove(lines, i, "///")
|
|
114
|
-
if doc == "" {
|
|
115
|
-
if a := regexp.MustCompile(`about\s*=\s*"([^"]*)"`).FindStringSubmatch(strings.Join(lines[max(0, i-3):i], "\n")); a != nil {
|
|
116
|
-
doc = a[1]
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
add(kebab(m[1]), doc, base+i)
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
lines := strings.Split(src, "\n")
|
|
123
|
-
for _, m := range xtaskArm.FindAllStringIndex(src, -1) {
|
|
124
|
-
// `Some("bench") | Some("perf") =>` is one arm and two names, and
|
|
125
|
-
// the `//` comment over the arm is what both are for.
|
|
126
|
-
line := strings.Count(src[:m[0]], "\n")
|
|
127
|
-
doc := commentAbove(lines, line, "//")
|
|
128
|
-
for _, literal := range xtaskLiteral.FindAllStringSubmatch(src[m[0]:m[1]], -1) {
|
|
129
|
-
add(literal[1], doc, line+1)
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return out
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return nil
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
func kebab(name string) string {
|
|
140
|
-
var b strings.Builder
|
|
141
|
-
for i, r := range name {
|
|
142
|
-
if r >= 'A' && r <= 'Z' {
|
|
143
|
-
if i > 0 {
|
|
144
|
-
b.WriteByte('-')
|
|
145
|
-
}
|
|
146
|
-
b.WriteRune(r + 'a' - 'A')
|
|
147
|
-
|
|
148
|
-
continue
|
|
149
|
-
}
|
|
150
|
-
b.WriteRune(r)
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return b.String()
|
|
154
|
-
}
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
// Package commands reads what a developer types against a checkout - the make
|
|
2
|
-
// targets, npm scripts, just recipes and task-runner tasks a repository
|
|
3
|
-
// declares - into catalog.Command values.
|
|
4
|
-
//
|
|
5
|
-
// It reads the runner files and nothing else. A README that says "run make
|
|
6
|
-
// test" is a claim; a Makefile with a test target is the fact, and the two
|
|
7
|
-
// drift apart exactly when the README stops being read. Every parser here is
|
|
8
|
-
// deliberately shallow: it knows the file well enough to list its entries and
|
|
9
|
-
// their descriptions, and it does not evaluate anything. A make target hidden
|
|
10
|
-
// behind an `ifeq` is listed; a target spelled through a variable is not,
|
|
11
|
-
// because the name it would have depends on a value nobody here can know.
|
|
12
|
-
package commands
|
|
13
|
-
|
|
14
|
-
import (
|
|
15
|
-
"os"
|
|
16
|
-
"path/filepath"
|
|
17
|
-
"strconv"
|
|
18
|
-
"strings"
|
|
19
|
-
|
|
20
|
-
"github.com/shortlink-org/portolan/catalog"
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
// Read lists the commands declared at root, in a fixed order of files - make,
|
|
24
|
-
// just, Taskfile, the package manifest, pyproject, pom, the Gradle script,
|
|
25
|
-
// cargo's aliases - and in file order inside each. Source is spelled root-relative with the line, the way the rest of the
|
|
26
|
-
// catalog spells one.
|
|
27
|
-
//
|
|
28
|
-
// Warnings name what was seen and not read: a Taskfile that is not YAML, a
|
|
29
|
-
// package.json whose scripts are not an object.
|
|
30
|
-
func Read(root string) ([]catalog.Command, []string) {
|
|
31
|
-
var out []catalog.Command
|
|
32
|
-
var warnings []string
|
|
33
|
-
|
|
34
|
-
add := func(cmds []catalog.Command, warns []string) {
|
|
35
|
-
out = append(out, cmds...)
|
|
36
|
-
warnings = append(warnings, warns...)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if file, src, ok := first(root, "Makefile", "makefile", "GNUmakefile"); ok {
|
|
40
|
-
add(readMakefile(file, src), nil)
|
|
41
|
-
}
|
|
42
|
-
if file, src, ok := first(root, "justfile", "Justfile", ".justfile"); ok {
|
|
43
|
-
add(readJustfile(file, src), nil)
|
|
44
|
-
}
|
|
45
|
-
if file, src, ok := first(root, "Taskfile.yml", "Taskfile.yaml", "taskfile.yml", "taskfile.yaml", "Taskfile.dist.yml", "Taskfile.dist.yaml"); ok {
|
|
46
|
-
add(readTaskfile(file, src))
|
|
47
|
-
}
|
|
48
|
-
if file, src, ok := first(root, "package.json"); ok {
|
|
49
|
-
add(readPackageJSON(file, src, nodeRunner(root)))
|
|
50
|
-
}
|
|
51
|
-
if file, src, ok := first(root, "pyproject.toml"); ok {
|
|
52
|
-
add(readPyproject(file, src), nil)
|
|
53
|
-
}
|
|
54
|
-
if file, src, ok := first(root, "pom.xml"); ok {
|
|
55
|
-
add(readPom(root, file, src), nil)
|
|
56
|
-
}
|
|
57
|
-
if file, src, ok := first(root, "build.gradle.kts", "build.gradle"); ok {
|
|
58
|
-
add(readGradle(root, file, src), nil)
|
|
59
|
-
}
|
|
60
|
-
if file, src, ok := first(root, ".cargo/config.toml", ".cargo/config"); ok {
|
|
61
|
-
add(readCargoAliases(root, file, src), nil)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return out, warnings
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// first opens the first of names that exists under root, answering its
|
|
68
|
-
// root-relative path and contents.
|
|
69
|
-
func first(root string, names ...string) (string, string, bool) {
|
|
70
|
-
for _, name := range names {
|
|
71
|
-
raw, err := os.ReadFile(filepath.Join(root, name))
|
|
72
|
-
if err != nil {
|
|
73
|
-
continue
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return filepath.ToSlash(filepath.Join(root, name)), string(raw), true
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return "", "", false
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// nodeRunner is the package manager a checkout is set up for, read off the
|
|
83
|
-
// lockfile it keeps - the one file that says which tool the last person used.
|
|
84
|
-
func nodeRunner(root string) string {
|
|
85
|
-
for _, lock := range []struct{ file, runner string }{
|
|
86
|
-
{"pnpm-lock.yaml", "pnpm"},
|
|
87
|
-
{"yarn.lock", "yarn"},
|
|
88
|
-
{"bun.lockb", "bun"},
|
|
89
|
-
{"bun.lock", "bun"},
|
|
90
|
-
} {
|
|
91
|
-
if _, err := os.Stat(filepath.Join(root, lock.file)); err == nil {
|
|
92
|
-
return lock.runner
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return "npm"
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
func at(file string, line int) string {
|
|
100
|
-
return file + ":" + strconv.Itoa(line)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// hooks drops the pre/post entries of a name that is itself listed, the way
|
|
104
|
-
// npm and pdm run them: `pretest` is part of `test`, not a second command.
|
|
105
|
-
func hooks(cmds []catalog.Command, prefixes ...string) []catalog.Command {
|
|
106
|
-
named := map[string]bool{}
|
|
107
|
-
for _, cmd := range cmds {
|
|
108
|
-
named[cmd.Name] = true
|
|
109
|
-
}
|
|
110
|
-
kept := cmds[:0]
|
|
111
|
-
for _, cmd := range cmds {
|
|
112
|
-
hook := false
|
|
113
|
-
for _, prefix := range prefixes {
|
|
114
|
-
if rest, ok := strings.CutPrefix(cmd.Name, prefix); ok && rest != "" && named[rest] {
|
|
115
|
-
hook = true
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
if !hook {
|
|
119
|
-
kept = append(kept, cmd)
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return kept
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// commentAbove is the contiguous block of `#` lines ending at line i-1, as one
|
|
127
|
-
// paragraph, or "" when the line above is not a comment. A blank line breaks
|
|
128
|
-
// the block: a comment two lines up is about something else.
|
|
129
|
-
func commentAbove(lines []string, i int, marker string) string {
|
|
130
|
-
var block []string
|
|
131
|
-
for j := i - 1; j >= 0; j-- {
|
|
132
|
-
text := strings.TrimSpace(lines[j])
|
|
133
|
-
if !strings.HasPrefix(text, marker) {
|
|
134
|
-
break
|
|
135
|
-
}
|
|
136
|
-
text = strings.TrimSpace(strings.TrimPrefix(text, marker))
|
|
137
|
-
// A `## help` line in a block is help; a `##` divider is not a word.
|
|
138
|
-
text = strings.TrimSpace(strings.TrimLeft(text, "#"))
|
|
139
|
-
block = append([]string{text}, block...)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return strings.TrimSpace(strings.Join(block, " "))
|
|
143
|
-
}
|