@shortlink-org/portolan 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +387 -0
- package/catalog/enum_test.go +46 -0
- package/catalog/model.go +932 -0
- package/catalog/roundtrip_test.go +185 -0
- package/catalog/via_test.go +38 -0
- package/cli/portolan.mjs +368 -0
- package/go.mod +14 -0
- package/go.sum +14 -0
- package/index.html +13 -0
- package/internal/commands/cargo.go +154 -0
- package/internal/commands/commands.go +143 -0
- package/internal/commands/commands_test.go +323 -0
- package/internal/commands/gradle.go +77 -0
- package/internal/commands/justfile.go +82 -0
- package/internal/commands/makefile.go +106 -0
- package/internal/commands/maven.go +93 -0
- package/internal/commands/packagejson.go +159 -0
- package/internal/commands/pyproject.go +169 -0
- package/internal/commands/taskfile.go +101 -0
- package/internal/commands/testdata/estate/.cargo/config.toml +7 -0
- package/internal/commands/testdata/estate/Makefile +33 -0
- package/internal/commands/testdata/estate/Taskfile.yml +21 -0
- package/internal/commands/testdata/estate/build.gradle.kts +21 -0
- package/internal/commands/testdata/estate/justfile +20 -0
- package/internal/commands/testdata/estate/package.json +13 -0
- package/internal/commands/testdata/estate/pom.xml +29 -0
- package/internal/commands/testdata/estate/pyproject.toml +27 -0
- package/internal/commands/testdata/estate/xtask/src/main.rs +27 -0
- package/internal/commands/testdata/golden/commands.json +305 -0
- package/internal/gohttp/analyze.go +2500 -0
- package/internal/gohttp/endpoints.go +1067 -0
- package/internal/gohttp/roots.go +320 -0
- package/internal/gohttp/typed.go +143 -0
- package/internal/goscan/constants.go +85 -0
- package/internal/goscan/goscan_test.go +227 -0
- package/internal/goscan/names.go +52 -0
- package/internal/goscan/parse_test.go +11 -0
- package/internal/goscan/source.go +36 -0
- package/internal/goscan/tree.go +155 -0
- package/internal/goscan/types.go +99 -0
- package/internal/wsdl/ids.go +127 -0
- package/internal/wsdl/ids_test.go +21 -0
- package/internal/wsdl/model.go +62 -0
- package/internal/wsdl/parse.go +920 -0
- package/internal/wsdl/parse_test.go +133 -0
- package/package.json +117 -0
- package/plugin/describe.go +107 -0
- package/plugin/describe_test.go +114 -0
- package/plugin/protocol.go +117 -0
- package/plugin/schematest/schematest.go +126 -0
- package/plugins/README.md +1160 -0
- package/plugins/extract-adr/describe.go +19 -0
- package/plugins/extract-adr/describe_test.go +11 -0
- package/plugins/extract-adr/extract.go +153 -0
- package/plugins/extract-adr/extract_test.go +350 -0
- package/plugins/extract-adr/history.go +99 -0
- package/plugins/extract-adr/main.go +65 -0
- package/plugins/extract-adr/options.schema.json +26 -0
- package/plugins/extract-adr/parse.go +642 -0
- package/plugins/extract-adr/parse_test.go +405 -0
- package/plugins/extract-asyncapi/describe.go +19 -0
- package/plugins/extract-asyncapi/describe_test.go +11 -0
- package/plugins/extract-asyncapi/extract.go +315 -0
- package/plugins/extract-asyncapi/extract_test.go +197 -0
- package/plugins/extract-asyncapi/main.go +48 -0
- package/plugins/extract-asyncapi/options.schema.json +26 -0
- package/plugins/extract-asyncapi/spec.go +151 -0
- package/plugins/extract-celery/README.md +169 -0
- package/plugins/extract-celery/extract.py +346 -0
- package/plugins/extract-celery/extract_test.py +192 -0
- package/plugins/extract-celery/main.py +66 -0
- package/plugins/extract-celery/options.py +31 -0
- package/plugins/extract-celery/options.schema.json +31 -0
- package/plugins/extract-celery/producers.py +156 -0
- package/plugins/extract-celery/routes_test.py +106 -0
- package/plugins/extract-commands/describe.go +19 -0
- package/plugins/extract-commands/describe_test.go +11 -0
- package/plugins/extract-commands/extract.go +79 -0
- package/plugins/extract-commands/extract_test.go +92 -0
- package/plugins/extract-commands/main.go +55 -0
- package/plugins/extract-commands/options.schema.json +20 -0
- package/plugins/extract-csr/avro.go +258 -0
- package/plugins/extract-csr/describe.go +19 -0
- package/plugins/extract-csr/describe_test.go +11 -0
- package/plugins/extract-csr/extract.go +338 -0
- package/plugins/extract-csr/extract_test.go +374 -0
- package/plugins/extract-csr/jsonschema.go +343 -0
- package/plugins/extract-csr/lock.go +25 -0
- package/plugins/extract-csr/main.go +84 -0
- package/plugins/extract-csr/options.schema.json +43 -0
- package/plugins/extract-csr/subject.go +102 -0
- package/plugins/extract-django/README.md +386 -0
- package/plugins/extract-django/apps.py +100 -0
- package/plugins/extract-django/auth.py +302 -0
- package/plugins/extract-django/auth_test.py +188 -0
- package/plugins/extract-django/clients.py +121 -0
- package/plugins/extract-django/contracts.py +458 -0
- package/plugins/extract-django/database.py +119 -0
- package/plugins/extract-django/domain.py +318 -0
- package/plugins/extract-django/events.py +86 -0
- package/plugins/extract-django/extract.py +601 -0
- package/plugins/extract-django/extract_test.py +397 -0
- package/plugins/extract-django/flows.py +1278 -0
- package/plugins/extract-django/flows_test.py +338 -0
- package/plugins/extract-django/ids.py +42 -0
- package/plugins/extract-django/ids_test.py +30 -0
- package/plugins/extract-django/lifecycle.py +222 -0
- package/plugins/extract-django/lifecycle_test.py +76 -0
- package/plugins/extract-django/main.py +66 -0
- package/plugins/extract-django/openapi.py +229 -0
- package/plugins/extract-django/openapi_test.py +60 -0
- package/plugins/extract-django/operations.py +96 -0
- package/plugins/extract-django/options.py +61 -0
- package/plugins/extract-django/options.schema.json +126 -0
- package/plugins/extract-django/routing.py +214 -0
- package/plugins/extract-django/routing_test.py +198 -0
- package/plugins/extract-django/serializers.py +558 -0
- package/plugins/extract-django/store.py +434 -0
- package/plugins/extract-django/transport.py +242 -0
- package/plugins/extract-flows/describe.go +19 -0
- package/plugins/extract-flows/describe_test.go +11 -0
- package/plugins/extract-flows/extract.go +91 -0
- package/plugins/extract-flows/main.go +45 -0
- package/plugins/extract-flows/options.schema.json +16 -0
- package/plugins/extract-flows/parse.go +593 -0
- package/plugins/extract-flows/parse_test.go +204 -0
- package/plugins/extract-glossary/describe.go +19 -0
- package/plugins/extract-glossary/describe_test.go +11 -0
- package/plugins/extract-glossary/extract.go +115 -0
- package/plugins/extract-glossary/extract_test.go +220 -0
- package/plugins/extract-glossary/main.go +59 -0
- package/plugins/extract-glossary/options.schema.json +21 -0
- package/plugins/extract-glossary/parse.go +214 -0
- package/plugins/extract-glossary/parse_test.go +203 -0
- package/plugins/extract-go/aggregate.go +214 -0
- package/plugins/extract-go/client.go +409 -0
- package/plugins/extract-go/client_test.go +266 -0
- package/plugins/extract-go/describe.go +19 -0
- package/plugins/extract-go/describe_test.go +11 -0
- package/plugins/extract-go/enum.go +195 -0
- package/plugins/extract-go/enum_test.go +82 -0
- package/plugins/extract-go/event.go +99 -0
- package/plugins/extract-go/extract.go +191 -0
- package/plugins/extract-go/extract_test.go +261 -0
- package/plugins/extract-go/flow.go +1441 -0
- package/plugins/extract-go/flow_test.go +609 -0
- package/plugins/extract-go/httpclient.go +174 -0
- package/plugins/extract-go/httpclient_test.go +296 -0
- package/plugins/extract-go/ids.go +92 -0
- package/plugins/extract-go/layout.go +225 -0
- package/plugins/extract-go/layout_test.go +125 -0
- package/plugins/extract-go/lifecycle.go +324 -0
- package/plugins/extract-go/lifecycle_test.go +108 -0
- package/plugins/extract-go/main.go +79 -0
- package/plugins/extract-go/operation.go +157 -0
- package/plugins/extract-go/options.schema.json +66 -0
- package/plugins/extract-go/source.go +316 -0
- package/plugins/extract-go/transport.go +321 -0
- package/plugins/extract-go/transport_test.go +145 -0
- package/plugins/extract-go/wiring.go +434 -0
- package/plugins/extract-go-nats/describe.go +19 -0
- package/plugins/extract-go-nats/describe_test.go +11 -0
- package/plugins/extract-go-nats/extract.go +177 -0
- package/plugins/extract-go-nats/extract_test.go +389 -0
- package/plugins/extract-go-nats/index.go +379 -0
- package/plugins/extract-go-nats/main.go +42 -0
- package/plugins/extract-go-nats/options.schema.json +21 -0
- package/plugins/extract-go-nats/resolve.go +161 -0
- package/plugins/extract-go-nats/sites.go +224 -0
- package/plugins/extract-graphql/describe.go +19 -0
- package/plugins/extract-graphql/describe_test.go +11 -0
- package/plugins/extract-graphql/extract.go +433 -0
- package/plugins/extract-graphql/extract_test.go +256 -0
- package/plugins/extract-graphql/ids.go +49 -0
- package/plugins/extract-graphql/lex.go +237 -0
- package/plugins/extract-graphql/main.go +51 -0
- package/plugins/extract-graphql/options.schema.json +31 -0
- package/plugins/extract-graphql/parse.go +621 -0
- package/plugins/extract-graphql/parse_test.go +122 -0
- package/plugins/extract-http-clients/describe.go +19 -0
- package/plugins/extract-http-clients/describe_test.go +11 -0
- package/plugins/extract-http-clients/extract.go +705 -0
- package/plugins/extract-http-clients/extract_test.go +1263 -0
- package/plugins/extract-http-clients/main.go +42 -0
- package/plugins/extract-http-clients/options.schema.json +33 -0
- package/plugins/extract-java/README.md +190 -0
- package/plugins/extract-java/build/org/portolan/extract/Catalog.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$1.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$2.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$Call.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$Client.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients$Route.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Clients.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Domain$Aggregate.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Domain.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Events$Found.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Events.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Extract.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$1.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$Binding.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$Draft.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$Frame.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows$Options.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Flows.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Ids.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Json$Reader.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Json.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Lifecycle$1.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Lifecycle$Move.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Lifecycle.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Main.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/OpenApi$Operation.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/OpenApi$Spec.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/OpenApi.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Operations$1.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Operations$UseCase.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Operations.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Proto$Rpc.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Proto$Service.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Proto.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol$Builder.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol$Input.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol$Options.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Protocol.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Source$Project.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Source$Unit.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Source.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Transport$Endpoint.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Transport.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Yaml$Line.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Yaml$Reader.class +0 -0
- package/plugins/extract-java/build/org/portolan/extract/Yaml.class +0 -0
- package/plugins/extract-java/options.schema.json +70 -0
- package/plugins/extract-openapi/describe.go +19 -0
- package/plugins/extract-openapi/describe_test.go +11 -0
- package/plugins/extract-openapi/discover.go +243 -0
- package/plugins/extract-openapi/extract.go +526 -0
- package/plugins/extract-openapi/extract_test.go +545 -0
- package/plugins/extract-openapi/main.go +75 -0
- package/plugins/extract-openapi/options.schema.json +62 -0
- package/plugins/extract-openapi/spec.go +350 -0
- package/plugins/extract-project/README.md +22 -0
- package/plugins/extract-project/describe.go +19 -0
- package/plugins/extract-project/describe_test.go +11 -0
- package/plugins/extract-project/extract.go +221 -0
- package/plugins/extract-project/extract_test.go +109 -0
- package/plugins/extract-project/main.go +41 -0
- package/plugins/extract-project/options.schema.json +48 -0
- package/plugins/extract-proto/ast.go +125 -0
- package/plugins/extract-proto/consumes.go +77 -0
- package/plugins/extract-proto/describe.go +19 -0
- package/plugins/extract-proto/extract.go +293 -0
- package/plugins/extract-proto/extract_test.go +459 -0
- package/plugins/extract-proto/ids.go +89 -0
- package/plugins/extract-proto/ids_test.go +57 -0
- package/plugins/extract-proto/lex.go +285 -0
- package/plugins/extract-proto/main.go +100 -0
- package/plugins/extract-proto/module.go +120 -0
- package/plugins/extract-proto/options.schema.json +51 -0
- package/plugins/extract-proto/parse.go +720 -0
- package/plugins/extract-proto/parse_test.go +307 -0
- package/plugins/extract-proto/provides.go +236 -0
- package/plugins/extract-proto/resolve.go +222 -0
- package/plugins/extract-proto/resolve_test.go +119 -0
- package/plugins/extract-python-kafka/README.md +36 -0
- package/plugins/extract-python-kafka/extract.py +211 -0
- package/plugins/extract-python-kafka/extract_test.py +68 -0
- package/plugins/extract-python-kafka/main.py +59 -0
- package/plugins/extract-python-kafka/options.py +29 -0
- package/plugins/extract-python-kafka/options.schema.json +31 -0
- package/plugins/extract-redis/README.md +11 -0
- package/plugins/extract-redis/describe.go +19 -0
- package/plugins/extract-redis/describe_test.go +11 -0
- package/plugins/extract-redis/extract.go +183 -0
- package/plugins/extract-redis/extract_test.go +168 -0
- package/plugins/extract-redis/keyspaces.go +469 -0
- package/plugins/extract-redis/main.go +44 -0
- package/plugins/extract-redis/options.schema.json +30 -0
- package/plugins/extract-river/describe.go +19 -0
- package/plugins/extract-river/describe_test.go +11 -0
- package/plugins/extract-river/extract.go +507 -0
- package/plugins/extract-river/extract_test.go +132 -0
- package/plugins/extract-river/main.go +42 -0
- package/plugins/extract-river/options.schema.json +21 -0
- package/plugins/extract-rust/Cargo.lock +133 -0
- package/plugins/extract-rust/Cargo.toml +23 -0
- package/plugins/extract-rust/README.md +204 -0
- package/plugins/extract-rust/options.schema.json +65 -0
- package/plugins/extract-rust/rustfmt.toml +1 -0
- package/plugins/extract-sql/ddl.go +893 -0
- package/plugins/extract-sql/ddl_test.go +401 -0
- package/plugins/extract-sql/describe.go +19 -0
- package/plugins/extract-sql/describe_test.go +11 -0
- package/plugins/extract-sql/layout.go +221 -0
- package/plugins/extract-sql/layout_test.go +55 -0
- package/plugins/extract-sql/lineage.go +107 -0
- package/plugins/extract-sql/main.go +141 -0
- package/plugins/extract-sql/maps.go +564 -0
- package/plugins/extract-sql/maps_java.go +117 -0
- package/plugins/extract-sql/maps_rust.go +333 -0
- package/plugins/extract-sql/maps_rust_test.go +70 -0
- package/plugins/extract-sql/maps_test.go +204 -0
- package/plugins/extract-sql/maps_ts.go +398 -0
- package/plugins/extract-sql/maps_ts_test.go +136 -0
- package/plugins/extract-sql/options.schema.json +53 -0
- package/plugins/extract-sql/projection.go +70 -0
- package/plugins/extract-sql/projection_test.go +50 -0
- package/plugins/extract-sql/store.go +420 -0
- package/plugins/extract-sql/store_test.go +233 -0
- package/plugins/extract-sql/view.go +295 -0
- package/plugins/extract-ts/README.md +306 -0
- package/plugins/extract-ts/ast.test.ts +178 -0
- package/plugins/extract-ts/ast.ts +648 -0
- package/plugins/extract-ts/clients.ts +185 -0
- package/plugins/extract-ts/domain.ts +164 -0
- package/plugins/extract-ts/extract.test.ts +208 -0
- package/plugins/extract-ts/extract.ts +200 -0
- package/plugins/extract-ts/flows.ts +783 -0
- package/plugins/extract-ts/graphql.test.ts +73 -0
- package/plugins/extract-ts/graphql.ts +181 -0
- package/plugins/extract-ts/ids.test.ts +21 -0
- package/plugins/extract-ts/ids.ts +52 -0
- package/plugins/extract-ts/lifecycle.ts +138 -0
- package/plugins/extract-ts/main.ts +48 -0
- package/plugins/extract-ts/openapi.test.ts +64 -0
- package/plugins/extract-ts/openapi.ts +99 -0
- package/plugins/extract-ts/operations.ts +93 -0
- package/plugins/extract-ts/options.schema.json +96 -0
- package/plugins/extract-ts/source.test.ts +174 -0
- package/plugins/extract-ts/source.ts +465 -0
- package/plugins/extract-ts/transport.ts +147 -0
- package/plugins/extract-ts/tsconfig.json +13 -0
- package/plugins/extract-ts/wiring.ts +190 -0
- package/plugins/extract-watermill/describe.go +19 -0
- package/plugins/extract-watermill/describe_test.go +11 -0
- package/plugins/extract-watermill/extract.go +1228 -0
- package/plugins/extract-watermill/extract_test.go +234 -0
- package/plugins/extract-watermill/main.go +41 -0
- package/plugins/extract-watermill/options.schema.json +21 -0
- package/plugins/extract-wsdl/describe.go +19 -0
- package/plugins/extract-wsdl/describe_test.go +11 -0
- package/plugins/extract-wsdl/extract.go +148 -0
- package/plugins/extract-wsdl/extract_test.go +45 -0
- package/plugins/extract-wsdl/main.go +53 -0
- package/plugins/extract-wsdl/options.schema.json +59 -0
- package/plugins/fetch-bsr/auth.go +114 -0
- package/plugins/fetch-bsr/bsr.go +240 -0
- package/plugins/fetch-bsr/cache.go +66 -0
- package/plugins/fetch-bsr/describe.go +19 -0
- package/plugins/fetch-bsr/fetch.go +192 -0
- package/plugins/fetch-bsr/fetch_test.go +465 -0
- package/plugins/fetch-bsr/lock.go +71 -0
- package/plugins/fetch-bsr/main.go +117 -0
- package/plugins/fetch-bsr/options.schema.json +42 -0
- package/plugins/fetch-csr/auth.go +95 -0
- package/plugins/fetch-csr/cache.go +69 -0
- package/plugins/fetch-csr/describe.go +19 -0
- package/plugins/fetch-csr/describe_test.go +11 -0
- package/plugins/fetch-csr/fetch.go +254 -0
- package/plugins/fetch-csr/fetch_test.go +494 -0
- package/plugins/fetch-csr/lock.go +95 -0
- package/plugins/fetch-csr/main.go +122 -0
- package/plugins/fetch-csr/options.schema.json +42 -0
- package/plugins/fetch-csr/registry.go +209 -0
- package/plugins/fetch-git/cache.go +65 -0
- package/plugins/fetch-git/describe.go +19 -0
- package/plugins/fetch-git/describe_test.go +11 -0
- package/plugins/fetch-git/fetch.go +181 -0
- package/plugins/fetch-git/fetch_test.go +332 -0
- package/plugins/fetch-git/git.go +169 -0
- package/plugins/fetch-git/lock.go +72 -0
- package/plugins/fetch-git/main.go +127 -0
- package/plugins/fetch-git/offline.go +39 -0
- package/plugins/fetch-git/options.schema.json +42 -0
- package/plugins/fetch-git/pin.go +90 -0
- package/plugins/fetch-git/pin_test.go +74 -0
- package/plugins/gen-backstage/describe.go +17 -0
- package/plugins/gen-backstage/main.go +22 -0
- package/plugins/gen-backstage/options.schema.json +30 -0
- package/plugins/gen-backstage/plugin.go +473 -0
- package/plugins/gen-backstage/plugin_test.go +145 -0
- package/plugins/gen-backstage.wasm +0 -0
- package/plugins/gen-markdown/adr.go +162 -0
- package/plugins/gen-markdown/aggregate.go +362 -0
- package/plugins/gen-markdown/canonical.go +93 -0
- package/plugins/gen-markdown/context.go +90 -0
- package/plugins/gen-markdown/coverage_test.go +89 -0
- package/plugins/gen-markdown/describe.go +19 -0
- package/plugins/gen-markdown/describe_test.go +11 -0
- package/plugins/gen-markdown/external.go +71 -0
- package/plugins/gen-markdown/flow.go +277 -0
- package/plugins/gen-markdown/glossary.go +76 -0
- package/plugins/gen-markdown/glossary_test.go +148 -0
- package/plugins/gen-markdown/llms.go +302 -0
- package/plugins/gen-markdown/main.go +22 -0
- package/plugins/gen-markdown/markdown.go +254 -0
- package/plugins/gen-markdown/markdown_test.go +100 -0
- package/plugins/gen-markdown/module.go +107 -0
- package/plugins/gen-markdown/options.schema.json +16 -0
- package/plugins/gen-markdown/plugin.go +39 -0
- package/plugins/gen-markdown/quality_test.go +176 -0
- package/plugins/gen-markdown/redis_test.go +38 -0
- package/plugins/gen-markdown/render.go +344 -0
- package/plugins/gen-markdown/render_test.go +186 -0
- package/plugins/gen-markdown/service.go +456 -0
- package/plugins/gen-markdown/source.go +177 -0
- package/plugins/gen-markdown/store.go +201 -0
- package/plugins/gen-markdown.wasm +0 -0
- package/plugins/gen-mermaid/describe.go +17 -0
- package/plugins/gen-mermaid/main.go +22 -0
- package/plugins/gen-mermaid/options.schema.json +10 -0
- package/plugins/gen-mermaid/plugin.go +104 -0
- package/plugins/gen-mermaid/plugin_test.go +33 -0
- package/plugins/gen-mermaid.wasm +0 -0
- package/plugins/openapi/ids.go +261 -0
- package/plugins/openapi/ids_test.go +98 -0
- package/plugins/pyplugin/catalog.py +209 -0
- package/plugins/pyplugin/celery_conf.py +436 -0
- package/plugins/pyplugin/celery_tasks.py +76 -0
- package/plugins/pyplugin/kafka.py +570 -0
- package/plugins/pyplugin/names.py +38 -0
- package/plugins/pyplugin/protocol.py +79 -0
- package/plugins/pyplugin/source.py +285 -0
- package/plugins/verify-codeowners/describe.go +19 -0
- package/plugins/verify-codeowners/describe_test.go +11 -0
- package/plugins/verify-codeowners/main.go +75 -0
- package/plugins/verify-codeowners/match.go +85 -0
- package/plugins/verify-codeowners/match_test.go +47 -0
- package/plugins/verify-codeowners/options.schema.json +15 -0
- package/plugins/verify-codeowners/owners.go +164 -0
- package/plugins/verify-codeowners/owners_test.go +225 -0
- package/plugins/verify-codeowners/parse.go +90 -0
- package/plugins/verify-codeowners/parse_test.go +62 -0
- package/plugins/verify-otel/describe.go +19 -0
- package/plugins/verify-otel/describe_test.go +11 -0
- package/plugins/verify-otel/main.go +53 -0
- package/plugins/verify-otel/match.go +336 -0
- package/plugins/verify-otel/options.schema.json +30 -0
- package/plugins/verify-otel/otlp.go +200 -0
- package/plugins/verify-otel/verify.go +734 -0
- package/plugins/verify-otel/verify_test.go +460 -0
- package/portolan.json +1073 -0
- package/public/favicon.svg +12 -0
- package/schema/portolan.schema.json +2558 -0
- package/scripts/README.md +53 -0
- package/scripts/build-report.mjs +60 -0
- package/scripts/build-report.test.mjs +44 -0
- package/scripts/builtin-plugins.mjs +49 -0
- package/scripts/catalog-sources.mjs +67 -0
- package/scripts/diff.mjs +315 -0
- package/scripts/diff.test.mjs +151 -0
- package/scripts/forge-comment.mjs +144 -0
- package/scripts/forge-comment.test.mjs +151 -0
- package/scripts/forge-release.mjs +138 -0
- package/scripts/forge-release.test.mjs +106 -0
- package/scripts/forge.mjs +61 -0
- package/scripts/gen-likec4.mjs +854 -0
- package/scripts/gen-likec4.test.mjs +258 -0
- package/scripts/gen.mjs +603 -0
- package/scripts/generated-docs.test.mjs +66 -0
- package/scripts/local-api.mjs +1192 -0
- package/scripts/local-api.test.mjs +387 -0
- package/scripts/manifest.mjs +214 -0
- package/scripts/manifest.test.mjs +148 -0
- package/scripts/output-path.mjs +79 -0
- package/scripts/output-path.test.mjs +45 -0
- package/scripts/package-smoke.mjs +37 -0
- package/scripts/plugin-host.mjs +419 -0
- package/scripts/plugin-host.test.mjs +109 -0
- package/scripts/plugin-wasm-worker.mjs +34 -0
- package/scripts/run-builtin.mjs +81 -0
- package/scripts/schema.mjs +357 -0
- package/scripts/site-docs.mjs +295 -0
- package/scripts/site-docs.test.mjs +181 -0
- package/scripts/vendor-lock.mjs +58 -0
- package/scripts/vendor-lock.test.mjs +69 -0
- package/src/README.md +38 -0
- package/src/app/App.tsx +448 -0
- package/src/app/BranchPicker.test.ts +46 -0
- package/src/app/BranchPicker.tsx +153 -0
- package/src/app/Breadcrumbs.test.ts +38 -0
- package/src/app/Breadcrumbs.tsx +223 -0
- package/src/app/BuildStamp.tsx +146 -0
- package/src/app/CommandPalette.tsx +292 -0
- package/src/app/HashScroll.tsx +45 -0
- package/src/app/Sidebar.tsx +1742 -0
- package/src/app/TopBar.tsx +393 -0
- package/src/app/density.tsx +64 -0
- package/src/app/forge-access.test.ts +27 -0
- package/src/app/forge-access.tsx +80 -0
- package/src/app/panels.tsx +141 -0
- package/src/app/pins.tsx +242 -0
- package/src/app/query-client.ts +24 -0
- package/src/app/responsive.ts +55 -0
- package/src/app/shortcuts.test.ts +39 -0
- package/src/app/shortcuts.tsx +282 -0
- package/src/app/theme.tsx +51 -0
- package/src/app/title.test.ts +14 -0
- package/src/app/title.ts +30 -0
- package/src/app/toast.tsx +59 -0
- package/src/app/tree-keys.test.ts +80 -0
- package/src/app/tree-keys.ts +87 -0
- package/src/app/ui-store.ts +52 -0
- package/src/catalog-error.test.ts +105 -0
- package/src/catalog-profile.test.ts +59 -0
- package/src/catalog-profile.ts +101 -0
- package/src/catalog-stores.test.ts +431 -0
- package/src/catalog.test.ts +1215 -0
- package/src/catalog.ts +3125 -0
- package/src/chat/Cards.tsx +408 -0
- package/src/chat/ChatPanel.tsx +79 -0
- package/src/chat/ChatSettings.tsx +219 -0
- package/src/chat/Composer.tsx +99 -0
- package/src/chat/Conversation.tsx +281 -0
- package/src/chat/Header.tsx +46 -0
- package/src/chat/Message.tsx +49 -0
- package/src/chat/Notice.tsx +195 -0
- package/src/chat/Starter.tsx +67 -0
- package/src/chat/Steps.tsx +45 -0
- package/src/chat/Waiting.tsx +87 -0
- package/src/chat/flags.test.ts +59 -0
- package/src/chat/flags.ts +155 -0
- package/src/chat/linkify.test.ts +30 -0
- package/src/chat/linkify.ts +45 -0
- package/src/chat/prefs.ts +56 -0
- package/src/chat/prompt.test.ts +43 -0
- package/src/chat/prompt.ts +157 -0
- package/src/chat/store.ts +35 -0
- package/src/chat/tools.ts +58 -0
- package/src/chat/transport.ts +70 -0
- package/src/components/AdrRow.tsx +29 -0
- package/src/components/AnchorLink.tsx +67 -0
- package/src/components/ApiReference.tsx +134 -0
- package/src/components/AsyncApiReference.tsx +120 -0
- package/src/components/CatalogStamp.tsx +155 -0
- package/src/components/ChannelRows.tsx +132 -0
- package/src/components/CommandRows.tsx +139 -0
- package/src/components/DiagramSkeleton.tsx +71 -0
- package/src/components/EditorLink.tsx +85 -0
- package/src/components/FieldTree.tsx +305 -0
- package/src/components/FlowTrigger.tsx +34 -0
- package/src/components/Ident.tsx +89 -0
- package/src/components/Integrations.tsx +243 -0
- package/src/components/LifecycleDiagram.tsx +110 -0
- package/src/components/MachineDocs.tsx +42 -0
- package/src/components/Markdown.tsx +173 -0
- package/src/components/MarkdownTable.tsx +206 -0
- package/src/components/Mermaid.tsx +211 -0
- package/src/components/MethodRows.tsx +309 -0
- package/src/components/Overlay.tsx +125 -0
- package/src/components/PageHeader.tsx +189 -0
- package/src/components/RowActions.tsx +97 -0
- package/src/components/SchemaDocument.tsx +89 -0
- package/src/components/Select.tsx +126 -0
- package/src/components/ShapeRows.tsx +118 -0
- package/src/components/SourceDoc.tsx +82 -0
- package/src/components/SourcePreview.tsx +441 -0
- package/src/components/TabRow.tsx +182 -0
- package/src/components/TechIcon.tsx +34 -0
- package/src/components/Toc.tsx +132 -0
- package/src/components/WhatLinksHere.tsx +273 -0
- package/src/components/WsdlReference.tsx +84 -0
- package/src/components/ddd-icons.tsx +107 -0
- package/src/components/kind.tsx +157 -0
- package/src/components/logo.tsx +61 -0
- package/src/components/primitives.tsx +264 -0
- package/src/data.test.ts +18 -0
- package/src/data.ts +202 -0
- package/src/enrich.test.ts +1150 -0
- package/src/enrich.ts +672 -0
- package/src/er/ErCanvas.tsx +533 -0
- package/src/er/RedisSchema.tsx +74 -0
- package/src/er/RelationCard.tsx +267 -0
- package/src/er/StoreHeader.tsx +155 -0
- package/src/er/TableNode.tsx +84 -0
- package/src/er/ViewNode.tsx +83 -0
- package/src/er/layout.test.ts +115 -0
- package/src/er/layout.ts +77 -0
- package/src/er/lineage.test.ts +140 -0
- package/src/er/lineage.ts +107 -0
- package/src/er/markers.tsx +79 -0
- package/src/er/spec.test.ts +344 -0
- package/src/er/spec.ts +426 -0
- package/src/flow/ChainList.tsx +162 -0
- package/src/flow/FlowTable.tsx +123 -0
- package/src/flow/FlowToolbar.tsx +372 -0
- package/src/flow/StepDetail.tsx +380 -0
- package/src/flow/StepRail.tsx +428 -0
- package/src/flow/answers.test.ts +50 -0
- package/src/flow/answers.ts +58 -0
- package/src/flow/chain.test.ts +383 -0
- package/src/flow/chain.ts +353 -0
- package/src/flow/chapters.test.ts +185 -0
- package/src/flow/chapters.ts +225 -0
- package/src/flow/continues.test.ts +102 -0
- package/src/flow/continues.ts +65 -0
- package/src/flow/cross-context.test.ts +97 -0
- package/src/flow/cross-context.ts +35 -0
- package/src/flow/mermaid.test.ts +22 -0
- package/src/flow/mermaid.ts +141 -0
- package/src/flow/outline.test.ts +212 -0
- package/src/flow/outline.ts +170 -0
- package/src/flow/paths.test.ts +129 -0
- package/src/flow/paths.ts +147 -0
- package/src/flow/prefs.test.ts +80 -0
- package/src/flow/prefs.ts +104 -0
- package/src/graph/DependencyGraph.tsx +283 -0
- package/src/graph/DependencyNodes.tsx +162 -0
- package/src/graph/EdgeLabel.tsx +61 -0
- package/src/graph/FocusedEventGraph.tsx +211 -0
- package/src/graph/GraphToolbar.tsx +187 -0
- package/src/graph/RoutedEdge.tsx +80 -0
- package/src/graph/dependency-layout.test.ts +360 -0
- package/src/graph/dependency-layout.ts +444 -0
- package/src/graph/elk.test.ts +70 -0
- package/src/graph/elk.ts +287 -0
- package/src/graph/nodes.tsx +97 -0
- package/src/graph/theme.ts +81 -0
- package/src/graph/useElkFlow.ts +125 -0
- package/src/index.css +1547 -0
- package/src/language/InLanguage.tsx +40 -0
- package/src/language/TermCard.tsx +132 -0
- package/src/language/cards.test.ts +114 -0
- package/src/language/cards.ts +111 -0
- package/src/lib/admonition.test.ts +49 -0
- package/src/lib/admonition.ts +48 -0
- package/src/lib/adr.test.ts +131 -0
- package/src/lib/adr.ts +68 -0
- package/src/lib/api.test.ts +122 -0
- package/src/lib/api.ts +135 -0
- package/src/lib/backlinks.test.ts +330 -0
- package/src/lib/backlinks.ts +567 -0
- package/src/lib/branch-compare.ts +16 -0
- package/src/lib/build-info.test.ts +76 -0
- package/src/lib/build-info.ts +80 -0
- package/src/lib/catalog-diff.test.ts +275 -0
- package/src/lib/catalog-diff.ts +655 -0
- package/src/lib/clipboard.ts +43 -0
- package/src/lib/comparison-memory.test.ts +40 -0
- package/src/lib/comparison-memory.ts +39 -0
- package/src/lib/context-color.ts +27 -0
- package/src/lib/context-map.test.ts +148 -0
- package/src/lib/context-map.ts +399 -0
- package/src/lib/data-model.test.ts +245 -0
- package/src/lib/data-model.ts +399 -0
- package/src/lib/data-problems.test.ts +178 -0
- package/src/lib/data-problems.ts +314 -0
- package/src/lib/derive.test.ts +251 -0
- package/src/lib/derive.ts +515 -0
- package/src/lib/editor-link.test.ts +125 -0
- package/src/lib/editor-link.ts +96 -0
- package/src/lib/editor-prefs.ts +27 -0
- package/src/lib/event-graph.test.ts +237 -0
- package/src/lib/event-graph.ts +327 -0
- package/src/lib/export-canvas.ts +37 -0
- package/src/lib/export-file.test.ts +30 -0
- package/src/lib/export-file.ts +20 -0
- package/src/lib/flow-tree.test.ts +177 -0
- package/src/lib/flow-tree.ts +160 -0
- package/src/lib/forge-refs.test.ts +50 -0
- package/src/lib/forge-refs.ts +60 -0
- package/src/lib/format.test.ts +35 -0
- package/src/lib/format.ts +64 -0
- package/src/lib/github-catalog.test.ts +301 -0
- package/src/lib/github-catalog.ts +610 -0
- package/src/lib/integrations.test.ts +119 -0
- package/src/lib/integrations.ts +133 -0
- package/src/lib/kinds.test.ts +91 -0
- package/src/lib/kinds.ts +204 -0
- package/src/lib/lifecycle.test.ts +93 -0
- package/src/lib/lifecycle.ts +165 -0
- package/src/lib/local-api.ts +194 -0
- package/src/lib/motion-features.ts +11 -0
- package/src/lib/motion.test.ts +120 -0
- package/src/lib/motion.tsx +269 -0
- package/src/lib/palette-recent.test.ts +80 -0
- package/src/lib/palette-recent.ts +90 -0
- package/src/lib/palette.test.ts +365 -0
- package/src/lib/palette.ts +593 -0
- package/src/lib/pins.test.ts +139 -0
- package/src/lib/pins.ts +130 -0
- package/src/lib/problems.test.ts +112 -0
- package/src/lib/project-preview.ts +5 -0
- package/src/lib/proto-problems.test.ts +121 -0
- package/src/lib/proto-problems.ts +65 -0
- package/src/lib/queries.test.ts +113 -0
- package/src/lib/queries.ts +131 -0
- package/src/lib/registry.test.ts +219 -0
- package/src/lib/registry.ts +208 -0
- package/src/lib/scenarios.ts +547 -0
- package/src/lib/setup-info.test.ts +199 -0
- package/src/lib/setup-info.ts +415 -0
- package/src/lib/shape.test.ts +289 -0
- package/src/lib/shape.ts +454 -0
- package/src/lib/sidebar-prefs.test.ts +32 -0
- package/src/lib/sidebar-prefs.ts +75 -0
- package/src/lib/source-code.test.ts +159 -0
- package/src/lib/source-code.ts +286 -0
- package/src/lib/source-doc.test.ts +131 -0
- package/src/lib/source-doc.ts +103 -0
- package/src/lib/source-highlight.test.ts +29 -0
- package/src/lib/source-highlight.ts +24 -0
- package/src/lib/source-link.test.ts +153 -0
- package/src/lib/source-link.ts +201 -0
- package/src/lib/spec-files.test.ts +24 -0
- package/src/lib/spec-files.ts +23 -0
- package/src/lib/table-directive.test.ts +139 -0
- package/src/lib/table-directive.ts +106 -0
- package/src/lib/tech.test.ts +120 -0
- package/src/lib/tech.ts +421 -0
- package/src/lib/terms.test.ts +67 -0
- package/src/lib/terms.ts +179 -0
- package/src/lib/wire-problems.test.ts +263 -0
- package/src/lib/wire-problems.ts +281 -0
- package/src/likec4/C4View.tsx +55 -0
- package/src/likec4/CanvasBridge.tsx +187 -0
- package/src/likec4/FlowView.tsx +235 -0
- package/src/likec4/InteractiveView.tsx +144 -0
- package/src/likec4/canvas-viewport.test.ts +149 -0
- package/src/likec4/canvas-viewport.ts +135 -0
- package/src/likec4/flow-edges.test.ts +51 -0
- package/src/likec4/flow-edges.ts +89 -0
- package/src/likec4/frame-theme.test.ts +76 -0
- package/src/likec4/frame-theme.ts +101 -0
- package/src/likec4/highlight-css.test.ts +49 -0
- package/src/likec4/highlight-css.ts +52 -0
- package/src/likec4/ids.test.ts +151 -0
- package/src/likec4/ids.ts +115 -0
- package/src/likec4/levels.tsx +70 -0
- package/src/likec4/mapping.test.ts +66 -0
- package/src/likec4/mapping.ts +54 -0
- package/src/likec4/reserved.json +141 -0
- package/src/likec4/view-index.ts +78 -0
- package/src/main.tsx +13 -0
- package/src/map/ContextMapGraph.tsx +274 -0
- package/src/map/ContextNode.tsx +70 -0
- package/src/map/FloatingEdge.tsx +86 -0
- package/src/merge.test.ts +1038 -0
- package/src/merge.ts +1004 -0
- package/src/pages/AdrDetail.tsx +242 -0
- package/src/pages/AdrIndex.tsx +114 -0
- package/src/pages/AggregatePage.tsx +727 -0
- package/src/pages/BlockPage.tsx +478 -0
- package/src/pages/CatalogFailure.tsx +111 -0
- package/src/pages/Changes.tsx +313 -0
- package/src/pages/ContextMap.tsx +534 -0
- package/src/pages/ContextPage.tsx +346 -0
- package/src/pages/EnumPage.tsx +282 -0
- package/src/pages/EventPage.tsx +686 -0
- package/src/pages/ExternalPage.tsx +204 -0
- package/src/pages/FlowDetail.tsx +663 -0
- package/src/pages/FlowIndex.tsx +303 -0
- package/src/pages/GraphPage.tsx +217 -0
- package/src/pages/Language.tsx +257 -0
- package/src/pages/ModulePage.tsx +366 -0
- package/src/pages/NotFound.tsx +54 -0
- package/src/pages/Overview.tsx +344 -0
- package/src/pages/Problems.tsx +360 -0
- package/src/pages/RegistryIndex.tsx +118 -0
- package/src/pages/ServicePage.tsx +746 -0
- package/src/pages/Settings.tsx +975 -0
- package/src/pages/StorePage.tsx +114 -0
- package/src/peek/PeekCard.test.ts +35 -0
- package/src/peek/PeekCard.tsx +118 -0
- package/src/peek/PeekLayer.tsx +147 -0
- package/src/peek/model.test.ts +156 -0
- package/src/peek/model.ts +253 -0
- package/src/routes.test.ts +222 -0
- package/src/routes.ts +449 -0
- package/src/selection/DetailPanel.tsx +1407 -0
- package/src/selection/hash.test.ts +73 -0
- package/src/selection/hash.ts +58 -0
- package/src/selection/model.test.ts +199 -0
- package/src/selection/model.ts +473 -0
- package/src/selection/pages.test.ts +115 -0
- package/src/selection/pages.ts +268 -0
- package/src/selection/store.test.ts +62 -0
- package/src/selection/store.ts +46 -0
- package/src/selection/sync.tsx +99 -0
- package/src/table/ColumnsMenu.tsx +72 -0
- package/src/table/DataTable.tsx +780 -0
- package/src/table/Facets.tsx +54 -0
- package/src/table/GroupMenu.tsx +69 -0
- package/src/table/Toolbar.tsx +190 -0
- package/src/table/cells.tsx +117 -0
- package/src/table/compare.test.ts +117 -0
- package/src/table/compare.ts +196 -0
- package/src/table/export.test.ts +88 -0
- package/src/table/export.ts +66 -0
- package/src/table/facet-groups.test.ts +74 -0
- package/src/table/facet-groups.ts +56 -0
- package/src/table/grouping.test.ts +84 -0
- package/src/table/grouping.ts +82 -0
- package/src/table/infer.test.ts +57 -0
- package/src/table/infer.ts +50 -0
- package/src/table/persist.test.ts +76 -0
- package/src/table/persist.ts +112 -0
- package/src/table/sort-url.test.ts +75 -0
- package/src/table/sort-url.ts +52 -0
- package/src/table/types.ts +80 -0
- package/src/table/useTableState.ts +220 -0
- package/src/test-catalog.ts +7 -0
- package/src/testing/estate/data__catalog.json +2847 -0
- package/src/testing/estate/data__flows.json +1724 -0
- package/src/testing/estate/examples__auth__portolan__api.json +212 -0
- package/src/testing/estate/examples__auth__portolan__domain.json +1204 -0
- package/src/testing/estate/examples__auth__portolan__glossary.json +226 -0
- package/src/testing/estate/examples__auth__portolan__observed.json +757 -0
- package/src/testing/estate/examples__auth__portolan__stores.json +195 -0
- package/src/testing/estate/examples__shop__cart__portolan__api.json +234 -0
- package/src/testing/estate/examples__shop__cart__portolan__commands.json +86 -0
- package/src/testing/estate/examples__shop__cart__portolan__domain.json +966 -0
- package/src/testing/estate/examples__shop__cart__portolan__observed.json +498 -0
- package/src/testing/estate/examples__shop__cart__portolan__stores.json +208 -0
- package/src/testing/estate/examples__shop__oms__portolan__glossary.json +98 -0
- package/src/testing/estate/examples__shop__oms__portolan__proto.json +186 -0
- package/src/testing/estate.ts +49 -0
- package/src/trail/Trail.tsx +81 -0
- package/src/trail/model.test.ts +157 -0
- package/src/trail/model.ts +189 -0
- package/src/trail/record.tsx +32 -0
- package/src/trail/store.test.ts +66 -0
- package/src/trail/store.ts +102 -0
- package/tsconfig.json +35 -0
- package/vite.config.ts +171 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
// The mapping: protos in a tree, a catalog fragment out.
|
|
4
|
+
//
|
|
5
|
+
// Shaped like plugins/extract-openapi/extract_test.go, which is the house style
|
|
6
|
+
// for an extractor test - one behaviour per test, and a whole-fragment golden
|
|
7
|
+
// underneath so an unintended field change is a diff rather than an assertion
|
|
8
|
+
// nobody thought to write.
|
|
9
|
+
|
|
10
|
+
import (
|
|
11
|
+
"encoding/json"
|
|
12
|
+
"flag"
|
|
13
|
+
"os"
|
|
14
|
+
"strings"
|
|
15
|
+
"testing"
|
|
16
|
+
|
|
17
|
+
"github.com/shortlink-org/portolan/catalog"
|
|
18
|
+
"github.com/shortlink-org/portolan/plugin"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
var update = flag.Bool("update", false, "rewrite the golden fragment instead of comparing against it")
|
|
22
|
+
|
|
23
|
+
const goldenPath = "testdata/golden/proto.json"
|
|
24
|
+
|
|
25
|
+
func options() Options {
|
|
26
|
+
return Options{
|
|
27
|
+
Context: "shop",
|
|
28
|
+
Service: "oms",
|
|
29
|
+
Paths: []string{"proto"},
|
|
30
|
+
Vendored: []string{"internal/infrastructure/pricing"},
|
|
31
|
+
Peers: map[string]string{"pricing.v1": "shop.pricing"},
|
|
32
|
+
Out: "proto.json",
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
func input() plugin.Input {
|
|
37
|
+
// The stamp comes from the host, which derives it from git. A plugin that
|
|
38
|
+
// read a clock would write a different file every run.
|
|
39
|
+
return plugin.Input{
|
|
40
|
+
Root: "testdata/estate",
|
|
41
|
+
Commit: "abc1234",
|
|
42
|
+
GeneratedAt: "2024-01-01T00:00:00Z",
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
func response(t *testing.T) plugin.Response {
|
|
47
|
+
t.Helper()
|
|
48
|
+
|
|
49
|
+
resp, err := extract(input(), options())
|
|
50
|
+
if err != nil {
|
|
51
|
+
t.Fatal(err)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return resp
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
func fragment(t *testing.T) catalog.Catalog {
|
|
58
|
+
t.Helper()
|
|
59
|
+
|
|
60
|
+
resp := response(t)
|
|
61
|
+
if len(resp.Files) != 1 || resp.Files[0].Name != "proto.json" {
|
|
62
|
+
t.Fatalf("files: %+v", resp.Files)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
var out catalog.Catalog
|
|
66
|
+
if err := json.Unmarshal([]byte(resp.Files[0].Contents), &out); err != nil {
|
|
67
|
+
t.Fatal(err)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return out
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
func service(t *testing.T) catalog.Service {
|
|
74
|
+
t.Helper()
|
|
75
|
+
|
|
76
|
+
return fragment(t).Contexts[0].Services[0]
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// A proto service is an interface, named by its package and its own name -
|
|
80
|
+
// already the spelling RpcService.id documents.
|
|
81
|
+
func TestProtoServiceBecomesAnInterface(t *testing.T) {
|
|
82
|
+
provides := service(t).Provides
|
|
83
|
+
|
|
84
|
+
if len(provides) != 1 {
|
|
85
|
+
t.Fatalf("provides: %+v", provides)
|
|
86
|
+
}
|
|
87
|
+
orders := provides[0]
|
|
88
|
+
if orders.ID != "shop.v1.Orders" {
|
|
89
|
+
t.Errorf("interface id: %q", orders.ID)
|
|
90
|
+
}
|
|
91
|
+
if orders.Source != "testdata/estate/proto/shop/v1/orders.proto:16" {
|
|
92
|
+
t.Errorf("source must name the file and the line: %q", orders.Source)
|
|
93
|
+
}
|
|
94
|
+
if orders.Module != "buf.build/acme/shop" {
|
|
95
|
+
t.Errorf("the interface does not name the module it came from: %q", orders.Module)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// The shapes on either side and how the method streams: the whole reason
|
|
100
|
+
// RpcService.methods stopped being a list of strings.
|
|
101
|
+
func TestMethodsCarryShapesAndStreaming(t *testing.T) {
|
|
102
|
+
methods := map[string]catalog.RpcMethod{}
|
|
103
|
+
for _, m := range service(t).Provides[0].Methods {
|
|
104
|
+
methods[m.Name] = m
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
place := methods["PlaceOrder"]
|
|
108
|
+
if place.Request != "PlaceOrderRequest" || place.Response != "PlaceOrderResponse" {
|
|
109
|
+
t.Errorf("PlaceOrder: %q -> %q", place.Request, place.Response)
|
|
110
|
+
}
|
|
111
|
+
if place.Streaming != "" {
|
|
112
|
+
t.Errorf("a unary method must not claim to stream: %q", place.Streaming)
|
|
113
|
+
}
|
|
114
|
+
if place.Doc == "" {
|
|
115
|
+
t.Error("the comment above a method did not reach the catalog")
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if got := methods["WatchOrder"].Streaming; got != catalog.StreamingServer {
|
|
119
|
+
t.Errorf("WatchOrder streams %q", got)
|
|
120
|
+
}
|
|
121
|
+
if got := methods["ImportOrders"].Streaming; got != catalog.StreamingClient {
|
|
122
|
+
t.Errorf("ImportOrders streams %q", got)
|
|
123
|
+
}
|
|
124
|
+
if got := methods["Sync"].Streaming; got != catalog.StreamingBidi {
|
|
125
|
+
t.Errorf("Sync streams %q", got)
|
|
126
|
+
}
|
|
127
|
+
if !methods["CancelOrder"].Deprecated {
|
|
128
|
+
t.Error("a deprecated method is not marked deprecated")
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Reachable messages, not every message in the file: a reader wants what the
|
|
133
|
+
// methods actually move.
|
|
134
|
+
func TestMessagesAreReachedTransitively(t *testing.T) {
|
|
135
|
+
names := map[string]bool{}
|
|
136
|
+
for _, m := range service(t).Provides[0].Messages {
|
|
137
|
+
names[m.Name] = true
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
for _, want := range []string{"PlaceOrderRequest", "PlaceOrderResponse", "Order", "LineItem"} {
|
|
141
|
+
if !names[want] {
|
|
142
|
+
t.Errorf("%s is moved by a method but is not listed", want)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Money is reached through PlaceOrderRequest.total, two hops from a method.
|
|
146
|
+
if !names["Money"] {
|
|
147
|
+
t.Error("a message reached through another message was not followed")
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// A type the author put in ANOTHER file is shared: an import is their own
|
|
152
|
+
// signal that it is not local to this message.
|
|
153
|
+
func TestImportedTypesBecomeDefs(t *testing.T) {
|
|
154
|
+
frag := fragment(t)
|
|
155
|
+
|
|
156
|
+
if _, ok := frag.Defs["Money"]; !ok {
|
|
157
|
+
t.Fatalf("Money was not promoted to a shared type: %v", frag.Defs)
|
|
158
|
+
}
|
|
159
|
+
// The key is BARE, not fully qualified - see src/merge.ts on why.
|
|
160
|
+
for key := range frag.Defs {
|
|
161
|
+
if strings.Contains(key, ".") {
|
|
162
|
+
t.Errorf("a def key is fully qualified: %q", key)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
var total *catalog.Field
|
|
167
|
+
for _, msg := range frag.Contexts[0].Services[0].Provides[0].Messages {
|
|
168
|
+
if msg.Name != "PlaceOrderRequest" {
|
|
169
|
+
continue
|
|
170
|
+
}
|
|
171
|
+
for i := range msg.Fields {
|
|
172
|
+
if msg.Fields[i].Name == "total" {
|
|
173
|
+
total = &msg.Fields[i]
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if total == nil {
|
|
178
|
+
t.Fatal("no total field")
|
|
179
|
+
}
|
|
180
|
+
if total.Ref != "Money" {
|
|
181
|
+
t.Errorf("the field does not point at the shared type: %+v", total)
|
|
182
|
+
}
|
|
183
|
+
// A type local to the file it is used in is NOT shared.
|
|
184
|
+
if _, ok := frag.Defs["LineItem"]; ok {
|
|
185
|
+
t.Error("a type local to its own file was promoted to a shared type")
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Types as written, because a reader comparing the page against the file it
|
|
190
|
+
// came from should recognise what they are looking at.
|
|
191
|
+
func TestFieldTypesAreRenderedTheWayTheCatalogRendersThem(t *testing.T) {
|
|
192
|
+
byName := map[string]string{}
|
|
193
|
+
for _, msg := range service(t).Provides[0].Messages {
|
|
194
|
+
if msg.Name != "PlaceOrderRequest" {
|
|
195
|
+
continue
|
|
196
|
+
}
|
|
197
|
+
for _, f := range msg.Fields {
|
|
198
|
+
byName[f.Name] = f.Type
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
want := map[string]string{
|
|
203
|
+
"customer_id": "string",
|
|
204
|
+
"items": "[]LineItem",
|
|
205
|
+
"coupon": "string",
|
|
206
|
+
"metadata": "map[string]string",
|
|
207
|
+
"total": "Money",
|
|
208
|
+
}
|
|
209
|
+
for name, typ := range want {
|
|
210
|
+
if byName[name] != typ {
|
|
211
|
+
t.Errorf("%s: %q, want %q", name, byName[name], typ)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// A vendored copy is a statement about what this service intends to call.
|
|
217
|
+
func TestVendoredProtosBecomeCalls(t *testing.T) {
|
|
218
|
+
consumes := service(t).Consumes
|
|
219
|
+
|
|
220
|
+
if len(consumes) != 2 {
|
|
221
|
+
t.Fatalf("consumes: %+v", consumes)
|
|
222
|
+
}
|
|
223
|
+
quote := consumes[0]
|
|
224
|
+
if quote.ID != "pricing.v1.Pricing/GetQuote" {
|
|
225
|
+
t.Errorf("call id: %q", quote.ID)
|
|
226
|
+
}
|
|
227
|
+
// The id is exactly the key buildIndex builds rpcProviderByMethod by, which
|
|
228
|
+
// is what makes a call and a provided method meet with no other machinery.
|
|
229
|
+
if quote.Peer != "shop.pricing" {
|
|
230
|
+
t.Errorf("a mapped peer was not resolved: %q", quote.Peer)
|
|
231
|
+
}
|
|
232
|
+
if !strings.Contains(quote.Note, "narrowed copy") {
|
|
233
|
+
t.Errorf("the header comment of the vendored copy did not reach the note: %q", quote.Note)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// THE INVARIANT MOST LIKELY TO BE HELPFULLY BROKEN LATER.
|
|
238
|
+
//
|
|
239
|
+
// Reading a .proto proves the call was WRITTEN DOWN, which is what `declared`
|
|
240
|
+
// means. `verified` in the shipped catalog means a test exercises the call end
|
|
241
|
+
// to end, and no extractor can know that: verification is a property of the
|
|
242
|
+
// union, and every extractor runs before one exists.
|
|
243
|
+
func TestNoCallIsEverVerified(t *testing.T) {
|
|
244
|
+
for _, call := range service(t).Consumes {
|
|
245
|
+
if call.Status != catalog.StatusDeclared {
|
|
246
|
+
t.Errorf("%s is %q; an extractor may only declare", call.ID, call.Status)
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Without a peer mapping the raw package name survives, because guessing a
|
|
252
|
+
// service id from a proto package would be inventing an edge.
|
|
253
|
+
func TestUnmappedPeerKeepsTheRawPackageName(t *testing.T) {
|
|
254
|
+
opts := options()
|
|
255
|
+
opts.Peers = nil
|
|
256
|
+
|
|
257
|
+
resp, err := extract(input(), opts)
|
|
258
|
+
if err != nil {
|
|
259
|
+
t.Fatal(err)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
var frag catalog.Catalog
|
|
263
|
+
if err := json.Unmarshal([]byte(resp.Files[0].Contents), &frag); err != nil {
|
|
264
|
+
t.Fatal(err)
|
|
265
|
+
}
|
|
266
|
+
call := frag.Contexts[0].Services[0].Consumes[0]
|
|
267
|
+
if call.Peer != "pricing.v1" {
|
|
268
|
+
t.Errorf("peer: %q, want the raw package name", call.Peer)
|
|
269
|
+
}
|
|
270
|
+
if !warned(resp, "no peer is mapped") {
|
|
271
|
+
t.Error("an unmapped peer was resolved silently")
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// A module the estate publishes has an owner; the lock beside it says which
|
|
276
|
+
// commit it was built from.
|
|
277
|
+
func TestOwnedModuleIsDescribed(t *testing.T) {
|
|
278
|
+
modules := fragment(t).Modules
|
|
279
|
+
|
|
280
|
+
var shop *catalog.ProtoModule
|
|
281
|
+
for i := range modules {
|
|
282
|
+
if modules[i].ID == "buf.build/acme/shop" {
|
|
283
|
+
shop = &modules[i]
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if shop == nil {
|
|
287
|
+
t.Fatalf("modules: %+v", modules)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if shop.Slug != "acme-shop" || shop.Name != "acme/shop" || shop.Registry != "buf.build" {
|
|
291
|
+
t.Errorf("module identity: %+v", shop)
|
|
292
|
+
}
|
|
293
|
+
if shop.Owner != "shop.oms" {
|
|
294
|
+
t.Errorf("a module this service publishes has no owner: %q", shop.Owner)
|
|
295
|
+
}
|
|
296
|
+
if shop.Commit == "" || shop.Digest == "" {
|
|
297
|
+
t.Errorf("the lock's commit and digest did not reach the module: %+v", shop)
|
|
298
|
+
}
|
|
299
|
+
if len(shop.Packages) != 1 || shop.Packages[0] != "shop.v1" {
|
|
300
|
+
t.Errorf("packages: %v", shop.Packages)
|
|
301
|
+
}
|
|
302
|
+
if len(shop.Files) != 2 || shop.Files[0] != "shop/v1/money.proto" {
|
|
303
|
+
t.Errorf("files must be module-relative and sorted: %v", shop.Files)
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// A vendored module is published by somebody else. Owner is left empty rather
|
|
308
|
+
// than guessed - a publisher outside the estate is the ordinary case.
|
|
309
|
+
func TestVendoredModuleHasNoOwner(t *testing.T) {
|
|
310
|
+
for _, m := range fragment(t).Modules {
|
|
311
|
+
if m.ID == "buf.build/acme/shop" {
|
|
312
|
+
continue
|
|
313
|
+
}
|
|
314
|
+
if m.Owner != "" {
|
|
315
|
+
t.Errorf("a vendored module claims an owner: %+v", m)
|
|
316
|
+
}
|
|
317
|
+
if !strings.HasPrefix(m.ID, "local:") {
|
|
318
|
+
t.Errorf("an unpinned directory should be listed as local: %q", m.ID)
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// A narrowed copy imports files nobody vendored beside it - `pricing.proto`
|
|
324
|
+
// here imports a `money.proto` that is not in the tree, and its `Quote.total`
|
|
325
|
+
// names a type nothing declares.
|
|
326
|
+
//
|
|
327
|
+
// A compiler refuses to produce anything for that input. This must read every
|
|
328
|
+
// service and method that IS present, which is the whole reason the parser is
|
|
329
|
+
// tolerant rather than correct.
|
|
330
|
+
func TestNarrowedCopyIsStillFullyRead(t *testing.T) {
|
|
331
|
+
consumes := service(t).Consumes
|
|
332
|
+
|
|
333
|
+
if len(consumes) != 2 {
|
|
334
|
+
t.Fatalf("a copy with an unresolvable import was not fully read: %+v", consumes)
|
|
335
|
+
}
|
|
336
|
+
for _, call := range consumes {
|
|
337
|
+
if call.Source == "" || call.Peer == "" {
|
|
338
|
+
t.Errorf("a call from a narrowed copy is incomplete: %+v", call)
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// The fragment claims only what this extractor knows. The name, repo, readme
|
|
344
|
+
// and aggregates belong to other extractors reading other files, and a fragment
|
|
345
|
+
// that filled them in would be inventing.
|
|
346
|
+
func TestFragmentClaimsNothingItDoesNotKnow(t *testing.T) {
|
|
347
|
+
svc := service(t)
|
|
348
|
+
|
|
349
|
+
if svc.Name != "" || svc.Repo != "" || svc.Readme != "" || svc.Path != "" {
|
|
350
|
+
t.Errorf("the fragment named the service: %+v", svc)
|
|
351
|
+
}
|
|
352
|
+
if len(svc.Aggregates) != 0 {
|
|
353
|
+
t.Errorf("the fragment invented aggregates: %+v", svc.Aggregates)
|
|
354
|
+
}
|
|
355
|
+
if len(fragment(t).Flows) != 0 || len(fragment(t).Adrs) != 0 {
|
|
356
|
+
t.Error("the fragment invented flows or decisions")
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// The fragment is committed and compared by gen:check. A map iterated in Go's
|
|
361
|
+
// order would rewrite the file every run and turn every build into a diff.
|
|
362
|
+
func TestOutputIsByteIdentical(t *testing.T) {
|
|
363
|
+
first, err := extract(input(), options())
|
|
364
|
+
if err != nil {
|
|
365
|
+
t.Fatal(err)
|
|
366
|
+
}
|
|
367
|
+
for i := 0; i < 5; i++ {
|
|
368
|
+
again, err := extract(input(), options())
|
|
369
|
+
if err != nil {
|
|
370
|
+
t.Fatal(err)
|
|
371
|
+
}
|
|
372
|
+
if again.Files[0].Contents != first.Files[0].Contents {
|
|
373
|
+
t.Fatal("two runs over the same tree produced different fragments")
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// The whole fragment, so a field that changes shape shows up as a diff rather
|
|
379
|
+
// than slipping past every assertion above.
|
|
380
|
+
func TestGoldenFragment(t *testing.T) {
|
|
381
|
+
got := response(t).Files[0].Contents
|
|
382
|
+
|
|
383
|
+
if *update {
|
|
384
|
+
if err := os.WriteFile(goldenPath, []byte(got), 0o644); err != nil {
|
|
385
|
+
t.Fatal(err)
|
|
386
|
+
}
|
|
387
|
+
t.Log("golden fragment rewritten")
|
|
388
|
+
|
|
389
|
+
return
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
want, err := os.ReadFile(goldenPath)
|
|
393
|
+
if err != nil {
|
|
394
|
+
t.Fatalf("reading the golden fragment: %v (run `go test ./plugins/extract-proto -update`)", err)
|
|
395
|
+
}
|
|
396
|
+
if string(want) != got {
|
|
397
|
+
t.Errorf("the fragment differs from the golden file\n%s", firstDifference(string(want), got))
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
func warned(resp plugin.Response, substring string) bool {
|
|
402
|
+
for _, d := range resp.Warnings() {
|
|
403
|
+
if strings.Contains(d.Message, substring) {
|
|
404
|
+
return true
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return false
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
func firstDifference(want, got string) string {
|
|
412
|
+
a := strings.Split(want, "\n")
|
|
413
|
+
b := strings.Split(got, "\n")
|
|
414
|
+
for i := 0; i < len(a) && i < len(b); i++ {
|
|
415
|
+
if a[i] != b[i] {
|
|
416
|
+
return "line " + itoa(i+1) + ":\n want: " + a[i] + "\n got: " + b[i]
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return "want " + itoa(len(a)) + " lines, got " + itoa(len(b))
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
func itoa(n int) string {
|
|
424
|
+
return strings.TrimSpace(strings.Replace(strings.Repeat(" ", 0)+string(rune(0)), string(rune(0)), fmtInt(n), 1))
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
func fmtInt(n int) string {
|
|
428
|
+
if n == 0 {
|
|
429
|
+
return "0"
|
|
430
|
+
}
|
|
431
|
+
var digits []byte
|
|
432
|
+
for n > 0 {
|
|
433
|
+
digits = append([]byte{byte('0' + n%10)}, digits...)
|
|
434
|
+
n /= 10
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return string(digits)
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// An enum a field names is listed beside the messages, values and numbers
|
|
441
|
+
// in declaration order. Only the ones reached: a set no method moves is
|
|
442
|
+
// not what the interface says.
|
|
443
|
+
func TestEnumsAreReachedThroughFields(t *testing.T) {
|
|
444
|
+
byName := map[string]catalog.RpcEnum{}
|
|
445
|
+
for _, e := range service(t).Provides[0].Enums {
|
|
446
|
+
byName[e.Name] = e
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
channel, ok := byName["Channel"]
|
|
450
|
+
if !ok {
|
|
451
|
+
t.Fatalf("Order.channel names Channel, which is not listed: %v", byName)
|
|
452
|
+
}
|
|
453
|
+
if status, ok := byName["Status"]; !ok || status.Doc != "How far along an order is." || status.Values[1].Doc != "The shop has it." {
|
|
454
|
+
t.Errorf("Status, reached through Order.status, lost its docs: %+v", status)
|
|
455
|
+
}
|
|
456
|
+
if len(channel.Values) != 2 || channel.Values[1].Name != "CHANNEL_WEB" || channel.Values[1].Number != 1 {
|
|
457
|
+
t.Errorf("values = %+v", channel.Values)
|
|
458
|
+
}
|
|
459
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
// The id and slug rules, written once.
|
|
4
|
+
//
|
|
5
|
+
// Every other extractor keeps these in one file for the same reason: the ids
|
|
6
|
+
// are the join between fragments that never see each other, and a rule spelled
|
|
7
|
+
// twice is a rule that drifts. `plugins/extract-go/ids.go` is the precedent.
|
|
8
|
+
|
|
9
|
+
import (
|
|
10
|
+
"regexp"
|
|
11
|
+
"strings"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
// interfaceID is what a service in a .proto is called across the catalog:
|
|
15
|
+
// its proto package and its name. `shop.v1.Orders`.
|
|
16
|
+
//
|
|
17
|
+
// This is already the spelling `RpcService.id` documents, so a proto read here
|
|
18
|
+
// lands beside interfaces every other extractor names the same way.
|
|
19
|
+
func interfaceID(pkg, service string) string {
|
|
20
|
+
if pkg == "" {
|
|
21
|
+
return service
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return pkg + "." + service
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// callID is one method of one interface: `shop.v1.Orders/PlaceOrder`.
|
|
28
|
+
//
|
|
29
|
+
// The same string `buildIndex` keys `rpcProviderByMethod` by, which is what
|
|
30
|
+
// makes a consumed call and a provided method meet with no other machinery.
|
|
31
|
+
func callID(iface, method string) string {
|
|
32
|
+
return iface + "/" + method
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// moduleID is the module's registry-global name, or a local stand-in.
|
|
36
|
+
//
|
|
37
|
+
// A module never published still needs an id, because the interfaces read out
|
|
38
|
+
// of it have to say where they came from. `local:` prefixes it so nobody
|
|
39
|
+
// mistakes the path for a module someone could go and fetch.
|
|
40
|
+
func localModuleID(dir string) string {
|
|
41
|
+
return localPrefix + strings.Trim(dir, "/")
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var notSlug = regexp.MustCompile(`[^a-z0-9]+`)
|
|
45
|
+
|
|
46
|
+
const localPrefix = "local:"
|
|
47
|
+
|
|
48
|
+
// moduleName is the module as a reader says it: `acme/shop` for a published
|
|
49
|
+
// module, and the whole path for a local one.
|
|
50
|
+
//
|
|
51
|
+
// A published module drops its registry host, because it is the same for every
|
|
52
|
+
// module in almost every estate and repeating it would say nothing. A local id
|
|
53
|
+
// drops NOTHING - its path is not `host/owner/name`, and trimming its first
|
|
54
|
+
// segment would turn `internal/infrastructure/pricing` into a directory that
|
|
55
|
+
// does not exist.
|
|
56
|
+
func moduleName(id string) string {
|
|
57
|
+
if strings.HasPrefix(id, localPrefix) {
|
|
58
|
+
return strings.TrimPrefix(id, localPrefix)
|
|
59
|
+
}
|
|
60
|
+
if parts := strings.Split(id, "/"); len(parts) > 2 {
|
|
61
|
+
return strings.Join(parts[1:], "/")
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return id
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// moduleSlug is what the URL uses. `buf.build/acme/shop` gives `acme-shop`,
|
|
68
|
+
// `local:internal/infrastructure/pricing` gives
|
|
69
|
+
// `internal-infrastructure-pricing`.
|
|
70
|
+
//
|
|
71
|
+
// Should two registries ever host the same owner and name, the validator
|
|
72
|
+
// refuses the catalog rather than letting two entities share an address.
|
|
73
|
+
func moduleSlug(id string) string {
|
|
74
|
+
slug := notSlug.ReplaceAllString(strings.ToLower(moduleName(id)), "-")
|
|
75
|
+
|
|
76
|
+
return strings.Trim(slug, "-")
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// registryOf is the host a module was published to, empty for a local set.
|
|
80
|
+
func registryOf(id string) string {
|
|
81
|
+
if strings.HasPrefix(id, localPrefix) {
|
|
82
|
+
return ""
|
|
83
|
+
}
|
|
84
|
+
if parts := strings.Split(id, "/"); len(parts) > 2 {
|
|
85
|
+
return parts[0]
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return ""
|
|
89
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
// The id rules, which are the join between fragments that never see each other.
|
|
4
|
+
|
|
5
|
+
import "testing"
|
|
6
|
+
|
|
7
|
+
func TestModuleIdentity(t *testing.T) {
|
|
8
|
+
cases := []struct{ id, name, slug, registry string }{
|
|
9
|
+
{"buf.build/acme/shop", "acme/shop", "acme-shop", "buf.build"},
|
|
10
|
+
{"buf.build/acme/shop-events", "acme/shop-events", "acme-shop-events", "buf.build"},
|
|
11
|
+
// A local id is a path, not `host/owner/name`. Trimming its first
|
|
12
|
+
// segment would name a directory that does not exist.
|
|
13
|
+
{"local:internal/infrastructure/pricing", "internal/infrastructure/pricing", "internal-infrastructure-pricing", ""},
|
|
14
|
+
{"local:proto", "proto", "proto", ""},
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
for _, c := range cases {
|
|
18
|
+
if got := moduleName(c.id); got != c.name {
|
|
19
|
+
t.Errorf("%s name: %q, want %q", c.id, got, c.name)
|
|
20
|
+
}
|
|
21
|
+
if got := moduleSlug(c.id); got != c.slug {
|
|
22
|
+
t.Errorf("%s slug: %q, want %q", c.id, got, c.slug)
|
|
23
|
+
}
|
|
24
|
+
if got := registryOf(c.id); got != c.registry {
|
|
25
|
+
t.Errorf("%s registry: %q, want %q", c.id, got, c.registry)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// A slug goes in a URL segment, so it may never carry a dot or a slash -
|
|
31
|
+
// src/routes.test.ts holds every catalog path to that.
|
|
32
|
+
func TestSlugIsUrlSafe(t *testing.T) {
|
|
33
|
+
for _, id := range []string{"buf.build/acme/shop.v1", "local:proto/shop/v1"} {
|
|
34
|
+
slug := moduleSlug(id)
|
|
35
|
+
for _, bad := range []rune{'.', '/', ':', ' '} {
|
|
36
|
+
for _, r := range slug {
|
|
37
|
+
if r == bad {
|
|
38
|
+
t.Errorf("%s gives slug %q, which cannot go in a URL segment", id, slug)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// The ids the catalog joins on, spelled the way RpcService.id documents.
|
|
46
|
+
func TestInterfaceAndCallIds(t *testing.T) {
|
|
47
|
+
if got := interfaceID("shop.v1", "Orders"); got != "shop.v1.Orders" {
|
|
48
|
+
t.Errorf("interface id: %q", got)
|
|
49
|
+
}
|
|
50
|
+
if got := callID("shop.v1.Orders", "PlaceOrder"); got != "shop.v1.Orders/PlaceOrder" {
|
|
51
|
+
t.Errorf("call id: %q", got)
|
|
52
|
+
}
|
|
53
|
+
// A proto with no package still has to produce something findable.
|
|
54
|
+
if got := interfaceID("", "Orders"); got != "Orders" {
|
|
55
|
+
t.Errorf("interface id with no package: %q", got)
|
|
56
|
+
}
|
|
57
|
+
}
|