@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,343 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
// JSON Schema, read for the same two things Avro is read for.
|
|
4
|
+
//
|
|
5
|
+
// The one thing that has to be careful here is ORDER. An Avro record lists its
|
|
6
|
+
// fields in an array, so reading them into Go keeps the order the author wrote
|
|
7
|
+
// them in. A JSON Schema lists them as the keys of an object, and decoding an
|
|
8
|
+
// object into a map loses that order - which would put the fields on the page
|
|
9
|
+
// in a different arrangement every run and rewrite the fragment each time. So
|
|
10
|
+
// the properties are walked with a token decoder instead.
|
|
11
|
+
|
|
12
|
+
import (
|
|
13
|
+
"bytes"
|
|
14
|
+
"encoding/json"
|
|
15
|
+
"fmt"
|
|
16
|
+
"sort"
|
|
17
|
+
"strings"
|
|
18
|
+
|
|
19
|
+
"github.com/shortlink-org/portolan/catalog"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
// jsonSchema reads one .json into the shapes it declares, the same way avro
|
|
23
|
+
// does: the name of the shape at the top, and every named shape inside it.
|
|
24
|
+
//
|
|
25
|
+
// fallback names the top-level shape when the document does not name itself,
|
|
26
|
+
// which most of them do not: a JSON Schema's `title` is optional and a
|
|
27
|
+
// registered one usually leans on the subject to say what it is.
|
|
28
|
+
func jsonSchema(raw []byte, fallback string) (string, map[string]catalog.TypeDef, error) {
|
|
29
|
+
var node jsonNode
|
|
30
|
+
if err := json.Unmarshal(raw, &node); err != nil {
|
|
31
|
+
return "", nil, fmt.Errorf("not a JSON Schema: %w", err)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
name := firstNonEmpty(node.Title, fallback)
|
|
35
|
+
r := &jsonReader{defs: map[string]catalog.TypeDef{}, prefix: name}
|
|
36
|
+
|
|
37
|
+
// The named shapes a document keeps to one side are read first, so a `$ref`
|
|
38
|
+
// pointing at one resolves to a def rather than to a bare label.
|
|
39
|
+
//
|
|
40
|
+
// They are filed under the document's own name. `definitions` is local to
|
|
41
|
+
// the document by definition, and `defs` in the catalog is not: two
|
|
42
|
+
// services that both keep a "Carrier" to one side, meaning different
|
|
43
|
+
// things, would otherwise collide in the merge and be reported as a
|
|
44
|
+
// disagreement neither of them is having.
|
|
45
|
+
for _, held := range []map[string]json.RawMessage{node.Definitions, node.Defs} {
|
|
46
|
+
for _, key := range keysInOrder(held) {
|
|
47
|
+
var nested jsonNode
|
|
48
|
+
if err := json.Unmarshal(held[key], &nested); err != nil {
|
|
49
|
+
continue
|
|
50
|
+
}
|
|
51
|
+
r.shape(nested, r.qualify(key))
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
r.shape(node, name)
|
|
56
|
+
|
|
57
|
+
return name, r.defs, nil
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// jsonNode is the part of a JSON Schema this reads. Everything it leaves out -
|
|
61
|
+
// every keyword that constrains a value rather than naming or shaping it - is
|
|
62
|
+
// the registry's business, not the catalog's.
|
|
63
|
+
type jsonNode struct {
|
|
64
|
+
Title string `json:"title"`
|
|
65
|
+
Description string `json:"description"`
|
|
66
|
+
Type json.RawMessage `json:"type"`
|
|
67
|
+
Format string `json:"format"`
|
|
68
|
+
Ref string `json:"$ref"`
|
|
69
|
+
Items *jsonNode `json:"items"`
|
|
70
|
+
Required []string `json:"required"`
|
|
71
|
+
OneOf []jsonNode `json:"oneOf"`
|
|
72
|
+
AnyOf []jsonNode `json:"anyOf"`
|
|
73
|
+
|
|
74
|
+
Properties json.RawMessage `json:"properties"`
|
|
75
|
+
Definitions map[string]json.RawMessage `json:"definitions"`
|
|
76
|
+
Defs map[string]json.RawMessage `json:"$defs"`
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
type jsonReader struct {
|
|
80
|
+
defs map[string]catalog.TypeDef
|
|
81
|
+
open map[string]bool
|
|
82
|
+
|
|
83
|
+
// prefix is the document's own shape name, which is what makes a
|
|
84
|
+
// document-local definition globally addressable.
|
|
85
|
+
prefix string
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// qualify files a document-local name under the document.
|
|
89
|
+
func (r *jsonReader) qualify(name string) string {
|
|
90
|
+
if r.prefix == "" || name == "" {
|
|
91
|
+
return name
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return r.prefix + "." + name
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// declared says whether a shape is one this reader wrote down, including one
|
|
98
|
+
// still being read further up the stack.
|
|
99
|
+
func (r *jsonReader) declared(name string) bool {
|
|
100
|
+
if r.open[name] {
|
|
101
|
+
return true
|
|
102
|
+
}
|
|
103
|
+
_, written := r.defs[name]
|
|
104
|
+
|
|
105
|
+
return written
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// shape writes down one object's fields, under the name given, and returns
|
|
109
|
+
// whether it wrote anything. A schema with no properties is not a shape.
|
|
110
|
+
func (r *jsonReader) shape(node jsonNode, name string) bool {
|
|
111
|
+
if name == "" || len(node.Properties) == 0 {
|
|
112
|
+
return false
|
|
113
|
+
}
|
|
114
|
+
if r.open[name] {
|
|
115
|
+
return true
|
|
116
|
+
}
|
|
117
|
+
if _, written := r.defs[name]; written {
|
|
118
|
+
return true
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if r.open == nil {
|
|
122
|
+
r.open = map[string]bool{}
|
|
123
|
+
}
|
|
124
|
+
r.open[name] = true
|
|
125
|
+
defer delete(r.open, name)
|
|
126
|
+
|
|
127
|
+
required := map[string]bool{}
|
|
128
|
+
for _, key := range node.Required {
|
|
129
|
+
required[key] = true
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Written before the fields are read, so a schema that names itself inside
|
|
133
|
+
// itself finds an entry rather than recursing forever.
|
|
134
|
+
r.defs[name] = catalog.TypeDef{Fields: []catalog.Field{}}
|
|
135
|
+
|
|
136
|
+
fields := []catalog.Field{}
|
|
137
|
+
for _, key := range propertiesInOrder(node.Properties) {
|
|
138
|
+
var property jsonNode
|
|
139
|
+
if err := json.Unmarshal(key.value, &property); err != nil {
|
|
140
|
+
continue
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
label, ref := r.typeOf(property, name+"."+key.name)
|
|
144
|
+
if !required[key.name] && !strings.HasSuffix(label, "?") {
|
|
145
|
+
label += "?"
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
fields = append(fields, catalog.Field{
|
|
149
|
+
Name: key.name,
|
|
150
|
+
Type: label,
|
|
151
|
+
Doc: strings.TrimSpace(property.Description),
|
|
152
|
+
Ref: ref,
|
|
153
|
+
})
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
r.defs[name] = catalog.TypeDef{Fields: fields}
|
|
157
|
+
|
|
158
|
+
return true
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// typeOf renders one property, and returns the defs key when it is an object
|
|
162
|
+
// this reader wrote down.
|
|
163
|
+
//
|
|
164
|
+
// path is what an anonymous nested object is called: a schema that inlines an
|
|
165
|
+
// address under `shipping` has named it, just not with a `title`, and
|
|
166
|
+
// "OrderPlaced.shipping" is the name it gave it.
|
|
167
|
+
func (r *jsonReader) typeOf(node jsonNode, path string) (label, ref string) {
|
|
168
|
+
if node.Ref != "" {
|
|
169
|
+
// The label stays the name the document uses - "Carrier" is what a
|
|
170
|
+
// reader of the schema sees - while the ref carries the qualified key
|
|
171
|
+
// the catalog files it under. The two are allowed to differ, and here
|
|
172
|
+
// they have to.
|
|
173
|
+
name := refName(node.Ref)
|
|
174
|
+
if key := r.qualify(name); r.declared(key) {
|
|
175
|
+
return name, key
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return name, ""
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if members := append(append([]jsonNode{}, node.OneOf...), node.AnyOf...); len(members) > 0 {
|
|
182
|
+
return r.choice(members, path), ""
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
kinds, nullable := typeNames(node.Type)
|
|
186
|
+
|
|
187
|
+
if node.Items != nil {
|
|
188
|
+
items, _ := r.typeOf(*node.Items, path)
|
|
189
|
+
|
|
190
|
+
return suffix(items+"[]", nullable), ""
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if len(node.Properties) > 0 {
|
|
194
|
+
name := firstNonEmpty(node.Title, path)
|
|
195
|
+
if r.shape(node, name) {
|
|
196
|
+
return suffix(name, nullable), name
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// A format says what the string MEANS, and it is what belongs on a page:
|
|
201
|
+
// "date-time" says more than the "string" underneath it.
|
|
202
|
+
if node.Format != "" {
|
|
203
|
+
return suffix(node.Format, nullable), ""
|
|
204
|
+
}
|
|
205
|
+
if len(kinds) == 0 {
|
|
206
|
+
return suffix(firstNonEmpty(node.Title, "any"), nullable), ""
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return suffix(strings.Join(kinds, "|"), nullable), ""
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// choice renders oneOf/anyOf. A member that is only `{"type":"null"}` is the
|
|
213
|
+
// document saying the value is optional, which is a "?" rather than a member.
|
|
214
|
+
func (r *jsonReader) choice(members []jsonNode, path string) string {
|
|
215
|
+
var (
|
|
216
|
+
labels []string
|
|
217
|
+
nullable bool
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
for _, member := range members {
|
|
221
|
+
kinds, memberNull := typeNames(member.Type)
|
|
222
|
+
if memberNull || (len(kinds) == 1 && kinds[0] == "null") {
|
|
223
|
+
nullable = true
|
|
224
|
+
if len(kinds) <= 1 && member.Ref == "" && len(member.Properties) == 0 {
|
|
225
|
+
continue
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
label, _ := r.typeOf(member, path)
|
|
230
|
+
labels = append(labels, strings.TrimSuffix(label, "?"))
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if len(labels) == 0 {
|
|
234
|
+
return "null"
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return suffix(strings.Join(labels, "|"), nullable)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// typeNames reads `type`, which is either a string or an array of them, and
|
|
241
|
+
// pulls "null" out of the array into the nullability it actually means.
|
|
242
|
+
func typeNames(raw json.RawMessage) (kinds []string, nullable bool) {
|
|
243
|
+
if len(raw) == 0 {
|
|
244
|
+
return nil, false
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
var one string
|
|
248
|
+
if json.Unmarshal(raw, &one) == nil {
|
|
249
|
+
if one == "null" {
|
|
250
|
+
return nil, true
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return []string{one}, false
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
var many []string
|
|
257
|
+
if json.Unmarshal(raw, &many) != nil {
|
|
258
|
+
return nil, false
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
for _, kind := range many {
|
|
262
|
+
if kind == "null" {
|
|
263
|
+
nullable = true
|
|
264
|
+
|
|
265
|
+
continue
|
|
266
|
+
}
|
|
267
|
+
kinds = append(kinds, kind)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return kinds, nullable
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
func suffix(label string, nullable bool) string {
|
|
274
|
+
if nullable && !strings.HasSuffix(label, "?") {
|
|
275
|
+
return label + "?"
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return label
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// refName is the last segment of a `$ref`, which is the name the definition is
|
|
282
|
+
// filed under. A `$ref` reaching outside the document names something this
|
|
283
|
+
// extractor has never seen, and the last segment is still the best label for
|
|
284
|
+
// it.
|
|
285
|
+
func refName(ref string) string {
|
|
286
|
+
at := strings.LastIndex(ref, "/")
|
|
287
|
+
if at < 0 {
|
|
288
|
+
return ref
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return ref[at+1:]
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
type property struct {
|
|
295
|
+
name string
|
|
296
|
+
value json.RawMessage
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// propertiesInOrder walks an object with a token decoder, which is the only
|
|
300
|
+
// way to keep the order its keys were written in.
|
|
301
|
+
func propertiesInOrder(raw json.RawMessage) []property {
|
|
302
|
+
if len(raw) == 0 {
|
|
303
|
+
return nil
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
decoder := json.NewDecoder(bytes.NewReader(raw))
|
|
307
|
+
if _, err := decoder.Token(); err != nil { // the opening brace
|
|
308
|
+
return nil
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
var out []property
|
|
312
|
+
for decoder.More() {
|
|
313
|
+
key, err := decoder.Token()
|
|
314
|
+
if err != nil {
|
|
315
|
+
return out
|
|
316
|
+
}
|
|
317
|
+
name, isString := key.(string)
|
|
318
|
+
if !isString {
|
|
319
|
+
return out
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
var value json.RawMessage
|
|
323
|
+
if err := decoder.Decode(&value); err != nil {
|
|
324
|
+
return out
|
|
325
|
+
}
|
|
326
|
+
out = append(out, property{name: name, value: value})
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return out
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// keysInOrder is the same problem for `definitions`, which is decoded into a
|
|
333
|
+
// map because nothing about it is ordered on the page - only sorted, so the
|
|
334
|
+
// fragment comes out the same way every run.
|
|
335
|
+
func keysInOrder(held map[string]json.RawMessage) []string {
|
|
336
|
+
names := make([]string, 0, len(held))
|
|
337
|
+
for name := range held {
|
|
338
|
+
names = append(names, name)
|
|
339
|
+
}
|
|
340
|
+
sort.Strings(names)
|
|
341
|
+
|
|
342
|
+
return names
|
|
343
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
// The lock, as this side reads it.
|
|
4
|
+
//
|
|
5
|
+
// A narrower copy of what portolan-fetch-csr writes, on purpose: this plugin
|
|
6
|
+
// needs the subject, the version and which file holds the schema, and reading
|
|
7
|
+
// a shape it does not use would be a second place to keep the writer's
|
|
8
|
+
// decisions in step. The two are held together by the fields' names, which is
|
|
9
|
+
// the same contract every fragment in this repository is held to.
|
|
10
|
+
type Lock struct {
|
|
11
|
+
Registry string `json:"registry"`
|
|
12
|
+
Subjects []LockSubject `json:"subjects"`
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type LockSubject struct {
|
|
16
|
+
Subject string `json:"subject"`
|
|
17
|
+
Version int `json:"version"`
|
|
18
|
+
ID int `json:"id"`
|
|
19
|
+
SchemaType string `json:"schemaType"`
|
|
20
|
+
Files []LockEntry `json:"files"`
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type LockEntry struct {
|
|
24
|
+
Path string `json:"path"`
|
|
25
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Package main is portolan-extract-csr: schemas vendored out of a Confluent
|
|
2
|
+
// Schema Registry in, a catalog fragment out.
|
|
3
|
+
//
|
|
4
|
+
// It reads what portolan-fetch-csr committed - a directory per subject, each
|
|
5
|
+
// holding one schema and the `csr.lock.json` that says which registration it
|
|
6
|
+
// is - and answers with the two facts a registry knows that nothing else in
|
|
7
|
+
// the estate does: which topics carry which messages, and what those messages
|
|
8
|
+
// are shaped like, field by field.
|
|
9
|
+
//
|
|
10
|
+
// It opens nothing. That is the point of the split: portolan-fetch-csr owns
|
|
11
|
+
// the socket and the credential, this owns the reading, and CI runs this over
|
|
12
|
+
// a tree it can verify without a registry existing at all.
|
|
13
|
+
//
|
|
14
|
+
// What it does NOT do is invent events. An Event in the catalog belongs to an
|
|
15
|
+
// aggregate, and a registry has no idea which aggregate raises what - it holds
|
|
16
|
+
// schemas, not domains. So the shapes land in `defs`, where a shared shape
|
|
17
|
+
// belongs, and the topics land in the service's channels, the same place an
|
|
18
|
+
// AsyncAPI document's do. The domain extractor says an aggregate raises
|
|
19
|
+
// OrderPlaced and calls it `shop.oms.OrderPlaced` on the wire; this says a
|
|
20
|
+
// schema by that name is registered against topic `shop.oms.order` and has
|
|
21
|
+
// these fields. Neither knows the other exists, and the pages hold the two
|
|
22
|
+
// against each other.
|
|
23
|
+
//
|
|
24
|
+
// PROTOBUF subjects are named but not shaped. Reading protobuf properly is
|
|
25
|
+
// portolan-extract-proto's whole job, and a second, worse parser here would
|
|
26
|
+
// be a second answer to one question. Point extract-proto at the vendored
|
|
27
|
+
// directory for those.
|
|
28
|
+
package main
|
|
29
|
+
|
|
30
|
+
import (
|
|
31
|
+
"fmt"
|
|
32
|
+
"io"
|
|
33
|
+
"os"
|
|
34
|
+
|
|
35
|
+
"github.com/shortlink-org/portolan/plugin"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
// Options are what the manifest tells the extractor: the things a registry
|
|
39
|
+
// does not say about the estate its schemas belong to.
|
|
40
|
+
type Options struct {
|
|
41
|
+
Context string `json:"context,omitempty"`
|
|
42
|
+
Service string `json:"service,omitempty"`
|
|
43
|
+
|
|
44
|
+
// Paths narrows the search to the directories fetch-csr wrote into,
|
|
45
|
+
// relative to the input root. Left out, the whole root is walked for
|
|
46
|
+
// locks.
|
|
47
|
+
Paths []string `json:"paths,omitempty"`
|
|
48
|
+
|
|
49
|
+
// Strategy is how a subject name relates to a topic and a record. It is
|
|
50
|
+
// the producer's choice of SubjectNameStrategy, and nothing in the
|
|
51
|
+
// registry's answer says which one was used - the same string is a topic
|
|
52
|
+
// plus a suffix under one and a record's full name under another.
|
|
53
|
+
Strategy string `json:"strategy,omitempty"`
|
|
54
|
+
|
|
55
|
+
// Direction is which way the channels this service registers schemas for
|
|
56
|
+
// travel, from this service's side. A registry records no producer and no
|
|
57
|
+
// consumer, so this cannot be read and has to be told; "send" is the
|
|
58
|
+
// default because the service that registers a schema is usually the one
|
|
59
|
+
// putting it on the bus.
|
|
60
|
+
Direction string `json:"direction,omitempty"`
|
|
61
|
+
|
|
62
|
+
// Subjects overrides Direction for named subjects, for the service that
|
|
63
|
+
// both publishes and listens.
|
|
64
|
+
Subjects map[string]string `json:"subjects,omitempty"`
|
|
65
|
+
|
|
66
|
+
Out string `json:"out,omitempty"`
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
func main() {
|
|
70
|
+
if err := run(os.Stdin, os.Stdout); err != nil {
|
|
71
|
+
fmt.Fprintln(os.Stderr, "portolan-extract-csr:", err)
|
|
72
|
+
os.Exit(1)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
func run(stdin io.Reader, stdout io.Writer) error {
|
|
77
|
+
return plugin.Serve(stdin, stdout, descriptor(), func(req plugin.Request, opts Options) (plugin.Response, error) {
|
|
78
|
+
if req.Input.Root == "" {
|
|
79
|
+
return plugin.Response{}, fmt.Errorf("no input root: an extractor has nothing to read")
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return extract(req.Input, opts)
|
|
83
|
+
})
|
|
84
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "object",
|
|
3
|
+
"additionalProperties": false,
|
|
4
|
+
"properties": {
|
|
5
|
+
"context": {
|
|
6
|
+
"type": "string",
|
|
7
|
+
"description": "Slug of the bounded context that owns the service these schemas belong to. Defaults to the name of the input directory.",
|
|
8
|
+
"examples": ["shop"]
|
|
9
|
+
},
|
|
10
|
+
"service": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "Slug of the service that registers them. Defaults to the name of the input directory.",
|
|
13
|
+
"examples": ["oms"]
|
|
14
|
+
},
|
|
15
|
+
"paths": {
|
|
16
|
+
"type": "array",
|
|
17
|
+
"items": { "type": "string" },
|
|
18
|
+
"description": "Directories fetch-csr vendored into, relative to the input root. Left out, the whole root is walked for locks.",
|
|
19
|
+
"examples": [["vendor/schemas"]]
|
|
20
|
+
},
|
|
21
|
+
"strategy": {
|
|
22
|
+
"enum": ["topic", "record", "topic-record"],
|
|
23
|
+
"default": "topic",
|
|
24
|
+
"description": "How a subject name relates to a topic and a record - the producer's SubjectNameStrategy. Nothing in the registry's answer says which one was used, so it is told here. `topic` reads \"<topic>-value\" and \"<topic>-key\"; `record` reads the whole subject as the record's full name and yields no topic; `topic-record` reads \"<topic>-<record full name>\"."
|
|
25
|
+
},
|
|
26
|
+
"direction": {
|
|
27
|
+
"enum": ["send", "receive"],
|
|
28
|
+
"default": "send",
|
|
29
|
+
"description": "Which way these channels travel, from this service's side. A registry records no producer and no consumer, so this cannot be read and has to be told."
|
|
30
|
+
},
|
|
31
|
+
"subjects": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"additionalProperties": { "enum": ["send", "receive"] },
|
|
34
|
+
"description": "Direction per subject, for a service that both publishes and listens. Overrides `direction`.",
|
|
35
|
+
"examples": [{ "shop.oms.order-value": "send", "payments.ledger.payment-value": "receive" }]
|
|
36
|
+
},
|
|
37
|
+
"out": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"description": "Name of the fragment file, inside the step's output directory.",
|
|
40
|
+
"default": "schemas.json"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
// Reading a subject name.
|
|
4
|
+
//
|
|
5
|
+
// A registry stores subjects. A subject is whatever the producer's serializer
|
|
6
|
+
// decided to call the registration, and the rule it used - the
|
|
7
|
+
// SubjectNameStrategy - is not recorded anywhere in the answer. The same
|
|
8
|
+
// string "shop.oms.order-value" is a topic plus a suffix under one strategy
|
|
9
|
+
// and a record's full name under another, and nothing but the manifest can
|
|
10
|
+
// say which.
|
|
11
|
+
//
|
|
12
|
+
// So the strategy is told, and everything here is the consequence of being
|
|
13
|
+
// told it.
|
|
14
|
+
|
|
15
|
+
import "strings"
|
|
16
|
+
|
|
17
|
+
// Strategies, by the names Confluent's own serializers go by, shortened.
|
|
18
|
+
const (
|
|
19
|
+
StrategyTopic = "topic" // TopicNameStrategy
|
|
20
|
+
StrategyRecord = "record" // RecordNameStrategy
|
|
21
|
+
StrategyTopicRecord = "topic-record" // TopicRecordNameStrategy
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
// registration is what a subject name resolves to.
|
|
25
|
+
type registration struct {
|
|
26
|
+
// Topic is the channel address the schema is registered against, empty
|
|
27
|
+
// under RecordNameStrategy - which deliberately says nothing about topics,
|
|
28
|
+
// so a record can be reused across many.
|
|
29
|
+
Topic string
|
|
30
|
+
|
|
31
|
+
// Record is the schema's full name, and it is the name a message on the
|
|
32
|
+
// bus goes by - the same string an event's Wire.Name carries.
|
|
33
|
+
Record string
|
|
34
|
+
|
|
35
|
+
// Key is set for the "-key" half of a topic. A key is not a message on the
|
|
36
|
+
// channel; it is part of every message on it. So its shape is kept and its
|
|
37
|
+
// name is not put on the channel.
|
|
38
|
+
Key bool
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// resolve reads a subject name into what it registers.
|
|
42
|
+
//
|
|
43
|
+
// declared is the record's full name as the schema itself gives it, which is
|
|
44
|
+
// the only reliable way to split a TopicRecordNameStrategy subject: the
|
|
45
|
+
// separator is a hyphen and both halves may contain one, so the suffix is
|
|
46
|
+
// matched rather than searched for. Under the other two strategies it is a
|
|
47
|
+
// fallback for a schema that names itself nothing.
|
|
48
|
+
func resolve(subject, declared, strategy string) registration {
|
|
49
|
+
switch strategy {
|
|
50
|
+
case StrategyRecord:
|
|
51
|
+
return registration{Record: firstNonEmpty(declared, subject)}
|
|
52
|
+
|
|
53
|
+
case StrategyTopicRecord:
|
|
54
|
+
if declared != "" && strings.HasSuffix(subject, "-"+declared) {
|
|
55
|
+
return registration{
|
|
56
|
+
Topic: strings.TrimSuffix(subject, "-"+declared),
|
|
57
|
+
Record: declared,
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// The schema did not name itself, or named itself something the
|
|
61
|
+
// subject does not end with. Splitting at the first hyphen is the only
|
|
62
|
+
// thing left, and it is right for the ordinary "orders-com.acme.Order".
|
|
63
|
+
topic, record, found := strings.Cut(subject, "-")
|
|
64
|
+
if !found {
|
|
65
|
+
return registration{Record: firstNonEmpty(declared, subject)}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return registration{Topic: topic, Record: firstNonEmpty(declared, record)}
|
|
69
|
+
|
|
70
|
+
default: // StrategyTopic
|
|
71
|
+
if topic, found := strings.CutSuffix(subject, "-value"); found {
|
|
72
|
+
return registration{Topic: topic, Record: firstNonEmpty(declared, subject)}
|
|
73
|
+
}
|
|
74
|
+
if topic, found := strings.CutSuffix(subject, "-key"); found {
|
|
75
|
+
return registration{Topic: topic, Record: firstNonEmpty(declared, subject), Key: true}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// A subject under this strategy always ends in one of the two, so one
|
|
79
|
+
// that does not is a subject registered some other way. It still names
|
|
80
|
+
// a shape; it just cannot name a topic.
|
|
81
|
+
return registration{Record: firstNonEmpty(declared, subject)}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
func strategyOf(declared string) string {
|
|
86
|
+
switch declared {
|
|
87
|
+
case StrategyRecord, StrategyTopicRecord, StrategyTopic:
|
|
88
|
+
return declared
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return StrategyTopic
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
func firstNonEmpty(values ...string) string {
|
|
95
|
+
for _, value := range values {
|
|
96
|
+
if strings.TrimSpace(value) != "" {
|
|
97
|
+
return value
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return ""
|
|
102
|
+
}
|