From a7b2332794be545c8a12482abf4ea104cec75f83 Mon Sep 17 00:00:00 2001 From: Andreas Zwinkau Date: Fri, 22 May 2026 14:48:16 +0200 Subject: [PATCH] feat: add sphinx-jsonschema extension for JSON Schema rendering Use it in docs/reference/metamodel.rst Closes #472 --- docs/internals/extensions/metamodel.md | 2 +- docs/reference/bazel_macros.rst | 2 +- docs/reference/index.rst | 1 + docs/reference/metamodel.rst | 56 +++++++++++++ .../score_metamodel/metamodel-schema.json | 81 ++++++++++++++----- .../score_sphinx_bundle/__init__.py | 1 + src/requirements.in | 3 + src/requirements.txt | 12 ++- 8 files changed, 134 insertions(+), 24 deletions(-) create mode 100644 docs/reference/metamodel.rst diff --git a/docs/internals/extensions/metamodel.md b/docs/internals/extensions/metamodel.md index d846779a8..cdfc759ca 100644 --- a/docs/internals/extensions/metamodel.md +++ b/docs/internals/extensions/metamodel.md @@ -19,7 +19,7 @@ This extension serves multiple critical functions: ### Metamodel Definition The extension contains: - `metamodel.yaml`: The main metamodel definition -- `metamodel-schema.json`: JSON schema for validation +- `metamodel-schema.json`: JSON schema for validation (see the rendered [Schema Reference](../../reference/metamodel.rst)) - Setting configuration parameters based on input that get passed on to sphinx-needs ### Validation System diff --git a/docs/reference/bazel_macros.rst b/docs/reference/bazel_macros.rst index 70cfe74bc..b88a8bd8f 100644 --- a/docs/reference/bazel_macros.rst +++ b/docs/reference/bazel_macros.rst @@ -80,7 +80,7 @@ Minimal example (root ``BUILD``) ) The custom ``metamodel.yaml`` must follow the same schema as the default one - (see :doc:`score_metamodel `). + (see :doc:`score_metamodel ` and :ref:`metamodel_reference`). You may use ``@score_docs_as_code//src/extensions/score_metamodel:metamodel_yaml`` for extension processing. When ``metamodel`` is omitted the default metamodel is used unchanged. diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 7cc693b71..e94e65550 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -23,3 +23,4 @@ Here you find the API and usage reference for docs-as-code. commands bazel_macros + metamodel diff --git a/docs/reference/metamodel.rst b/docs/reference/metamodel.rst new file mode 100644 index 000000000..ee8c81d36 --- /dev/null +++ b/docs/reference/metamodel.rst @@ -0,0 +1,56 @@ +.. + # ******************************************************************************* + # Copyright (c) 2026 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # This program and the accompanying materials are made available under the + # terms of the Apache License Version 2.0 which is available at + # https://www.apache.org/licenses/LICENSE-2.0 + # + # SPDX-License-Identifier: Apache-2.0 + # Assisted-by: Anthropic Claude-opus-4.6 + # ******************************************************************************* + +.. _metamodel_reference: + +Metamodel Schema Reference +========================== + +The S-CORE documentation metamodel is defined in a YAML file. +It declares all Sphinx-Needs types (directives), their mandatory and optional options, +link relationships, and validation rules used across S-CORE documentation repositories. + +For details on the extension internals, validation checks, and how to add new need +types, see the :doc:`score_metamodel extension guide `. + +Schema +------ + +Below is the JSON Schema that validates the structure of ``metamodel.yaml``. + +.. jsonschema:: ../../src/extensions/score_metamodel/metamodel-schema.json + +Quick example +------------- + +A minimal type definition in ``metamodel.yaml`` looks like this: + +.. code-block:: yaml + + needs_types: + feat_req: + title: Feature Requirement + prefix: feat_req__ + mandatory_options: + id: ^feat_req__[0-9a-z_]*$ + status: ^(valid|draft)$ + optional_links: + satisfies: ^std_req__.*$ + tags: + - requirement + parts: 2 + +Each option value is a regex pattern that the corresponding field must match. +The ``parts`` key specifies how many segments (separated by ``__``) the need ID contains. diff --git a/src/extensions/score_metamodel/metamodel-schema.json b/src/extensions/score_metamodel/metamodel-schema.json index def36e539..f25a27223 100644 --- a/src/extensions/score_metamodel/metamodel-schema.json +++ b/src/extensions/score_metamodel/metamodel-schema.json @@ -1,55 +1,94 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://example.com/metamodel-schema.json", + "$id": "https://eclipse-score.github.io/docs-as-code/metamodel-schema.json", "title": "S-CORE Metamodel Schema", + "description": "Validates the structure of metamodel.yaml, which defines all Sphinx-Needs types, their options, and link relationships used across S-CORE documentation.", "type": "object", "properties": { "types": { "type": "object", - "description": "All Sphinx-Needs types (directives)", + "description": "Map of need type identifiers to their definitions. Each key becomes a Sphinx-Needs directive (e.g. ``feat_req``, ``comp_arc_sta``).", "additionalProperties": { "type": "object", + "description": "Definition of a single need type.", "properties": { - "title": { "type": "string" }, - "prefix": { "type": "string" }, - "color": { "type": "string" }, - "style": { "type": "string" }, + "title": { + "type": "string", + "description": "Human-readable display name shown in rendered documentation (e.g. 'Feature Requirement')." + }, + "prefix": { + "type": "string", + "description": "ID prefix for auto-generated need IDs. Defaults to ``__`` when omitted." + }, + "color": { + "type": "string", + "description": "CSS color used when rendering this need type in diagrams and tables." + }, + "style": { + "type": "string", + "description": "Visual style hint for diagram rendering (e.g. Plantuml stereotype)." + }, "mandatory_options": { "type": "object", - "description": "Map of field_name -> regex pattern (these fields are required).", - "additionalProperties": { "type": "string" } + "description": "Options that every need of this type must provide. Each key is a field name and its value is a regex pattern the field value must match.", + "additionalProperties": { + "type": "string" + } }, "optional_options": { "type": "object", - "description": "Map of field_name -> regex pattern (these fields are optional).", - "additionalProperties": { "type": "string" } + "description": "Options that may optionally appear on a need of this type. Validated against the regex pattern when present.", + "additionalProperties": { + "type": "string" + } }, "mandatory_links": { "type": "object", - "description": "Map of link_field_name -> regex pattern (these link fields are required).", - "additionalProperties": { "type": "string" } + "description": "Link fields that every need of this type must include. Values are regex patterns restricting which target need IDs are allowed.", + "additionalProperties": { + "type": "string" + } }, "optional_links": { "type": "object", - "description": "Map of link_field_name -> regex pattern (these link fields are optional).", - "additionalProperties": { "type": "string" } + "description": "Link fields that may optionally appear. Values are regex patterns restricting allowed target need IDs.", + "additionalProperties": { + "type": "string" + } } }, - "required": ["title", "prefix", "mandatory_options"] + "required": [ + "title", + "prefix", + "mandatory_options" + ] } }, "links": { "type": "object", - "description": "All extra link definitions. Key is the link 'option' name.", + "description": "Extra Sphinx-Needs link type definitions. Each key is the link option name used in directives (e.g. ``implements``, ``satisfies``).", "additionalProperties": { "type": "object", + "description": "A bidirectional link type definition.", "properties": { - "incoming": { "type": "string" }, - "outgoing": { "type": "string" } + "incoming": { + "type": "string", + "description": "Label shown on the target side of the link (e.g. 'is implemented by')." + }, + "outgoing": { + "type": "string", + "description": "Label shown on the source side of the link (e.g. 'implements')." + } }, - "required": ["incoming", "outgoing"] + "required": [ + "incoming", + "outgoing" + ] } } }, - "required": ["types", "links"] - } + "required": [ + "types", + "links" + ] +} diff --git a/src/extensions/score_sphinx_bundle/__init__.py b/src/extensions/score_sphinx_bundle/__init__.py index 6ae04008b..ccf160c28 100644 --- a/src/extensions/score_sphinx_bundle/__init__.py +++ b/src/extensions/score_sphinx_bundle/__init__.py @@ -31,6 +31,7 @@ "sphinxcontrib.mermaid", "needs_config_writer", "score_sync_toml", + "sphinx-jsonschema", ] diff --git a/src/requirements.in b/src/requirements.in index aff2c3d05..03aaebf82 100644 --- a/src/requirements.in +++ b/src/requirements.in @@ -33,6 +33,9 @@ needs-config-writer == 0.2.4 # Need this to enable non bazel execution bazel-runfiles +# Render JSON Schema files as documentation tables +sphinx-jsonschema + # Local development pytest basedpyright diff --git a/src/requirements.txt b/src/requirements.txt index 6c0b03a13..2457ea57b 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -446,6 +446,7 @@ docutils==0.22.4 \ # myst-parser # pydata-sphinx-theme # sphinx + # sphinx-jsonschema esbonio==0.16.5 \ --hash=sha256:04ba926e3603f7b1fde1abc690b47afd60749b64b1029b6bce8e1de0bb284921 \ --hash=sha256:acab2e16c6cf8f7232fb04e0d48514ce50566516b1f6fcf669ccf2f247e8b10f @@ -536,6 +537,10 @@ jinja2==3.1.6 \ # sphinx # sphinx-collections # sphinxcontrib-mermaid +jsonpointer==3.1.1 \ + --hash=sha256:0b801c7db33a904024f6004d526dcc53bbb8a4a0f4e32bfd10beadf60adf1900 \ + --hash=sha256:8ff8b95779d071ba472cf5bc913028df06031797532f08a7d5b602d8b2a488ca + # via sphinx-jsonschema jsonschema-rs==0.37.4 \ --hash=sha256:03b34f911e99343fc388651688683010daee538a3cf8cf86a7997bca28fdf16b \ --hash=sha256:0f17a61deb557faa57dffb9596e4f022873404f935114367788b1eebdec2bb00 \ @@ -1202,6 +1207,7 @@ pyyaml==6.0.3 \ --hash=sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0 # via # myst-parser + # sphinx-jsonschema # sphinxcontrib-mermaid requests==2.33.1 \ --hash=sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517 \ @@ -1210,6 +1216,7 @@ requests==2.33.1 \ # pygithub # requests-file # sphinx + # sphinx-jsonschema # sphinx-needs requests-file==2.1.0 \ --hash=sha256:0f549a3f3b0699415ac04d167e9cb39bccfb730cb832b4d20be3d9867356e658 \ @@ -1275,7 +1282,10 @@ sphinx-data-viewer==0.1.5 \ sphinx-design==0.7.0 \ --hash=sha256:d2a3f5b19c24b916adb52f97c5f00efab4009ca337812001109084a740ec9b7a \ --hash=sha256:f82bf179951d58f55dca78ab3706aeafa496b741a91b1911d371441127d64282 - # via -r requirements.in + # via -r src/requirements.in +sphinx-jsonschema==1.19.2 \ + --hash=sha256:1a48954217c2b3c6759c89b9ddd2c8e5b668b8730564e0283b009f23932be150 + # via -r src/requirements.in sphinx-needs[plotting]==8.0.0 \ --hash=sha256:540c380c074d4088a557ea353e91513bfc1cb7712b10925c13ac9e5ebb7be091 \ --hash=sha256:c4336ee0e3c949eff9eb11a14910f7b6b68cb8284d731cfddf97694037337674