@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,567 @@
|
|
|
1
|
+
// What links here.
|
|
2
|
+
//
|
|
3
|
+
// Every entity page answers what it depends on: an event lists its schema, a
|
|
4
|
+
// service its calls, a flow its steps. None of that answers the question a
|
|
5
|
+
// reader actually arrives with — "who depends on THIS?" — because the answer
|
|
6
|
+
// is not held by the thing itself. It is spread across everything else.
|
|
7
|
+
//
|
|
8
|
+
// So it is derived, once, here. A consumer, a flow step, a decision record and
|
|
9
|
+
// a field naming a shared type are four different edges in the catalog, and a
|
|
10
|
+
// reader scanning the bottom of a page asks one question of all four, so they
|
|
11
|
+
// are one row type here and one component downstream.
|
|
12
|
+
//
|
|
13
|
+
// Pure, like derive.ts: catalog and index in, plain values out. Nothing builds
|
|
14
|
+
// a URL — a Backlink says WHAT points at the target and routes.ts says where
|
|
15
|
+
// that thing lives, which keeps this file testable without a router.
|
|
16
|
+
|
|
17
|
+
import type { Adr, Catalog, CatalogIndex, Flow, Status, Term } from "../catalog";
|
|
18
|
+
import { allServices, walkSteps } from "../catalog";
|
|
19
|
+
import { sortAdrs, adrNumber } from "./adr";
|
|
20
|
+
import { readersOfStore } from "./data-model";
|
|
21
|
+
import { flowsForService, usagesOfDef } from "./derive";
|
|
22
|
+
import { usagesOfEnum } from "./shape";
|
|
23
|
+
import { bindTerms } from "./terms";
|
|
24
|
+
import type { DefUsage } from "./derive";
|
|
25
|
+
import type { Kind } from "./kinds";
|
|
26
|
+
|
|
27
|
+
/** Flows are named by slug, because that is what a route and a step id use. */
|
|
28
|
+
export interface BacklinkTarget {
|
|
29
|
+
kind: Kind;
|
|
30
|
+
id: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface Backlink {
|
|
34
|
+
/** What is doing the pointing. */
|
|
35
|
+
kind: Kind;
|
|
36
|
+
/** Its catalog id — what a link is built from, and what "copy" copies. */
|
|
37
|
+
id: string;
|
|
38
|
+
/** What to print: an identifier, not a sentence. */
|
|
39
|
+
name: string;
|
|
40
|
+
/** What holds it — a context name, an aggregate id, a decision's title. */
|
|
41
|
+
owner: string | null;
|
|
42
|
+
/** For the colour dot; null for anything outside every context. */
|
|
43
|
+
context: string | null;
|
|
44
|
+
/**
|
|
45
|
+
* Why it points here, said in the catalog's own words: "consumes",
|
|
46
|
+
* "step 12", "relates.events", the names of the fields that carry a type.
|
|
47
|
+
* Without it a backlink is a name with no reason attached, which is exactly
|
|
48
|
+
* the thing a reader would have to open the page to find out.
|
|
49
|
+
*/
|
|
50
|
+
via: string;
|
|
51
|
+
/** The exact place inside the linking thing — a flow's step id. */
|
|
52
|
+
at?: string;
|
|
53
|
+
/** Carried through from the edge, so an unresolved one still says so. */
|
|
54
|
+
status?: Status;
|
|
55
|
+
/** Event versions in which a shared type appears, oldest first. */
|
|
56
|
+
versions?: string[];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface BacklinkGroup {
|
|
60
|
+
kind: Kind;
|
|
61
|
+
links: Backlink[];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Group order, loudest dependency first. Services are what breaks when this
|
|
66
|
+
* changes; flows are where that break is seen; decisions are what was said
|
|
67
|
+
* about it; the rest is structure.
|
|
68
|
+
*/
|
|
69
|
+
const GROUP_ORDER: readonly Kind[] = [
|
|
70
|
+
"service",
|
|
71
|
+
"flow",
|
|
72
|
+
"adr",
|
|
73
|
+
"event",
|
|
74
|
+
"aggregate",
|
|
75
|
+
"entity",
|
|
76
|
+
"vo",
|
|
77
|
+
"enum",
|
|
78
|
+
"def",
|
|
79
|
+
"context",
|
|
80
|
+
// Last. A term does not depend on this page in the sense every row above
|
|
81
|
+
// does - nothing breaks when the aggregate changes - it is what the thing
|
|
82
|
+
// is CALLED, which a reader wants after they know who breaks.
|
|
83
|
+
"term",
|
|
84
|
+
] as const;
|
|
85
|
+
|
|
86
|
+
function grouped(links: Backlink[]): BacklinkGroup[] {
|
|
87
|
+
const by = new Map<Kind, Backlink[]>();
|
|
88
|
+
for (const link of links) {
|
|
89
|
+
const list = by.get(link.kind) ?? [];
|
|
90
|
+
list.push(link);
|
|
91
|
+
by.set(link.kind, list);
|
|
92
|
+
}
|
|
93
|
+
return GROUP_ORDER.filter((kind) => by.has(kind)).map((kind) => ({
|
|
94
|
+
kind,
|
|
95
|
+
links: by.get(kind) ?? [],
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function backlinkCount(groups: readonly BacklinkGroup[]): number {
|
|
100
|
+
return groups.reduce((n, g) => n + g.links.length, 0);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
// Row builders. One per kind of thing that can do the pointing.
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
function serviceLink(
|
|
108
|
+
index: CatalogIndex,
|
|
109
|
+
id: string,
|
|
110
|
+
via: string,
|
|
111
|
+
status?: Status,
|
|
112
|
+
): Backlink {
|
|
113
|
+
const context = index.serviceContext.get(id);
|
|
114
|
+
return {
|
|
115
|
+
kind: "service",
|
|
116
|
+
id,
|
|
117
|
+
name: id,
|
|
118
|
+
// A consumer named by an event but absent from the catalog is still a real
|
|
119
|
+
// dependency. The graph draws it as a ghost; this row says so in words.
|
|
120
|
+
owner: context ? context.name : "not in the catalog",
|
|
121
|
+
context: context?.id ?? null,
|
|
122
|
+
via,
|
|
123
|
+
...(status ? { status } : {}),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** The word the context's glossary uses for this thing. */
|
|
128
|
+
function termLink(term: Term): Backlink {
|
|
129
|
+
return {
|
|
130
|
+
kind: "term",
|
|
131
|
+
id: term.id,
|
|
132
|
+
name: term.name,
|
|
133
|
+
owner: `glossary of ${term.context}`,
|
|
134
|
+
context: term.context,
|
|
135
|
+
via: "names it",
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function flowLink(flow: Flow, via: string, at?: string): Backlink {
|
|
140
|
+
return {
|
|
141
|
+
kind: "flow",
|
|
142
|
+
id: flow.slug,
|
|
143
|
+
name: flow.slug,
|
|
144
|
+
owner: flow.name,
|
|
145
|
+
// A flow belongs to no single context; the wash on its own page takes the
|
|
146
|
+
// first one it crosses, and so does its dot here.
|
|
147
|
+
context: flow.participants.find((p) => p.context)?.context ?? null,
|
|
148
|
+
via,
|
|
149
|
+
...(at ? { at } : {}),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function adrLink(index: CatalogIndex, adr: Adr, via: string): Backlink {
|
|
154
|
+
const context =
|
|
155
|
+
adr.scope.kind === "context"
|
|
156
|
+
? adr.scope.context
|
|
157
|
+
: adr.scope.kind === "service"
|
|
158
|
+
? (index.serviceContext.get(adr.scope.service)?.id ?? null)
|
|
159
|
+
: null;
|
|
160
|
+
return {
|
|
161
|
+
kind: "adr",
|
|
162
|
+
id: adr.id,
|
|
163
|
+
name: adrNumber(adr),
|
|
164
|
+
owner: adr.title,
|
|
165
|
+
context,
|
|
166
|
+
via,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* A usage of a shared type, as a row. An RPC message has no page of its own,
|
|
172
|
+
* so it is filed under the service that answers it and says "rpc" in its
|
|
173
|
+
* reason rather than pretending to be one.
|
|
174
|
+
*/
|
|
175
|
+
function usageLink(index: CatalogIndex, usage: DefUsage): Backlink {
|
|
176
|
+
const via =
|
|
177
|
+
usage.fields.length > 0 ? usage.fields.join(", ") : "the same shape";
|
|
178
|
+
switch (usage.kind) {
|
|
179
|
+
case "event": {
|
|
180
|
+
const owner = index.eventOwner.get(usage.id);
|
|
181
|
+
return {
|
|
182
|
+
kind: "event",
|
|
183
|
+
id: usage.id,
|
|
184
|
+
name: usage.name,
|
|
185
|
+
owner: usage.owner,
|
|
186
|
+
context: owner
|
|
187
|
+
? (index.serviceContext.get(owner.service.id)?.id ?? null)
|
|
188
|
+
: null,
|
|
189
|
+
via,
|
|
190
|
+
...(usage.versions && usage.versions.length > 0
|
|
191
|
+
? { versions: usage.versions }
|
|
192
|
+
: {}),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
case "entity":
|
|
196
|
+
case "vo":
|
|
197
|
+
return {
|
|
198
|
+
kind: usage.kind,
|
|
199
|
+
id: usage.id,
|
|
200
|
+
name: usage.name,
|
|
201
|
+
owner: usage.owner,
|
|
202
|
+
context: index.blockById.get(usage.id)?.context.id ?? null,
|
|
203
|
+
via,
|
|
204
|
+
};
|
|
205
|
+
case "rpc":
|
|
206
|
+
return {
|
|
207
|
+
kind: "service",
|
|
208
|
+
id: usage.owner,
|
|
209
|
+
name: usage.name,
|
|
210
|
+
owner: usage.owner,
|
|
211
|
+
context: index.serviceContext.get(usage.owner)?.id ?? null,
|
|
212
|
+
via: `rpc · ${via}`,
|
|
213
|
+
};
|
|
214
|
+
case "def":
|
|
215
|
+
return {
|
|
216
|
+
kind: "def",
|
|
217
|
+
id: usage.id,
|
|
218
|
+
name: usage.name,
|
|
219
|
+
owner: "shared types",
|
|
220
|
+
context: null,
|
|
221
|
+
via,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ---------------------------------------------------------------------------
|
|
227
|
+
// Traversals
|
|
228
|
+
// ---------------------------------------------------------------------------
|
|
229
|
+
|
|
230
|
+
export interface StepInto {
|
|
231
|
+
flow: Flow;
|
|
232
|
+
stepId: string;
|
|
233
|
+
/** The step's place in the whole flow, frames included. */
|
|
234
|
+
number: number;
|
|
235
|
+
eventId: string;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Every step across every flow that carries one of these events. The generic
|
|
240
|
+
* form of derive's `stepsReferencing`: an aggregate is reached through all of
|
|
241
|
+
* its events at once, and the rows must still come out in flow order.
|
|
242
|
+
*/
|
|
243
|
+
export function stepsInto(catalog: Catalog, eventIds: Set<string>): StepInto[] {
|
|
244
|
+
const out: StepInto[] = [];
|
|
245
|
+
for (const flow of catalog.flows) {
|
|
246
|
+
walkSteps(flow.steps).forEach((step, i) => {
|
|
247
|
+
if (step.ref && eventIds.has(step.ref)) {
|
|
248
|
+
out.push({ flow, stepId: step.id, number: i + 1, eventId: step.ref });
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
return out;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ---------------------------------------------------------------------------
|
|
256
|
+
// Per-target derivations
|
|
257
|
+
// ---------------------------------------------------------------------------
|
|
258
|
+
|
|
259
|
+
function eventBacklinks(
|
|
260
|
+
catalog: Catalog,
|
|
261
|
+
index: CatalogIndex,
|
|
262
|
+
eventId: string,
|
|
263
|
+
): Backlink[] {
|
|
264
|
+
const event = index.eventById.get(eventId);
|
|
265
|
+
if (!event) return [];
|
|
266
|
+
const out: Backlink[] = [];
|
|
267
|
+
for (const consumer of event.consumers) {
|
|
268
|
+
out.push(serviceLink(index, consumer.service, "consumes", consumer.status));
|
|
269
|
+
}
|
|
270
|
+
for (const step of stepsInto(catalog, new Set([eventId]))) {
|
|
271
|
+
out.push(flowLink(step.flow, `step ${step.number}`, step.stepId));
|
|
272
|
+
}
|
|
273
|
+
for (const adr of index.adrsByEvent.get(eventId) ?? []) {
|
|
274
|
+
out.push(adrLink(index, adr, "relates.events"));
|
|
275
|
+
}
|
|
276
|
+
return out;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function aggregateBacklinks(
|
|
280
|
+
catalog: Catalog,
|
|
281
|
+
index: CatalogIndex,
|
|
282
|
+
aggregateId: string,
|
|
283
|
+
): Backlink[] {
|
|
284
|
+
const aggregate = index.aggregateById.get(aggregateId);
|
|
285
|
+
if (!aggregate) return [];
|
|
286
|
+
const out: Backlink[] = [];
|
|
287
|
+
const names = new Map(aggregate.events.map((e) => [e.id, e.name]));
|
|
288
|
+
|
|
289
|
+
for (const event of aggregate.events) {
|
|
290
|
+
for (const consumer of event.consumers) {
|
|
291
|
+
out.push(
|
|
292
|
+
serviceLink(
|
|
293
|
+
index,
|
|
294
|
+
consumer.service,
|
|
295
|
+
`consumes ${event.name}`,
|
|
296
|
+
consumer.status,
|
|
297
|
+
),
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
for (const step of stepsInto(catalog, new Set(names.keys()))) {
|
|
302
|
+
out.push(
|
|
303
|
+
flowLink(
|
|
304
|
+
step.flow,
|
|
305
|
+
`step ${step.number} · ${names.get(step.eventId) ?? step.eventId}`,
|
|
306
|
+
step.stepId,
|
|
307
|
+
),
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
// A decision naming two of this aggregate's events is one decision, not two
|
|
311
|
+
// rows, so the events it names are joined into its reason instead.
|
|
312
|
+
const byAdr = new Map<string, { adr: Adr; events: string[] }>();
|
|
313
|
+
for (const event of aggregate.events) {
|
|
314
|
+
for (const adr of index.adrsByEvent.get(event.id) ?? []) {
|
|
315
|
+
const seen = byAdr.get(adr.id) ?? { adr, events: [] };
|
|
316
|
+
seen.events.push(event.name);
|
|
317
|
+
byAdr.set(adr.id, seen);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
for (const { adr, events } of byAdr.values()) {
|
|
321
|
+
out.push(adrLink(index, adr, `relates ${events.join(", ")}`));
|
|
322
|
+
}
|
|
323
|
+
return out;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function serviceBacklinks(
|
|
327
|
+
catalog: Catalog,
|
|
328
|
+
index: CatalogIndex,
|
|
329
|
+
serviceId: string,
|
|
330
|
+
): Backlink[] {
|
|
331
|
+
const service = index.serviceById.get(serviceId);
|
|
332
|
+
if (!service) return [];
|
|
333
|
+
const out: Backlink[] = [];
|
|
334
|
+
|
|
335
|
+
// Who calls it. The service page lists `provides` and `consumes`, both of
|
|
336
|
+
// which point outwards; this is the only place the callers are named.
|
|
337
|
+
for (const other of allServices(catalog)) {
|
|
338
|
+
if (other.id === serviceId) continue;
|
|
339
|
+
for (const call of other.consumes) {
|
|
340
|
+
if (call.peer === serviceId) {
|
|
341
|
+
out.push(serviceLink(index, other.id, `calls ${call.id}`, call.status));
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
for (const aggregate of service.aggregates) {
|
|
346
|
+
for (const event of aggregate.events) {
|
|
347
|
+
for (const consumer of event.consumers) {
|
|
348
|
+
if (consumer.service === serviceId) continue;
|
|
349
|
+
out.push(
|
|
350
|
+
serviceLink(
|
|
351
|
+
index,
|
|
352
|
+
consumer.service,
|
|
353
|
+
`consumes ${event.name}`,
|
|
354
|
+
consumer.status,
|
|
355
|
+
),
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
for (const flow of flowsForService(catalog, serviceId)) {
|
|
361
|
+
out.push(flowLink(flow, "participant"));
|
|
362
|
+
}
|
|
363
|
+
// Only decisions that NAME this service. An org-wide record governs it too,
|
|
364
|
+
// but "everything" is not a backlink, and the decisions tab already has it.
|
|
365
|
+
for (const adr of sortAdrs(catalog.adrs)) {
|
|
366
|
+
if (adr.scope.kind === "service" && adr.scope.service === serviceId) {
|
|
367
|
+
out.push(adrLink(index, adr, "scope"));
|
|
368
|
+
} else if ((adr.relates.services ?? []).includes(serviceId)) {
|
|
369
|
+
out.push(adrLink(index, adr, "relates.services"));
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return out;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function contextBacklinks(
|
|
376
|
+
catalog: Catalog,
|
|
377
|
+
index: CatalogIndex,
|
|
378
|
+
contextId: string,
|
|
379
|
+
): Backlink[] {
|
|
380
|
+
const context = catalog.contexts.find((c) => c.id === contextId);
|
|
381
|
+
if (!context) return [];
|
|
382
|
+
const out: Backlink[] = [];
|
|
383
|
+
const inside = new Set(context.services.map((s) => s.id));
|
|
384
|
+
const events = context.services.flatMap((s) =>
|
|
385
|
+
s.aggregates.flatMap((a) => a.events),
|
|
386
|
+
);
|
|
387
|
+
const eventIds = new Set(events.map((e) => e.id));
|
|
388
|
+
|
|
389
|
+
// Traffic that starts outside. A call between two of its own services is
|
|
390
|
+
// internal wiring, not something the context is depended on for.
|
|
391
|
+
for (const other of allServices(catalog)) {
|
|
392
|
+
if (inside.has(other.id)) continue;
|
|
393
|
+
for (const call of other.consumes) {
|
|
394
|
+
if (inside.has(call.peer)) {
|
|
395
|
+
out.push(serviceLink(index, other.id, `calls ${call.id}`, call.status));
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
for (const event of events) {
|
|
400
|
+
for (const consumer of event.consumers) {
|
|
401
|
+
if (inside.has(consumer.service)) continue;
|
|
402
|
+
out.push(
|
|
403
|
+
serviceLink(
|
|
404
|
+
index,
|
|
405
|
+
consumer.service,
|
|
406
|
+
`consumes ${event.name}`,
|
|
407
|
+
consumer.status,
|
|
408
|
+
),
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
for (const flow of catalog.flows) {
|
|
413
|
+
const here = flow.participants
|
|
414
|
+
.filter((p) => p.context === contextId)
|
|
415
|
+
.map((p) => p.id);
|
|
416
|
+
if (here.length > 0) out.push(flowLink(flow, here.join(", ")));
|
|
417
|
+
}
|
|
418
|
+
for (const adr of sortAdrs(catalog.adrs)) {
|
|
419
|
+
const scope = adr.scope;
|
|
420
|
+
const services = (adr.relates.services ?? []).filter((s) => inside.has(s));
|
|
421
|
+
if (scope.kind === "context" && scope.context === contextId) {
|
|
422
|
+
out.push(adrLink(index, adr, "scope"));
|
|
423
|
+
} else if (scope.kind === "service" && inside.has(scope.service)) {
|
|
424
|
+
out.push(adrLink(index, adr, `scope ${scope.service}`));
|
|
425
|
+
} else if (services.length > 0) {
|
|
426
|
+
out.push(adrLink(index, adr, `relates ${services.join(", ")}`));
|
|
427
|
+
} else {
|
|
428
|
+
const named = (adr.relates.events ?? []).filter((e) => eventIds.has(e));
|
|
429
|
+
if (named.length > 0) {
|
|
430
|
+
out.push(
|
|
431
|
+
adrLink(
|
|
432
|
+
index,
|
|
433
|
+
adr,
|
|
434
|
+
`relates ${named.map((e) => index.eventById.get(e)?.name ?? e).join(", ")}`,
|
|
435
|
+
),
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return out;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function blockBacklinks(
|
|
444
|
+
catalog: Catalog,
|
|
445
|
+
index: CatalogIndex,
|
|
446
|
+
blockId: string,
|
|
447
|
+
): Backlink[] {
|
|
448
|
+
const owner = index.blockById.get(blockId);
|
|
449
|
+
const ref = owner?.block.ref;
|
|
450
|
+
// An inline shape is used only where it is written. There is nothing to
|
|
451
|
+
// find, which is a fact about the block rather than an empty answer.
|
|
452
|
+
if (!ref) return [];
|
|
453
|
+
return usagesOfDef(catalog, ref, blockId).map((usage) =>
|
|
454
|
+
usageLink(index, usage),
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* The fields that switch on an enum. Found by the resolver's name match
|
|
460
|
+
* rather than by a ref, and each row says "by name" so that a reader knows
|
|
461
|
+
* the claim is the catalog's and not the source's.
|
|
462
|
+
*/
|
|
463
|
+
function enumBacklinks(
|
|
464
|
+
catalog: Catalog,
|
|
465
|
+
index: CatalogIndex,
|
|
466
|
+
enumId: string,
|
|
467
|
+
): Backlink[] {
|
|
468
|
+
if (!index.enumById.has(enumId)) return [];
|
|
469
|
+
return usagesOfEnum(catalog, enumId).map((usage) => {
|
|
470
|
+
const link = usageLink(index, usage);
|
|
471
|
+
return { ...link, via: `${link.via} · by name` };
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Who depends on a schema: the services that read it - allowed, and exactly
|
|
477
|
+
* what makes a column rename expensive - and the aggregates its tables hold.
|
|
478
|
+
* The owner is not a row; it is the page's own header.
|
|
479
|
+
*/
|
|
480
|
+
function storeBacklinks(
|
|
481
|
+
catalog: Catalog,
|
|
482
|
+
index: CatalogIndex,
|
|
483
|
+
storeId: string,
|
|
484
|
+
): Backlink[] {
|
|
485
|
+
const store = index.storeById.get(storeId);
|
|
486
|
+
if (!store) return [];
|
|
487
|
+
const out: Backlink[] = [];
|
|
488
|
+
for (const reader of readersOfStore(catalog, storeId, store.owner)) {
|
|
489
|
+
out.push(serviceLink(index, reader.id, "reads"));
|
|
490
|
+
}
|
|
491
|
+
for (const table of store.tables) {
|
|
492
|
+
const aggregateId = table.persists?.aggregate;
|
|
493
|
+
const aggregate = aggregateId
|
|
494
|
+
? index.aggregateById.get(aggregateId)
|
|
495
|
+
: undefined;
|
|
496
|
+
const owner = aggregateId ? index.aggregateOwner.get(aggregateId) : undefined;
|
|
497
|
+
if (!aggregateId || !aggregate || !owner) continue;
|
|
498
|
+
out.push({
|
|
499
|
+
kind: "aggregate",
|
|
500
|
+
id: aggregateId,
|
|
501
|
+
name: aggregate.name,
|
|
502
|
+
owner: owner.id,
|
|
503
|
+
context: index.serviceContext.get(owner.id)?.id ?? null,
|
|
504
|
+
via: `persisted in ${table.name}`,
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
return out;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function flowBacklinks(
|
|
511
|
+
catalog: Catalog,
|
|
512
|
+
index: CatalogIndex,
|
|
513
|
+
slug: string,
|
|
514
|
+
): Backlink[] {
|
|
515
|
+
if (!index.flowBySlug.has(slug)) return [];
|
|
516
|
+
return sortAdrs(catalog.adrs)
|
|
517
|
+
.filter((adr) => (adr.relates.flows ?? []).includes(slug))
|
|
518
|
+
.map((adr) => adrLink(index, adr, "relates.flows"));
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Everything in the catalog that points at one thing, grouped by what does the
|
|
523
|
+
* pointing.
|
|
524
|
+
*
|
|
525
|
+
* Decision records are not a target: the only thing that names an ADR is
|
|
526
|
+
* another ADR, through supersedes / supersededBy, and that is already drawn at
|
|
527
|
+
* the top of its page as a banner — a warning that the record is no longer in
|
|
528
|
+
* force says more than a row in a list can.
|
|
529
|
+
*/
|
|
530
|
+
/** The rows, plus the word the glossary uses for the thing they point at. */
|
|
531
|
+
function named(catalog: Catalog, id: string, links: Backlink[]): Backlink[] {
|
|
532
|
+
const term = bindTerms(catalog).byTarget.get(id);
|
|
533
|
+
|
|
534
|
+
return term ? [...links, termLink(term)] : links;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
export function backlinksFor(
|
|
538
|
+
catalog: Catalog,
|
|
539
|
+
index: CatalogIndex,
|
|
540
|
+
target: BacklinkTarget,
|
|
541
|
+
): BacklinkGroup[] {
|
|
542
|
+
switch (target.kind) {
|
|
543
|
+
case "context":
|
|
544
|
+
return grouped(contextBacklinks(catalog, index, target.id));
|
|
545
|
+
case "service":
|
|
546
|
+
return grouped(serviceBacklinks(catalog, index, target.id));
|
|
547
|
+
// The three kinds a glossary can name. A context, a service and a flow are
|
|
548
|
+
// not words in a vocabulary - they are places the words are spoken.
|
|
549
|
+
case "aggregate":
|
|
550
|
+
return grouped(named(catalog, target.id, aggregateBacklinks(catalog, index, target.id)));
|
|
551
|
+
case "event":
|
|
552
|
+
return grouped(named(catalog, target.id, eventBacklinks(catalog, index, target.id)));
|
|
553
|
+
case "vo":
|
|
554
|
+
case "entity":
|
|
555
|
+
return grouped(named(catalog, target.id, blockBacklinks(catalog, index, target.id)));
|
|
556
|
+
case "enum":
|
|
557
|
+
return grouped(named(catalog, target.id, enumBacklinks(catalog, index, target.id)));
|
|
558
|
+
case "flow":
|
|
559
|
+
return grouped(flowBacklinks(catalog, index, target.id));
|
|
560
|
+
case "store":
|
|
561
|
+
return grouped(storeBacklinks(catalog, index, target.id));
|
|
562
|
+
// A module and an external API list their callers in a section of their
|
|
563
|
+
// own; a decision's incoming edges are its banner. Nothing to add here.
|
|
564
|
+
default:
|
|
565
|
+
return [];
|
|
566
|
+
}
|
|
567
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { buildInfo } from "./build-info";
|
|
2
|
+
import type { BuildInfo } from "./build-info";
|
|
3
|
+
|
|
4
|
+
/** A forge comparison for the selected pair, when this build knows its forge. */
|
|
5
|
+
export function branchCompareHref(
|
|
6
|
+
base: string,
|
|
7
|
+
head: string,
|
|
8
|
+
info: BuildInfo = buildInfo,
|
|
9
|
+
): string | null {
|
|
10
|
+
if (!info.repoUrl || !base || !head || base === head) return null;
|
|
11
|
+
const pair = `${encodeURIComponent(base)}...${encodeURIComponent(head)}`;
|
|
12
|
+
const root = info.repoUrl.replace(/\/$/, "");
|
|
13
|
+
return info.forge === "gitlab" || /gitlab/i.test(root)
|
|
14
|
+
? `${root}/-/compare/${pair}`
|
|
15
|
+
: `${root}/compare/${pair}`;
|
|
16
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
buildHref,
|
|
4
|
+
buildLabel,
|
|
5
|
+
buildTitle,
|
|
6
|
+
type BuildInfo,
|
|
7
|
+
} from "./build-info";
|
|
8
|
+
|
|
9
|
+
const CI: BuildInfo = {
|
|
10
|
+
commit: "4f1c9ae0c1b2d3e4f5a6b7c8d9e0f1a2b3c4d5e6",
|
|
11
|
+
shortCommit: "4f1c9ae",
|
|
12
|
+
branch: "main",
|
|
13
|
+
builtAt: "2026-08-29T09:14:22Z",
|
|
14
|
+
commitUrl:
|
|
15
|
+
"https://gitlab.com/acme/portolan/-/commit/4f1c9ae0c1b2d3e4f5a6b7c8d9e0f1a2b3c4d5e6",
|
|
16
|
+
buildUrl: "https://gitlab.com/acme/portolan/-/pipelines/17390211",
|
|
17
|
+
buildNumber: "128",
|
|
18
|
+
dirty: false,
|
|
19
|
+
repoUrl: "https://gitlab.com/acme/portolan",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const UNKNOWN: BuildInfo = {
|
|
23
|
+
commit: "",
|
|
24
|
+
shortCommit: "",
|
|
25
|
+
branch: "",
|
|
26
|
+
builtAt: "",
|
|
27
|
+
commitUrl: "",
|
|
28
|
+
buildUrl: "",
|
|
29
|
+
buildNumber: "",
|
|
30
|
+
dirty: false,
|
|
31
|
+
repoUrl: "",
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
describe("buildHref", () => {
|
|
35
|
+
it("opens the commit the stamp names", () => {
|
|
36
|
+
expect(buildHref(CI)).toBe(CI.commitUrl);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("settles for the pipeline when the forge is unknown", () => {
|
|
40
|
+
expect(buildHref({ ...CI, commitUrl: "" })).toBe(CI.buildUrl);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("is null when there is nowhere to go", () => {
|
|
44
|
+
expect(buildHref(UNKNOWN)).toBeNull();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe("buildLabel", () => {
|
|
49
|
+
it("reads as the commit, not the build number, even on CI", () => {
|
|
50
|
+
expect(buildLabel(CI)).toBe("4f1c9ae");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("marks a tree that was dirty when it was built", () => {
|
|
54
|
+
expect(buildLabel({ ...CI, dirty: true })).toBe("4f1c9ae+");
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("falls back to the build number when there is no commit", () => {
|
|
58
|
+
expect(buildLabel({ ...UNKNOWN, buildNumber: "128" })).toBe("#128");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("says dev rather than nothing when git knew nothing", () => {
|
|
62
|
+
expect(buildLabel(UNKNOWN)).toBe("dev");
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe("buildTitle", () => {
|
|
67
|
+
it("spells out every field that has an answer", () => {
|
|
68
|
+
expect(buildTitle(CI)).toBe(
|
|
69
|
+
"commit 4f1c9ae · branch main · build #128 · built 2026-08-29 09:14:22Z",
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("drops the parts it cannot fill", () => {
|
|
74
|
+
expect(buildTitle(UNKNOWN)).toBe("built at an unrecorded time");
|
|
75
|
+
});
|
|
76
|
+
});
|