@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,515 @@
|
|
|
1
|
+
// Pure derivations over the catalog. Nothing here reads the DOM or the router,
|
|
2
|
+
// so every number a Phase 2 page shows can be asserted in a test.
|
|
3
|
+
|
|
4
|
+
import type {
|
|
5
|
+
Block,
|
|
6
|
+
BoundedContext,
|
|
7
|
+
Catalog,
|
|
8
|
+
Event,
|
|
9
|
+
Field,
|
|
10
|
+
Flow,
|
|
11
|
+
Service,
|
|
12
|
+
Step,
|
|
13
|
+
} from "../catalog";
|
|
14
|
+
import { aggregateBlocks, flowContexts, ownersOf, walkSteps } from "../catalog";
|
|
15
|
+
|
|
16
|
+
export interface ContextStats {
|
|
17
|
+
services: number;
|
|
18
|
+
aggregates: number;
|
|
19
|
+
events: number;
|
|
20
|
+
/** unresolved rpc calls plus unresolved event consumers owned by this context */
|
|
21
|
+
unresolved: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function contextStats(context: BoundedContext): ContextStats {
|
|
25
|
+
let aggregates = 0;
|
|
26
|
+
let events = 0;
|
|
27
|
+
let unresolved = 0;
|
|
28
|
+
for (const service of context.services) {
|
|
29
|
+
aggregates += service.aggregates.length;
|
|
30
|
+
for (const call of service.consumes) {
|
|
31
|
+
if (call.status === "unresolved") unresolved += 1;
|
|
32
|
+
}
|
|
33
|
+
for (const aggregate of service.aggregates) {
|
|
34
|
+
events += aggregate.events.length;
|
|
35
|
+
for (const event of aggregate.events) {
|
|
36
|
+
for (const consumer of event.consumers) {
|
|
37
|
+
if (consumer.status === "unresolved") unresolved += 1;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return { services: context.services.length, aggregates, events, unresolved };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface ContextOwner {
|
|
46
|
+
/** A CODEOWNERS handle, exactly as the file spells it. */
|
|
47
|
+
handle: string;
|
|
48
|
+
/** The services of the context this handle owns, in catalog order. */
|
|
49
|
+
services: Service[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Who to ask about a context, folded up from what its services say.
|
|
54
|
+
*
|
|
55
|
+
* A context names no owner of its own: the estate's CODEOWNERS speaks in
|
|
56
|
+
* paths, and a path is a service. So the context's owners are the union of
|
|
57
|
+
* its services' owners, widest first - the handle behind most of the context
|
|
58
|
+
* is the one most likely to know, and a tie keeps the order the services
|
|
59
|
+
* came in. An empty answer means no service named anybody, which is not the
|
|
60
|
+
* same as nobody owning it.
|
|
61
|
+
*/
|
|
62
|
+
export function contextOwners(context: BoundedContext): ContextOwner[] {
|
|
63
|
+
const byHandle = new Map<string, Service[]>();
|
|
64
|
+
for (const service of context.services) {
|
|
65
|
+
for (const handle of ownersOf(service)) {
|
|
66
|
+
const owned = byHandle.get(handle);
|
|
67
|
+
if (owned) {
|
|
68
|
+
if (!owned.includes(service)) owned.push(service);
|
|
69
|
+
} else {
|
|
70
|
+
byHandle.set(handle, [service]);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return [...byHandle]
|
|
75
|
+
.map(([handle, services]) => ({ handle, services }))
|
|
76
|
+
.sort((a, b) => b.services.length - a.services.length);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Flows ordered by how many contexts they cross, widest first. */
|
|
80
|
+
export function flowsByReach(
|
|
81
|
+
catalog: Catalog,
|
|
82
|
+
): { flow: Flow; contexts: string[] }[] {
|
|
83
|
+
return catalog.flows
|
|
84
|
+
.map((flow) => ({ flow, contexts: flowContexts(flow) }))
|
|
85
|
+
.sort(
|
|
86
|
+
(a, b) =>
|
|
87
|
+
b.contexts.length - a.contexts.length ||
|
|
88
|
+
a.flow.name.localeCompare(b.flow.name),
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** The widest flows that fit on an overview without turning it into an index. */
|
|
93
|
+
export function widestFlows(
|
|
94
|
+
catalog: Catalog,
|
|
95
|
+
limit = 8,
|
|
96
|
+
): { flow: Flow; contexts: string[] }[] {
|
|
97
|
+
return flowsByReach(catalog).slice(0, Math.max(0, limit));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Flows in which a service appears as a participant. */
|
|
101
|
+
export function flowsForService(catalog: Catalog, serviceId: string): Flow[] {
|
|
102
|
+
return catalog.flows.filter((f) =>
|
|
103
|
+
f.participants.some((p) => p.id === serviceId),
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** What a service does in a flow, read off the steps it is on. */
|
|
108
|
+
export interface FlowRole {
|
|
109
|
+
flow: Flow;
|
|
110
|
+
/**
|
|
111
|
+
* `initiates`: the flow opens with somebody calling this service;
|
|
112
|
+
* `reacts`: it opens with an event arriving at this service;
|
|
113
|
+
* `participates`: the service is on a later step only.
|
|
114
|
+
*/
|
|
115
|
+
role: "initiates" | "reacts" | "participates";
|
|
116
|
+
/** The operation called or the event that arrived, for the two roles that have one. */
|
|
117
|
+
trigger: string | null;
|
|
118
|
+
/** The first step the service is on, for a link that lands on it. */
|
|
119
|
+
firstStepId: string | null;
|
|
120
|
+
/** How many steps the service is on either end of. */
|
|
121
|
+
steps: number;
|
|
122
|
+
/** Event names the service publishes and consumes in this flow, each once. */
|
|
123
|
+
publishes: string[];
|
|
124
|
+
consumes: string[];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* The flows a service is in, and what it does in each. The list a service
|
|
129
|
+
* page needs: not "which flows mention me" but "which do I start, which do I
|
|
130
|
+
* answer to, and where am I merely on the way".
|
|
131
|
+
*/
|
|
132
|
+
export function flowRoles(catalog: Catalog, serviceId: string): FlowRole[] {
|
|
133
|
+
return flowsForService(catalog, serviceId).map((flow) => {
|
|
134
|
+
const steps = walkSteps(flow.steps);
|
|
135
|
+
const brokers = new Set(
|
|
136
|
+
flow.participants.filter((p) => p.kind === "broker").map((p) => p.id),
|
|
137
|
+
);
|
|
138
|
+
const mine = steps.filter((s) => s.from === serviceId || s.to === serviceId);
|
|
139
|
+
const first = steps[0];
|
|
140
|
+
let role: FlowRole["role"] = "participates";
|
|
141
|
+
let trigger: string | null = null;
|
|
142
|
+
if (first && first.to === serviceId && first.from !== serviceId) {
|
|
143
|
+
if (first.kind === "event" && brokers.has(first.from)) {
|
|
144
|
+
role = "reacts";
|
|
145
|
+
trigger = first.label ?? first.ref ?? null;
|
|
146
|
+
} else if (first.kind === "rpc") {
|
|
147
|
+
role = "initiates";
|
|
148
|
+
trigger = first.label ?? first.ref ?? null;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const names = (list: Step[]) =>
|
|
152
|
+
[...new Set(list.map((s) => s.label ?? s.ref ?? "").filter(Boolean))];
|
|
153
|
+
return {
|
|
154
|
+
flow,
|
|
155
|
+
role,
|
|
156
|
+
trigger,
|
|
157
|
+
firstStepId: mine[0]?.id ?? null,
|
|
158
|
+
steps: mine.length,
|
|
159
|
+
publishes: names(mine.filter((s) => s.kind === "event" && s.from === serviceId)),
|
|
160
|
+
consumes: names(mine.filter((s) => s.kind === "event" && s.to === serviceId)),
|
|
161
|
+
};
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* The service whose repository a flow's paths are written against: the first
|
|
167
|
+
* service lane in the context that owns the flow. A flow's source and its
|
|
168
|
+
* steps' lines are spelled relative to that repository, so it is the one a
|
|
169
|
+
* link has to be built from.
|
|
170
|
+
*/
|
|
171
|
+
export function flowRepoService(catalog: Catalog, flow: Flow): Service | null {
|
|
172
|
+
const lanes = flow.participants.filter((p) => p.kind === "service");
|
|
173
|
+
const owned = lanes.find((p) => p.context === flow.owner) ?? lanes[0];
|
|
174
|
+
if (!owned) return null;
|
|
175
|
+
for (const context of catalog.contexts) {
|
|
176
|
+
const service = context.services.find((s) => s.id === owned.id);
|
|
177
|
+
if (service) return service;
|
|
178
|
+
}
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export interface StepRef {
|
|
183
|
+
flow: Flow;
|
|
184
|
+
stepId: string;
|
|
185
|
+
number: number;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** Every step across every flow that references an event, with its 1-based number. */
|
|
189
|
+
export function stepsReferencing(catalog: Catalog, eventId: string): StepRef[] {
|
|
190
|
+
const out: StepRef[] = [];
|
|
191
|
+
for (const flow of catalog.flows) {
|
|
192
|
+
walkSteps(flow.steps).forEach((step, i) => {
|
|
193
|
+
if (step.ref === eventId)
|
|
194
|
+
out.push({ flow, stepId: step.id, number: i + 1 });
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
return out;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
// Shared types. A value object earns its page by being the same type wherever
|
|
202
|
+
// it turns up, so "used in" is computed from defs refs rather than from names:
|
|
203
|
+
// two blocks called Money are the same Money only if they name the same def.
|
|
204
|
+
// ---------------------------------------------------------------------------
|
|
205
|
+
|
|
206
|
+
export type UsageKind = "event" | "entity" | "vo" | "def" | "rpc";
|
|
207
|
+
|
|
208
|
+
export interface DefUsage {
|
|
209
|
+
kind: UsageKind;
|
|
210
|
+
/** event id, block id, defs key, or "<rpc service id>.<message>" */
|
|
211
|
+
id: string;
|
|
212
|
+
name: string;
|
|
213
|
+
/** aggregate id, service id, or "defs" - what the usage sits inside */
|
|
214
|
+
owner: string;
|
|
215
|
+
/** the fields that carry the ref; empty when the usage IS the def */
|
|
216
|
+
fields: string[];
|
|
217
|
+
/** event versions in which the ref appears, oldest first */
|
|
218
|
+
versions?: string[];
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function refFields(fields: Field[], defKey: string): string[] {
|
|
222
|
+
return fields.filter((f) => f.ref === defKey).map((f) => f.name);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** The fields of a block that name a def, whether the block refs it or holds it inline. */
|
|
226
|
+
function blockRefFields(block: Block, defKey: string): string[] {
|
|
227
|
+
if (block.ref === defKey) return [];
|
|
228
|
+
return refFields(block.fields ?? [], defKey);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function usesDef(block: Block, defKey: string): boolean {
|
|
232
|
+
return block.ref === defKey || blockRefFields(block, defKey).length > 0;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Everything in the catalog that names a shared type. `exclude` drops one
|
|
237
|
+
* block id, so a value object's own page does not list itself.
|
|
238
|
+
*/
|
|
239
|
+
export function usagesOfDef(
|
|
240
|
+
catalog: Catalog,
|
|
241
|
+
defKey: string,
|
|
242
|
+
exclude?: string,
|
|
243
|
+
): DefUsage[] {
|
|
244
|
+
const events: DefUsage[] = [];
|
|
245
|
+
const entities: DefUsage[] = [];
|
|
246
|
+
const valueObjects: DefUsage[] = [];
|
|
247
|
+
const defs: DefUsage[] = [];
|
|
248
|
+
const rpc: DefUsage[] = [];
|
|
249
|
+
|
|
250
|
+
for (const context of catalog.contexts) {
|
|
251
|
+
for (const service of context.services) {
|
|
252
|
+
for (const provided of service.provides) {
|
|
253
|
+
for (const message of provided.messages ?? []) {
|
|
254
|
+
const fields = refFields(message.fields, defKey);
|
|
255
|
+
if (fields.length === 0) continue;
|
|
256
|
+
rpc.push({
|
|
257
|
+
kind: "rpc",
|
|
258
|
+
id: `${provided.id}.${message.name}`,
|
|
259
|
+
name: message.name,
|
|
260
|
+
owner: service.id,
|
|
261
|
+
fields,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
for (const aggregate of service.aggregates) {
|
|
266
|
+
for (const event of aggregate.events) {
|
|
267
|
+
const names = new Set<string>();
|
|
268
|
+
const versions: string[] = [];
|
|
269
|
+
for (const version of event.versions) {
|
|
270
|
+
const fields = refFields(version.fields, defKey);
|
|
271
|
+
if (fields.length === 0) continue;
|
|
272
|
+
for (const name of fields) names.add(name);
|
|
273
|
+
versions.push(version.version);
|
|
274
|
+
}
|
|
275
|
+
if (names.size === 0) continue;
|
|
276
|
+
events.push({
|
|
277
|
+
kind: "event",
|
|
278
|
+
id: event.id,
|
|
279
|
+
name: event.name,
|
|
280
|
+
owner: aggregate.id,
|
|
281
|
+
fields: [...names],
|
|
282
|
+
versions,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
for (const { kind, block } of aggregateBlocks(aggregate)) {
|
|
286
|
+
if (block.id === exclude || !usesDef(block, defKey)) continue;
|
|
287
|
+
const usage: DefUsage = {
|
|
288
|
+
kind,
|
|
289
|
+
id: block.id,
|
|
290
|
+
name: block.name,
|
|
291
|
+
owner: aggregate.id,
|
|
292
|
+
fields: blockRefFields(block, defKey),
|
|
293
|
+
};
|
|
294
|
+
(kind === "entity" ? entities : valueObjects).push(usage);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
for (const [id, def] of Object.entries(catalog.defs)) {
|
|
301
|
+
if (id === defKey) continue;
|
|
302
|
+
const fields = refFields(def.fields, defKey);
|
|
303
|
+
if (fields.length > 0) {
|
|
304
|
+
defs.push({ kind: "def", id, name: id, owner: "defs", fields });
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return [...events, ...entities, ...valueObjects, ...defs, ...rpc];
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// ---------------------------------------------------------------------------
|
|
312
|
+
// Markdown outline, for the sticky heading rail on aggregate pages.
|
|
313
|
+
// ---------------------------------------------------------------------------
|
|
314
|
+
|
|
315
|
+
export interface Heading {
|
|
316
|
+
depth: number;
|
|
317
|
+
text: string;
|
|
318
|
+
slug: string;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export function headingSlug(text: string): string {
|
|
322
|
+
return text
|
|
323
|
+
.toLowerCase()
|
|
324
|
+
.replace(/`/g, "")
|
|
325
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
326
|
+
.replace(/^-+|-+$/g, "");
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/** Headings outside fenced code blocks, in document order. */
|
|
330
|
+
export function markdownOutline(markdown: string): Heading[] {
|
|
331
|
+
const out: Heading[] = [];
|
|
332
|
+
let fenced = false;
|
|
333
|
+
for (const line of markdown.split("\n")) {
|
|
334
|
+
if (/^\s*```/.test(line)) {
|
|
335
|
+
fenced = !fenced;
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
if (fenced) continue;
|
|
339
|
+
const match = /^(#{1,3})\s+(.+?)\s*$/.exec(line);
|
|
340
|
+
if (!match) continue;
|
|
341
|
+
const hashes = match[1];
|
|
342
|
+
const text = match[2];
|
|
343
|
+
if (!hashes || !text) continue;
|
|
344
|
+
out.push({ depth: hashes.length, text, slug: headingSlug(text) });
|
|
345
|
+
}
|
|
346
|
+
return out;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// ---------------------------------------------------------------------------
|
|
350
|
+
// Event helpers
|
|
351
|
+
// ---------------------------------------------------------------------------
|
|
352
|
+
|
|
353
|
+
/** Fields added by a version relative to the one before it. */
|
|
354
|
+
export function addedFields(event: Event, version: string): Set<string> {
|
|
355
|
+
const i = event.versions.findIndex((v) => v.version === version);
|
|
356
|
+
if (i <= 0) return new Set();
|
|
357
|
+
const prev = event.versions[i - 1];
|
|
358
|
+
const current = event.versions[i];
|
|
359
|
+
if (!prev || !current) return new Set();
|
|
360
|
+
const before = new Set(prev.fields.map((f) => f.name));
|
|
361
|
+
return new Set(
|
|
362
|
+
current.fields.filter((f) => !before.has(f.name)).map((f) => f.name),
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// ---------------------------------------------------------------------------
|
|
367
|
+
// Shared types
|
|
368
|
+
// ---------------------------------------------------------------------------
|
|
369
|
+
|
|
370
|
+
export interface DefUse {
|
|
371
|
+
/** Events with a field pointing at the def, with the versions that do. */
|
|
372
|
+
events: { eventId: string; versions: string[] }[];
|
|
373
|
+
/** Other defs that embed it. */
|
|
374
|
+
defs: string[];
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Where a shared type is actually used. A value object has no page of its own,
|
|
379
|
+
* so this is the only answer to "what breaks if I change it?".
|
|
380
|
+
*/
|
|
381
|
+
export function usesOfDef(catalog: Catalog, defId: string): DefUse {
|
|
382
|
+
const events: DefUse["events"] = [];
|
|
383
|
+
for (const context of catalog.contexts) {
|
|
384
|
+
for (const service of context.services) {
|
|
385
|
+
for (const aggregate of service.aggregates) {
|
|
386
|
+
for (const event of aggregate.events) {
|
|
387
|
+
const versions = event.versions
|
|
388
|
+
.filter((v) => v.fields.some((f) => f.ref === defId))
|
|
389
|
+
.map((v) => v.version);
|
|
390
|
+
if (versions.length > 0) events.push({ eventId: event.id, versions });
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
const defs = Object.entries(catalog.defs)
|
|
396
|
+
.filter(
|
|
397
|
+
([id, def]) => id !== defId && def.fields.some((f) => f.ref === defId),
|
|
398
|
+
)
|
|
399
|
+
.map(([id]) => id);
|
|
400
|
+
return { events, defs };
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// ---------------------------------------------------------------------------
|
|
404
|
+
// Problems
|
|
405
|
+
// ---------------------------------------------------------------------------
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* One edge in the estate that does not land. Two things can be wrong, and they
|
|
409
|
+
* are wrong in the same way: a service calls an rpc whose provider is not in
|
|
410
|
+
* the catalog, or an event names a consumer that is not either. Both mean the
|
|
411
|
+
* chart draws an arrow into open water.
|
|
412
|
+
*/
|
|
413
|
+
export type ProblemKind =
|
|
414
|
+
| "rpc"
|
|
415
|
+
| "consumer"
|
|
416
|
+
| "cross-service-fk"
|
|
417
|
+
| "cross-service-lineage"
|
|
418
|
+
| "shared-store"
|
|
419
|
+
| "persistence-drift"
|
|
420
|
+
| "column-type"
|
|
421
|
+
| "outbox-payload"
|
|
422
|
+
| "proto-missing"
|
|
423
|
+
| "shared-channel"
|
|
424
|
+
| "channel-undeclared"
|
|
425
|
+
| "channel-unpublished"
|
|
426
|
+
| "subscription-unresolved";
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* How wrong a problem is. Two values, not five: an edge either lands somewhere
|
|
430
|
+
* the catalog knows about or it does not (an error), or the catalog holds two
|
|
431
|
+
* claims that do not quite agree and one of them is probably stale (a warning).
|
|
432
|
+
* Nothing in between is a distinction a reader could act on differently.
|
|
433
|
+
*/
|
|
434
|
+
export type Severity = "error" | "warning";
|
|
435
|
+
|
|
436
|
+
export interface Problem {
|
|
437
|
+
kind: ProblemKind;
|
|
438
|
+
severity: Severity;
|
|
439
|
+
/** The context that owns the end we can see. */
|
|
440
|
+
context: string;
|
|
441
|
+
/** The service that owns the end we can see. */
|
|
442
|
+
service: string;
|
|
443
|
+
/** The call id or the event id - what is on the near end of the edge. */
|
|
444
|
+
id: string;
|
|
445
|
+
/** The name that resolves to nothing. */
|
|
446
|
+
peer: string;
|
|
447
|
+
note: string | undefined;
|
|
448
|
+
source: string | undefined;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Every unresolved edge, contexts in catalog order. Nothing is scored and
|
|
453
|
+
* nothing is ranked: an unresolved consumer is exactly as broken as an
|
|
454
|
+
* unresolved call, and sorting them by badness would invent a fact.
|
|
455
|
+
*/
|
|
456
|
+
/**
|
|
457
|
+
* How many edges there were to resolve at all - every rpc call a service makes
|
|
458
|
+
* and every consumer an event names, whatever their status.
|
|
459
|
+
*
|
|
460
|
+
* The Problems page needs this to tell two silences apart. Zero problems out
|
|
461
|
+
* of two hundred edges is a clean estate; zero out of zero is a catalog whose
|
|
462
|
+
* services have not been wired together yet, and calling that "every edge
|
|
463
|
+
* resolved" hands the reader a green tick for work nobody has done.
|
|
464
|
+
*/
|
|
465
|
+
export function edgeCount(catalog: Catalog): number {
|
|
466
|
+
let n = 0;
|
|
467
|
+
for (const context of catalog.contexts) {
|
|
468
|
+
for (const service of context.services) {
|
|
469
|
+
n += service.consumes.length;
|
|
470
|
+
for (const aggregate of service.aggregates) {
|
|
471
|
+
for (const event of aggregate.events) n += event.consumers.length;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return n;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
export function problems(catalog: Catalog): Problem[] {
|
|
479
|
+
const out: Problem[] = [];
|
|
480
|
+
for (const context of catalog.contexts) {
|
|
481
|
+
for (const service of context.services) {
|
|
482
|
+
for (const call of service.consumes) {
|
|
483
|
+
if (call.status !== "unresolved") continue;
|
|
484
|
+
out.push({
|
|
485
|
+
kind: "rpc",
|
|
486
|
+
severity: "error",
|
|
487
|
+
context: context.id,
|
|
488
|
+
service: service.id,
|
|
489
|
+
id: call.id,
|
|
490
|
+
peer: call.peer,
|
|
491
|
+
note: call.note,
|
|
492
|
+
source: call.source,
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
for (const aggregate of service.aggregates) {
|
|
496
|
+
for (const event of aggregate.events) {
|
|
497
|
+
for (const consumer of event.consumers) {
|
|
498
|
+
if (consumer.status !== "unresolved") continue;
|
|
499
|
+
out.push({
|
|
500
|
+
kind: "consumer",
|
|
501
|
+
severity: "error",
|
|
502
|
+
context: context.id,
|
|
503
|
+
service: service.id,
|
|
504
|
+
id: event.id,
|
|
505
|
+
peer: consumer.service,
|
|
506
|
+
note: consumer.note,
|
|
507
|
+
source: undefined,
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
return out;
|
|
515
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
DEFAULT_EDITOR,
|
|
4
|
+
EDITORS,
|
|
5
|
+
absolutePath,
|
|
6
|
+
editorHref,
|
|
7
|
+
editorName,
|
|
8
|
+
editorWhere,
|
|
9
|
+
isEditorId,
|
|
10
|
+
} from "./editor-link";
|
|
11
|
+
import { parseEditor } from "./editor-prefs";
|
|
12
|
+
import type { BuildInfo } from "./build-info";
|
|
13
|
+
|
|
14
|
+
const ws = "/Users/me/estate";
|
|
15
|
+
|
|
16
|
+
describe("absolutePath", () => {
|
|
17
|
+
it("joins the workspace and a relative path", () => {
|
|
18
|
+
expect(absolutePath(ws, "internal/oms/app/checkout.go")).toBe(
|
|
19
|
+
"/Users/me/estate/internal/oms/app/checkout.go",
|
|
20
|
+
);
|
|
21
|
+
expect(absolutePath(`${ws}/`, "./a.go")).toBe("/Users/me/estate/a.go");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("refuses what the server would refuse", () => {
|
|
25
|
+
expect(absolutePath(ws, "/etc/passwd")).toBeNull();
|
|
26
|
+
expect(absolutePath(ws, "../outside.go")).toBeNull();
|
|
27
|
+
expect(absolutePath(ws, "a/../../b.go")).toBeNull();
|
|
28
|
+
expect(absolutePath(ws, "")).toBeNull();
|
|
29
|
+
expect(absolutePath("", "a.go")).toBeNull();
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("editorHref", () => {
|
|
34
|
+
it("opens a file at a line in VS Code and its relatives", () => {
|
|
35
|
+
expect(editorHref("vscode", ws, "order_repo.go:141")).toBe(
|
|
36
|
+
"vscode://file/Users/me/estate/order_repo.go:141",
|
|
37
|
+
);
|
|
38
|
+
expect(editorHref("cursor", ws, "order_repo.go")).toBe(
|
|
39
|
+
"cursor://file/Users/me/estate/order_repo.go",
|
|
40
|
+
);
|
|
41
|
+
expect(editorHref("zed", ws, "a/b.rs:7")).toBe(
|
|
42
|
+
"zed://file/Users/me/estate/a/b.rs:7",
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("speaks JetBrains' own scheme", () => {
|
|
47
|
+
expect(editorHref("idea", ws, "src/Main.java:12")).toBe(
|
|
48
|
+
"idea://open?file=%2FUsers%2Fme%2Festate%2Fsrc%2FMain.java&line=12",
|
|
49
|
+
);
|
|
50
|
+
expect(editorHref("idea", ws, "src/Main.java")).toBe(
|
|
51
|
+
"idea://open?file=%2FUsers%2Fme%2Festate%2Fsrc%2FMain.java",
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("encodes a space in a directory name", () => {
|
|
56
|
+
expect(editorHref("vscode", "/Users/me/my estate", "a/c.go:3")).toBe(
|
|
57
|
+
"vscode://file/Users/me/my%20estate/a/c.go:3",
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("is null for what is not a path in the workspace", () => {
|
|
62
|
+
expect(editorHref("vscode", ws, "trace 9f2c1a../span 04")).toBeNull();
|
|
63
|
+
expect(editorHref("vscode", ws, "/abs/path.go:1")).toBeNull();
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe("editorWhere", () => {
|
|
68
|
+
const info = {
|
|
69
|
+
repoUrl: "https://github.com/acme/estate",
|
|
70
|
+
commit: "abc",
|
|
71
|
+
forge: "github",
|
|
72
|
+
} as unknown as BuildInfo;
|
|
73
|
+
|
|
74
|
+
it("keeps a local path, with its line", () => {
|
|
75
|
+
expect(
|
|
76
|
+
editorWhere({ kind: "local", path: "a/b.go", line: 3, href: null }, info),
|
|
77
|
+
).toBe("a/b.go:3");
|
|
78
|
+
expect(
|
|
79
|
+
editorWhere({ kind: "local", path: "a/b.go", line: null, href: null }, info),
|
|
80
|
+
).toBe("a/b.go");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("keeps a forge path only in the repository this was built from", () => {
|
|
84
|
+
const remote = {
|
|
85
|
+
kind: "remote" as const,
|
|
86
|
+
provider: "github" as const,
|
|
87
|
+
origin: "https://github.com",
|
|
88
|
+
ref: "abc",
|
|
89
|
+
path: "a/b.go",
|
|
90
|
+
line: 9,
|
|
91
|
+
href: "https://github.com/acme/estate/blob/abc/a/b.go#L9",
|
|
92
|
+
};
|
|
93
|
+
expect(
|
|
94
|
+
editorWhere(
|
|
95
|
+
{ ...remote, repositoryUrl: "https://github.com/acme/estate" },
|
|
96
|
+
info,
|
|
97
|
+
),
|
|
98
|
+
).toBe("a/b.go:9");
|
|
99
|
+
expect(
|
|
100
|
+
editorWhere(
|
|
101
|
+
{ ...remote, repositoryUrl: "https://github.com/acme/other" },
|
|
102
|
+
info,
|
|
103
|
+
),
|
|
104
|
+
).toBeNull();
|
|
105
|
+
expect(
|
|
106
|
+
editorWhere(
|
|
107
|
+
{ ...remote, repositoryUrl: "https://github.com/acme/estate" },
|
|
108
|
+
{ ...info, repoUrl: "" },
|
|
109
|
+
),
|
|
110
|
+
).toBeNull();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe("editors", () => {
|
|
115
|
+
it("names every editor and defaults to VS Code", () => {
|
|
116
|
+
for (const e of EDITORS) {
|
|
117
|
+
expect(isEditorId(e.id)).toBe(true);
|
|
118
|
+
expect(editorName(e.id)).toBe(e.name);
|
|
119
|
+
}
|
|
120
|
+
expect(isEditorId("emacs")).toBe(false);
|
|
121
|
+
expect(parseEditor(null)).toBe(DEFAULT_EDITOR);
|
|
122
|
+
expect(parseEditor("emacs")).toBe(DEFAULT_EDITOR);
|
|
123
|
+
expect(parseEditor("zed")).toBe("zed");
|
|
124
|
+
});
|
|
125
|
+
});
|