@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,398 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"path/filepath"
|
|
6
|
+
"regexp"
|
|
7
|
+
"strings"
|
|
8
|
+
|
|
9
|
+
"github.com/pgplex/pgparser/nodes"
|
|
10
|
+
pgsql "github.com/pgplex/pgparser/parser"
|
|
11
|
+
"github.com/shortlink-org/portolan/plugin"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
// The same fact read out of a repository written in TypeScript, where the
|
|
15
|
+
// statement and its arguments sit side by side in one call:
|
|
16
|
+
//
|
|
17
|
+
// client.query(
|
|
18
|
+
// "INSERT INTO baskets (id, token, customer_id, touched_at) VALUES ($1, $2, $3, $4)",
|
|
19
|
+
// [basket.id, basket.token, basket.customerId, basket.touchedAt.toISOString()],
|
|
20
|
+
// )
|
|
21
|
+
//
|
|
22
|
+
// There is no parser for the language here, and none is needed for this
|
|
23
|
+
// shape: the statement is a string literal, the arguments are an array
|
|
24
|
+
// literal right after it, and each argument is a property chain from the
|
|
25
|
+
// aggregate - possibly wrapped in one conversion. Anything else is left
|
|
26
|
+
// unmapped, for the same reason as in the Go reader: a blank is a reader
|
|
27
|
+
// looking the column up, a wrong one is a reader believing something untrue.
|
|
28
|
+
func readMapsTS(root, repositoryDir, aggregate string, b *plugin.Builder) map[string]map[string]string {
|
|
29
|
+
out := map[string]map[string]string{}
|
|
30
|
+
dir := mapSourceDir(root, repositoryDir, aggregate)
|
|
31
|
+
entries, err := os.ReadDir(filepath.Join(root, filepath.FromSlash(dir)))
|
|
32
|
+
if err != nil {
|
|
33
|
+
return out
|
|
34
|
+
}
|
|
35
|
+
root_ := title(aggregate)
|
|
36
|
+
|
|
37
|
+
for _, entry := range entries {
|
|
38
|
+
name := entry.Name()
|
|
39
|
+
if entry.IsDir() || !strings.HasSuffix(name, ".ts") || strings.HasSuffix(name, ".test.ts") || strings.HasSuffix(name, ".d.ts") {
|
|
40
|
+
continue
|
|
41
|
+
}
|
|
42
|
+
source, err := os.ReadFile(filepath.Join(root, filepath.FromSlash(dir), name))
|
|
43
|
+
if err != nil {
|
|
44
|
+
continue
|
|
45
|
+
}
|
|
46
|
+
roots := rootVarsTS(string(source), root_)
|
|
47
|
+
aliases := loopAliasesTS(string(source))
|
|
48
|
+
for _, stmt := range insertCalls(string(source)) {
|
|
49
|
+
table, columns, values := parseInsert(stmt.sql)
|
|
50
|
+
if table == "" {
|
|
51
|
+
continue
|
|
52
|
+
}
|
|
53
|
+
mapped := out[table]
|
|
54
|
+
if mapped == nil {
|
|
55
|
+
mapped = map[string]string{}
|
|
56
|
+
out[table] = mapped
|
|
57
|
+
}
|
|
58
|
+
numbers := placeholderNumbers(stmt.sql)
|
|
59
|
+
if numbers == nil || countParams(values) != len(numbers) {
|
|
60
|
+
if countParams(values) > 0 {
|
|
61
|
+
b.Warn(table, "the insert into "+table+" has placeholders this reader cannot number; its columns are left unmapped")
|
|
62
|
+
}
|
|
63
|
+
continue
|
|
64
|
+
}
|
|
65
|
+
seen := 0
|
|
66
|
+
for i, column := range columns {
|
|
67
|
+
if i >= len(values) {
|
|
68
|
+
break
|
|
69
|
+
}
|
|
70
|
+
if _, ok := values[i].(*nodes.ParamRef); !ok {
|
|
71
|
+
continue
|
|
72
|
+
}
|
|
73
|
+
number := numbers[seen]
|
|
74
|
+
seen++
|
|
75
|
+
if number < 1 || number > len(stmt.args) {
|
|
76
|
+
b.Warn(table, "the insert refers to $"+itoa(number)+" but the call passes "+itoa(len(stmt.args))+" values; "+column+" is left unmapped")
|
|
77
|
+
continue
|
|
78
|
+
}
|
|
79
|
+
field := fieldOfTS(stmt.args[number-1], roots, aliases)
|
|
80
|
+
if field == "" {
|
|
81
|
+
continue
|
|
82
|
+
}
|
|
83
|
+
mapped[column] = root_ + "." + field
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return out
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// tsInsert is one statement and the array of arguments written after it.
|
|
92
|
+
type tsInsert struct {
|
|
93
|
+
sql string
|
|
94
|
+
args []string
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// insertCalls walks the source one character at a time, because a string
|
|
98
|
+
// literal can only be found by reading from its opening quote to its closing
|
|
99
|
+
// one: a pattern that skips ahead to the next quote it likes will start in
|
|
100
|
+
// one literal and end in another, and read the code between them as SQL.
|
|
101
|
+
// Comments are stepped over the same way. A literal that holds an INSERT and
|
|
102
|
+
// is followed by a comma and an array is a statement with its arguments.
|
|
103
|
+
func insertCalls(source string) []tsInsert {
|
|
104
|
+
var out []tsInsert
|
|
105
|
+
for i := 0; i < len(source); i++ {
|
|
106
|
+
c := source[i]
|
|
107
|
+
switch {
|
|
108
|
+
case c == '/' && i+1 < len(source) && source[i+1] == '/':
|
|
109
|
+
for i < len(source) && source[i] != '\n' {
|
|
110
|
+
i++
|
|
111
|
+
}
|
|
112
|
+
case c == '/' && i+1 < len(source) && source[i+1] == '*':
|
|
113
|
+
end := strings.Index(source[i+2:], "*/")
|
|
114
|
+
if end < 0 {
|
|
115
|
+
return out
|
|
116
|
+
}
|
|
117
|
+
i += 2 + end + 1
|
|
118
|
+
case c == '"' || c == '\'' || c == '`':
|
|
119
|
+
end := closingQuote(source, i)
|
|
120
|
+
if end < 0 {
|
|
121
|
+
return out
|
|
122
|
+
}
|
|
123
|
+
sql := source[i+1 : end]
|
|
124
|
+
i = end
|
|
125
|
+
j := skipSpace(source, end+1)
|
|
126
|
+
if j >= len(source) || source[j] != ',' {
|
|
127
|
+
continue
|
|
128
|
+
}
|
|
129
|
+
j = skipSpace(source, j+1)
|
|
130
|
+
if j >= len(source) || source[j] != '[' || !strings.Contains(strings.ToUpper(sql), "INSERT INTO") {
|
|
131
|
+
continue
|
|
132
|
+
}
|
|
133
|
+
close := matchingBracket(source, j)
|
|
134
|
+
if close < 0 {
|
|
135
|
+
continue
|
|
136
|
+
}
|
|
137
|
+
out = append(out, tsInsert{sql: sql, args: splitTopLevel(source[j+1 : close])})
|
|
138
|
+
i = close
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return out
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// closingQuote finds the quote that closes the one at open, stepping over
|
|
146
|
+
// escapes.
|
|
147
|
+
func closingQuote(source string, open int) int {
|
|
148
|
+
quote := source[open]
|
|
149
|
+
for i := open + 1; i < len(source); i++ {
|
|
150
|
+
switch source[i] {
|
|
151
|
+
case '\\':
|
|
152
|
+
i++
|
|
153
|
+
case quote:
|
|
154
|
+
return i
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return -1
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
func skipSpace(source string, i int) int {
|
|
162
|
+
for i < len(source) && (source[i] == ' ' || source[i] == '\t' || source[i] == '\n' || source[i] == '\r') {
|
|
163
|
+
i++
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return i
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// matchingBracket finds the `]` that closes the `[` at open, stepping over
|
|
170
|
+
// nested brackets, parentheses, braces and string literals.
|
|
171
|
+
func matchingBracket(source string, open int) int {
|
|
172
|
+
depth := 0
|
|
173
|
+
var quote byte
|
|
174
|
+
for i := open; i < len(source); i++ {
|
|
175
|
+
c := source[i]
|
|
176
|
+
if quote != 0 {
|
|
177
|
+
if c == '\\' {
|
|
178
|
+
i++
|
|
179
|
+
} else if c == quote {
|
|
180
|
+
quote = 0
|
|
181
|
+
}
|
|
182
|
+
continue
|
|
183
|
+
}
|
|
184
|
+
switch c {
|
|
185
|
+
case '"', '\'', '`':
|
|
186
|
+
quote = c
|
|
187
|
+
case '[', '(', '{':
|
|
188
|
+
depth++
|
|
189
|
+
case ']', ')', '}':
|
|
190
|
+
depth--
|
|
191
|
+
if depth == 0 {
|
|
192
|
+
return i
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return -1
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// splitTopLevel splits an argument list on the commas that are not inside a
|
|
201
|
+
// call, an object, an array or a string.
|
|
202
|
+
func splitTopLevel(list string) []string {
|
|
203
|
+
var out []string
|
|
204
|
+
depth := 0
|
|
205
|
+
var quote byte
|
|
206
|
+
start := 0
|
|
207
|
+
for i := 0; i < len(list); i++ {
|
|
208
|
+
c := list[i]
|
|
209
|
+
if quote != 0 {
|
|
210
|
+
if c == '\\' {
|
|
211
|
+
i++
|
|
212
|
+
} else if c == quote {
|
|
213
|
+
quote = 0
|
|
214
|
+
}
|
|
215
|
+
continue
|
|
216
|
+
}
|
|
217
|
+
switch c {
|
|
218
|
+
case '"', '\'', '`':
|
|
219
|
+
quote = c
|
|
220
|
+
case '[', '(', '{':
|
|
221
|
+
depth++
|
|
222
|
+
case ']', ')', '}':
|
|
223
|
+
depth--
|
|
224
|
+
case ',':
|
|
225
|
+
if depth == 0 {
|
|
226
|
+
out = append(out, strings.TrimSpace(list[start:i]))
|
|
227
|
+
start = i + 1
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if last := strings.TrimSpace(list[start:]); last != "" {
|
|
232
|
+
out = append(out, last)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return out
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
var tsChain = regexp.MustCompile(`^[A-Za-z_$][\w$]*(?:\??\.[A-Za-z_$][\w$]*)+$`)
|
|
239
|
+
|
|
240
|
+
// fieldOfTS follows an argument back to the field it carries, the way fieldOf
|
|
241
|
+
// does for Go: `basket.customerId` is customerId, `basket.touchedAt.toISOString()`
|
|
242
|
+
// is touchedAt, `nullable(basket.checkedOutAt)` is checkedOutAt. A bare name,
|
|
243
|
+
// a literal, a call that makes its own value - `randomUUID()`, `new Date()` -
|
|
244
|
+
// and a call over several values carry no field.
|
|
245
|
+
func fieldOfTS(expr string, roots map[string]bool, aliases map[string]string) string {
|
|
246
|
+
expr = strings.TrimSpace(expr)
|
|
247
|
+
// `basket.customerId ?? null` writes the field with a default for its
|
|
248
|
+
// absence; the column still carries the field.
|
|
249
|
+
if at := strings.LastIndex(expr, "??"); at >= 0 && tsLiteral.MatchString(strings.TrimSpace(expr[at+2:])) {
|
|
250
|
+
expr = strings.TrimSpace(expr[:at])
|
|
251
|
+
}
|
|
252
|
+
for strings.HasSuffix(expr, ")") {
|
|
253
|
+
open := openingParen(expr)
|
|
254
|
+
if open <= 0 {
|
|
255
|
+
return ""
|
|
256
|
+
}
|
|
257
|
+
callee, inner := expr[:open], expr[open+1:len(expr)-1]
|
|
258
|
+
args := splitTopLevel(inner)
|
|
259
|
+
switch {
|
|
260
|
+
case tsChain.MatchString(callee) && (len(args) == 0 || tsChain.MatchString(strings.TrimSuffix(callee[:strings.LastIndex(callee, ".")], "?"))):
|
|
261
|
+
// A method on the value: the value is the chain before it. With
|
|
262
|
+
// no arguments it is a conversion of the value - toISOString() -
|
|
263
|
+
// and with some it is still the value's own method when what it
|
|
264
|
+
// stands on is itself a chain: basket.items.slice(1) walks the
|
|
265
|
+
// items, where JSON.stringify(x) stands on a bare name and is
|
|
266
|
+
// the conversion read below.
|
|
267
|
+
expr = callee[:strings.LastIndex(callee, ".")]
|
|
268
|
+
expr = strings.TrimSuffix(expr, "?")
|
|
269
|
+
case len(args) == 1:
|
|
270
|
+
// A conversion wrapped round the value.
|
|
271
|
+
expr = strings.TrimSpace(args[0])
|
|
272
|
+
default:
|
|
273
|
+
return ""
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if !tsChain.MatchString(expr) {
|
|
277
|
+
return ""
|
|
278
|
+
}
|
|
279
|
+
parts := strings.Split(strings.ReplaceAll(expr, "?.", "."), ".")
|
|
280
|
+
if over, ok := aliases[parts[0]]; ok {
|
|
281
|
+
// The variable of a loop stands for one element of what it walks:
|
|
282
|
+
// `for (const item of basket.items)` makes item.sku items.sku. What
|
|
283
|
+
// is walked is read as an argument is, so a slice of the items is
|
|
284
|
+
// still the items. The alias is forgotten for the rest of the read,
|
|
285
|
+
// so that a loop written over its own name cannot stand for itself.
|
|
286
|
+
rest := make(map[string]string, len(aliases))
|
|
287
|
+
for name, chain := range aliases {
|
|
288
|
+
if name != parts[0] {
|
|
289
|
+
rest[name] = chain
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
head := fieldOfTS(over, roots, rest)
|
|
293
|
+
if head == "" {
|
|
294
|
+
return ""
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return strings.Join(append([]string{head}, parts[1:]...), ".")
|
|
298
|
+
}
|
|
299
|
+
if roots != nil && !roots[parts[0]] {
|
|
300
|
+
return ""
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return strings.Join(parts[1:], ".")
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// tsForOf is the head of a for-of loop, up to what it walks:
|
|
307
|
+
// `for (const item of `. What follows runs to the parenthesis that closes
|
|
308
|
+
// the loop's own, found by matching rather than by pattern because a slice
|
|
309
|
+
// or a filter carries parentheses of its own.
|
|
310
|
+
var tsForOf = regexp.MustCompile(`for\s*\(\s*(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s+of\s+`)
|
|
311
|
+
|
|
312
|
+
// loopAliasesTS reads every for-of loop of the file: the variable, and the
|
|
313
|
+
// expression it walks.
|
|
314
|
+
func loopAliasesTS(source string) map[string]string {
|
|
315
|
+
var aliases map[string]string
|
|
316
|
+
for _, m := range tsForOf.FindAllStringSubmatchIndex(source, -1) {
|
|
317
|
+
open := strings.IndexByte(source[m[0]:], '(') + m[0]
|
|
318
|
+
close := matchingBracket(source, open)
|
|
319
|
+
if close < 0 || close < m[1] {
|
|
320
|
+
continue
|
|
321
|
+
}
|
|
322
|
+
if aliases == nil {
|
|
323
|
+
aliases = map[string]string{}
|
|
324
|
+
}
|
|
325
|
+
aliases[source[m[2]:m[3]]] = strings.TrimSpace(source[m[1]:close])
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return aliases
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// tsLiteral is what may stand after `??` without changing which field the
|
|
332
|
+
// argument carries: nothing, or a constant.
|
|
333
|
+
var tsLiteral = regexp.MustCompile(`^(null|undefined|true|false|-?\d+(\.\d+)?|"[^"]*"|'[^']*')$`)
|
|
334
|
+
|
|
335
|
+
// tsParam is a name declared with the type after it: a parameter, a field, a
|
|
336
|
+
// variable. `route: Route` is the aggregate wherever it appears in the file.
|
|
337
|
+
var tsParam = regexp.MustCompile(`\b([A-Za-z_$][\w$]*)\??\s*:\s*([A-Za-z_$][\w$]*)\b`)
|
|
338
|
+
|
|
339
|
+
// rootVarsTS names the variables the file declares with the root's type, or
|
|
340
|
+
// nil when it declares none. Inside save(route: Route, ...) the aggregate is
|
|
341
|
+
// route and nothing else: the loop variable over its stops carries a stop's
|
|
342
|
+
// fields, and a column mapped from it onto the root would be a claim about
|
|
343
|
+
// the wrong type. A file that never names the type - a repository over a row
|
|
344
|
+
// type of its own - is read as before, any bare name standing for the root.
|
|
345
|
+
func rootVarsTS(source, root string) map[string]bool {
|
|
346
|
+
var roots map[string]bool
|
|
347
|
+
for _, m := range tsParam.FindAllStringSubmatch(source, -1) {
|
|
348
|
+
if m[2] != root {
|
|
349
|
+
continue
|
|
350
|
+
}
|
|
351
|
+
if roots == nil {
|
|
352
|
+
roots = map[string]bool{}
|
|
353
|
+
}
|
|
354
|
+
roots[m[1]] = true
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return roots
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// openingParen finds the `(` that the closing paren at the end of expr pairs
|
|
361
|
+
// with.
|
|
362
|
+
func openingParen(expr string) int {
|
|
363
|
+
depth := 0
|
|
364
|
+
for i := len(expr) - 1; i >= 0; i-- {
|
|
365
|
+
switch expr[i] {
|
|
366
|
+
case ')':
|
|
367
|
+
depth++
|
|
368
|
+
case '(':
|
|
369
|
+
depth--
|
|
370
|
+
if depth == 0 {
|
|
371
|
+
return i
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return -1
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// parseInsert reads the table, its column list and its values out of one
|
|
380
|
+
// INSERT statement.
|
|
381
|
+
func parseInsert(sql string) (string, []string, []nodes.Node) {
|
|
382
|
+
tree, err := pgsql.Parse(sql)
|
|
383
|
+
if err != nil || len(tree.Items) == 0 {
|
|
384
|
+
return "", nil, nil
|
|
385
|
+
}
|
|
386
|
+
insert, ok := tree.Items[0].(*nodes.InsertStmt)
|
|
387
|
+
if !ok || insert.Relation == nil {
|
|
388
|
+
return "", nil, nil
|
|
389
|
+
}
|
|
390
|
+
var columns []string
|
|
391
|
+
for _, item := range items(insert.Cols) {
|
|
392
|
+
if target, ok := item.(*nodes.ResTarget); ok {
|
|
393
|
+
columns = append(columns, target.Name)
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return relationName(insert.Relation), columns, insertValues(insert)
|
|
398
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"testing"
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
// The same rule as for Go, read off text: the chain from the aggregate, one
|
|
8
|
+
// conversion allowed round it, a method on the value stripped.
|
|
9
|
+
func TestFieldOfTSFollowsTheChainAndOneWrapper(t *testing.T) {
|
|
10
|
+
cases := map[string]string{
|
|
11
|
+
"basket.id": "id",
|
|
12
|
+
"basket.customerId": "customerId",
|
|
13
|
+
"basket.touchedAt.toISOString()": "touchedAt",
|
|
14
|
+
"basket.unitPrice?.amountMinor": "unitPrice.amountMinor",
|
|
15
|
+
"nullable(basket.checkedOutAt)": "checkedOutAt",
|
|
16
|
+
"String(basket.version)": "version",
|
|
17
|
+
"JSON.stringify(toWire(event))": "",
|
|
18
|
+
"randomUUID()": "",
|
|
19
|
+
"new Date()": "",
|
|
20
|
+
"combine(basket.a, basket.b)": "",
|
|
21
|
+
"TOPIC": "",
|
|
22
|
+
"'literal'": "",
|
|
23
|
+
"basket.items.slice(1)": "items",
|
|
24
|
+
"JSON.stringify(basket.shipTo)": "shipTo",
|
|
25
|
+
"basket.customerId ?? null": "customerId",
|
|
26
|
+
"basket.currency?.code ?? null": "currency.code",
|
|
27
|
+
"basket.version ?? 0": "version",
|
|
28
|
+
"basket.a ?? basket.b": "",
|
|
29
|
+
}
|
|
30
|
+
for in, want := range cases {
|
|
31
|
+
if got := fieldOfTS(in, nil, nil); got != want {
|
|
32
|
+
t.Errorf("fieldOfTS(%q) = %q, want %q", in, got, want)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Once the file says which name is the aggregate, only that name maps: the
|
|
38
|
+
// item of a loop over its lines is not the basket.
|
|
39
|
+
func TestFieldOfTSReadsOnlyTheRootWhenTheFileNamesIt(t *testing.T) {
|
|
40
|
+
roots := rootVarsTS("async save(basket: Basket, ...events: BasketEvent[]) { for (const item of basket.items) {} }", "Basket")
|
|
41
|
+
if !roots["basket"] || roots["events"] || roots["item"] {
|
|
42
|
+
t.Fatalf("roots = %v", roots)
|
|
43
|
+
}
|
|
44
|
+
cases := map[string]string{
|
|
45
|
+
"basket.id": "id",
|
|
46
|
+
"item.sku": "",
|
|
47
|
+
"item.quantity": "",
|
|
48
|
+
}
|
|
49
|
+
for in, want := range cases {
|
|
50
|
+
if got := fieldOfTS(in, roots, nil); got != want {
|
|
51
|
+
t.Errorf("fieldOfTS(%q) = %q, want %q", in, got, want)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if rootVarsTS("const rows = await pool.query<Row>(sql)", "Basket") != nil {
|
|
55
|
+
t.Error("a file that never names the root should leave every name open")
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// The variable of a for-of loop stands for one element of what it walks, so
|
|
60
|
+
// a column written from it carries a field of the elements of a field.
|
|
61
|
+
func TestFieldOfTSFollowsALoopVariable(t *testing.T) {
|
|
62
|
+
aliases := loopAliasesTS(`for (const item of basket.items) { for (const event of events) {} } for (const self of self.items) {}
|
|
63
|
+
for (const scan of basket.scans.slice(stored.rows[0]?.n ?? 0)) {}`)
|
|
64
|
+
if aliases["item"] != "basket.items" || aliases["event"] != "events" || aliases["self"] != "self.items" || aliases["scan"] != "basket.scans.slice(stored.rows[0]?.n ?? 0)" {
|
|
65
|
+
t.Fatalf("aliases = %v", aliases)
|
|
66
|
+
}
|
|
67
|
+
roots := map[string]bool{"basket": true}
|
|
68
|
+
cases := map[string]string{
|
|
69
|
+
"item.sku": "items.sku",
|
|
70
|
+
"item.unitPrice.currency.code": "items.unitPrice.currency.code",
|
|
71
|
+
"item.touchedAt.toISOString()": "items.touchedAt",
|
|
72
|
+
"scan.parcelId": "scans.parcelId",
|
|
73
|
+
"event.name": "",
|
|
74
|
+
"self.name": "",
|
|
75
|
+
}
|
|
76
|
+
for in, want := range cases {
|
|
77
|
+
if got := fieldOfTS(in, roots, aliases); got != want {
|
|
78
|
+
t.Errorf("fieldOfTS(%q) = %q, want %q", in, got, want)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
func TestMapsTSAgainstTheRealService(t *testing.T) {
|
|
84
|
+
b := builderFor(t)
|
|
85
|
+
mapped := readMapsTS("../../examples/shop/cart", "src/infrastructure/repository/basket", "basket", b)
|
|
86
|
+
|
|
87
|
+
want := map[string]map[string]string{
|
|
88
|
+
"baskets": {
|
|
89
|
+
"id": "Basket.id",
|
|
90
|
+
"token": "Basket.token",
|
|
91
|
+
"customer_id": "Basket.customerId",
|
|
92
|
+
"currency": "Basket.currency.code",
|
|
93
|
+
"status": "Basket.status",
|
|
94
|
+
"touched_at": "Basket.touchedAt",
|
|
95
|
+
},
|
|
96
|
+
"basket_items": {
|
|
97
|
+
"basket_id": "Basket.id",
|
|
98
|
+
"sku": "Basket.items.sku",
|
|
99
|
+
"quantity": "Basket.items.quantity",
|
|
100
|
+
"unit_price_minor": "Basket.items.unitPrice.amountMinor",
|
|
101
|
+
"currency": "Basket.items.unitPrice.currency.code",
|
|
102
|
+
},
|
|
103
|
+
}
|
|
104
|
+
for table, columns := range want {
|
|
105
|
+
for column, field := range columns {
|
|
106
|
+
if got := mapped[table][column]; got != field {
|
|
107
|
+
t.Errorf("%s.%s -> %q, want %q", table, column, got, field)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if len(mapped[table]) != len(columns) {
|
|
111
|
+
t.Errorf("%s: mapped %v, want exactly %v", table, mapped[table], columns)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
func TestInsertCallsPairAStatementWithItsArray(t *testing.T) {
|
|
117
|
+
source := `
|
|
118
|
+
await client.query("BEGIN"); // a literal before, which must not swallow what follows
|
|
119
|
+
await client.query(
|
|
120
|
+
"INSERT INTO baskets (id, token, version) VALUES ($1, $2, 1)",
|
|
121
|
+
[basket.id, basket.token],
|
|
122
|
+
);
|
|
123
|
+
const rows = await this.pool.query<Row>("SELECT * FROM baskets WHERE id = $1", [id]);
|
|
124
|
+
await client.query("INSERT INTO outbox (uuid, payload) VALUES ($1, $2)", [randomUUID(), JSON.stringify({ a: [1, 2] })]);
|
|
125
|
+
`
|
|
126
|
+
calls := insertCalls(source)
|
|
127
|
+
if len(calls) != 2 {
|
|
128
|
+
t.Fatalf("found %d inserts, want 2", len(calls))
|
|
129
|
+
}
|
|
130
|
+
if len(calls[0].args) != 2 || calls[0].args[1] != "basket.token" {
|
|
131
|
+
t.Fatalf("first insert args = %q", calls[0].args)
|
|
132
|
+
}
|
|
133
|
+
if len(calls[1].args) != 2 || calls[1].args[1] != "JSON.stringify({ a: [1, 2] })" {
|
|
134
|
+
t.Fatalf("second insert args = %q", calls[1].args)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "object",
|
|
3
|
+
"additionalProperties": false,
|
|
4
|
+
"properties": {
|
|
5
|
+
"context": {
|
|
6
|
+
"type": "string",
|
|
7
|
+
"description": "Slug of the bounded context that owns the service these migrations belong to. Defaults to the name of the input directory.",
|
|
8
|
+
"examples": ["auth"]
|
|
9
|
+
},
|
|
10
|
+
"service": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "Slug of the service that owns the database. A store belongs to exactly one service. Defaults to the name of the input directory.",
|
|
13
|
+
"examples": ["auth"]
|
|
14
|
+
},
|
|
15
|
+
"store": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "Slug of the database these migrations build. One service can keep state in more than one, and a slug is how the two are told apart. Give the go-domain extractor the same one.",
|
|
18
|
+
"default": "pg"
|
|
19
|
+
},
|
|
20
|
+
"name": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"description": "What the database is called on the page.",
|
|
23
|
+
"examples": ["Auth database"]
|
|
24
|
+
},
|
|
25
|
+
"kind": {
|
|
26
|
+
"enum": [
|
|
27
|
+
"postgres",
|
|
28
|
+
"mysql",
|
|
29
|
+
"sqlite",
|
|
30
|
+
"redis",
|
|
31
|
+
"mongodb",
|
|
32
|
+
"clickhouse",
|
|
33
|
+
"s3",
|
|
34
|
+
"other"
|
|
35
|
+
],
|
|
36
|
+
"description": "What kind of store it is.",
|
|
37
|
+
"default": "postgres"
|
|
38
|
+
},
|
|
39
|
+
"repositories": {
|
|
40
|
+
"type": "string",
|
|
41
|
+
"description": "Optional adapter root relative to the input root: either one package per aggregate with migrations below each package, or one feature repository package with migrations directly below it. When omitted, Go layouts are discovered under both internal/infrastructure/repository/<aggregate> and internal/<aggregate>/infrastructure/repository. The migrations and repository writes determine which aggregate and fields the tables persist."
|
|
42
|
+
},
|
|
43
|
+
"projectors": {
|
|
44
|
+
"type": "string",
|
|
45
|
+
"description": "Optional projector root relative to the input root, using the same collection-or-feature-package convention as repositories. When omitted, horizontal and feature-sliced Go projector packages are discovered. Every table created there gets the role projection. Its aggregate is read from a `-- aggregate: <id>` line above CREATE TABLE; columns copied from elsewhere carry `-- from:`."
|
|
46
|
+
},
|
|
47
|
+
"out": {
|
|
48
|
+
"type": "string",
|
|
49
|
+
"description": "Name of the fragment file, inside the step's output directory.",
|
|
50
|
+
"default": "stores.json"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
// Whose rows a projection is a picture of, when the migration says.
|
|
4
|
+
//
|
|
5
|
+
// A repository package names its aggregate by where it sits: the directory is
|
|
6
|
+
// the aggregate, and the first table it creates is the root. A projector
|
|
7
|
+
// package cannot say it that way. The projection is named after the question
|
|
8
|
+
// it answers, not after an aggregate, and the aggregate it is built from may
|
|
9
|
+
// belong to another service whose name appears nowhere in this tree.
|
|
10
|
+
//
|
|
11
|
+
// So it is declared, in the same form a copied column already uses, above the
|
|
12
|
+
// CREATE TABLE it speaks for:
|
|
13
|
+
//
|
|
14
|
+
// -- Planned stops, rebuilt from RoutePlanned.
|
|
15
|
+
// -- aggregate: shop.oms.order
|
|
16
|
+
// CREATE TABLE route_stops (
|
|
17
|
+
//
|
|
18
|
+
// A bare slug (`route`) is an aggregate of the service that owns the store and
|
|
19
|
+
// is spelled the way the repository layout would spell it: `price_list` is
|
|
20
|
+
// `price-list`. Anything with a dot in it is a full id and is taken as
|
|
21
|
+
// written. Other comment lines may sit between the note and the statement; a
|
|
22
|
+
// statement may not, and a note that reaches nothing is dropped.
|
|
23
|
+
|
|
24
|
+
import (
|
|
25
|
+
"regexp"
|
|
26
|
+
"strings"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
var aggregateComment = regexp.MustCompile(`(?i)^\s*--\s*aggregate:\s*(.+?)\s*$`)
|
|
30
|
+
|
|
31
|
+
// readProjected reads the `-- aggregate:` lines of one migration, as
|
|
32
|
+
// unqualified table name -> aggregate id.
|
|
33
|
+
func readProjected(sql, owner string) map[string]string {
|
|
34
|
+
out := map[string]string{}
|
|
35
|
+
pending := ""
|
|
36
|
+
|
|
37
|
+
for _, line := range strings.Split(sql, "\n") {
|
|
38
|
+
if found := aggregateComment.FindStringSubmatch(line); found != nil {
|
|
39
|
+
pending = aggregateID(found[1], owner)
|
|
40
|
+
|
|
41
|
+
continue
|
|
42
|
+
}
|
|
43
|
+
if found := createTable.FindStringSubmatch(line); found != nil {
|
|
44
|
+
if pending != "" {
|
|
45
|
+
out[unqualified(found[1])] = pending
|
|
46
|
+
}
|
|
47
|
+
pending = ""
|
|
48
|
+
|
|
49
|
+
continue
|
|
50
|
+
}
|
|
51
|
+
trimmed := strings.TrimSpace(line)
|
|
52
|
+
if trimmed == "" || strings.HasPrefix(trimmed, "--") {
|
|
53
|
+
continue
|
|
54
|
+
}
|
|
55
|
+
// Anything else is a statement, and the note was not about it.
|
|
56
|
+
pending = ""
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return out
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// aggregateID spells the note as an id: a bare slug belongs to the owner of the
|
|
63
|
+
// store, a dotted name is already one.
|
|
64
|
+
func aggregateID(note, owner string) string {
|
|
65
|
+
if strings.Contains(note, ".") {
|
|
66
|
+
return note
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return owner + "." + slug(note)
|
|
70
|
+
}
|