@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,214 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"regexp"
|
|
6
|
+
"strings"
|
|
7
|
+
|
|
8
|
+
"github.com/shortlink-org/portolan/catalog"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// The format, in one place.
|
|
12
|
+
//
|
|
13
|
+
// # Glossary — auth
|
|
14
|
+
//
|
|
15
|
+
// One meaning per word inside this context.
|
|
16
|
+
//
|
|
17
|
+
// **Session.** Proof that a user logged in, how long that proof is good for,
|
|
18
|
+
// and whether it has been taken away.
|
|
19
|
+
//
|
|
20
|
+
// A title, an optional line or two saying what the vocabulary covers, then one
|
|
21
|
+
// paragraph per term in alphabetical order. The paragraph opens with the term
|
|
22
|
+
// in bold and the full stop inside the bold, so `**Email address.**` names a
|
|
23
|
+
// two-word term and nothing has to guess where the name ends. Everything after
|
|
24
|
+
// it is the definition, carried through as written.
|
|
25
|
+
//
|
|
26
|
+
// That is the whole format. Nothing here reads the prose for structure: a
|
|
27
|
+
// glossary is a person explaining a word to another person, and a parser that
|
|
28
|
+
// went looking for shapes inside the explanation would be a parser telling an
|
|
29
|
+
// estate how to phrase itself.
|
|
30
|
+
var (
|
|
31
|
+
titleLine = regexp.MustCompile(`^#\s+Glossary\b`)
|
|
32
|
+
entryOpen = regexp.MustCompile(`^\*\*(.+?)\.\*\*\s*(.*)$`)
|
|
33
|
+
listItem = regexp.MustCompile(`^([-*+]|\d+\.)\s`)
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
// A paragraph of the file, flattened to one line, and where it started.
|
|
37
|
+
//
|
|
38
|
+
// Flattening is what makes the rest of this file about words rather than about
|
|
39
|
+
// line breaks: a glossary is hard-wrapped at whatever width its author likes,
|
|
40
|
+
// and a soft break inside a paragraph is a space in every markdown renderer
|
|
41
|
+
// there is. The line number survives because it is the only thing an error
|
|
42
|
+
// message can point at.
|
|
43
|
+
type paragraph struct {
|
|
44
|
+
line int
|
|
45
|
+
text string
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// blocks splits a file into paragraphs on blank lines.
|
|
49
|
+
func blocks(src string) []paragraph {
|
|
50
|
+
var out []paragraph
|
|
51
|
+
|
|
52
|
+
lines := strings.Split(strings.ReplaceAll(src, "\r\n", "\n"), "\n")
|
|
53
|
+
start := 0
|
|
54
|
+
var held []string
|
|
55
|
+
flush := func() {
|
|
56
|
+
if len(held) == 0 {
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
out = append(out, paragraph{line: start, text: strings.Join(held, " ")})
|
|
60
|
+
held = nil
|
|
61
|
+
}
|
|
62
|
+
for i, line := range lines {
|
|
63
|
+
trimmed := strings.TrimSpace(line)
|
|
64
|
+
if trimmed == "" {
|
|
65
|
+
flush()
|
|
66
|
+
|
|
67
|
+
continue
|
|
68
|
+
}
|
|
69
|
+
if len(held) == 0 {
|
|
70
|
+
start = i + 1
|
|
71
|
+
}
|
|
72
|
+
held = append(held, trimmed)
|
|
73
|
+
}
|
|
74
|
+
flush()
|
|
75
|
+
|
|
76
|
+
return out
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// slug turns a term into the kebab-case form ids and urls use: "Email address"
|
|
80
|
+
// becomes email-address, "Password policy" becomes password-policy.
|
|
81
|
+
func slug(name string) string {
|
|
82
|
+
var b strings.Builder
|
|
83
|
+
|
|
84
|
+
dash := false
|
|
85
|
+
for _, r := range strings.ToLower(name) {
|
|
86
|
+
switch {
|
|
87
|
+
case r >= 'a' && r <= 'z', r >= '0' && r <= '9':
|
|
88
|
+
b.WriteRune(r)
|
|
89
|
+
dash = false
|
|
90
|
+
default:
|
|
91
|
+
if !dash && b.Len() > 0 {
|
|
92
|
+
b.WriteRune('-')
|
|
93
|
+
dash = true
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return strings.Trim(b.String(), "-")
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
func where(file string, line int) string {
|
|
102
|
+
return fmt.Sprintf("%s:%d: ", file, line)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// short quotes the head of a paragraph, for an error that has to say what it
|
|
106
|
+
// found instead of what it wanted.
|
|
107
|
+
func short(text string) string {
|
|
108
|
+
runes := []rune(text)
|
|
109
|
+
if len(runes) > 40 {
|
|
110
|
+
return `"` + string(runes[:40]) + `…"`
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return `"` + text + `"`
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// refuse names what a paragraph is, when it is not an entry. A paragraph
|
|
117
|
+
// before the first entry is the preamble and is allowed to be anything; after
|
|
118
|
+
// one, everything is an entry, and the shapes worth naming are the shapes a
|
|
119
|
+
// glossary is otherwise written in.
|
|
120
|
+
func refuse(text string, started bool) string {
|
|
121
|
+
switch {
|
|
122
|
+
case strings.HasPrefix(text, "|"):
|
|
123
|
+
return "a table: a glossary is prose, one paragraph per term, so that an entry has room to say what the term is not"
|
|
124
|
+
case strings.HasPrefix(text, "#"):
|
|
125
|
+
return "a heading under the title: a term is a paragraph, not a section of its own"
|
|
126
|
+
case listItem.MatchString(text):
|
|
127
|
+
return "a list: a term is a paragraph opening with **Term.**"
|
|
128
|
+
case started:
|
|
129
|
+
return "a paragraph naming no term; after the first entry every paragraph is one, and it opens with **Term.**"
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return ""
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// parseGlossary reads one file into terms, the notes worth making about it,
|
|
136
|
+
// and the reasons it cannot be read at all.
|
|
137
|
+
//
|
|
138
|
+
// Errors and warnings are kept apart all the way up: an error is something the
|
|
139
|
+
// catalog cannot hold, a warning is something a person should go and write.
|
|
140
|
+
func parseGlossary(file, context, src string) (terms []catalog.Term, warns, errs []string) {
|
|
141
|
+
paras := blocks(src)
|
|
142
|
+
if len(paras) == 0 {
|
|
143
|
+
return nil, nil, []string{file + ": the file is empty"}
|
|
144
|
+
}
|
|
145
|
+
if !titleLine.MatchString(paras[0].text) {
|
|
146
|
+
return nil, nil, []string{where(file, paras[0].line) +
|
|
147
|
+
"a glossary opens with `# Glossary — <context>`, and this file opens with " + short(paras[0].text)}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
seen := map[string]int{}
|
|
151
|
+
previous := ""
|
|
152
|
+
started := false
|
|
153
|
+
for _, p := range paras[1:] {
|
|
154
|
+
if !strings.HasPrefix(p.text, "**") {
|
|
155
|
+
if msg := refuse(p.text, started); msg != "" {
|
|
156
|
+
errs = append(errs, where(file, p.line)+msg)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
continue
|
|
160
|
+
}
|
|
161
|
+
started = true
|
|
162
|
+
|
|
163
|
+
m := entryOpen.FindStringSubmatch(p.text)
|
|
164
|
+
if m == nil {
|
|
165
|
+
errs = append(errs, where(file, p.line)+
|
|
166
|
+
"an entry opens with the term in bold and the full stop inside it, `**Session.**`")
|
|
167
|
+
|
|
168
|
+
continue
|
|
169
|
+
}
|
|
170
|
+
name := strings.TrimSpace(m[1])
|
|
171
|
+
body := strings.TrimSpace(m[2])
|
|
172
|
+
id := slug(name)
|
|
173
|
+
if id == "" {
|
|
174
|
+
errs = append(errs, where(file, p.line)+"a term with no name")
|
|
175
|
+
|
|
176
|
+
continue
|
|
177
|
+
}
|
|
178
|
+
if body == "" {
|
|
179
|
+
errs = append(errs, where(file, p.line)+name+" says nothing")
|
|
180
|
+
|
|
181
|
+
continue
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if at, taken := seen[id]; taken {
|
|
185
|
+
errs = append(errs, where(file, p.line)+name+fmt.Sprintf(" is already defined on line %d", at))
|
|
186
|
+
|
|
187
|
+
continue
|
|
188
|
+
}
|
|
189
|
+
seen[id] = p.line
|
|
190
|
+
|
|
191
|
+
// Order is a warning because it costs a reader a moment and costs the
|
|
192
|
+
// catalog nothing: every page sorts what it draws anyway.
|
|
193
|
+
lower := strings.ToLower(name)
|
|
194
|
+
if previous != "" && lower < previous {
|
|
195
|
+
warns = append(warns, where(file, p.line)+name+" sits after "+previous+"; the glossary is alphabetical")
|
|
196
|
+
}
|
|
197
|
+
previous = lower
|
|
198
|
+
|
|
199
|
+
terms = append(terms, catalog.Term{
|
|
200
|
+
ID: context + "." + id,
|
|
201
|
+
Slug: id,
|
|
202
|
+
Context: context,
|
|
203
|
+
Name: name,
|
|
204
|
+
Definition: body,
|
|
205
|
+
Source: fmt.Sprintf("%s:%d", file, p.line),
|
|
206
|
+
})
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if !started && len(errs) == 0 {
|
|
210
|
+
warns = append(warns, file+": a glossary with no terms in it")
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return terms, warns, errs
|
|
214
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"strings"
|
|
6
|
+
"testing"
|
|
7
|
+
|
|
8
|
+
"github.com/shortlink-org/portolan/catalog"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
const sample = `# Glossary — auth
|
|
12
|
+
|
|
13
|
+
One meaning per word inside this context. The code, the events and the API
|
|
14
|
+
spell these the same way.
|
|
15
|
+
|
|
16
|
+
**Email address.** The address a user logs in with, normalised on creation.
|
|
17
|
+
|
|
18
|
+
**Session.** Proof that a user logged in, and how long that proof is good for,
|
|
19
|
+
and whether it has been taken away.
|
|
20
|
+
|
|
21
|
+
**Version.** The number the store compares before writing an aggregate. Zero
|
|
22
|
+
means never stored.
|
|
23
|
+
`
|
|
24
|
+
|
|
25
|
+
const file = "examples/auth/GLOSSARY.md"
|
|
26
|
+
|
|
27
|
+
func parsed(t *testing.T, src string) []catalog.Term {
|
|
28
|
+
t.Helper()
|
|
29
|
+
|
|
30
|
+
terms, _, errs := parseGlossary(file, "auth", src)
|
|
31
|
+
if len(errs) > 0 {
|
|
32
|
+
t.Fatalf("errors: %s", strings.Join(errs, "\n"))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return terms
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
func refused(t *testing.T, src string) string {
|
|
39
|
+
t.Helper()
|
|
40
|
+
|
|
41
|
+
_, _, errs := parseGlossary(file, "auth", src)
|
|
42
|
+
if len(errs) == 0 {
|
|
43
|
+
t.Fatal("parsed without complaint")
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return strings.Join(errs, "\n")
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
func warned(t *testing.T, src string) string {
|
|
50
|
+
t.Helper()
|
|
51
|
+
|
|
52
|
+
_, warns, errs := parseGlossary(file, "auth", src)
|
|
53
|
+
if len(errs) > 0 {
|
|
54
|
+
t.Fatalf("errors: %s", strings.Join(errs, "\n"))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return strings.Join(warns, "\n")
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
func term(t *testing.T, terms []catalog.Term, name string) catalog.Term {
|
|
61
|
+
t.Helper()
|
|
62
|
+
|
|
63
|
+
for _, candidate := range terms {
|
|
64
|
+
if candidate.Name == name {
|
|
65
|
+
return candidate
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
t.Fatalf("no term called %q", name)
|
|
69
|
+
|
|
70
|
+
return catalog.Term{}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
func TestTheDefinitionIsTheParagraph(t *testing.T) {
|
|
74
|
+
session := term(t, parsed(t, sample), "Session")
|
|
75
|
+
|
|
76
|
+
want := "Proof that a user logged in, and how long that proof is good for, and whether it has been taken away."
|
|
77
|
+
if session.Definition != want {
|
|
78
|
+
t.Errorf("definition is %q, want %q", session.Definition, want)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// The hard wrap in the file is a soft break in markdown, and a definition that
|
|
83
|
+
// carried it would be a definition nothing could put on a card.
|
|
84
|
+
func TestParagraphIsOneLine(t *testing.T) {
|
|
85
|
+
for _, term := range parsed(t, sample) {
|
|
86
|
+
if strings.ContainsAny(term.Definition, "\n") {
|
|
87
|
+
t.Errorf("%s carries a line break", term.Name)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
func TestTwoWordTerm(t *testing.T) {
|
|
93
|
+
address := term(t, parsed(t, sample), "Email address")
|
|
94
|
+
|
|
95
|
+
if address.Slug != "email-address" {
|
|
96
|
+
t.Errorf("slug is %q", address.Slug)
|
|
97
|
+
}
|
|
98
|
+
if address.ID != "auth.email-address" {
|
|
99
|
+
t.Errorf("id is %q", address.ID)
|
|
100
|
+
}
|
|
101
|
+
if address.Context != "auth" {
|
|
102
|
+
t.Errorf("context is %q", address.Context)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
func TestSourceIsTheLineTheEntryStartsOn(t *testing.T) {
|
|
107
|
+
if got := term(t, parsed(t, sample), "Session").Source; got != file+":8" {
|
|
108
|
+
t.Errorf("source is %q, want %s:8", got, file)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
func TestPreambleIsNotATerm(t *testing.T) {
|
|
113
|
+
if terms := parsed(t, sample); len(terms) != 3 {
|
|
114
|
+
names := []string{}
|
|
115
|
+
for _, term := range terms {
|
|
116
|
+
names = append(names, term.Name)
|
|
117
|
+
}
|
|
118
|
+
t.Errorf("read %d terms: %s", len(terms), strings.Join(names, ", "))
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
func TestTableIsRefused(t *testing.T) {
|
|
123
|
+
src := "# Glossary — auth\n\n| Term | Meaning |\n| --- | --- |\n| Session | Proof. |\n"
|
|
124
|
+
|
|
125
|
+
if got := refused(t, src); !strings.Contains(got, "prose") {
|
|
126
|
+
t.Errorf("refusal is %q", got)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
func TestHeadingPerTermIsRefused(t *testing.T) {
|
|
131
|
+
src := "# Glossary — auth\n\n## Session\n\nProof that a user logged in.\n"
|
|
132
|
+
|
|
133
|
+
if got := refused(t, src); !strings.Contains(got, "a term is a paragraph") {
|
|
134
|
+
t.Errorf("refusal is %q", got)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
func TestListIsRefused(t *testing.T) {
|
|
139
|
+
src := "# Glossary — auth\n\n- **Session.** Proof that a user logged in.\n"
|
|
140
|
+
|
|
141
|
+
if got := refused(t, src); !strings.Contains(got, "a list") {
|
|
142
|
+
t.Errorf("refusal is %q", got)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
func TestAFileThatIsNotAGlossaryIsRefused(t *testing.T) {
|
|
147
|
+
src := "# Sessions\n\n**Session.** Proof that a user logged in.\n"
|
|
148
|
+
|
|
149
|
+
if got := refused(t, src); !strings.Contains(got, "opens with `# Glossary") {
|
|
150
|
+
t.Errorf("refusal is %q", got)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// A word with two meanings inside one context is the failure the glossary is
|
|
155
|
+
// written to prevent, so it is the one duplication that cannot be a warning.
|
|
156
|
+
func TestTheSameWordTwiceIsRefused(t *testing.T) {
|
|
157
|
+
src := sample + "\n**Session.** Something else entirely.\n"
|
|
158
|
+
|
|
159
|
+
if got := refused(t, src); !strings.Contains(got, "already defined on line 8") {
|
|
160
|
+
t.Errorf("refusal is %q", got)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
func TestOutOfOrderIsAWarning(t *testing.T) {
|
|
165
|
+
src := "# Glossary — auth\n\n**Lockout.** An account refusing passwords.\n\n**Locked.** The state of a lockout while it refuses.\n"
|
|
166
|
+
|
|
167
|
+
if got := warned(t, src); !strings.Contains(got, "alphabetical") {
|
|
168
|
+
t.Errorf("warnings are %q", got)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
func TestAnEntryThatNamesNothing(t *testing.T) {
|
|
173
|
+
src := "# Glossary — auth\n\n**Session** proof that a user logged in.\n"
|
|
174
|
+
|
|
175
|
+
if got := refused(t, src); !strings.Contains(got, "the full stop inside it") {
|
|
176
|
+
t.Errorf("refusal is %q", got)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// The estate's own glossaries parse, and are held to the format they document.
|
|
181
|
+
func TestTheEstatesOwnGlossaries(t *testing.T) {
|
|
182
|
+
for _, tt := range []struct{ path, context string }{
|
|
183
|
+
{"../../examples/auth/GLOSSARY.md", "auth"},
|
|
184
|
+
{"../../examples/shop/oms/GLOSSARY.md", "shop"},
|
|
185
|
+
} {
|
|
186
|
+
t.Run(tt.path, func(t *testing.T) {
|
|
187
|
+
src, err := os.ReadFile(tt.path)
|
|
188
|
+
if err != nil {
|
|
189
|
+
t.Fatal(err)
|
|
190
|
+
}
|
|
191
|
+
terms, warns, errs := parseGlossary(tt.path, tt.context, string(src))
|
|
192
|
+
if len(errs) > 0 {
|
|
193
|
+
t.Fatalf("errors: %s", strings.Join(errs, "\n"))
|
|
194
|
+
}
|
|
195
|
+
if len(warns) > 0 {
|
|
196
|
+
t.Errorf("warnings: %s", strings.Join(warns, "\n"))
|
|
197
|
+
}
|
|
198
|
+
if len(terms) == 0 {
|
|
199
|
+
t.Error("no terms read")
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"path"
|
|
6
|
+
"path/filepath"
|
|
7
|
+
"strings"
|
|
8
|
+
|
|
9
|
+
"github.com/shortlink-org/portolan/catalog"
|
|
10
|
+
"github.com/shortlink-org/portolan/plugin"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
// extractAggregate reads one discovered aggregate domain package.
|
|
14
|
+
//
|
|
15
|
+
// The layout is the claim: a directory there is an aggregate, the struct named
|
|
16
|
+
// after it is the root, `vo/` holds its value objects and `event/` the facts it
|
|
17
|
+
// publishes. Nothing is inferred from a comment or a marker interface, so a
|
|
18
|
+
// package that does not follow the layout produces a diagnostic instead of a
|
|
19
|
+
// half-right aggregate.
|
|
20
|
+
func extractAggregate(root, aggregateName, domainPath string, layout sourceLayout, svcID string, b *plugin.Builder) (catalog.Aggregate, bool) {
|
|
21
|
+
pkg, err := parsePkg(root, domainPath)
|
|
22
|
+
if err != nil {
|
|
23
|
+
if !os.IsNotExist(err) {
|
|
24
|
+
b.Warn(aggregateID(svcID, aggregateName), domainPath+" could not be parsed: "+err.Error())
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return catalog.Aggregate{}, false
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
id := aggregateID(svcID, slug(aggregateName))
|
|
31
|
+
name := title(pkg.name)
|
|
32
|
+
|
|
33
|
+
aggregate := catalog.Aggregate{
|
|
34
|
+
ID: id,
|
|
35
|
+
Slug: slug(aggregateName),
|
|
36
|
+
Name: name,
|
|
37
|
+
Readme: aggregateReadme(root, domainPath, pkg.name, name, pkg.doc()),
|
|
38
|
+
Entities: []catalog.Block{},
|
|
39
|
+
ValueObjects: []catalog.Block{},
|
|
40
|
+
Operations: []catalog.Operation{},
|
|
41
|
+
Events: []catalog.Event{},
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
for _, decl := range pkg.structs() {
|
|
45
|
+
if !exported(decl.name) {
|
|
46
|
+
continue
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
aggregate.Entities = append(aggregate.Entities, catalog.Block{
|
|
50
|
+
ID: blockID(id, slug(decl.name)),
|
|
51
|
+
Slug: slug(decl.name),
|
|
52
|
+
Name: decl.name,
|
|
53
|
+
Doc: decl.doc,
|
|
54
|
+
Fields: fields(decl.fields),
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// The root is the entity named after its package: package user holds User,
|
|
59
|
+
// and package price_list holds PriceList. It is a rule rather than a guess,
|
|
60
|
+
// and a package that breaks it is not read as an aggregate at all. Taking
|
|
61
|
+
// whichever struct came first instead would put a package of error types
|
|
62
|
+
// on the page as a model with a root and seven fields, and a reader
|
|
63
|
+
// believes a table; a warning and no page is the honest answer.
|
|
64
|
+
aggregate.Root = pascal(pkg.name)
|
|
65
|
+
if !hasBlock(aggregate.Entities, aggregate.Root) {
|
|
66
|
+
if len(aggregate.Entities) == 0 {
|
|
67
|
+
b.Warn(id, domainPath+" declares no exported struct, so the aggregate has no root")
|
|
68
|
+
|
|
69
|
+
return catalog.Aggregate{}, false
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
b.Warn(id, domainPath+" has no struct called "+pascal(pkg.name)+", so it is not read as an aggregate; the root is the struct named after its package")
|
|
73
|
+
|
|
74
|
+
return catalog.Aggregate{}, false
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
aggregate.ValueObjects = extractValueObjects(root, domainPath, id, b)
|
|
78
|
+
aggregate.Enums = extractEnums(root, domainPath, id, pkg, b)
|
|
79
|
+
aggregate.Events = extractEvents(root, aggregateName, domainPath, layout, id, b)
|
|
80
|
+
aggregate.Lifecycle = readLifecycle(pkg, aggregate.Root, aggregate.Events, id, b)
|
|
81
|
+
|
|
82
|
+
return aggregate, true
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// extractValueObjects reads vo/* below a discovered aggregate domain package.
|
|
86
|
+
//
|
|
87
|
+
// Each directory there is one value object, and the exported struct inside it
|
|
88
|
+
// is its shape. `rules/` is skipped: a validation specification is how the
|
|
89
|
+
// value object refuses a value, not part of what it holds.
|
|
90
|
+
func extractValueObjects(root, domainPath, aggID string, b *plugin.Builder) []catalog.Block {
|
|
91
|
+
out := []catalog.Block{}
|
|
92
|
+
|
|
93
|
+
for _, name := range subdirs(root, path.Join(domainPath, "vo")) {
|
|
94
|
+
if name == "rules" {
|
|
95
|
+
continue
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
pkg, err := parsePkg(root, path.Join(domainPath, "vo", name))
|
|
99
|
+
if err != nil {
|
|
100
|
+
continue
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
found := false
|
|
104
|
+
for _, decl := range pkg.structs() {
|
|
105
|
+
if !exported(decl.name) {
|
|
106
|
+
continue
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
doc := decl.doc
|
|
110
|
+
if doc == "" {
|
|
111
|
+
doc = firstSentenceOrAll(pkg.doc())
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Qualified the way Go refers to it, so that the value object and
|
|
115
|
+
// the field that holds it are visibly the same thing: User.Password
|
|
116
|
+
// is a `password.Hash`, and a block called just `Hash` says nothing
|
|
117
|
+
// about which one.
|
|
118
|
+
label := qualified(pkg.name, decl.name)
|
|
119
|
+
|
|
120
|
+
out = append(out, catalog.Block{
|
|
121
|
+
ID: blockID(aggID, slug(label)),
|
|
122
|
+
Slug: slug(label),
|
|
123
|
+
Name: label,
|
|
124
|
+
Doc: doc,
|
|
125
|
+
Fields: fields(decl.fields),
|
|
126
|
+
})
|
|
127
|
+
found = true
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if !found {
|
|
131
|
+
b.Warn(aggID, path.Join(domainPath, "vo", name)+" declares no exported struct; skipped")
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return out
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
func hasBlock(blocks []catalog.Block, name string) bool {
|
|
139
|
+
for i := range blocks {
|
|
140
|
+
if blocks[i].Name == name {
|
|
141
|
+
return true
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return false
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// qualified is pkg.Name, unless the package is named after the type it holds -
|
|
149
|
+
// token.Token adds nothing over Token.
|
|
150
|
+
func qualified(pkg, name string) string {
|
|
151
|
+
if strings.EqualFold(pkg, name) {
|
|
152
|
+
return name
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return pkg + "." + name
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
func exported(name string) bool {
|
|
159
|
+
return name != "" && name[0] >= 'A' && name[0] <= 'Z'
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// aggregateReadme prefers the package's README.md, which is written for a
|
|
163
|
+
// reader and can draw the states, over the package comment, which is written
|
|
164
|
+
// for whoever opens the file next. Same preference as operationDoc, for the
|
|
165
|
+
// same reason. The comment is a fallback, not a second source: a package that
|
|
166
|
+
// has both is described by its README alone.
|
|
167
|
+
func aggregateReadme(root, domainPath, pkgName, name, doc string) string {
|
|
168
|
+
if md := readFile(filepath.Join(root, filepath.FromSlash(domainPath), "README.md")); md != "" {
|
|
169
|
+
return md
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return readme(pkgName, name, doc)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// readme turns a package comment into the markdown the catalog carries. The
|
|
176
|
+
// heading is added because every other readme in a catalog has one, and a page
|
|
177
|
+
// that starts mid-paragraph reads as a fragment of something else.
|
|
178
|
+
func readme(pkgName, name, doc string) string {
|
|
179
|
+
doc = withoutPackagePrefix(pkgName, strings.TrimSpace(doc))
|
|
180
|
+
if doc == "" {
|
|
181
|
+
return ""
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return "# " + name + "\n\n" + doc
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// withoutPackagePrefix drops the "Package user " that Go doc convention puts at
|
|
188
|
+
// the front of a package comment.
|
|
189
|
+
//
|
|
190
|
+
// It is a convention for godoc, where the sentence is read next to the package
|
|
191
|
+
// clause. On a page headed "User" it reads as a leftover from somewhere else,
|
|
192
|
+
// and the sentence works perfectly well without it.
|
|
193
|
+
func withoutPackagePrefix(pkgName, doc string) string {
|
|
194
|
+
return withoutLeading("Package "+pkgName+" ", doc)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// withoutLeading is the same for anything else Go doc convention names before
|
|
198
|
+
// it says anything: a type comment opens with the type.
|
|
199
|
+
func withoutLeading(prefix, doc string) string {
|
|
200
|
+
rest, ok := strings.CutPrefix(doc, prefix)
|
|
201
|
+
if !ok {
|
|
202
|
+
return doc
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
runes := []rune(rest)
|
|
206
|
+
if len(runes) == 0 {
|
|
207
|
+
return doc
|
|
208
|
+
}
|
|
209
|
+
if runes[0] >= 'a' && runes[0] <= 'z' {
|
|
210
|
+
runes[0] = runes[0] - 'a' + 'A'
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return string(runes)
|
|
214
|
+
}
|