@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,285 @@
|
|
|
1
|
+
"""The tree, read as syntax.
|
|
2
|
+
|
|
3
|
+
The project is never imported: `django.setup()` runs the code it finds, reads
|
|
4
|
+
the environment and opens sockets, and an extractor that does any of those is
|
|
5
|
+
no longer a pure function of the tree. Everything here is `ast`, and names are
|
|
6
|
+
resolved by import and by file, the way `extract-ts` resolves them without a
|
|
7
|
+
type checker.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import ast
|
|
13
|
+
import os
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
from typing import Dict, Iterator, List, Optional, Tuple
|
|
16
|
+
|
|
17
|
+
# Directories that hold no claim about the model: someone else's code, a build,
|
|
18
|
+
# a history of the schema rather than the schema, and the tests.
|
|
19
|
+
SKIP = {
|
|
20
|
+
".git",
|
|
21
|
+
".mypy_cache",
|
|
22
|
+
".pytest_cache",
|
|
23
|
+
".ruff_cache",
|
|
24
|
+
".tox",
|
|
25
|
+
".venv",
|
|
26
|
+
"__pycache__",
|
|
27
|
+
"build",
|
|
28
|
+
"dist",
|
|
29
|
+
"env",
|
|
30
|
+
"migrations",
|
|
31
|
+
"node_modules",
|
|
32
|
+
"site-packages",
|
|
33
|
+
"static",
|
|
34
|
+
"templates",
|
|
35
|
+
"tests",
|
|
36
|
+
"venv",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class Import:
|
|
42
|
+
"""A name a module can see, and where it came from."""
|
|
43
|
+
|
|
44
|
+
module: str # dotted, as the project spells it: "invoices.events"
|
|
45
|
+
name: str # the name in that module, "*" for `import x`
|
|
46
|
+
line: int = 0
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass
|
|
50
|
+
class Module:
|
|
51
|
+
path: str # absolute
|
|
52
|
+
rel: str # relative to the working directory, forward slashes
|
|
53
|
+
dotted: str # "invoices.models"
|
|
54
|
+
tree: ast.Module
|
|
55
|
+
imports: Dict[str, Import] = field(default_factory=dict)
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def package(self) -> str:
|
|
59
|
+
return self.dotted.rsplit(".", 1)[0] if "." in self.dotted else ""
|
|
60
|
+
|
|
61
|
+
def where(self, node: ast.AST) -> str:
|
|
62
|
+
return "%s:%d" % (self.rel, getattr(node, "lineno", 0))
|
|
63
|
+
|
|
64
|
+
def classes(self) -> List[ast.ClassDef]:
|
|
65
|
+
return [n for n in self.tree.body if isinstance(n, ast.ClassDef)]
|
|
66
|
+
|
|
67
|
+
def functions(self) -> List[ast.FunctionDef]:
|
|
68
|
+
return [n for n in self.tree.body if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef))]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class Project:
|
|
72
|
+
"""Every module under the source root, by its dotted name."""
|
|
73
|
+
|
|
74
|
+
def __init__(self, root: str, source: str, rel):
|
|
75
|
+
self.root = root
|
|
76
|
+
self.source = source
|
|
77
|
+
self.rel = rel
|
|
78
|
+
self.modules: Dict[str, Module] = {}
|
|
79
|
+
self.broken: List[Tuple[str, str]] = []
|
|
80
|
+
self._load()
|
|
81
|
+
|
|
82
|
+
def _load(self) -> None:
|
|
83
|
+
for path in walk(self.source):
|
|
84
|
+
dotted = dotted_name(self.source, path)
|
|
85
|
+
try:
|
|
86
|
+
tree = ast.parse(read(path), filename=path)
|
|
87
|
+
except SyntaxError as err:
|
|
88
|
+
self.broken.append((self.rel(path), str(err)))
|
|
89
|
+
continue
|
|
90
|
+
module = Module(path=path, rel=self.rel(path), dotted=dotted, tree=tree)
|
|
91
|
+
module.imports = read_imports(module)
|
|
92
|
+
self.modules[dotted] = module
|
|
93
|
+
|
|
94
|
+
def module(self, dotted: str) -> Optional[Module]:
|
|
95
|
+
hit = self.modules.get(dotted)
|
|
96
|
+
if hit is not None:
|
|
97
|
+
return hit
|
|
98
|
+
return self.modules.get(dotted + ".__init__")
|
|
99
|
+
|
|
100
|
+
def under(self, package: str) -> List[Module]:
|
|
101
|
+
"""Every module of a package, the package's own `__init__` included, in
|
|
102
|
+
path order so the fragment does not move when a directory is re-read."""
|
|
103
|
+
prefix = package + "."
|
|
104
|
+
out = [m for name, m in self.modules.items() if name == package or name.startswith(prefix)]
|
|
105
|
+
return sorted(out, key=lambda m: m.rel)
|
|
106
|
+
|
|
107
|
+
def resolve(self, module: Module, name: str) -> Optional[Tuple[Module, str]]:
|
|
108
|
+
"""The module a name in this one came from, and what it is called
|
|
109
|
+
there. A name defined here resolves to here."""
|
|
110
|
+
imported = module.imports.get(name)
|
|
111
|
+
if imported is None:
|
|
112
|
+
if any(node_name(n) == name for n in module.tree.body):
|
|
113
|
+
return module, name
|
|
114
|
+
return None
|
|
115
|
+
target = self.module(imported.module)
|
|
116
|
+
if target is None:
|
|
117
|
+
return None
|
|
118
|
+
if imported.name == "*":
|
|
119
|
+
return target, name
|
|
120
|
+
return target, imported.name
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def walk(root: str) -> Iterator[str]:
|
|
124
|
+
"""Every .py file under a directory, in a stable order."""
|
|
125
|
+
for base, dirs, files in os.walk(root):
|
|
126
|
+
dirs[:] = sorted(d for d in dirs if d not in SKIP and not d.startswith("."))
|
|
127
|
+
for name in sorted(files):
|
|
128
|
+
if name.endswith(".py"):
|
|
129
|
+
yield os.path.join(base, name)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def read(path: str) -> str:
|
|
133
|
+
with open(path, "r", encoding="utf-8") as handle:
|
|
134
|
+
return handle.read()
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def dotted_name(source: str, path: str) -> str:
|
|
138
|
+
rel = os.path.relpath(path, source)
|
|
139
|
+
rel = rel.replace(os.sep, "/")
|
|
140
|
+
if rel.endswith(".py"):
|
|
141
|
+
rel = rel[: -len(".py")]
|
|
142
|
+
return rel.replace("/", ".")
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def read_imports(module: Module) -> Dict[str, Import]:
|
|
146
|
+
"""What each name in a module refers to. A relative import is resolved
|
|
147
|
+
against the module's own package, which is how `from .events import X`
|
|
148
|
+
finds the file beside it."""
|
|
149
|
+
out: Dict[str, Import] = {}
|
|
150
|
+
for node in ast.walk(module.tree):
|
|
151
|
+
if isinstance(node, ast.Import):
|
|
152
|
+
for alias in node.names:
|
|
153
|
+
out[alias.asname or alias.name.split(".")[0]] = Import(alias.name, "*", node.lineno)
|
|
154
|
+
elif isinstance(node, ast.ImportFrom):
|
|
155
|
+
base = node.module or ""
|
|
156
|
+
if node.level:
|
|
157
|
+
parts = module.dotted.split(".")
|
|
158
|
+
# A package's __init__ is one level shallower than its path says.
|
|
159
|
+
if parts and parts[-1] == "__init__":
|
|
160
|
+
parts = parts[:-1]
|
|
161
|
+
parts = parts[: len(parts) - node.level]
|
|
162
|
+
base = ".".join([p for p in parts if p] + ([base] if base else []))
|
|
163
|
+
for alias in node.names:
|
|
164
|
+
out[alias.asname or alias.name] = Import(base, alias.name, node.lineno)
|
|
165
|
+
return out
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def node_name(node: ast.AST) -> str:
|
|
169
|
+
if isinstance(node, (ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
170
|
+
return node.name
|
|
171
|
+
if isinstance(node, ast.Assign) and len(node.targets) == 1 and isinstance(node.targets[0], ast.Name):
|
|
172
|
+
return node.targets[0].id
|
|
173
|
+
if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
|
|
174
|
+
return node.target.id
|
|
175
|
+
return ""
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def dotted(node: ast.AST) -> str:
|
|
179
|
+
"""`models.CharField` for an attribute chain, `Invoice` for a name, "" for
|
|
180
|
+
anything else."""
|
|
181
|
+
if isinstance(node, ast.Name):
|
|
182
|
+
return node.id
|
|
183
|
+
if isinstance(node, ast.Attribute):
|
|
184
|
+
base = dotted(node.value)
|
|
185
|
+
return base + "." + node.attr if base else node.attr
|
|
186
|
+
if isinstance(node, ast.Call):
|
|
187
|
+
return dotted(node.func)
|
|
188
|
+
return ""
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def const_str(node: Optional[ast.AST]) -> str:
|
|
192
|
+
if isinstance(node, ast.Constant) and isinstance(node.value, str):
|
|
193
|
+
return node.value
|
|
194
|
+
return ""
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def keyword(call: ast.Call, name: str) -> Optional[ast.AST]:
|
|
198
|
+
for kw in call.keywords:
|
|
199
|
+
if kw.arg == name:
|
|
200
|
+
return kw.value
|
|
201
|
+
return None
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def keyword_str(call: ast.Call, name: str) -> str:
|
|
205
|
+
return const_str(keyword(call, name))
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def keyword_bool(call: ast.Call, name: str) -> bool:
|
|
209
|
+
value = keyword(call, name)
|
|
210
|
+
return isinstance(value, ast.Constant) and value.value is True
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def keyword_int(call: ast.Call, name: str) -> Optional[int]:
|
|
214
|
+
value = keyword(call, name)
|
|
215
|
+
if isinstance(value, ast.Constant) and isinstance(value.value, int) and not isinstance(value.value, bool):
|
|
216
|
+
return value.value
|
|
217
|
+
return None
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def doc(node: ast.AST) -> str:
|
|
221
|
+
"""The docstring, first paragraph only: the rest is for whoever opens the
|
|
222
|
+
file, and a page wants the sentence."""
|
|
223
|
+
if not isinstance(node, (ast.Module, ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
224
|
+
return ""
|
|
225
|
+
text = ast.get_docstring(node, clean=True) or ""
|
|
226
|
+
return text.split("\n\n")[0].strip().replace("\n", " ")
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def type_of(node: Optional[ast.AST]) -> str:
|
|
230
|
+
"""An annotation as written. `Optional[Money]` stays `Optional[Money]`: the
|
|
231
|
+
catalog keeps types the way the author declared them."""
|
|
232
|
+
if node is None:
|
|
233
|
+
return ""
|
|
234
|
+
try:
|
|
235
|
+
return ast.unparse(node) # type: ignore[attr-defined]
|
|
236
|
+
except Exception:
|
|
237
|
+
return dotted(node)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def bases(node: ast.ClassDef) -> List[str]:
|
|
241
|
+
return [dotted(b) for b in node.bases]
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def decorators(node: ast.AST) -> List[ast.AST]:
|
|
245
|
+
return list(getattr(node, "decorator_list", []) or [])
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def decorator_named(node: ast.AST, *names: str) -> Optional[ast.AST]:
|
|
249
|
+
"""The decorator whose last segment is one of these: `@action`, `@receiver`,
|
|
250
|
+
`@transition`, however it was imported."""
|
|
251
|
+
for dec in decorators(node):
|
|
252
|
+
if dotted(dec).split(".")[-1] in names:
|
|
253
|
+
return dec
|
|
254
|
+
return None
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def assigned(node: ast.AST) -> List[Tuple[str, ast.AST, ast.AST]]:
|
|
258
|
+
"""(name, value, node) for each simple assignment in a class or module body."""
|
|
259
|
+
out = []
|
|
260
|
+
for stmt in getattr(node, "body", []) or []:
|
|
261
|
+
if isinstance(stmt, ast.Assign):
|
|
262
|
+
for target in stmt.targets:
|
|
263
|
+
if isinstance(target, ast.Name):
|
|
264
|
+
out.append((target.id, stmt.value, stmt))
|
|
265
|
+
elif isinstance(stmt, ast.AnnAssign) and isinstance(stmt.target, ast.Name) and stmt.value is not None:
|
|
266
|
+
out.append((stmt.target.id, stmt.value, stmt))
|
|
267
|
+
return out
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def methods(node: ast.ClassDef) -> List[ast.AST]:
|
|
271
|
+
return [n for n in node.body if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef))]
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def method(node: ast.ClassDef, name: str) -> Optional[ast.AST]:
|
|
275
|
+
for m in methods(node):
|
|
276
|
+
if m.name == name:
|
|
277
|
+
return m
|
|
278
|
+
return None
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def inner_class(node: ast.ClassDef, name: str) -> Optional[ast.ClassDef]:
|
|
282
|
+
for stmt in node.body:
|
|
283
|
+
if isinstance(stmt, ast.ClassDef) and stmt.name == name:
|
|
284
|
+
return stmt
|
|
285
|
+
return None
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
_ "embed"
|
|
5
|
+
|
|
6
|
+
"github.com/shortlink-org/portolan/plugin"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
//go:embed options.schema.json
|
|
10
|
+
var optionsSchema []byte
|
|
11
|
+
|
|
12
|
+
func descriptor() plugin.Descriptor {
|
|
13
|
+
return plugin.Descriptor{
|
|
14
|
+
Name: "verify-codeowners",
|
|
15
|
+
Summary: "Reads the repository's CODEOWNERS against the catalog: who to ask about each service, which services nobody owns, and which rules own nothing.",
|
|
16
|
+
Phases: []string{plugin.PhaseVerify},
|
|
17
|
+
Options: optionsSchema,
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Command verify-codeowners says who to ask about each service, by reading the
|
|
2
|
+
// CODEOWNERS file the repository already keeps.
|
|
3
|
+
//
|
|
4
|
+
// Ownership is the question a catalog is opened for and the one it answered
|
|
5
|
+
// worst: `owner` on a flow or a store means the bounded context, not a team,
|
|
6
|
+
// so "who do I ask about shop.oms" had no answer anywhere on the page. The
|
|
7
|
+
// answer was already written down - every repository with review rules has it,
|
|
8
|
+
// in a file the forge itself enforces - and typing it a second time into the
|
|
9
|
+
// manifest would make the copy the thing that goes stale.
|
|
10
|
+
//
|
|
11
|
+
// So it is read, never written, and never resolved. A handle is what the file
|
|
12
|
+
// says and what a reviewer types; turning `@acme/oms-team` into the people in
|
|
13
|
+
// it is a call to a forge's API, which needs a credential this deliberately
|
|
14
|
+
// does not have and would answer differently tomorrow.
|
|
15
|
+
//
|
|
16
|
+
// It is a verifier rather than an extractor because a rule is a path and only
|
|
17
|
+
// the merged catalog knows where each service is. It earns the name twice
|
|
18
|
+
// over: a service no rule matches, and a rule that matches no service, are
|
|
19
|
+
// both reported - the second being the failure a CODEOWNERS file has and can
|
|
20
|
+
// never report about itself, a team believing it owns something it does not.
|
|
21
|
+
//
|
|
22
|
+
// Nothing here is forge-specific. GitHub, GitLab and Gitea read the same file
|
|
23
|
+
// from the same three places; where GitLab's sections change whose rule wins,
|
|
24
|
+
// the file is read the flatter way and said so out loud.
|
|
25
|
+
//
|
|
26
|
+
// {
|
|
27
|
+
// "plugins": [
|
|
28
|
+
// { "name": "codeowners", "process": { "command": "go", "args": ["run", "./plugins/verify-codeowners"] } }
|
|
29
|
+
// ],
|
|
30
|
+
// "verify": [
|
|
31
|
+
// { "plugin": "codeowners", "in": ".github", "out": "data", "options": { "out": "owners.json" } }
|
|
32
|
+
// ]
|
|
33
|
+
// }
|
|
34
|
+
//
|
|
35
|
+
// Point `in` at the directory the file is in rather than at the repository
|
|
36
|
+
// root. The host dates a fragment from the last commit to touch the step's
|
|
37
|
+
// input, and the subject of this one is the CODEOWNERS file: rooted at the
|
|
38
|
+
// repository, it would be restamped by every commit ever made.
|
|
39
|
+
package main
|
|
40
|
+
|
|
41
|
+
import (
|
|
42
|
+
"fmt"
|
|
43
|
+
"io"
|
|
44
|
+
"os"
|
|
45
|
+
|
|
46
|
+
"github.com/shortlink-org/portolan/plugin"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
// Options are what the manifest tells the verifier.
|
|
50
|
+
type Options struct {
|
|
51
|
+
// File is the CODEOWNERS to read, relative to the input root. Left out,
|
|
52
|
+
// the three places a forge looks: CODEOWNERS, .github/CODEOWNERS and
|
|
53
|
+
// docs/CODEOWNERS, in that order.
|
|
54
|
+
File string `json:"file,omitempty"`
|
|
55
|
+
|
|
56
|
+
// Out names the fragment file.
|
|
57
|
+
Out string `json:"out,omitempty"`
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
func main() {
|
|
61
|
+
if err := run(os.Stdin, os.Stdout); err != nil {
|
|
62
|
+
fmt.Fprintln(os.Stderr, "portolan-verify-codeowners:", err)
|
|
63
|
+
os.Exit(1)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
func run(stdin io.Reader, stdout io.Writer) error {
|
|
68
|
+
return plugin.Serve(stdin, stdout, descriptor(), func(req plugin.Request, opts Options) (plugin.Response, error) {
|
|
69
|
+
if req.Input.Root == "" {
|
|
70
|
+
return plugin.Response{}, fmt.Errorf("no input root: there is nowhere to look for a CODEOWNERS")
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return verify(req, opts)
|
|
74
|
+
})
|
|
75
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
// Whether a rule owns a directory.
|
|
4
|
+
//
|
|
5
|
+
// CODEOWNERS patterns are gitignore patterns, and the question asked here is
|
|
6
|
+
// narrower than the one gitignore answers: not "does this pattern match this
|
|
7
|
+
// file" but "does this pattern own this SERVICE", where a service is a
|
|
8
|
+
// directory. A rule owns a directory when it matches the directory itself or
|
|
9
|
+
// anything above it - `services/` owns `services/oms` - and does not when it
|
|
10
|
+
// matches only something inside it: `services/oms/internal` is a rule about
|
|
11
|
+
// part of the service, and reading it as ownership of the whole would hand a
|
|
12
|
+
// team a page they never asked for.
|
|
13
|
+
//
|
|
14
|
+
// The two shapes a pattern comes in are the whole of the rule:
|
|
15
|
+
//
|
|
16
|
+
// - anchored, when it has a `/` anywhere but the end - `services/oms`,
|
|
17
|
+
// `/docs` - and is matched against the path from the repository root;
|
|
18
|
+
// - floating, when it is a single segment - `*.go`, `internal` - and matches
|
|
19
|
+
// that segment at any depth, which is how gitignore has always read one.
|
|
20
|
+
//
|
|
21
|
+
// `*` and `?` stay inside a segment, `**` spans any number of them.
|
|
22
|
+
|
|
23
|
+
import (
|
|
24
|
+
"path"
|
|
25
|
+
"strings"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
// owns reports whether pattern owns the directory at target, both written
|
|
29
|
+
// repository-relative and with forward slashes.
|
|
30
|
+
func owns(pattern, target string) bool {
|
|
31
|
+
pattern = strings.TrimSpace(pattern)
|
|
32
|
+
target = strings.Trim(target, "/")
|
|
33
|
+
if pattern == "" || target == "" {
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// A pattern that is only a `/*` or `*` owns everything at that level.
|
|
38
|
+
anchored := strings.HasPrefix(pattern, "/") || strings.Contains(strings.TrimSuffix(pattern, "/"), "/")
|
|
39
|
+
pattern = strings.Trim(pattern, "/")
|
|
40
|
+
if pattern == "" {
|
|
41
|
+
return true // "/" - the whole repository.
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
segments := strings.Split(target, "/")
|
|
45
|
+
if !anchored {
|
|
46
|
+
// Any segment matching means the directory it names is owned, and so
|
|
47
|
+
// is everything under it - including this one.
|
|
48
|
+
for _, segment := range segments {
|
|
49
|
+
if ok, _ := path.Match(pattern, segment); ok {
|
|
50
|
+
return true
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return false
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return matchPrefix(strings.Split(pattern, "/"), segments)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// matchPrefix reports whether the pattern matches the target or a prefix of
|
|
61
|
+
// it. A pattern longer than the target names something inside the directory
|
|
62
|
+
// and owns no more of it than that.
|
|
63
|
+
func matchPrefix(pattern, target []string) bool {
|
|
64
|
+
if len(pattern) == 0 {
|
|
65
|
+
return true // Every segment of the pattern matched; the rest is inside it.
|
|
66
|
+
}
|
|
67
|
+
if pattern[0] == "**" {
|
|
68
|
+
// Zero or more segments: try here, then one deeper.
|
|
69
|
+
for i := 0; i <= len(target); i++ {
|
|
70
|
+
if matchPrefix(pattern[1:], target[i:]) {
|
|
71
|
+
return true
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return false
|
|
76
|
+
}
|
|
77
|
+
if len(target) == 0 {
|
|
78
|
+
return false
|
|
79
|
+
}
|
|
80
|
+
if ok, _ := path.Match(pattern[0], target[0]); !ok {
|
|
81
|
+
return false
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return matchPrefix(pattern[1:], target[1:])
|
|
85
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import "testing"
|
|
4
|
+
|
|
5
|
+
// The rule the whole plugin turns on: a pattern owns a directory when it names
|
|
6
|
+
// the directory or anything above it, and does not when it names only
|
|
7
|
+
// something inside it.
|
|
8
|
+
func TestOwns(t *testing.T) {
|
|
9
|
+
cases := []struct {
|
|
10
|
+
pattern string
|
|
11
|
+
target string
|
|
12
|
+
want bool
|
|
13
|
+
why string
|
|
14
|
+
}{
|
|
15
|
+
{"examples/shop/oms", "examples/shop/oms", true, "the directory itself"},
|
|
16
|
+
{"examples/shop", "examples/shop/oms", true, "a directory above it"},
|
|
17
|
+
{"examples/", "examples/shop/oms", true, "a trailing slash is still a directory"},
|
|
18
|
+
{"/examples", "examples/shop/oms", true, "anchored at the root"},
|
|
19
|
+
{"*", "examples/shop/oms", true, "everything"},
|
|
20
|
+
{"/", "examples/shop/oms", true, "the whole repository"},
|
|
21
|
+
|
|
22
|
+
{"examples/shop/oms/internal", "examples/shop/oms", false, "a rule about part of the service is not a rule about the service"},
|
|
23
|
+
{"examples/auth", "examples/shop/oms", false, "a sibling"},
|
|
24
|
+
{"docs", "examples/shop/oms", false, "somewhere else entirely"},
|
|
25
|
+
|
|
26
|
+
// Floating patterns match at any depth, which is what gitignore has
|
|
27
|
+
// always meant by a pattern with no slash in it.
|
|
28
|
+
{"oms", "examples/shop/oms", true, "a single segment matches at any depth"},
|
|
29
|
+
{"shop", "examples/shop/oms", true, "including a segment above"},
|
|
30
|
+
{"om", "examples/shop/oms", false, "and matches whole segments, not prefixes"},
|
|
31
|
+
|
|
32
|
+
{"examples/*/oms", "examples/shop/oms", true, "a star stays inside its segment"},
|
|
33
|
+
{"examples/*", "examples/shop/oms", true, "and matches the segment above"},
|
|
34
|
+
{"examples/*/oms", "examples/shop/cart/oms", false, "so it does not cross a slash"},
|
|
35
|
+
{"examples/**/oms", "examples/shop/cart/oms", true, "two stars do"},
|
|
36
|
+
{"examples/**", "examples/shop/oms", true, "two stars also match nothing at all"},
|
|
37
|
+
|
|
38
|
+
{"", "examples/shop/oms", false, "an empty pattern owns nothing"},
|
|
39
|
+
{"examples", "", false, "and nothing is owned by no pattern"},
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for _, c := range cases {
|
|
43
|
+
if got := owns(c.pattern, c.target); got != c.want {
|
|
44
|
+
t.Errorf("owns(%q, %q) = %v, want %v - %s", c.pattern, c.target, got, c.want, c.why)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "object",
|
|
3
|
+
"additionalProperties": false,
|
|
4
|
+
"properties": {
|
|
5
|
+
"file": {
|
|
6
|
+
"type": "string",
|
|
7
|
+
"description": "The CODEOWNERS to read, relative to the input root. Left out, the three places a forge looks, in order: CODEOWNERS, .github/CODEOWNERS, docs/CODEOWNERS. Its patterns are matched against each service's path as the catalog holds it, so they are repository-relative wherever the file itself sits.",
|
|
8
|
+
"examples": ["CODEOWNERS", ".github/CODEOWNERS"]
|
|
9
|
+
},
|
|
10
|
+
"out": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "Name of the fragment file, inside the step's output directory. Left out, owners.json."
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|