@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,115 @@
|
|
|
1
|
+
// Layout, on the two catalogs built to break it.
|
|
2
|
+
//
|
|
3
|
+
// elk itself is not under test here. What is: that the graph handed to it says
|
|
4
|
+
// what we mean — roots first, one constraint per relationship, no self-edges —
|
|
5
|
+
// and that it survives an estate too big to draw and a schema shaped wrong.
|
|
6
|
+
|
|
7
|
+
import { describe, expect, it } from "vitest";
|
|
8
|
+
import { buildIndex, validateCatalog } from "../catalog";
|
|
9
|
+
import { pathologicalCatalog, wideCatalog } from "../lib/scenarios";
|
|
10
|
+
import { erSpec } from "./spec";
|
|
11
|
+
import { layoutEr, layoutInput } from "./layout";
|
|
12
|
+
|
|
13
|
+
describe("layoutInput", () => {
|
|
14
|
+
const bad = pathologicalCatalog();
|
|
15
|
+
const index = buildIndex(validateCatalog(bad));
|
|
16
|
+
const store = (bad.stores ?? [])[0];
|
|
17
|
+
if (!store) throw new Error("scenario has no store");
|
|
18
|
+
const spec = erSpec(index, store, { mode: "keys" });
|
|
19
|
+
const input = layoutInput(spec);
|
|
20
|
+
|
|
21
|
+
it("reverses every edge, so the table pointed AT is laid out first", () => {
|
|
22
|
+
// The drawn edge runs child → parent. Laid out that way, the aggregate
|
|
23
|
+
// root ends up at the far right, which is the opposite of how a schema is
|
|
24
|
+
// read.
|
|
25
|
+
const drawn = spec.edges.find(
|
|
26
|
+
(e) => e.from === "edge.core.pg.a" && e.to === "edge.core.pg.b",
|
|
27
|
+
);
|
|
28
|
+
expect(drawn).toBeDefined();
|
|
29
|
+
expect(
|
|
30
|
+
input.edges.some(
|
|
31
|
+
(e) => e.source === "edge.core.pg.b" && e.target === "edge.core.pg.a",
|
|
32
|
+
),
|
|
33
|
+
).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("drops a self-reference, which constrains nothing", () => {
|
|
37
|
+
expect(
|
|
38
|
+
input.edges.some((e) => e.source === e.target),
|
|
39
|
+
).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("keeps every table as a node, self-referencing or not", () => {
|
|
43
|
+
expect(input.nodes.map((n) => n.id).sort()).toEqual(
|
|
44
|
+
spec.nodes.map((n) => n.id).sort(),
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("collapses two keys between the same pair into one constraint", () => {
|
|
49
|
+
const pairs = input.edges.map((e) => `${e.source}->${e.target}`);
|
|
50
|
+
expect(new Set(pairs).size).toBe(pairs.length);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe("layoutEr", () => {
|
|
55
|
+
it("places every table in the pathological store, cycle and all", async () => {
|
|
56
|
+
const bad = pathologicalCatalog();
|
|
57
|
+
const index = buildIndex(validateCatalog(bad));
|
|
58
|
+
const store = (bad.stores ?? [])[0];
|
|
59
|
+
if (!store) throw new Error("scenario has no store");
|
|
60
|
+
const spec = erSpec(index, store, { mode: "all" });
|
|
61
|
+
|
|
62
|
+
const { positions } = await layoutEr(spec);
|
|
63
|
+
for (const node of spec.nodes) {
|
|
64
|
+
expect(positions[node.id]).toBeDefined();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("puts a chain's first table left of its last", async () => {
|
|
69
|
+
const wide = wideCatalog();
|
|
70
|
+
const index = buildIndex(validateCatalog(wide));
|
|
71
|
+
const store = (wide.stores ?? [])[0];
|
|
72
|
+
if (!store) throw new Error("scenario has no store");
|
|
73
|
+
const spec = erSpec(index, store, { mode: "keys" });
|
|
74
|
+
|
|
75
|
+
const { positions } = await layoutEr(spec);
|
|
76
|
+
const first = positions[`${store.id}.t0`];
|
|
77
|
+
const last = positions[`${store.id}.t5`];
|
|
78
|
+
expect(first).toBeDefined();
|
|
79
|
+
expect(last).toBeDefined();
|
|
80
|
+
expect(first?.x ?? 0).toBeLessThan(last?.x ?? 0);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("answers for an empty store without asking elk anything", async () => {
|
|
84
|
+
const result = await layoutEr({ nodes: [], edges: [] });
|
|
85
|
+
expect(result).toEqual({ positions: {}, width: 0, height: 0 });
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe("the wide estate", () => {
|
|
90
|
+
const wide = wideCatalog();
|
|
91
|
+
|
|
92
|
+
it("validates, which is the first thing a scenario has to do", () => {
|
|
93
|
+
expect(() => validateCatalog(wide)).not.toThrow();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("is the size it claims to be", () => {
|
|
97
|
+
expect(wide.stores).toHaveLength(40);
|
|
98
|
+
const tables = (wide.stores ?? []).reduce(
|
|
99
|
+
(n, s) => n + s.tables.length,
|
|
100
|
+
0,
|
|
101
|
+
);
|
|
102
|
+
expect(tables).toBeGreaterThanOrEqual(200);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("lays out one of its stores", async () => {
|
|
106
|
+
const index = buildIndex(validateCatalog(wide));
|
|
107
|
+
const store = (wide.stores ?? [])[0];
|
|
108
|
+
if (!store) throw new Error("scenario has no store");
|
|
109
|
+
const { positions, width } = await layoutEr(
|
|
110
|
+
erSpec(index, store, { mode: "all" }),
|
|
111
|
+
);
|
|
112
|
+
expect(Object.keys(positions)).toHaveLength(store.tables.length);
|
|
113
|
+
expect(width).toBeGreaterThan(0);
|
|
114
|
+
});
|
|
115
|
+
});
|
package/src/er/layout.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Where the cards go.
|
|
2
|
+
//
|
|
3
|
+
// One decision worth spelling out: the FK edges handed to elk run the OPPOSITE
|
|
4
|
+
// way from the edges drawn. A foreign key points from the child to the parent,
|
|
5
|
+
// so a layered pass over the real direction puts the aggregate root on the
|
|
6
|
+
// right, at the end of every arrow. Readers do not read a schema that way —
|
|
7
|
+
// they start at the root and follow what hangs off it — so the layout is fed
|
|
8
|
+
// parent → child and the canvas draws child → parent over the top of it.
|
|
9
|
+
//
|
|
10
|
+
// Lineage is fed exactly as it is drawn. It already points the way a reader
|
|
11
|
+
// reads: source on the left, the view computed from it on the right. Reversing
|
|
12
|
+
// it too would put every view before the tables it reads, which is the one
|
|
13
|
+
// arrangement that makes a lineage picture unreadable.
|
|
14
|
+
|
|
15
|
+
import { layoutWithElk } from "../graph/elk";
|
|
16
|
+
import type { ErSpec } from "./spec";
|
|
17
|
+
|
|
18
|
+
export interface ErLayout {
|
|
19
|
+
positions: Record<string, { x: number; y: number }>;
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ErLayoutInput {
|
|
25
|
+
nodes: { id: string; width: number; height: number }[];
|
|
26
|
+
edges: { id: string; source: string; target: string }[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The layout graph: real nodes, reversed edges, and no duplicate pair. Two
|
|
31
|
+
* foreign keys between the same two tables are one constraint as far as
|
|
32
|
+
* placement is concerned, and feeding both makes elk pull them closer than a
|
|
33
|
+
* single relationship warrants.
|
|
34
|
+
*/
|
|
35
|
+
export function layoutInput(spec: ErSpec): ErLayoutInput {
|
|
36
|
+
const seen = new Set<string>();
|
|
37
|
+
const edges: ErLayoutInput["edges"] = [];
|
|
38
|
+
for (const edge of spec.edges) {
|
|
39
|
+
// A self-reference constrains nothing and elk lays it out as a cycle of
|
|
40
|
+
// one; the canvas still draws it.
|
|
41
|
+
if (edge.from === edge.to) continue;
|
|
42
|
+
const source = edge.kind === "fk" ? edge.to : edge.from;
|
|
43
|
+
const target = edge.kind === "fk" ? edge.from : edge.to;
|
|
44
|
+
const pair = `${source}->${target}`;
|
|
45
|
+
if (seen.has(pair)) continue;
|
|
46
|
+
seen.add(pair);
|
|
47
|
+
edges.push({ id: pair, source, target });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
nodes: spec.nodes.map((n) => ({
|
|
52
|
+
id: n.id,
|
|
53
|
+
width: n.width,
|
|
54
|
+
height: n.height,
|
|
55
|
+
})),
|
|
56
|
+
edges,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Lays a spec out left to right, roots first. Falls back to a column on failure. */
|
|
61
|
+
export async function layoutEr(spec: ErSpec): Promise<ErLayout> {
|
|
62
|
+
const input = layoutInput(spec);
|
|
63
|
+
if (input.nodes.length === 0) {
|
|
64
|
+
return { positions: {}, width: 0, height: 0 };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const { positions, width, height } = await layoutWithElk({
|
|
68
|
+
...input,
|
|
69
|
+
direction: "RIGHT",
|
|
70
|
+
// Wider than the graph views' default. A table card is 208px and an edge
|
|
71
|
+
// between two of them carries "on delete cascade" often enough that a
|
|
72
|
+
// narrow gap leaves the label sitting on top of the line it describes.
|
|
73
|
+
layerSpacing: 170,
|
|
74
|
+
nodeSpacing: 28,
|
|
75
|
+
});
|
|
76
|
+
return { positions, width, height };
|
|
77
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// Walking the lineage graph: both directions, and no walk that never ends.
|
|
2
|
+
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
import { rawCatalog } from "../test-catalog";
|
|
5
|
+
import { buildIndex, validateCatalog } from "../catalog";
|
|
6
|
+
import type { Catalog } from "../catalog";
|
|
7
|
+
import {
|
|
8
|
+
downstreamOf,
|
|
9
|
+
isIsolated,
|
|
10
|
+
lineageChain,
|
|
11
|
+
lineageEdgeId,
|
|
12
|
+
parseLineageEdgeId,
|
|
13
|
+
upstreamOf,
|
|
14
|
+
} from "./lineage";
|
|
15
|
+
import type { LineageMaps } from "./lineage";
|
|
16
|
+
|
|
17
|
+
/** A graph written the way a catalog declares it: derived end names its sources. */
|
|
18
|
+
function maps(declared: Record<string, string[]>): LineageMaps {
|
|
19
|
+
const from = new Map<string, string[]>();
|
|
20
|
+
const into = new Map<string, string[]>();
|
|
21
|
+
for (const [target, sources] of Object.entries(declared)) {
|
|
22
|
+
from.set(target, sources);
|
|
23
|
+
for (const source of sources) {
|
|
24
|
+
const list = into.get(source) ?? [];
|
|
25
|
+
list.push(target);
|
|
26
|
+
into.set(source, list);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return { from, into };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
describe("edge ids", () => {
|
|
33
|
+
it("round-trips", () => {
|
|
34
|
+
const id = lineageEdgeId("db.t.a", "db.v.b");
|
|
35
|
+
expect(id).toBe("db.t.a~>db.v.b");
|
|
36
|
+
expect(parseLineageEdgeId(id)).toEqual({
|
|
37
|
+
source: "db.t.a",
|
|
38
|
+
target: "db.v.b",
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("is not fooled by something that is not an edge id", () => {
|
|
43
|
+
expect(parseLineageEdgeId("db.t.a")).toBeNull();
|
|
44
|
+
expect(parseLineageEdgeId("~>db.t.a")).toBeNull();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe("walking", () => {
|
|
49
|
+
// t.a -> v.b -> w.c, with v.b also feeding w.d.
|
|
50
|
+
const graph = maps({
|
|
51
|
+
"db.v.b": ["db.t.a"],
|
|
52
|
+
"db.w.c": ["db.v.b"],
|
|
53
|
+
"db.w.d": ["db.v.b"],
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("follows sources to the far end", () => {
|
|
57
|
+
expect([...upstreamOf(graph, "db.w.c")].sort()).toEqual([
|
|
58
|
+
"db.t.a",
|
|
59
|
+
"db.v.b",
|
|
60
|
+
]);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("follows readers to the far end", () => {
|
|
64
|
+
expect([...downstreamOf(graph, "db.t.a")].sort()).toEqual([
|
|
65
|
+
"db.v.b",
|
|
66
|
+
"db.w.c",
|
|
67
|
+
"db.w.d",
|
|
68
|
+
]);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("says nothing about a column nobody copies", () => {
|
|
72
|
+
expect(upstreamOf(graph, "db.t.a").size).toBe(0);
|
|
73
|
+
expect(downstreamOf(graph, "db.w.c").size).toBe(0);
|
|
74
|
+
expect(isIsolated(graph, "db.z.x")).toBe(true);
|
|
75
|
+
expect(isIsolated(graph, "db.t.a")).toBe(false);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("lights the whole chain from anywhere on it, itself included", () => {
|
|
79
|
+
const chain = lineageChain(graph, "db.v.b");
|
|
80
|
+
expect([...chain.columns].sort()).toEqual([
|
|
81
|
+
"db.t.a",
|
|
82
|
+
"db.v.b",
|
|
83
|
+
"db.w.c",
|
|
84
|
+
"db.w.d",
|
|
85
|
+
]);
|
|
86
|
+
expect([...chain.edges].sort()).toEqual([
|
|
87
|
+
"db.t.a~>db.v.b",
|
|
88
|
+
"db.v.b~>db.w.c",
|
|
89
|
+
"db.v.b~>db.w.d",
|
|
90
|
+
]);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("terminates on a cycle", () => {
|
|
94
|
+
// A catalog mid-migration is allowed to claim a view feeds its own source.
|
|
95
|
+
const cyclic = maps({ "db.v.b": ["db.t.a"], "db.t.a": ["db.v.b"] });
|
|
96
|
+
const chain = lineageChain(cyclic, "db.t.a");
|
|
97
|
+
expect([...chain.columns].sort()).toEqual(["db.t.a", "db.v.b"]);
|
|
98
|
+
expect(chain.edges.size).toBe(2);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe("the catalog's own graph", () => {
|
|
103
|
+
const catalog = validateCatalog(
|
|
104
|
+
JSON.parse(JSON.stringify(rawCatalog)) as unknown as Catalog,
|
|
105
|
+
);
|
|
106
|
+
const index = buildIndex(catalog);
|
|
107
|
+
const graph: LineageMaps = {
|
|
108
|
+
from: index.lineageFrom,
|
|
109
|
+
into: index.lineageInto,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
it("has lineage to walk at all", () => {
|
|
113
|
+
expect(index.lineageFrom.size).toBeGreaterThan(0);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("only ever names columns the catalog has", () => {
|
|
117
|
+
for (const [target, sources] of index.lineageFrom) {
|
|
118
|
+
expect(
|
|
119
|
+
index.columnById.has(target) || index.viewColumnById.has(target),
|
|
120
|
+
target,
|
|
121
|
+
).toBe(true);
|
|
122
|
+
for (const source of sources) {
|
|
123
|
+
expect(
|
|
124
|
+
index.columnById.has(source) || index.viewColumnById.has(source),
|
|
125
|
+
source,
|
|
126
|
+
).toBe(true);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("reaches a source table from a view column", () => {
|
|
132
|
+
const [first] = [...index.viewColumnById.keys()].filter(
|
|
133
|
+
(id) => (index.lineageFrom.get(id)?.length ?? 0) > 0,
|
|
134
|
+
);
|
|
135
|
+
expect(first).toBeDefined();
|
|
136
|
+
const chain = lineageChain(graph, first as string);
|
|
137
|
+
expect(chain.columns.size).toBeGreaterThan(1);
|
|
138
|
+
expect(chain.edges.size).toBeGreaterThan(0);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// Where a value came from, and who reads it.
|
|
2
|
+
//
|
|
3
|
+
// Foreign keys are a picture of the schema at rest: this row points at that
|
|
4
|
+
// one. Lineage is a picture of the schema in motion — a column of a view, of a
|
|
5
|
+
// projection, of an outbox is a copy of a column somewhere else, and the only
|
|
6
|
+
// question worth asking of it is which one, and what else was copied from the
|
|
7
|
+
// same place.
|
|
8
|
+
//
|
|
9
|
+
// Pure, and deliberately ignorant of the catalog: two maps in, ids out. The
|
|
10
|
+
// index builds the maps once (catalog.ts), the canvas walks them on hover.
|
|
11
|
+
|
|
12
|
+
/** The lineage graph, in both directions. Keys and values are column ids. */
|
|
13
|
+
export interface LineageMaps {
|
|
14
|
+
/** column -> the columns it is computed from */
|
|
15
|
+
from: ReadonlyMap<string, readonly string[]>;
|
|
16
|
+
/** column -> the columns computed from it */
|
|
17
|
+
into: ReadonlyMap<string, readonly string[]>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* One lineage edge's id, source first. The canvas draws edges data-first —
|
|
22
|
+
* left to right, the way it flows — so the id reads the same way.
|
|
23
|
+
*/
|
|
24
|
+
export function lineageEdgeId(source: string, target: string): string {
|
|
25
|
+
return `${source}~>${target}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Splits an edge id back into its two ends, or null when it is not one. */
|
|
29
|
+
export function parseLineageEdgeId(
|
|
30
|
+
id: string,
|
|
31
|
+
): { source: string; target: string } | null {
|
|
32
|
+
const at = id.indexOf("~>");
|
|
33
|
+
if (at <= 0) return null;
|
|
34
|
+
return { source: id.slice(0, at), target: id.slice(at + 2) };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Walks one direction to exhaustion. Every step is guarded by `seen`, so a
|
|
39
|
+
* catalog that says a view feeds the table it reads — which a mid-migration
|
|
40
|
+
* catalog is allowed to say — is a cycle that terminates rather than a hang.
|
|
41
|
+
*/
|
|
42
|
+
function walk(
|
|
43
|
+
edges: ReadonlyMap<string, readonly string[]>,
|
|
44
|
+
start: string,
|
|
45
|
+
onEdge: (a: string, b: string) => void,
|
|
46
|
+
): Set<string> {
|
|
47
|
+
const seen = new Set<string>();
|
|
48
|
+
const queue = [start];
|
|
49
|
+
while (queue.length > 0) {
|
|
50
|
+
const current = queue.shift() as string;
|
|
51
|
+
for (const next of edges.get(current) ?? []) {
|
|
52
|
+
onEdge(current, next);
|
|
53
|
+
if (seen.has(next)) continue;
|
|
54
|
+
seen.add(next);
|
|
55
|
+
queue.push(next);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return seen;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Every column this one is computed from, however many hops away. */
|
|
62
|
+
export function upstreamOf(maps: LineageMaps, id: string): Set<string> {
|
|
63
|
+
return walk(maps.from, id, () => {});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Every column computed from this one, however many hops away. */
|
|
67
|
+
export function downstreamOf(maps: LineageMaps, id: string): Set<string> {
|
|
68
|
+
return walk(maps.into, id, () => {});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The whole chain through one column: everything it came from, everything read
|
|
73
|
+
* from it, and the edges joining them.
|
|
74
|
+
*
|
|
75
|
+
* Both directions, because a reader hovering a column is asking one question
|
|
76
|
+
* with two halves — "if this changes, what breaks, and if this is wrong, where
|
|
77
|
+
* did it go wrong". The column itself is in `columns`, so the caller can light
|
|
78
|
+
* the chain without special-casing where the pointer is.
|
|
79
|
+
*/
|
|
80
|
+
export interface LineageChain {
|
|
81
|
+
columns: Set<string>;
|
|
82
|
+
edges: Set<string>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function lineageChain(maps: LineageMaps, id: string): LineageChain {
|
|
86
|
+
const columns = new Set<string>([id]);
|
|
87
|
+
const edges = new Set<string>();
|
|
88
|
+
|
|
89
|
+
for (const found of walk(maps.from, id, (target, source) =>
|
|
90
|
+
edges.add(lineageEdgeId(source, target)),
|
|
91
|
+
)) {
|
|
92
|
+
columns.add(found);
|
|
93
|
+
}
|
|
94
|
+
for (const found of walk(maps.into, id, (source, target) =>
|
|
95
|
+
edges.add(lineageEdgeId(source, target)),
|
|
96
|
+
)) {
|
|
97
|
+
columns.add(found);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return { columns, edges };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** True when nothing in the catalog is derived from this column or feeds it. */
|
|
104
|
+
export function isIsolated(maps: LineageMaps, id: string): boolean {
|
|
105
|
+
return (maps.from.get(id)?.length ?? 0) === 0 &&
|
|
106
|
+
(maps.into.get(id)?.length ?? 0) === 0;
|
|
107
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Crow's-foot markers, defined once per canvas.
|
|
2
|
+
//
|
|
3
|
+
// The notation is the point: a foreign key is a MANY-to-one relationship, and
|
|
4
|
+
// an arrowhead says only "points at". The fan sits on the table holding the
|
|
5
|
+
// key, the bar on the table it points to, so the cardinality is readable
|
|
6
|
+
// without a legend.
|
|
7
|
+
//
|
|
8
|
+
// Both take their colour from the edge through `context-stroke`, so a
|
|
9
|
+
// highlighted edge highlights its ends with it rather than needing a second
|
|
10
|
+
// pair of markers.
|
|
11
|
+
|
|
12
|
+
export const MARKER_MANY = "er-many";
|
|
13
|
+
export const MARKER_ONE = "er-one";
|
|
14
|
+
/**
|
|
15
|
+
* Lineage is not a cardinality, so it gets neither end of the crow's foot: a
|
|
16
|
+
* plain arrow, pointing the way the data travels. A reader who has learned
|
|
17
|
+
* that a fan means "many" is not asked to unlearn it here.
|
|
18
|
+
*/
|
|
19
|
+
export const MARKER_FLOW = "er-flow";
|
|
20
|
+
|
|
21
|
+
export function ErMarkers() {
|
|
22
|
+
return (
|
|
23
|
+
<svg
|
|
24
|
+
aria-hidden
|
|
25
|
+
width="0"
|
|
26
|
+
height="0"
|
|
27
|
+
style={{ position: "absolute", pointerEvents: "none" }}
|
|
28
|
+
>
|
|
29
|
+
<defs>
|
|
30
|
+
<marker
|
|
31
|
+
id={MARKER_MANY}
|
|
32
|
+
viewBox="0 0 12 12"
|
|
33
|
+
markerWidth="12"
|
|
34
|
+
markerHeight="12"
|
|
35
|
+
refX="0"
|
|
36
|
+
refY="6"
|
|
37
|
+
orient="auto"
|
|
38
|
+
markerUnits="userSpaceOnUse"
|
|
39
|
+
>
|
|
40
|
+
<path
|
|
41
|
+
d="M0 1 L11 6 M0 6 L11 6 M0 11 L11 6"
|
|
42
|
+
fill="none"
|
|
43
|
+
stroke="context-stroke"
|
|
44
|
+
strokeWidth="1"
|
|
45
|
+
/>
|
|
46
|
+
</marker>
|
|
47
|
+
<marker
|
|
48
|
+
id={MARKER_FLOW}
|
|
49
|
+
viewBox="0 0 12 12"
|
|
50
|
+
markerWidth="9"
|
|
51
|
+
markerHeight="9"
|
|
52
|
+
refX="9"
|
|
53
|
+
refY="6"
|
|
54
|
+
orient="auto"
|
|
55
|
+
markerUnits="userSpaceOnUse"
|
|
56
|
+
>
|
|
57
|
+
<path d="M1 2 L9 6 L1 10 Z" fill="context-stroke" stroke="none" />
|
|
58
|
+
</marker>
|
|
59
|
+
<marker
|
|
60
|
+
id={MARKER_ONE}
|
|
61
|
+
viewBox="0 0 12 12"
|
|
62
|
+
markerWidth="12"
|
|
63
|
+
markerHeight="12"
|
|
64
|
+
refX="12"
|
|
65
|
+
refY="6"
|
|
66
|
+
orient="auto"
|
|
67
|
+
markerUnits="userSpaceOnUse"
|
|
68
|
+
>
|
|
69
|
+
<path
|
|
70
|
+
d="M7 2 L7 10"
|
|
71
|
+
fill="none"
|
|
72
|
+
stroke="context-stroke"
|
|
73
|
+
strokeWidth="1.2"
|
|
74
|
+
/>
|
|
75
|
+
</marker>
|
|
76
|
+
</defs>
|
|
77
|
+
</svg>
|
|
78
|
+
);
|
|
79
|
+
}
|