oapi-profile-builder 3.4.0__tar.gz → 3.5.0__tar.gz

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.
Files changed (20) hide show
  1. {oapi_profile_builder-3.4.0/src/oapi_profile_builder.egg-info → oapi_profile_builder-3.5.0}/PKG-INFO +96 -2
  2. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/README.md +95 -1
  3. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/pyproject.toml +1 -1
  4. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/src/oapi_profile_builder/generate.py +290 -37
  5. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/src/oapi_profile_builder/models.py +305 -0
  6. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0/src/oapi_profile_builder.egg-info}/PKG-INFO +96 -2
  7. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/LICENSE +0 -0
  8. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/setup.cfg +0 -0
  9. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/src/oapi_profile_builder/__init__.py +0 -0
  10. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/src/oapi_profile_builder/cite.py +0 -0
  11. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/src/oapi_profile_builder/cite_features.py +0 -0
  12. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/src/oapi_profile_builder/cli.py +0 -0
  13. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/src/oapi_profile_builder/compile.py +0 -0
  14. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/src/oapi_profile_builder/cover.py +0 -0
  15. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/src/oapi_profile_builder/server_validation.py +0 -0
  16. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/src/oapi_profile_builder.egg-info/SOURCES.txt +0 -0
  17. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/src/oapi_profile_builder.egg-info/dependency_links.txt +0 -0
  18. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/src/oapi_profile_builder.egg-info/entry_points.txt +0 -0
  19. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/src/oapi_profile_builder.egg-info/requires.txt +0 -0
  20. {oapi_profile_builder-3.4.0 → oapi_profile_builder-3.5.0}/src/oapi_profile_builder.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oapi-profile-builder
3
- Version: 3.4.0
3
+ Version: 3.5.0
4
4
  Summary: Authoritative tooling for creating OGC API Service Profiles (EDR, Features)
5
5
  Author-email: Shane Mill <shane.mill@noaa.gov>
6
6
  License: Apache License
@@ -239,15 +239,21 @@ Everything about the document — cover, title-page metadata, legal page, footer
239
239
  | PDF colours (titles, tables, cover, backgrounds) | `document_metadata.colors` | `:presentation-metadata-color-*:` |
240
240
  | Page-ii legal text (copyright / license / notice) | `document_metadata.boilerplate` | `:boilerplate-authority:` |
241
241
  | Footer organisation name | `document_metadata.copyright_holder` | `:copyright-holder:` |
242
+ | Cover layout (logo size/position, tagline/title size, bold edition) | `document_metadata.cover.{logo_width, logo_y, tagline_font_size, title_font_size, bold_edition}` | Generated cover image |
243
+ | Cover date | `document_metadata.doc_pub_date` | Long-format date on the generated cover + `:published-date:` |
242
244
  | Remove the OGC logo from the legal page | `document_metadata.suppress_flavor_logo` | targeted `:pdf-stylesheet-override:` |
243
245
  | Remove OGC design (crossing lines, circled numbers, rules, navy divider pages) | `document_metadata.suppress_design_elements` (or the individual `suppress_crossing_lines` / `plain_section_numbers` / `suppress_title_underlines`) | `:pdf-stylesheet-override:` + colour attributes |
246
+ | Remove the standalone section-divider pages | `document_metadata.suppress_section_divider_pages` | `:pdf-stylesheet-override:` |
247
+ | Inline section headings (`1 Scope` in one line, no circle) | `document_metadata.inline_section_headers` | `:pdf-stylesheet-override:` |
248
+ | Flatten reference hanging indent (title under authors) | `document_metadata.suppress_bibliography_indent` | `:pdf-stylesheet-override:` |
244
249
  | Every-page DRAFT-style watermark (over content) | `document_metadata.page_watermark` | `:pdf-stylesheet-override:` (footer overlay) |
245
250
  | Requirement / conformance identifier namespace | `spec_uri_base` | derives `req_uri` / `conf_uri` |
246
251
  | Submitter table, notice paragraph, normative refs, extra terms | `document_metadata.{submitters, notice, normative_references, terms}` | Metanorma attributes / sections |
252
+ | Features `/items` paging (`limit` parameter) | `paging.{enabled, default_limit, max_limit}` | OpenAPI query parameter |
247
253
 
