@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,126 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "object",
|
|
3
|
+
"additionalProperties": false,
|
|
4
|
+
"properties": {
|
|
5
|
+
"context": {
|
|
6
|
+
"type": "string",
|
|
7
|
+
"description": "Slug of the bounded context this service belongs to. Defaults to the name of the input directory.",
|
|
8
|
+
"examples": ["shop"]
|
|
9
|
+
},
|
|
10
|
+
"contextName": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "What the context is called on the page. Defaults to the slug, titled."
|
|
13
|
+
},
|
|
14
|
+
"contextSummary": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "A sentence or two on what the context is responsible for."
|
|
17
|
+
},
|
|
18
|
+
"classification": {
|
|
19
|
+
"enum": ["core", "supporting", "generic"],
|
|
20
|
+
"description": "Whether the context is core to the business, supports it, or is generic and could be bought."
|
|
21
|
+
},
|
|
22
|
+
"service": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "Slug of the service. Defaults to the name of the input directory.",
|
|
25
|
+
"examples": ["billing"]
|
|
26
|
+
},
|
|
27
|
+
"serviceName": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"description": "What the service is called on the page. Defaults to the title of its README, and failing that to the slug, titled."
|
|
30
|
+
},
|
|
31
|
+
"repo": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"description": "Where the source lives. Defaults to the repository url in pyproject.toml.",
|
|
34
|
+
"examples": ["github.com/shortlink-org/portolan"]
|
|
35
|
+
},
|
|
36
|
+
"store": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"description": "Slug of the database this service keeps its state in. Defaults from the kind of DATABASES['default'] when that setting is statically readable. The models are read as its schema, and a call into the ORM lands on its lane.",
|
|
39
|
+
"examples": ["pg"]
|
|
40
|
+
},
|
|
41
|
+
"storeName": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"description": "What the database is called on the page. Defaults to the service, titled, and the word database."
|
|
44
|
+
},
|
|
45
|
+
"storeKind": {
|
|
46
|
+
"enum": ["postgres", "mysql", "sqlite", "redis", "mongodb", "clickhouse", "s3", "other"],
|
|
47
|
+
"description": "Which database the models are the schema of. Read off DATABASES['default']['ENGINE'] in the settings module when left out; given here, it wins, and a disagreement with the settings is reported. It picks the column types a field becomes; only postgres has a mapping, and a kind without one keeps the field's own name and says so."
|
|
48
|
+
},
|
|
49
|
+
"apps": {
|
|
50
|
+
"type": "array",
|
|
51
|
+
"items": { "type": "string" },
|
|
52
|
+
"description": "The Django applications to read, as import packages, for a project that keeps them somewhere a models module would not be found. Every package holding one is read when this is left out.",
|
|
53
|
+
"examples": [["billing.invoices"]]
|
|
54
|
+
},
|
|
55
|
+
"aggregates": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"additionalProperties": { "type": "string" },
|
|
58
|
+
"description": "Which model is the root of an application's aggregate, as the application to the model. Only needed where the application is not named after its root - `invoices` finds `Invoice` on its own.",
|
|
59
|
+
"examples": [{ "invoices": "Invoice" }]
|
|
60
|
+
},
|
|
61
|
+
"peers": {
|
|
62
|
+
"type": "object",
|
|
63
|
+
"additionalProperties": { "type": "string" },
|
|
64
|
+
"description": "Which service answers for what this one calls, as the api id of the document vendored beside the client to the callee's service id. A client with no line here is called as unknown and its steps stay unresolved.",
|
|
65
|
+
"examples": [{ "pricing.v1": "shop.pricing" }]
|
|
66
|
+
},
|
|
67
|
+
"events": {
|
|
68
|
+
"type": "object",
|
|
69
|
+
"additionalProperties": { "type": "string" },
|
|
70
|
+
"description": "Which aggregate another service's events belong to, as the module a receiver imports the signal from to the aggregate id, so a policy reacting to a foreign event resolves.",
|
|
71
|
+
"examples": [{ "payments.events": "payments.ledger.payment" }]
|
|
72
|
+
},
|
|
73
|
+
"flowWrappers": {
|
|
74
|
+
"type": "object",
|
|
75
|
+
"additionalProperties": {
|
|
76
|
+
"type": "object",
|
|
77
|
+
"additionalProperties": false,
|
|
78
|
+
"properties": {
|
|
79
|
+
"label": {
|
|
80
|
+
"type": "string",
|
|
81
|
+
"description": "Business-facing label shown instead of expanding the wrapper's implementation. Defaults to the callable name, titled."
|
|
82
|
+
},
|
|
83
|
+
"target": {
|
|
84
|
+
"type": "string",
|
|
85
|
+
"description": "Service id the wrapper calls. Omit for a semantic operation inside this service."
|
|
86
|
+
},
|
|
87
|
+
"technical": {
|
|
88
|
+
"type": "boolean",
|
|
89
|
+
"default": false,
|
|
90
|
+
"description": "Collapse every call to this wrapper in one flow into one counted step."
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"description": "Project callables that form a meaningful flow boundary, keyed as module.function or module.Class.method. Their internals are replaced by one semantic step; technical wrappers are also deduplicated per flow.",
|
|
95
|
+
"examples": [{
|
|
96
|
+
"util.logger.send_log": { "label": "Record application log", "technical": true },
|
|
97
|
+
"mailer.client.send": { "label": "Send email", "target": "messaging.mailer" }
|
|
98
|
+
}]
|
|
99
|
+
},
|
|
100
|
+
"source": {
|
|
101
|
+
"type": "string",
|
|
102
|
+
"description": "The directory the applications are looked for in, relative to the input root.",
|
|
103
|
+
"default": "."
|
|
104
|
+
},
|
|
105
|
+
"settings": {
|
|
106
|
+
"type": "string",
|
|
107
|
+
"description": "The Django settings module Celery is configured from, as an import spells it, so an enqueue lands on the queue the routes give it. Defaults to what manage.py sets DJANGO_SETTINGS_MODULE to.",
|
|
108
|
+
"examples": ["config.settings"]
|
|
109
|
+
},
|
|
110
|
+
"out": {
|
|
111
|
+
"type": "string",
|
|
112
|
+
"description": "Name of the fragment file, inside the step's output directory.",
|
|
113
|
+
"default": "domain.json"
|
|
114
|
+
},
|
|
115
|
+
"storesOut": {
|
|
116
|
+
"type": "string",
|
|
117
|
+
"description": "Name of the fragment holding the database the models describe, inside the step's output directory. Written when store is set or inferred from DATABASES['default'].",
|
|
118
|
+
"default": "stores.json"
|
|
119
|
+
},
|
|
120
|
+
"openapiOut": {
|
|
121
|
+
"type": "string",
|
|
122
|
+
"description": "Name of the inferred OpenAPI 3.1 document, inside the step's output directory. Written when URLConf exposes HTTP operations.",
|
|
123
|
+
"default": "openapi.inferred.yaml"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"""Django URLConf, read without importing the project.
|
|
2
|
+
|
|
3
|
+
The runtime route table is assembled from ``path``/``re_path``, nested
|
|
4
|
+
``include`` calls and DRF routers. Importing it would execute settings and
|
|
5
|
+
application code, so this module follows the same declarations through the
|
|
6
|
+
AST instead. The result is deliberately the wire fact only: target view,
|
|
7
|
+
HTTP path and the URLConf line that declared it.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import ast
|
|
13
|
+
import re
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
from typing import Dict, List, Optional, Set, Tuple
|
|
16
|
+
|
|
17
|
+
from celery_conf import follow, settings_module_name, str_value
|
|
18
|
+
from source import Module, Project, const_str, dotted, keyword
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass(frozen=True)
|
|
22
|
+
class Route:
|
|
23
|
+
module: str
|
|
24
|
+
view: str
|
|
25
|
+
path: str
|
|
26
|
+
source: str
|
|
27
|
+
name: str = ""
|
|
28
|
+
router: bool = False
|
|
29
|
+
basename: str = ""
|
|
30
|
+
parameters: Tuple[Tuple[str, str], ...] = ()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class Routes:
|
|
35
|
+
root: Optional[Module]
|
|
36
|
+
entries: List[Route]
|
|
37
|
+
runtime_schema: str = ""
|
|
38
|
+
|
|
39
|
+
def for_view(self, module: str, view: str) -> List[Route]:
|
|
40
|
+
return [route for route in self.entries if route.module == module and route.view == view]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def read(project: Project, settings: str = "") -> Routes:
|
|
44
|
+
root = root_urlconf(project, settings)
|
|
45
|
+
if root is None:
|
|
46
|
+
return Routes(None, [])
|
|
47
|
+
entries: List[Route] = []
|
|
48
|
+
runtime_schema = ""
|
|
49
|
+
visit(project, root, "", (), entries, set())
|
|
50
|
+
for node in ast.walk(root.tree):
|
|
51
|
+
if isinstance(node, ast.Call) and dotted(node.func).split(".")[-1] in ("get_schema_view", "SpectacularAPIView"):
|
|
52
|
+
runtime_schema = root.where(node)
|
|
53
|
+
break
|
|
54
|
+
return Routes(root, entries, runtime_schema)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def root_urlconf(project: Project, settings: str = "") -> Optional[Module]:
|
|
58
|
+
settings_name = settings or settings_module_name(project)
|
|
59
|
+
module = project.module(settings_name) if settings_name else None
|
|
60
|
+
if module is not None:
|
|
61
|
+
for node in module.tree.body:
|
|
62
|
+
if not isinstance(node, (ast.Assign, ast.AnnAssign)):
|
|
63
|
+
continue
|
|
64
|
+
targets = node.targets if isinstance(node, ast.Assign) else [node.target]
|
|
65
|
+
if not any(isinstance(target, ast.Name) and target.id == "ROOT_URLCONF" for target in targets):
|
|
66
|
+
continue
|
|
67
|
+
value = node.value
|
|
68
|
+
name = str_value(follow(value, module), module)
|
|
69
|
+
if name and project.module(name) is not None:
|
|
70
|
+
return project.module(name)
|
|
71
|
+
package = settings_name.rsplit(".", 1)[0] if "." in settings_name else ""
|
|
72
|
+
if package and project.module(package + ".urls") is not None:
|
|
73
|
+
return project.module(package + ".urls")
|
|
74
|
+
|
|
75
|
+
# Conventional fallback for small projects whose settings are assembled
|
|
76
|
+
# dynamically: prefer a URLConf beside manage.py's package, otherwise the
|
|
77
|
+
# only non-application URLConf in the tree.
|
|
78
|
+
candidates = [m for m in project.modules.values() if m.dotted.endswith(".urls") or m.dotted == "urls"]
|
|
79
|
+
return candidates[0] if len(candidates) == 1 else None
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def visit(project: Project, module: Module, prefix: str, prefix_parameters: Tuple[Tuple[str, str], ...], out: List[Route], seen: Set[Tuple[str, str]]) -> None:
|
|
83
|
+
key = (module.dotted, prefix)
|
|
84
|
+
if key in seen:
|
|
85
|
+
return
|
|
86
|
+
seen.add(key)
|
|
87
|
+
|
|
88
|
+
for node in ast.walk(module.tree):
|
|
89
|
+
if not isinstance(node, ast.Call) or dotted(node.func).split(".")[-1] not in ("path", "re_path", "url"):
|
|
90
|
+
continue
|
|
91
|
+
if len(node.args) < 2:
|
|
92
|
+
continue
|
|
93
|
+
# An empty string is a route too: `path("", include("invoices.urls"))`
|
|
94
|
+
# mounts an application at the root, and `path("", index)` is the
|
|
95
|
+
# root itself. Only a pattern that is not a literal is skipped.
|
|
96
|
+
first = node.args[0]
|
|
97
|
+
if not (isinstance(first, ast.Constant) and isinstance(first.value, str)):
|
|
98
|
+
continue
|
|
99
|
+
fragment = first.value
|
|
100
|
+
regex = dotted(node.func).split(".")[-1] != "path"
|
|
101
|
+
path = join_path(prefix, fragment, regex)
|
|
102
|
+
parameters = prefix_parameters + route_parameters(fragment, regex)
|
|
103
|
+
target = node.args[1]
|
|
104
|
+
if isinstance(target, ast.Call) and dotted(target.func).split(".")[-1] == "include":
|
|
105
|
+
included = include_module(project, module, target)
|
|
106
|
+
if included is not None:
|
|
107
|
+
visit(project, included, path, parameters, out, seen)
|
|
108
|
+
continue
|
|
109
|
+
resolved = view_target(project, module, target)
|
|
110
|
+
if resolved is None:
|
|
111
|
+
continue
|
|
112
|
+
target_module, view = resolved
|
|
113
|
+
out.append(Route(target_module, view, path, module.where(node), const_str(keyword(node, "name")), parameters=parameters))
|
|
114
|
+
|
|
115
|
+
# ``urlpatterns = router.urls`` contributes routes without a path() call.
|
|
116
|
+
# Each registration is mounted at every prefix by which this URLConf was
|
|
117
|
+
# reached from the root.
|
|
118
|
+
for node in ast.walk(module.tree):
|
|
119
|
+
if not isinstance(node, ast.Call) or dotted(node.func).split(".")[-1] != "register" or len(node.args) < 2:
|
|
120
|
+
continue
|
|
121
|
+
route_prefix = const_str(node.args[0]).strip("^/$")
|
|
122
|
+
resolved = view_target(project, module, node.args[1])
|
|
123
|
+
if not route_prefix or resolved is None:
|
|
124
|
+
continue
|
|
125
|
+
target_module, view = resolved
|
|
126
|
+
basename = const_str(keyword(node, "basename")) or route_prefix.replace("/", "_")
|
|
127
|
+
out.append(Route(target_module, view, join_path(prefix, route_prefix + "/"), module.where(node), router=True, basename=basename, parameters=prefix_parameters))
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def route_parameters(fragment: str, regex: bool = False) -> Tuple[Tuple[str, str], ...]:
|
|
131
|
+
if regex:
|
|
132
|
+
return tuple((match.group(1), "str") for match in re.finditer(r"\(\?P<([A-Za-z_][A-Za-z0-9_]*)>[^)]+\)", fragment))
|
|
133
|
+
return tuple(
|
|
134
|
+
(match.group(2), match.group(1) or "str")
|
|
135
|
+
for match in re.finditer(r"<(?:(str|int|slug|uuid|path):)?([A-Za-z_][A-Za-z0-9_]*)>", fragment)
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def include_module(project: Project, module: Module, call: ast.Call) -> Optional[Module]:
|
|
140
|
+
if not call.args:
|
|
141
|
+
return None
|
|
142
|
+
value = call.args[0]
|
|
143
|
+
if isinstance(value, (ast.Tuple, ast.List)) and value.elts:
|
|
144
|
+
value = value.elts[0]
|
|
145
|
+
name = const_str(value)
|
|
146
|
+
if name:
|
|
147
|
+
return project.module(name)
|
|
148
|
+
resolved = imported_name(project, module, dotted(value))
|
|
149
|
+
return project.module(resolved) if resolved else None
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def view_target(project: Project, module: Module, node: ast.AST) -> Optional[Tuple[str, str]]:
|
|
153
|
+
# Decorators and ``SomeView().as_view()`` wrap the same target. Peeling
|
|
154
|
+
# calls is safe here because only names are read; nothing is executed.
|
|
155
|
+
while isinstance(node, ast.Call):
|
|
156
|
+
name = dotted(node.func)
|
|
157
|
+
if name.endswith(".as_view"):
|
|
158
|
+
node = node.func.value # type: ignore[union-attr]
|
|
159
|
+
continue
|
|
160
|
+
if node.args and name.split(".")[-1] in ("csrf_exempt", "login_required", "permission_required"):
|
|
161
|
+
node = node.args[0]
|
|
162
|
+
continue
|
|
163
|
+
if isinstance(node.func, ast.Attribute) and node.func.attr == "as_view":
|
|
164
|
+
node = node.func.value
|
|
165
|
+
continue
|
|
166
|
+
break
|
|
167
|
+
name = dotted(node)
|
|
168
|
+
if not name:
|
|
169
|
+
return None
|
|
170
|
+
parts = name.split(".")
|
|
171
|
+
resolved = imported_name(project, module, name)
|
|
172
|
+
if resolved:
|
|
173
|
+
parts = resolved.split(".")
|
|
174
|
+
for end in range(len(parts) - 1, 0, -1):
|
|
175
|
+
target_module = ".".join(parts[:end])
|
|
176
|
+
if project.module(target_module) is not None:
|
|
177
|
+
return target_module, ".".join(parts[end:])
|
|
178
|
+
if len(parts) == 1:
|
|
179
|
+
return module.dotted, parts[0]
|
|
180
|
+
return None
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def imported_name(project: Project, module: Module, name: str) -> str:
|
|
184
|
+
parts = name.split(".")
|
|
185
|
+
imported = module.imports.get(parts[0])
|
|
186
|
+
if imported is None:
|
|
187
|
+
return name if project.module(".".join(parts[:-1])) is not None else ""
|
|
188
|
+
base = imported.module
|
|
189
|
+
if imported.name != "*":
|
|
190
|
+
base = ".".join(part for part in (base, imported.name) if part)
|
|
191
|
+
rest = parts[1:]
|
|
192
|
+
# ``from avia.views import booking`` names the submodule
|
|
193
|
+
# ``avia.views.booking``; ``from .views import View`` names the class in
|
|
194
|
+
# ``app.views``. Prefer the longest prefix that is an actual module.
|
|
195
|
+
candidates = []
|
|
196
|
+
combined = [part for part in base.split(".") if part] + rest
|
|
197
|
+
for end in range(len(combined), 0, -1):
|
|
198
|
+
prefix = ".".join(combined[:end])
|
|
199
|
+
if project.module(prefix) is not None:
|
|
200
|
+
candidates.append(prefix + ("." + ".".join(combined[end:]) if combined[end:] else ""))
|
|
201
|
+
return candidates[0] if candidates else ".".join(combined)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def join_path(prefix: str, fragment: str, regex: bool = False) -> str:
|
|
205
|
+
value = fragment
|
|
206
|
+
if regex:
|
|
207
|
+
value = value.removeprefix("^").removesuffix("$")
|
|
208
|
+
value = re.sub(r"\(\?P<([A-Za-z_][A-Za-z0-9_]*)>[^)]+\)", r"{\1}", value)
|
|
209
|
+
value = value.replace("\\/", "/")
|
|
210
|
+
value = re.sub(r"\\[AbZ]", "", value)
|
|
211
|
+
value = re.sub(r"<(?:(?:str|int|slug|uuid|path):)?([A-Za-z_][A-Za-z0-9_]*)>", r"{\1}", value)
|
|
212
|
+
joined = "/".join(part.strip("/") for part in (prefix, value) if part.strip("/"))
|
|
213
|
+
trailing = value.endswith("/")
|
|
214
|
+
return "/" + joined + ("/" if trailing and joined else "")
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import tempfile
|
|
4
|
+
import unittest
|
|
5
|
+
|
|
6
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
7
|
+
sys.path.insert(1, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "pyplugin"))
|
|
8
|
+
|
|
9
|
+
import apps # noqa: E402
|
|
10
|
+
import routing # noqa: E402
|
|
11
|
+
import serializers # noqa: E402
|
|
12
|
+
import transport # noqa: E402
|
|
13
|
+
from extract import http_contracts, openapi_document, routed_applications # noqa: E402
|
|
14
|
+
from protocol import Builder # noqa: E402
|
|
15
|
+
from source import Project # noqa: E402
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class StaticRoutes(unittest.TestCase):
|
|
19
|
+
def setUp(self):
|
|
20
|
+
self.holder = tempfile.TemporaryDirectory(prefix="portolan-django-routes-")
|
|
21
|
+
root = self.holder.name
|
|
22
|
+
files = {
|
|
23
|
+
"manage.py": 'os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")\n',
|
|
24
|
+
"config/settings.py": 'ROOT_URLCONF = "config.urls"\n',
|
|
25
|
+
"config/urls.py": '''
|
|
26
|
+
from django.urls import include, path
|
|
27
|
+
from drf_yasg.views import get_schema_view
|
|
28
|
+
schema_view = get_schema_view()
|
|
29
|
+
urlpatterns = [
|
|
30
|
+
path("api/v2/", include("orders.urls")),
|
|
31
|
+
path("health/", include("health.urls")),
|
|
32
|
+
path("", include("home.urls")),
|
|
33
|
+
path("swagger/", schema_view.with_ui("swagger")),
|
|
34
|
+
]
|
|
35
|
+
''',
|
|
36
|
+
"home/urls.py": '''
|
|
37
|
+
from django.urls import path
|
|
38
|
+
from .views import Home
|
|
39
|
+
urlpatterns = [path("", Home.as_view()), path("about/", Home.as_view())]
|
|
40
|
+
''',
|
|
41
|
+
"home/views.py": '''
|
|
42
|
+
from rest_framework.views import APIView
|
|
43
|
+
class Home(APIView):
|
|
44
|
+
def get(self, request):
|
|
45
|
+
return None
|
|
46
|
+
''',
|
|
47
|
+
"health/urls.py": '''
|
|
48
|
+
from django.urls import path
|
|
49
|
+
from .views import Ready
|
|
50
|
+
urlpatterns = [path("ready/", Ready.as_view())]
|
|
51
|
+
''',
|
|
52
|
+
"health/views.py": '''
|
|
53
|
+
from rest_framework.views import APIView
|
|
54
|
+
class Ready(APIView):
|
|
55
|
+
def get(self, request):
|
|
56
|
+
return None
|
|
57
|
+
''',
|
|
58
|
+
"orders/models.py": '''
|
|
59
|
+
from django.db import models
|
|
60
|
+
class Order(models.Model):
|
|
61
|
+
active = models.BooleanField(default=True)
|
|
62
|
+
''',
|
|
63
|
+
"orders/serializers.py": '''
|
|
64
|
+
from rest_framework import serializers
|
|
65
|
+
from .models import Order
|
|
66
|
+
class OrderSerializer(serializers.ModelSerializer):
|
|
67
|
+
class Meta:
|
|
68
|
+
model = Order
|
|
69
|
+
fields = ("active",)
|
|
70
|
+
''',
|
|
71
|
+
"orders/views.py": '''
|
|
72
|
+
from rest_framework import generics, viewsets
|
|
73
|
+
from rest_framework.views import APIView
|
|
74
|
+
from .models import Order
|
|
75
|
+
from .serializers import OrderSerializer
|
|
76
|
+
|
|
77
|
+
class OrderList(generics.ListCreateAPIView):
|
|
78
|
+
queryset = Order.objects.filter(active=True)
|
|
79
|
+
serializer_class = OrderSerializer
|
|
80
|
+
|
|
81
|
+
class OrderDetail(APIView):
|
|
82
|
+
def get(self, request):
|
|
83
|
+
"""Read an order."""
|
|
84
|
+
pass
|
|
85
|
+
def delete(self, request):
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
class OrderViewSet(viewsets.ModelViewSet):
|
|
89
|
+
serializer_class = OrderSerializer
|
|
90
|
+
|
|
91
|
+
class Health:
|
|
92
|
+
def get(request):
|
|
93
|
+
pass
|
|
94
|
+
|
|
95
|
+
class Maintenance:
|
|
96
|
+
@classmethod
|
|
97
|
+
def fetch(cls, request):
|
|
98
|
+
return None
|
|
99
|
+
''',
|
|
100
|
+
"orders/urls.py": '''
|
|
101
|
+
from django.urls import path, re_path
|
|
102
|
+
from rest_framework.routers import DefaultRouter
|
|
103
|
+
from .views import Health, Maintenance, OrderDetail, OrderList, OrderViewSet
|
|
104
|
+
|
|
105
|
+
router = DefaultRouter()
|
|
106
|
+
router.register("orders", OrderViewSet, basename="order")
|
|
107
|
+
urlpatterns = [
|
|
108
|
+
path("manual/", OrderList.as_view(), name="order-list"),
|
|
109
|
+
path("manual/<uuid:pk>/", OrderDetail.as_view(), name="order-detail"),
|
|
110
|
+
re_path(r"^health/(?P<region>[^/]+)/$", Health.get),
|
|
111
|
+
path("maintenance/fetch", Maintenance.fetch),
|
|
112
|
+
] + router.urls
|
|
113
|
+
''',
|
|
114
|
+
}
|
|
115
|
+
for name, contents in files.items():
|
|
116
|
+
path = os.path.join(root, name)
|
|
117
|
+
directory = os.path.dirname(path)
|
|
118
|
+
if directory:
|
|
119
|
+
os.makedirs(directory, exist_ok=True)
|
|
120
|
+
with open(path, "w", encoding="utf-8") as handle:
|
|
121
|
+
handle.write(contents)
|
|
122
|
+
self.project = Project(root, root, lambda path: os.path.relpath(path, root).replace(os.sep, "/"))
|
|
123
|
+
|
|
124
|
+
def tearDown(self):
|
|
125
|
+
self.holder.cleanup()
|
|
126
|
+
|
|
127
|
+
def test_nested_includes_direct_views_regexes_and_runtime_swagger(self):
|
|
128
|
+
routes = routing.read(self.project)
|
|
129
|
+
self.assertEqual(routes.root.dotted, "config.urls")
|
|
130
|
+
self.assertEqual(routes.runtime_schema, "config/urls.py:4")
|
|
131
|
+
paths = {(route.view, route.path) for route in routes.entries}
|
|
132
|
+
self.assertIn(("OrderList", "/api/v2/manual/"), paths)
|
|
133
|
+
self.assertIn(("OrderDetail", "/api/v2/manual/{pk}/"), paths)
|
|
134
|
+
self.assertIn(("Health.get", "/api/v2/health/{region}/"), paths)
|
|
135
|
+
self.assertIn(("OrderViewSet", "/api/v2/orders/"), paths)
|
|
136
|
+
self.assertIn(("Ready", "/health/ready/"), paths)
|
|
137
|
+
# A root mount is the commonest way to include an application, and the
|
|
138
|
+
# empty prefix must not be read as "no route".
|
|
139
|
+
self.assertIn(("Home", "/"), paths)
|
|
140
|
+
self.assertIn(("Home", "/about/"), paths)
|
|
141
|
+
detail = next(route for route in routes.entries if route.view == "OrderDetail")
|
|
142
|
+
self.assertEqual(dict(detail.parameters), {"pk": "uuid"})
|
|
143
|
+
|
|
144
|
+
def test_drf_generic_and_router_methods_become_http_operations(self):
|
|
145
|
+
routes = routing.read(self.project)
|
|
146
|
+
app = apps.discover(self.project, ["orders"])[0]
|
|
147
|
+
endpoints = transport.read_endpoints(app, Builder(), routes)
|
|
148
|
+
http = {(item.verb, item.path) for item in endpoints}
|
|
149
|
+
self.assertIn(("GET", "/api/v2/manual/"), http)
|
|
150
|
+
self.assertIn(("POST", "/api/v2/manual/"), http)
|
|
151
|
+
self.assertIn(("GET", "/api/v2/manual/{pk}/"), http)
|
|
152
|
+
self.assertIn(("DELETE", "/api/v2/manual/{pk}/"), http)
|
|
153
|
+
self.assertIn(("GET", "/api/v2/orders/"), http)
|
|
154
|
+
self.assertIn(("POST", "/api/v2/orders/"), http)
|
|
155
|
+
self.assertIn(("GET", "/api/v2/orders/{id}/"), http)
|
|
156
|
+
self.assertIn(("PATCH", "/api/v2/orders/{id}/"), http)
|
|
157
|
+
self.assertIn(("GET", "/api/v2/health/{region}/"), http)
|
|
158
|
+
flow_only = next(item for item in endpoints if item.view == "Maintenance" and item.action == "fetch")
|
|
159
|
+
self.assertEqual((flow_only.verb, flow_only.path), ("", "/api/v2/maintenance/fetch"))
|
|
160
|
+
detail = next(item for item in endpoints if item.verb == "GET" and item.path.endswith("manual/{pk}/"))
|
|
161
|
+
self.assertEqual(detail.path_parameters, {"pk": "uuid"})
|
|
162
|
+
spec = openapi_document([(app, item) for item in endpoints], "Orders", Builder())
|
|
163
|
+
parameter = spec["paths"]["/api/v2/manual/{pk}/"]["get"]["parameters"][0]
|
|
164
|
+
self.assertEqual(parameter["schema"], {"type": "string", "format": "uuid"})
|
|
165
|
+
|
|
166
|
+
def test_queryset_and_serializer_metadata_resolve_the_inherited_action_model(self):
|
|
167
|
+
routes = routing.read(self.project)
|
|
168
|
+
app = apps.discover(self.project, ["orders"])[0]
|
|
169
|
+
endpoints = transport.read_endpoints(app, Builder(), routes)
|
|
170
|
+
registry = serializers.read(self.project, [app])
|
|
171
|
+
list_endpoint = next(item for item in endpoints if item.view == "OrderList" and item.action == "list")
|
|
172
|
+
create_endpoint = next(item for item in endpoints if item.view == "OrderViewSet" and item.action == "create")
|
|
173
|
+
self.assertEqual(registry.model_for_endpoint(list_endpoint).name, "Order")
|
|
174
|
+
self.assertEqual(registry.model_for_endpoint(create_endpoint).name, "Order")
|
|
175
|
+
|
|
176
|
+
def test_stateless_routed_app_still_contributes_an_http_interface(self):
|
|
177
|
+
routes = routing.read(self.project)
|
|
178
|
+
model_apps = apps.discover(self.project, [])
|
|
179
|
+
endpoint_apps = routed_applications(self.project, model_apps, routes)
|
|
180
|
+
self.assertEqual([app.dotted for app in endpoint_apps], ["health", "home", "orders"])
|
|
181
|
+
endpoints = []
|
|
182
|
+
for app in endpoint_apps:
|
|
183
|
+
endpoints += [(app, endpoint) for endpoint in transport.read_endpoints(app, Builder(), routes)]
|
|
184
|
+
contracts = http_contracts(endpoints, "shop.billing", "billing/portolan/openapi.inferred.yaml")
|
|
185
|
+
health = [contract for contract in contracts if contract["id"] == "shop.billing.health"][0]
|
|
186
|
+
self.assertEqual(health["methods"], [{"name": "health_ready_get", "http": {"method": "GET", "path": "/health/ready/"}}])
|
|
187
|
+
home = [contract for contract in contracts if contract["id"] == "shop.billing.home"][0]
|
|
188
|
+
self.assertEqual(
|
|
189
|
+
home["methods"],
|
|
190
|
+
[
|
|
191
|
+
{"name": "about_get", "http": {"method": "GET", "path": "/about/"}},
|
|
192
|
+
{"name": "home_get", "http": {"method": "GET", "path": "/"}},
|
|
193
|
+
],
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
if __name__ == "__main__":
|
|
198
|
+
unittest.main()
|