248
254
  Custom branding requires Pillow for the cover image: `pip install 'oapi-profile-builder[pdf]'`. Field-by-field detail is in the [`document_metadata`](#document_metadata) reference below; [`examples/nwp_radar.yaml`](examples/nwp_radar.yaml) is a complete DGIWG-branded example. Omit all of these fields and the output keeps the standard OGC house style.
249
255
 
250
- > The `suppress_flavor_logo`, `suppress_design_elements`/`suppress_*`, and `page_watermark` overrides reach into the OGC Metanorma flavor's XSL templates (e.g. `insertLogoPreface`, `insertCrossingLines`, `insertSectionNumInCircle`, `insertFooter`) and are coupled to that flavor. Everything else uses documented Metanorma attributes. mn2pdf merges our same-named templates over the flavor's at equal precedence (via `merge_override.xsl`), which is what makes these work; a future metanorma-ogc release could require refreshing the template names. For long-term SDO adoption, a dedicated Metanorma "taste"/flavor is the most durable path.
256
+ > The `suppress_flavor_logo`, `suppress_design_elements`/`suppress_*`, `suppress_section_divider_pages`, `inline_section_headers`, `suppress_bibliography_indent`, and `page_watermark` overrides reach into the OGC Metanorma flavor's XSL templates (e.g. `insertLogoPreface`, `insertCrossingLines`, `insertSectionNumInCircle`, `insertFooter`, the `sections` mode, `fmt-title`, and `bibitem-normative-style`) and are coupled to that flavor. Everything else uses documented Metanorma attributes. mn2pdf merges our same-named templates over the flavor's at equal precedence (via `merge_override.xsl`), which is what makes these work; a future metanorma-ogc release could require refreshing the template names. For long-term SDO adoption, a dedicated Metanorma "taste"/flavor is the most durable path.
251
257
 
252
258
  ---
253
259
 
@@ -336,11 +342,19 @@ abstract_tests: []
336
342
  | `spec_uri_base` | string | no | Base URI for the requirements/conformance class identifiers. Defaults to the OGC EDR Part 3 namespace; override to publish under another SDO namespace (e.g. DGIWG) |
337
343
  | `parameter_name_pattern` | string | no | Regex all `parameter_names` keys must match |
338
344
  | `parameter_schema` | object | no | JSON Schema for parameter objects — replaces the default schema in the generated OpenAPI (see below) |
345
+ | `collection_title_max_length` | int | no | When set, every collection title must be present and within this many characters (MetOcean `/req/core/collection_title`) |
346
+ | `require_license_link` | bool | no | When `true`, every collection must declare a `rel='license'` link (MetOcean `/req/core/collection_license`). Defaults to `false` |
347
+ | `license_link_type` | string | no | Expected media type of the `rel='license'` link when `require_license_link` is set. Defaults to `text/html`; set to null to accept any type |
348
+ | `required_data_queries` | list | no | Data-query types every collection must define (e.g. `[locations, area, radius]`) — enforces the mandatory data-query sets |
349
+ | `radius_within_units_required` | list | no | Unit tokens each radius query's `within_units` must contain (e.g. `[m]`) (MetOcean `/req/core/collection_radius_data_query`) |
350
+ | `locations_feature_required_properties` | list | no | Feature properties (e.g. `[name]`) marked required in the generated `/locations` GeoJSON response schema, in addition to the always-required string `id` |
351
+ | `conformance_class_requirements` | object | no | Map of conformance-class short name → constraints (`required_data_queries`, `radius_within_units_required`) applied only to collections that declare the class. Lets one profile document model several EDR Part 3 requirements classes (see below) |
339
352
  | `processes` | list | no | OGC API Processes to expose in the OpenAPI |
340
353
  | `requirements` | list | no | Normative requirements for the AsciiDoc/PDF |
341
354
  | `abstract_tests` | list | no | Conformance tests — each must reference a valid requirement `id` |
342
355
  | `pubsub` | object | no | OGC API - EDR Part 2 PubSub config — generates `asyncapi.yaml` |
343
356
  | `collection_examples` | object | no | `{collectionId: {instanceId: "..."}}` — used by `validate-server` |
357
+ | `paging` | object | no | Features `/items` paging — adds a validated `limit` query parameter to the generated OpenAPI (see below) |
344
358
  | `document_metadata` | object | no | Metanorma PDF header — doc number/type/subtype, status, editors, submitters, dates, notice, normative references (see below) |
345
359
 
346
360
  ---
@@ -374,6 +388,8 @@ Uses the [edr-pydantic](https://github.com/KNMI/edr-pydantic) `Collection` model
374
388
  | `output_formats` | no | Format names this collection supports (e.g. `[CoverageJSON, GeoJSON]`) |
375
389
  | `data_queries` | no | EDR query types: `position`, `area`, `radius`, `cube`, `trajectory`, `corridor`, `locations`, `items`, `instances` |
376
390
  | `parameter_names` | no | Map of parameter id → Parameter object. All parameters must have `unit` and `observedProperty` |
391
+ | `conformance_classes` | no | Profile conformance-class short names this collection implements (e.g. `[core, insitu-observations]`). Selects which `conformance_class_requirements` are enforced; surfaced as `x-conformance-classes` in the OpenAPI |
392
+ | `parameter_schema` | no | Per-collection JSON Schema for parameter objects, overriding the profile-level `parameter_schema` for this collection only (precedence: collection → profile → default) |
377
393
 
378
394
  #### `data_queries` example
379
395
 
@@ -506,6 +522,38 @@ extent_requirements:
506
522
 
507
523
  ---
508
524
 
525
+ ### Multiple conformance classes in one profile
526
+
527
+ OGC API - EDR Part 3 profiles are modular: a single profile document can define several requirements/conformance classes, and different collections in the same service may implement different classes. The MetOcean EDR Profile is a good example — Core applies everywhere, but only in-situ collections must offer `locations`/`area`/`radius` while NWP collections must offer `position`/`cube`.
528
+
529
+ Model this with `conformance_class_requirements` (profile level) plus `conformance_classes` (per collection):
530
+
531
+ ```yaml
532
+ # Core-level rules apply to every collection:
533
+ collection_title_max_length: 50
534
+ require_license_link: true
535
+
536
+ # Class-scoped rules apply only where a collection opts in:
537
+ conformance_class_requirements:
538
+ insitu-observations:
539
+ required_data_queries: [locations, area, radius]
540
+ radius_within_units_required: [m]
541
+ nwp:
542
+ required_data_queries: [position, cube]
543
+
544
+ collections:
545
+ - id: insitu-observations
546
+ conformance_classes: [core, insitu-observations] # must have locations/area/radius
547
+ # ...
548
+ - id: nwp-forecast
549
+ conformance_classes: [core, nwp] # must have position/cube
550
+ # ...
551
+ ```
552
+
553
+ The flat `required_data_queries` / `radius_within_units_required` fields still apply to *every* collection (the Core-applies-to-all shorthand); class-scoped rules are additive. See `examples/metocean_profile.yaml` for a full worked profile spanning all four MetOcean classes.
554
+
555
+ ---
556
+
509
557
  ### `output_formats`
510
558
 
511
559
  Maps format names (referenced by `collections[].output_formats` and `data_queries.*.variables.output_formats`) to a media type and, optionally, a schema reference. The `schema_ref` flows into the generated OpenAPI response `content` for that format — use it to point a format at a specific schema (e.g. a DGIWG-published schema for GeoTIFF or CoverageJSON) instead of the tool's built-in default.
@@ -624,6 +672,21 @@ Generates: `/processes/compute-difference`, `/processes/compute-difference/execu
624
672
 
625
673
  ---
626
674
 
675
+ ### `paging`
676
+
677
+ Controls Features `/items` paging in the generated OpenAPI. When enabled (the default), a validated `limit` query parameter is added to every `/items` endpoint (collection-level and instance-level).
678
+
679
+ ```yaml
680
+ paging:
681
+ enabled: true # default true; set false to omit the limit parameter
682
+ default_limit: 10 # OpenAPI schema default for limit (default 10)
683
+ max_limit: 100 # OpenAPI schema maximum for limit (default 10000)
684
+ ```
685
+
686
+ The emitted parameter is `limit` (`in: query`, `type: integer`, `minimum: 1`, `maximum: <max_limit>`, `default: <default_limit>`).
687
+
688
+ ---
689
+
627
690
  ### `pubsub`
628
691
 
629
692
  When present, generates `asyncapi.yaml` alongside `openapi.yaml`.
@@ -669,6 +732,8 @@ document_metadata:
669
732
  submission_date: "2026-05-01" # → :received-date:
670
733
  approval_date: "2026-06-15" # → :issued-date:
671
734
  publication_date: "2026-07-01" # → :published-date:
735
+ doc_pub_date: "2026-07-16" # optional; overrides publication_date for the cover
736
+ # (long-format "16 July 2026") and :published-date:
672
737
  # Custom notice paragraph rendered in the front matter. Note: the OGC cover-page
673
738
  # legal notice itself is generated by Metanorma from doc_type/status.
674
739
  notice: >
@@ -707,6 +772,12 @@ document_metadata:
707
772
  font_bold: "Source Sans Pro" # optional bold face; derived from font_regular when unset
708
773
  font_italic: "Source Sans Pro" # optional italic face for the tagline
709
774
  watermark: "DRAFT" # optional diagonal watermark stamped on the cover
775
+ # --- cover layout (all optional) ---
776
+ logo_width: 200 # target logo width in px (default 420)
777
+ logo_y: 100 # logo vertical offset from top in px (default 180)
778
+ tagline_font_size: 20 # tagline point size (default 30)
779
+ title_font_size: 40 # title point size (default 54)
780
+ bold_edition: true # render the "Edition X" line in bold (default false)
710
781
  colors:
711
782
  text: "#000000" # body text
712
783
  cover_text: "#1F3864" # cover text / section numbers / ToC
@@ -763,6 +834,23 @@ With `cover` + `colors` + `copyright_holder` + `boilerplate` + `suppress_flavor_
763
834
 
764
835
  > These design-element overrides (and the `page_watermark` footer overlay) reach into the OGC Metanorma flavor's XSL template names and are coupled to that flavor; a future metanorma-ogc release could require refreshing them.
765
836
 
837
+ #### Structural layout changes (divider pages, inline headers, references)
838
+
839
+ `suppress_design_elements` only changes *decorative* styling — it keeps the document's structure (standalone section-divider pages, the standard heading layout, and the reference hanging indent) intact. The following are **independent, opt-in** structural changes, so the default OGC output is unaffected unless you set them:
840
+
841
+ - **`suppress_section_divider_pages: true`** — removes the standalone full-page section dividers, so each section's content follows its heading directly.
842
+ - **`inline_section_headers: true`** — renders Level 1/2 headings inline with the title (e.g. `1 Scope`, `i Abstract`) rather than the OGC circled-number layout.
843
+ - **`suppress_bibliography_indent: true`** — flattens both the Normative References and the Bibliography so each entry is a single flush paragraph, removing the hanging indent that placed the title under the authors.
844
+
845
+ ```yaml
846
+ document_metadata:
847
+ suppress_section_divider_pages: true
848
+ inline_section_headers: true
849
+ suppress_bibliography_indent: true
850
+ ```
851
+
852
+ Additionally, when `copyright_holder` is set to a non-OGC organisation, the flavor's auto-generated "Submitting Organizations" sentence ("…submitted this Document to the Open Geospatial Consortium (OGC)") is rebranded to name that organisation instead, so no residual OGC text remains in the preface.
853
+
766
854
  #### Extending Terms and Definitions
767
855
 
768
856
  Add profile-specific terms (e.g. EDR Part 3 or Pub/Sub terms) appended after the base terms in the Terms and Definitions section:
@@ -851,6 +939,12 @@ The tool enforces these rules at build time. Violations produce clear error mess
851
939
  | Parameters need `unit` + `observedProperty` | Required by OGC API - EDR Part 3 |
852
940
  | `parameter_name_pattern` enforced | All `parameter_names` keys must match if set |
853
941
  | `collection_id_pattern` enforced | All collection IDs must match if set |
942
+ | `collection_title_max_length` enforced | If set, every collection title must be present and within the limit |
943
+ | `require_license_link` enforced | If set, every collection must have a `rel='license'` link (of `license_link_type` when specified) |
944
+ | `required_data_queries` enforced | If set, every collection with `data_queries` must define each listed query type |
945
+ | `radius_within_units_required` enforced | If set, each radius query's `within_units` must contain every listed unit token |
946
+ | `conformance_class_requirements` enforced | Class-scoped `required_data_queries` / `radius_within_units_required` applied to collections whose `conformance_classes` include the class key |
947
+ | `conformance_classes` references known class | When `conformance_class_requirements` is set, a collection's `conformance_classes` may only use `core` or a defined class key (catches typos) |
854
948
  | Abstract test IDs match requirements | `requirement_id` must reference an existing requirement |
855
949
  | Requirement IDs | Must match `^[a-z0-9][a-z0-9\-]*$`, no trailing hyphen |
856
950
 
@@ -192,15 +192,21 @@ Everything about the document — cover, title-page metadata, legal page, footer
192
192
  | PDF colours (titles, tables, cover, backgrounds) | `document_metadata.colors` | `:presentation-metadata-color-*:` |
193
193
  | Page-ii legal text (copyright / license / notice) | `document_metadata.boilerplate` | `:boilerplate-authority:` |
194
194
  | Footer organisation name | `document_metadata.copyright_holder` | `:copyright-holder:` |
195
+ | Cover layout (logo size/position, tagline/title size, bold edition) | `document_metadata.cover.{logo_width, logo_y, tagline_font_size, title_font_size, bold_edition}` | Generated cover image |
196
+ | Cover date | `document_metadata.doc_pub_date` | Long-format date on the generated cover + `:published-date:` |
195
197
  | Remove the OGC logo from the legal page | `document_metadata.suppress_flavor_logo` | targeted `:pdf-stylesheet-override:` |
196
198
  | Remove OGC design (crossing lines, circled numbers, rules, navy divider pages) | `document_metadata.suppress_design_elements` (or the individual `suppress_crossing_lines` / `plain_section_numbers` / `suppress_title_underlines`) | `:pdf-stylesheet-override:` + colour attributes |
199
+ | Remove the standalone section-divider pages | `document_metadata.suppress_section_divider_pages` | `:pdf-stylesheet-override:` |
200
+ | Inline section headings (`1 Scope` in one line, no circle) | `document_metadata.inline_section_headers` | `:pdf-stylesheet-override:` |
201
+ | Flatten reference hanging indent (title under authors) | `document_metadata.suppress_bibliography_indent` | `:pdf-stylesheet-override:` |
197
202
  | Every-page DRAFT-style watermark (over content) | `document_metadata.page_watermark` | `:pdf-stylesheet-override:` (footer overlay) |
198
203
  | Requirement / conformance identifier namespace | `spec_uri_base` | derives `req_uri` / `conf_uri` |
199
204
  | Submitter table, notice paragraph, normative refs, extra terms | `document_metadata.{submitters, notice, normative_references, terms}` | Metanorma attributes / sections |
205
+ | Features `/items` paging (`limit` parameter) | `paging.{enabled, default_limit, max_limit}` | OpenAPI query parameter |
200
206
 
201
207
  Custom branding requires Pillow for the cover image: `pip install 'oapi-profile-builder[pdf]'`. Field-by-field detail is in the [`document_metadata`](#document_metadata) reference below; [`examples/nwp_radar.yaml`](examples/nwp_radar.yaml) is a complete DGIWG-branded example. Omit all of these fields and the output keeps the standard OGC house style.
202
208
 
203
- > The `suppress_flavor_logo`, `suppress_design_elements`/`suppress_*`, and `page_watermark` overrides reach into the OGC Metanorma flavor's XSL templates (e.g. `insertLogoPreface`, `insertCrossingLines`, `insertSectionNumInCircle`, `insertFooter`) and are coupled to that flavor. Everything else uses documented Metanorma attributes. mn2pdf merges our same-named templates over the flavor's at equal precedence (via `merge_override.xsl`), which is what makes these work; a future metanorma-ogc release could require refreshing the template names. For long-term SDO adoption, a dedicated Metanorma "taste"/flavor is the most durable path.
209
+ > The `suppress_flavor_logo`, `suppress_design_elements`/`suppress_*`, `suppress_section_divider_pages`, `inline_section_headers`, `suppress_bibliography_indent`, and `page_watermark` overrides reach into the OGC Metanorma flavor's XSL templates (e.g. `insertLogoPreface`, `insertCrossingLines`, `insertSectionNumInCircle`, `insertFooter`, the `sections` mode, `fmt-title`, and `bibitem-normative-style`) and are coupled to that flavor. Everything else uses documented Metanorma attributes. mn2pdf merges our same-named templates over the flavor's at equal precedence (via `merge_override.xsl`), which is what makes these work; a future metanorma-ogc release could require refreshing the template names. For long-term SDO adoption, a dedicated Metanorma "taste"/flavor is the most durable path.
204
210
 
205
211
  ---
206
212
 
@@ -289,11 +295,19 @@ abstract_tests: []
289
295
  | `spec_uri_base` | string | no | Base URI for the requirements/conformance class identifiers. Defaults to the OGC EDR Part 3 namespace; override to publish under another SDO namespace (e.g. DGIWG) |
290
296
  | `parameter_name_pattern` | string | no | Regex all `parameter_names` keys must match |
291
297
  | `parameter_schema` | object | no | JSON Schema for parameter objects — replaces the default schema in the generated OpenAPI (see below) |
298
+ | `collection_title_max_length` | int | no | When set, every collection title must be present and within this many characters (MetOcean `/req/core/collection_title`) |
299
+ | `require_license_link` | bool | no | When `true`, every collection must declare a `rel='license'` link (MetOcean `/req/core/collection_license`). Defaults to `false` |
300
+ | `license_link_type` | string | no | Expected media type of the `rel='license'` link when `require_license_link` is set. Defaults to `text/html`; set to null to accept any type |
301
+ | `required_data_queries` | list | no | Data-query types every collection must define (e.g. `[locations, area, radius]`) — enforces the mandatory data-query sets |
302
+ | `radius_within_units_required` | list | no | Unit tokens each radius query's `within_units` must contain (e.g. `[m]`) (MetOcean `/req/core/collection_radius_data_query`) |
303
+ | `locations_feature_required_properties` | list | no | Feature properties (e.g. `[name]`) marked required in the generated `/locations` GeoJSON response schema, in addition to the always-required string `id` |
304
+ | `conformance_class_requirements` | object | no | Map of conformance-class short name → constraints (`required_data_queries`, `radius_within_units_required`) applied only to collections that declare the class. Lets one profile document model several EDR Part 3 requirements classes (see below) |
292
305
  | `processes` | list | no | OGC API Processes to expose in the OpenAPI |
293
306
  | `requirements` | list | no | Normative requirements for the AsciiDoc/PDF |
294
307
  | `abstract_tests` | list | no | Conformance tests — each must reference a valid requirement `id` |
295
308
  | `pubsub` | object | no | OGC API - EDR Part 2 PubSub config — generates `asyncapi.yaml` |
296
309
  | `collection_examples` | object | no | `{collectionId: {instanceId: "..."}}` — used by `validate-server` |
310
+ | `paging` | object | no | Features `/items` paging — adds a validated `limit` query parameter to the generated OpenAPI (see below) |
297
311
  | `document_metadata` | object | no | Metanorma PDF header — doc number/type/subtype, status, editors, submitters, dates, notice, normative references (see below) |
298
312
 
299
313
  ---
@@ -327,6 +341,8 @@ Uses the [edr-pydantic](https://github.com/KNMI/edr-pydantic) `Collection` model
327
341
  | `output_formats` | no | Format names this collection supports (e.g. `[CoverageJSON, GeoJSON]`) |
328
342
  | `data_queries` | no | EDR query types: `position`, `area`, `radius`, `cube`, `trajectory`, `corridor`, `locations`, `items`, `instances` |
329
343
  | `parameter_names` | no | Map of parameter id → Parameter object. All parameters must have `unit` and `observedProperty` |
344
+ | `conformance_classes` | no | Profile conformance-class short names this collection implements (e.g. `[core, insitu-observations]`). Selects which `conformance_class_requirements` are enforced; surfaced as `x-conformance-classes` in the OpenAPI |
345
+ | `parameter_schema` | no | Per-collection JSON Schema for parameter objects, overriding the profile-level `parameter_schema` for this collection only (precedence: collection → profile → default) |
330
346
 
331
347
  #### `data_queries` example
332
348
 
@@ -459,6 +475,38 @@ extent_requirements:
459
475
 
460
476
  ---
461
477
 
478
+ ### Multiple conformance classes in one profile
479
+
480
+ OGC API - EDR Part 3 profiles are modular: a single profile document can define several requirements/conformance classes, and different collections in the same service may implement different classes. The MetOcean EDR Profile is a good example — Core applies everywhere, but only in-situ collections must offer `locations`/`area`/`radius` while NWP collections must offer `position`/`cube`.
481
+
482
+ Model this with `conformance_class_requirements` (profile level) plus `conformance_classes` (per collection):
483
+
484
+ ```yaml
485
+ # Core-level rules apply to every collection:
486
+ collection_title_max_length: 50
487
+ require_license_link: true
488
+
489
+ # Class-scoped rules apply only where a collection opts in:
490
+ conformance_class_requirements:
491
+ insitu-observations:
492
+ required_data_queries: [locations, area, radius]
493
+ radius_within_units_required: [m]
494
+ nwp:
495
+ required_data_queries: [position, cube]
496
+
497
+ collections:
498
+ - id: insitu-observations
499
+ conformance_classes: [core, insitu-observations] # must have locations/area/radius
500
+ # ...
501
+ - id: nwp-forecast
502
+ conformance_classes: [core, nwp] # must have position/cube
503
+ # ...
504
+ ```
505
+
506
+ The flat `required_data_queries` / `radius_within_units_required` fields still apply to *every* collection (the Core-applies-to-all shorthand); class-scoped rules are additive. See `examples/metocean_profile.yaml` for a full worked profile spanning all four MetOcean classes.
507
+
508
+ ---
509
+
462
510
  ### `output_formats`
463
511
 
464
512
  Maps format names (referenced by `collections[].output_formats` and `data_queries.*.variables.output_formats`) to a media type and, optionally, a schema reference. The `schema_ref` flows into the generated OpenAPI response `content` for that format — use it to point a format at a specific schema (e.g. a DGIWG-published schema for GeoTIFF or CoverageJSON) instead of the tool's built-in default.
@@ -577,6 +625,21 @@ Generates: `/processes/compute-difference`, `/processes/compute-difference/execu
577
625
 
578
626
  ---
579
627
 
628
+ ### `paging`
629
+
630
+ Controls Features `/items` paging in the generated OpenAPI. When enabled (the default), a validated `limit` query parameter is added to every `/items` endpoint (collection-level and instance-level).
631
+
632
+ ```yaml
633
+ paging:
634
+ enabled: true # default true; set false to omit the limit parameter
635
+ default_limit: 10 # OpenAPI schema default for limit (default 10)
636
+ max_limit: 100 # OpenAPI schema maximum for limit (default 10000)
637
+ ```
638
+
639
+ The emitted parameter is `limit` (`in: query`, `type: integer`, `minimum: 1`, `maximum: <max_limit>`, `default: <default_limit>`).
640
+
641
+ ---
642
+
580
643
  ### `pubsub`
581
644
 
582
645
  When present, generates `asyncapi.yaml` alongside `openapi.yaml`.
@@ -622,6 +685,8 @@ document_metadata:
622
685
  submission_date: "2026-05-01" # → :received-date:
623
686
  approval_date: "2026-06-15" # → :issued-date:
624
687
  publication_date: "2026-07-01" # → :published-date:
688
+ doc_pub_date: "2026-07-16" # optional; overrides publication_date for the cover
689
+ # (long-format "16 July 2026") and :published-date:
625
690
  # Custom notice paragraph rendered in the front matter. Note: the OGC cover-page
626
691
  # legal notice itself is generated by Metanorma from doc_type/status.
627
692
  notice: >
@@ -660,6 +725,12 @@ document_metadata:
660
725
  font_bold: "Source Sans Pro" # optional bold face; derived from font_regular when unset
661
726
  font_italic: "Source Sans Pro" # optional italic face for the tagline
662
727
  watermark: "DRAFT" # optional diagonal watermark stamped on the cover
728
+ # --- cover layout (all optional) ---
729
+ logo_width: 200 # target logo width in px (default 420)
730
+ logo_y: 100 # logo vertical offset from top in px (default 180)
731
+ tagline_font_size: 20 # tagline point size (default 30)
732
+ title_font_size: 40 # title point size (default 54)
733
+ bold_edition: true # render the "Edition X" line in bold (default false)
663
734
  colors:
664
735
  text: "#000000" # body text
665
736
  cover_text: "#1F3864" # cover text / section numbers / ToC
@@ -716,6 +787,23 @@ With `cover` + `colors` + `copyright_holder` + `boilerplate` + `suppress_flavor_
716
787
 
717
788
  > These design-element overrides (and the `page_watermark` footer overlay) reach into the OGC Metanorma flavor's XSL template names and are coupled to that flavor; a future metanorma-ogc release could require refreshing them.
718
789
 
790
+ #### Structural layout changes (divider pages, inline headers, references)
791
+
792
+ `suppress_design_elements` only changes *decorative* styling — it keeps the document's structure (standalone section-divider pages, the standard heading layout, and the reference hanging indent) intact. The following are **independent, opt-in** structural changes, so the default OGC output is unaffected unless you set them:
793
+
794
+ - **`suppress_section_divider_pages: true`** — removes the standalone full-page section dividers, so each section's content follows its heading directly.
795
+ - **`inline_section_headers: true`** — renders Level 1/2 headings inline with the title (e.g. `1 Scope`, `i Abstract`) rather than the OGC circled-number layout.
796
+ - **`suppress_bibliography_indent: true`** — flattens both the Normative References and the Bibliography so each entry is a single flush paragraph, removing the hanging indent that placed the title under the authors.
797
+
798
+ ```yaml
799
+ document_metadata:
800
+ suppress_section_divider_pages: true
801
+ inline_section_headers: true
802
+ suppress_bibliography_indent: true
803
+ ```
804
+
805
+ Additionally, when `copyright_holder` is set to a non-OGC organisation, the flavor's auto-generated "Submitting Organizations" sentence ("…submitted this Document to the Open Geospatial Consortium (OGC)") is rebranded to name that organisation instead, so no residual OGC text remains in the preface.
806
+
719
807
  #### Extending Terms and Definitions
720
808
 
721
809
  Add profile-specific terms (e.g. EDR Part 3 or Pub/Sub terms) appended after the base terms in the Terms and Definitions section:
@@ -804,6 +892,12 @@ The tool enforces these rules at build time. Violations produce clear error mess
804
892
  | Parameters need `unit` + `observedProperty` | Required by OGC API - EDR Part 3 |
805
893
  | `parameter_name_pattern` enforced | All `parameter_names` keys must match if set |
806
894
  | `collection_id_pattern` enforced | All collection IDs must match if set |
895
+ | `collection_title_max_length` enforced | If set, every collection title must be present and within the limit |
896
+ | `require_license_link` enforced | If set, every collection must have a `rel='license'` link (of `license_link_type` when specified) |
897
+ | `required_data_queries` enforced | If set, every collection with `data_queries` must define each listed query type |
898
+ | `radius_within_units_required` enforced | If set, each radius query's `within_units` must contain every listed unit token |
899
+ | `conformance_class_requirements` enforced | Class-scoped `required_data_queries` / `radius_within_units_required` applied to collections whose `conformance_classes` include the class key |
900
+ | `conformance_classes` references known class | When `conformance_class_requirements` is set, a collection's `conformance_classes` may only use `core` or a defined class key (catches typos) |
807
901
  | Abstract test IDs match requirements | `requirement_id` must reference an existing requirement |
808
902
  | Requirement IDs | Must match `^[a-z0-9][a-z0-9\-]*$`, no trailing hyphen |
809
903
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "oapi-profile-builder"
7
- version = "3.4.0"
7
+ version = "3.5.0"
8
8
  description = "Authoritative tooling for creating OGC API Service Profiles (EDR, Features)"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }