diff --git a/.github/pr-screenshots/926/asyncapi-union-variants.png b/.github/pr-screenshots/926/asyncapi-union-variants.png new file mode 100644 index 000000000..27504b68f Binary files /dev/null and b/.github/pr-screenshots/926/asyncapi-union-variants.png differ diff --git a/docs-main/reference/json-api-asyncapi-reference/operations/v2-commands-completions/subscribe.mdx b/docs-main/reference/json-api-asyncapi-reference/operations/v2-commands-completions/subscribe.mdx index 03eedc353..980aaf8ca 100644 --- a/docs-main/reference/json-api-asyncapi-reference/operations/v2-commands-completions/subscribe.mdx +++ b/docs-main/reference/json-api-asyncapi-reference/operations/v2-commands-completions/subscribe.mdx @@ -131,6 +131,18 @@ title: "Subscribe completions" +
+
Variants
+ +
+
+

CompletionStreamResponse

+ +

object

+ +
+ +
@@ -144,6 +156,190 @@ title: "Subscribe completions"
+
+
Variants
+ +
+
+

completionResponse

+ +

oneOf

+ +
+ + +
+ +
+
+ Completion + object + +
+ +
+ +
+ +
+
Variants
+ +
+
+

Completion

+ +

object

+ +
+ + +
+ +
+
+ Completion + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

Empty

+ +

object

+ +
+ + +
+ +
+
+ Empty + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

OffsetCheckpoint

+ +

object

+ +
+ + +
+ +
+
+ OffsetCheckpoint + object + + required + +
+ +
+ +
+ + + +
+ +
+ + +
+ +
+ + +
+ +
+
+

JsCantonError

+ +

object

+ +
+ + +
+ +
+
+ code + string + + required + +
+ +
+ +
+
+ cause + string + + required + +
+ +
+ +
+
+ context + object + + required + +
+ +
+ +
+
+ errorCategory + string + + required + +
+ +
+ +
+ + + +
+ +
@@ -175,6 +371,18 @@ title: "Subscribe completions"
+
+
Variants
+ +
+
+

CompletionStreamResponse

+ +

object

+ +
+ +
@@ -188,6 +396,190 @@ title: "Subscribe completions"
+
+
Variants
+ +
+
+

completionResponse

+ +

oneOf

+ +
+ + +
+ +
+
+ Completion + object + +
+ +
+ +
+ +
+
Variants
+ +
+
+

Completion

+ +

object

+ +
+ + +
+ +
+
+ Completion + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

Empty

+ +

object

+ +
+ + +
+ +
+
+ Empty + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

OffsetCheckpoint

+ +

object

+ +
+ + +
+ +
+
+ OffsetCheckpoint + object + + required + +
+ +
+ +
+ + + +
+ +
+ + +
+ +
+ + +
+ +
+
+

JsCantonError

+ +

object

+ +
+ + +
+ +
+
+ code + string + + required + +
+ +
+ +
+
+ cause + string + + required + +
+ +
+ +
+
+ context + object + + required + +
+ +
+ +
+
+ errorCategory + string + + required + +
+ +
+ +
+ + + +
+ +
diff --git a/docs-main/reference/json-api-asyncapi-reference/operations/v2-state-active-contracts/subscribe.mdx b/docs-main/reference/json-api-asyncapi-reference/operations/v2-state-active-contracts/subscribe.mdx index 9a6103b4d..7cae38995 100644 --- a/docs-main/reference/json-api-asyncapi-reference/operations/v2-state-active-contracts/subscribe.mdx +++ b/docs-main/reference/json-api-asyncapi-reference/operations/v2-state-active-contracts/subscribe.mdx @@ -131,6 +131,18 @@ title: "Subscribe active contracts" +
+
Variants
+ +
+
+

JsCantonError

+ +

object

+ +
+ +
@@ -138,6 +150,8 @@ title: "Subscribe active contracts" code string + required +
@@ -147,6 +161,8 @@ title: "Subscribe active contracts" cause string + required +
@@ -156,6 +172,8 @@ title: "Subscribe active contracts" context object + required +
@@ -165,6 +183,132 @@ title: "Subscribe active contracts" errorCategory string + required + + + + + + + + + + + +
+
+

JsGetActiveContractsResponse

+ +

object

+ +
+ + +
+ +
+
+ workflowId + string + +
+ +
+ +
+
+ contractEntry + object + +
+ +
+ +
+
+ streamContinuationToken + string + +
+ +
+ +
+ +
+
Variants
+ +
+
+

contractEntry

+ +

oneOf

+ +
+ + +
+ +
+
+ JsActiveContract + object + +
+ +
+ +
+ +
+
Variants
+ +
+
+

JsActiveContract

+ +

object

+ +
+ + +
+ +
+
+ JsActiveContract + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

JsEmpty

+ +

object

+ +
+ + +
+ +
+
+ JsEmpty + object + + required +
@@ -173,6 +317,77 @@ title: "Subscribe active contracts" +
+ +
+
+

JsIncompleteAssigned

+ +

object

+ +
+ + +
+ +
+
+ JsIncompleteAssigned + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

JsIncompleteUnassigned

+ +

object

+ +
+ + +
+ +
+
+ JsIncompleteUnassigned + object + + required + +
+ +
+ +
+ + + +
+ +
+ + +
+ +
+ + +
+ +
+ + @@ -202,6 +417,18 @@ title: "Subscribe active contracts"
+
+
Variants
+ +
+
+

JsCantonError

+ +

object

+ +
+ +
@@ -209,6 +436,8 @@ title: "Subscribe active contracts" code string + required +
@@ -218,6 +447,8 @@ title: "Subscribe active contracts" cause string + required +
@@ -227,6 +458,8 @@ title: "Subscribe active contracts" context object + required +
@@ -236,6 +469,132 @@ title: "Subscribe active contracts" errorCategory string + required + + + + + + + + + + + +
+
+

JsGetActiveContractsResponse

+ +

object

+ +
+ + +
+ +
+
+ workflowId + string + +
+ +
+ +
+
+ contractEntry + object + +
+ +
+ +
+
+ streamContinuationToken + string + +
+ +
+ +
+ +
+
Variants
+ +
+
+

contractEntry

+ +

oneOf

+ +
+ + +
+ +
+
+ JsActiveContract + object + +
+ +
+ +
+ +
+
Variants
+ +
+
+

JsActiveContract

+ +

object

+ +
+ + +
+ +
+
+ JsActiveContract + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

JsEmpty

+ +

object

+ +
+ + +
+ +
+
+ JsEmpty + object + + required +
@@ -244,6 +603,77 @@ title: "Subscribe active contracts" +
+ +
+
+

JsIncompleteAssigned

+ +

object

+ +
+ + +
+ +
+
+ JsIncompleteAssigned + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

JsIncompleteUnassigned

+ +

object

+ +
+ + +
+ +
+
+ JsIncompleteUnassigned + object + + required + +
+ +
+ +
+ + + +
+ +
+ + +
+ +
+ + +
+ +
+ + diff --git a/docs-main/reference/json-api-asyncapi-reference/operations/v2-updates-flats/subscribe.mdx b/docs-main/reference/json-api-asyncapi-reference/operations/v2-updates-flats/subscribe.mdx index 5c7b7c409..ef9e109d4 100644 --- a/docs-main/reference/json-api-asyncapi-reference/operations/v2-updates-flats/subscribe.mdx +++ b/docs-main/reference/json-api-asyncapi-reference/operations/v2-updates-flats/subscribe.mdx @@ -131,6 +131,18 @@ title: "Subscribe flats" +
+
Variants
+ +
+
+

JsCantonError

+ +

object

+ +
+ +
@@ -138,6 +150,8 @@ title: "Subscribe flats" code string + required +
@@ -147,6 +161,8 @@ title: "Subscribe flats" cause string + required +
@@ -156,6 +172,8 @@ title: "Subscribe flats" context object + required + @@ -165,6 +183,142 @@ title: "Subscribe flats" errorCategory string + required + + + + + + + + + + + +
+
+

JsGetUpdatesResponse

+ +

object

+ +
+ + +
+ +
+
+ update + object + +
+ +
+ +
+ +
+
Variants
+ +
+
+

update

+ +

oneOf

+ +
+ + +
+ +
+
+ OffsetCheckpoint + object + +
+ +
+ +
+ +
+
Variants
+ +
+
+

OffsetCheckpoint

+ +

object

+ +
+ + +
+ +
+
+ OffsetCheckpoint + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

Reassignment

+ +

object

+ +
+ + +
+ +
+
+ Reassignment + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

TopologyTransaction

+ +

object

+ +
+ + +
+ +
+
+ TopologyTransaction + object + + required +
@@ -173,6 +327,49 @@ title: "Subscribe flats" +
+ +
+
+

Transaction

+ +

object

+ +
+ + +
+ +
+
+ Transaction + object + + required + +
+ +
+ +
+ + + +
+ +
+ + +
+ +
+ + +
+ +
+ + @@ -202,6 +399,18 @@ title: "Subscribe flats"
+
+
Variants
+ +
+
+

JsCantonError

+ +

object

+ +
+ +
@@ -209,6 +418,8 @@ title: "Subscribe flats" code string + required +
@@ -218,6 +429,8 @@ title: "Subscribe flats" cause string + required +
@@ -227,6 +440,8 @@ title: "Subscribe flats" context object + required +
@@ -236,6 +451,142 @@ title: "Subscribe flats" errorCategory string + required + + + + + + + + + + + +
+
+

JsGetUpdatesResponse

+ +

object

+ +
+ + +
+ +
+
+ update + object + +
+ +
+ +
+ +
+
Variants
+ +
+
+

update

+ +

oneOf

+ +
+ + +
+ +
+
+ OffsetCheckpoint + object + +
+ +
+ +
+ +
+
Variants
+ +
+
+

OffsetCheckpoint

+ +

object

+ +
+ + +
+ +
+
+ OffsetCheckpoint + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

Reassignment

+ +

object

+ +
+ + +
+ +
+
+ Reassignment + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

TopologyTransaction

+ +

object

+ +
+ + +
+ +
+
+ TopologyTransaction + object + + required +
@@ -244,6 +595,49 @@ title: "Subscribe flats" +
+ +
+
+

Transaction

+ +

object

+ +
+ + +
+ +
+
+ Transaction + object + + required + +
+ +
+ +
+ + + +
+ +
+ + +
+ +
+ + +
+ +
+ + diff --git a/docs-main/reference/json-api-asyncapi-reference/operations/v2-updates-trees/subscribe.mdx b/docs-main/reference/json-api-asyncapi-reference/operations/v2-updates-trees/subscribe.mdx index c9c889e4e..1dfa0446b 100644 --- a/docs-main/reference/json-api-asyncapi-reference/operations/v2-updates-trees/subscribe.mdx +++ b/docs-main/reference/json-api-asyncapi-reference/operations/v2-updates-trees/subscribe.mdx @@ -131,6 +131,18 @@ title: "Subscribe trees" +
+
Variants
+ +
+
+

JsCantonError

+ +

object

+ +
+ +
@@ -138,6 +150,8 @@ title: "Subscribe trees" code string + required +
@@ -147,6 +161,8 @@ title: "Subscribe trees" cause string + required +
@@ -156,6 +172,8 @@ title: "Subscribe trees" context object + required + @@ -165,6 +183,8 @@ title: "Subscribe trees" errorCategory string + required + @@ -173,6 +193,155 @@ title: "Subscribe trees" + + +
+
+

JsGetUpdateTreesResponse

+ +

object

+ +
+ + +
+ +
+
+ update + object + +
+ +
+ +
+ +
+
Variants
+ +
+
+

update

+ +

oneOf

+ +
+ + +
+ +
+
+ OffsetCheckpoint + object + +
+ +
+ +
+ +
+
Variants
+ +
+
+

OffsetCheckpoint

+ +

object

+ +
+ + +
+ +
+
+ OffsetCheckpoint + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

Reassignment

+ +

object

+ +
+ + +
+ +
+
+ Reassignment + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

TransactionTree

+ +

object

+ +
+ + +
+ +
+
+ TransactionTree + object + + required + +
+ +
+ +
+ + + +
+ +
+ + +
+ +
+ + +
+ + + + @@ -202,6 +371,18 @@ title: "Subscribe trees"
+
+
Variants
+ +
+
+

JsCantonError

+ +

object

+ +
+ +
@@ -209,6 +390,8 @@ title: "Subscribe trees" code string + required +
@@ -218,6 +401,8 @@ title: "Subscribe trees" cause string + required +
@@ -227,6 +412,8 @@ title: "Subscribe trees" context object + required +
@@ -236,6 +423,8 @@ title: "Subscribe trees" errorCategory string + required + @@ -244,6 +433,155 @@ title: "Subscribe trees" + + +
+
+

JsGetUpdateTreesResponse

+ +

object

+ +
+ + +
+ +
+
+ update + object + +
+ +
+ +
+ +
+
Variants
+ +
+
+

update

+ +

oneOf

+ +
+ + +
+ +
+
+ OffsetCheckpoint + object + +
+ +
+ +
+ +
+
Variants
+ +
+
+

OffsetCheckpoint

+ +

object

+ +
+ + +
+ +
+
+ OffsetCheckpoint + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

Reassignment

+ +

object

+ +
+ + +
+ +
+
+ Reassignment + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

TransactionTree

+ +

object

+ +
+ + +
+ +
+
+ TransactionTree + object + + required + +
+ +
+ +
+ + + +
+ +
+ + +
+ +
+ + +
+ + + + diff --git a/docs-main/reference/json-api-asyncapi-reference/operations/v2-updates/subscribe.mdx b/docs-main/reference/json-api-asyncapi-reference/operations/v2-updates/subscribe.mdx index 368afad16..a49ae0d0d 100644 --- a/docs-main/reference/json-api-asyncapi-reference/operations/v2-updates/subscribe.mdx +++ b/docs-main/reference/json-api-asyncapi-reference/operations/v2-updates/subscribe.mdx @@ -131,6 +131,18 @@ title: "Subscribe updates" +
+
Variants
+ +
+
+

JsCantonError

+ +

object

+ +
+ +
@@ -138,6 +150,8 @@ title: "Subscribe updates" code string + required +
@@ -147,6 +161,8 @@ title: "Subscribe updates" cause string + required +
@@ -156,6 +172,8 @@ title: "Subscribe updates" context object + required + @@ -165,6 +183,142 @@ title: "Subscribe updates" errorCategory string + required + + + + + + + + + + + +
+
+

JsGetUpdatesResponse

+ +

object

+ +
+ + +
+ +
+
+ update + object + +
+ +
+ +
+ +
+
Variants
+ +
+
+

update

+ +

oneOf

+ +
+ + +
+ +
+
+ OffsetCheckpoint + object + +
+ +
+ +
+ +
+
Variants
+ +
+
+

OffsetCheckpoint

+ +

object

+ +
+ + +
+ +
+
+ OffsetCheckpoint + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

Reassignment

+ +

object

+ +
+ + +
+ +
+
+ Reassignment + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

TopologyTransaction

+ +

object

+ +
+ + +
+ +
+
+ TopologyTransaction + object + + required +
@@ -173,6 +327,49 @@ title: "Subscribe updates" +
+ +
+
+

Transaction

+ +

object

+ +
+ + +
+ +
+
+ Transaction + object + + required + +
+ +
+ +
+ + + +
+ +
+ + +
+ +
+ + +
+ +
+ + @@ -202,6 +399,18 @@ title: "Subscribe updates"
+
+
Variants
+ +
+
+

JsCantonError

+ +

object

+ +
+ +
@@ -209,6 +418,8 @@ title: "Subscribe updates" code string + required +
@@ -218,6 +429,8 @@ title: "Subscribe updates" cause string + required +
@@ -227,6 +440,8 @@ title: "Subscribe updates" context object + required +
@@ -236,6 +451,142 @@ title: "Subscribe updates" errorCategory string + required + + + + + + + + + + + +
+
+

JsGetUpdatesResponse

+ +

object

+ +
+ + +
+ +
+
+ update + object + +
+ +
+ +
+ +
+
Variants
+ +
+
+

update

+ +

oneOf

+ +
+ + +
+ +
+
+ OffsetCheckpoint + object + +
+ +
+ +
+ +
+
Variants
+ +
+
+

OffsetCheckpoint

+ +

object

+ +
+ + +
+ +
+
+ OffsetCheckpoint + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

Reassignment

+ +

object

+ +
+ + +
+ +
+
+ Reassignment + object + + required + +
+ +
+ +
+ + + +
+ +
+
+

TopologyTransaction

+ +

object

+ +
+ + +
+ +
+
+ TopologyTransaction + object + + required +
@@ -244,6 +595,49 @@ title: "Subscribe updates" +
+ +
+
+

Transaction

+ +

object

+ +
+ + +
+ +
+
+ Transaction + object + + required + +
+ +
+ +
+ + + +
+ +
+ + +
+ +
+ + +
+ +
+ + diff --git a/docs-main/styles.css b/docs-main/styles.css index e174f4d38..12f9adb0f 100644 --- a/docs-main/styles.css +++ b/docs-main/styles.css @@ -970,6 +970,47 @@ body:has(.x2mdx-ref-page--operation) [aria-label="Table of contents"] { overflow-wrap: anywhere; } +.x2mdx-ref-schema-variants { + display: grid; + gap: 0.8rem; + margin-top: 0.9rem; +} + +.x2mdx-ref-schema-variant-label { + font-size: 0.77rem; + font-weight: 700; + text-transform: uppercase; + color: rgb(107, 114, 128); +} + +.x2mdx-ref-schema-variant { + display: grid; + gap: 0.65rem; + min-width: 0; + padding: 0.85rem; + border: 1px solid rgba(15, 23, 42, 0.08); + border-radius: 0.65rem; + background: rgba(248, 250, 252, 0.72); +} + +:root.dark .x2mdx-ref-schema-variant, +[data-theme="dark"] .x2mdx-ref-schema-variant { + border-color: rgba(255, 255, 255, 0.08); + background: rgba(17, 24, 39, 0.58); +} + +.x2mdx-ref-schema-variant-head { + display: grid; + gap: 0.25rem; +} + +.x2mdx-ref-schema-variant-head h4 { + margin: 0; + font-size: 0.94rem; + line-height: 1.3; + overflow-wrap: anywhere; +} + body:has(.x2mdx-ref-hero) #table-of-contents-content a, body:has(.x2mdx-ref-hero) [aria-label="Table of contents"] a { overflow-wrap: anywhere; diff --git a/src/x2mdx/asyncapi/lifecycle.py b/src/x2mdx/asyncapi/lifecycle.py index 56763c721..a9e693e6c 100644 --- a/src/x2mdx/asyncapi/lifecycle.py +++ b/src/x2mdx/asyncapi/lifecycle.py @@ -17,6 +17,7 @@ AsyncApiChannelLifecycle, AsyncApiMessageDetail, AsyncApiReport, + AsyncApiSchemaVariantDetail, AsyncApiSourceSnapshot, ) from x2mdx.types import JsonObject, JsonValue @@ -312,6 +313,113 @@ def schema_sample_value( return schema_type_token(doc, resolved) +def schema_variant_name(doc: AsyncApiDocument, schema: JsonValue | None, *, index: int) -> str: + ref_name = local_ref_name(schema, prefix="components/schemas") + if ref_name: + return ref_name + + resolved = resolve_local_ref(doc, schema) + if not isinstance(resolved, dict): + return f"Variant {index + 1}" + + title = resolved.get("title") + if isinstance(title, str) and title.strip(): + return title.strip() + + properties = resolved.get("properties") + if isinstance(properties, dict) and len(properties) == 1: + return str(next(iter(properties))) + + required = resolved.get("required") + if isinstance(required, list) and len(required) == 1: + return str(required[0]) + + return f"Variant {index + 1}" + + +def schema_variants( + doc: AsyncApiDocument, + schema: JsonValue | None, + *, + max_depth: int = REQUEST_SAMPLE_MAX_DEPTH, + seen_refs: set[str] | None = None, +) -> list[AsyncApiSchemaVariantDetail]: + if max_depth <= 0: + return [] + + if seen_refs is None: + seen_refs = set() + + if isinstance(schema, dict): + ref = schema.get("$ref") + if isinstance(ref, str): + if ref in seen_refs: + return [] + return schema_variants( + doc, + resolve_local_ref(doc, schema), + max_depth=max_depth, + seen_refs=seen_refs | {ref}, + ) + + resolved = resolve_local_ref(doc, schema) + if not isinstance(resolved, dict): + return [] + + raw_variants = resolved.get("oneOf") + if not isinstance(raw_variants, list): + raw_variants = resolved.get("anyOf") + if not isinstance(raw_variants, list): + property_variants: list[AsyncApiSchemaVariantDetail] = [] + properties, required = object_schema_properties_and_required(doc, resolved, max_depth=max_depth) + for property_name, property_schema in properties.items(): + nested_variants = schema_variants( + doc, + property_schema, + max_depth=max_depth - 1, + seen_refs=seen_refs, + ) + if nested_variants: + property_variants.append( + { + "name": property_name, + "payload_schema": schema_brief(doc, property_schema), + "required_fields": [property_name] if property_name in required else [], + "sample": schema_sample_value( + doc, + property_schema, + max_depth=max_depth, + seen_refs=seen_refs, + ), + "variants": nested_variants, + } + ) + return property_variants + + variants: list[AsyncApiSchemaVariantDetail] = [] + for index, variant_schema in enumerate(raw_variants): + variants.append( + { + "name": schema_variant_name(doc, variant_schema, index=index), + "payload_schema": schema_brief(doc, variant_schema), + "required_fields": schema_required_field_names(doc, variant_schema), + "sample": schema_sample_value( + doc, + variant_schema, + max_depth=max_depth, + seen_refs=seen_refs, + ), + "variants": schema_variants( + doc, + variant_schema, + max_depth=max_depth - 1, + seen_refs=seen_refs, + ), + } + ) + return variants + + def extract_message_detail(doc: AsyncApiDocument, message_node: JsonValue | None) -> AsyncApiMessageDetail: resolved_message = resolve_local_ref(doc, message_node) message_name = local_ref_name(message_node, prefix="components/messages") @@ -322,6 +430,7 @@ def extract_message_detail(doc: AsyncApiDocument, message_node: JsonValue | None "payload_schema": "-", "required_fields": [], "sample": None, + "variants": [], } payload = resolved_message.get("payload") @@ -331,6 +440,7 @@ def extract_message_detail(doc: AsyncApiDocument, message_node: JsonValue | None "payload_schema": schema_brief(doc, payload) if payload is not None else "-", "required_fields": schema_required_field_names(doc, payload) if payload is not None else [], "sample": schema_sample_value(doc, payload) if payload is not None else None, + "variants": schema_variants(doc, payload) if payload is not None else [], } diff --git a/src/x2mdx/asyncapi/models.py b/src/x2mdx/asyncapi/models.py index 1da10c837..5fb68faab 100644 --- a/src/x2mdx/asyncapi/models.py +++ b/src/x2mdx/asyncapi/models.py @@ -15,12 +15,21 @@ class AsyncApiDocument(TypedDict, total=False): components: JsonObject +class AsyncApiSchemaVariantDetail(TypedDict): + name: str + payload_schema: str + required_fields: list[str] + sample: JsonValue | None + variants: list["AsyncApiSchemaVariantDetail"] + + class AsyncApiMessageDetail(TypedDict): name: str content_type: str payload_schema: str required_fields: list[str] sample: JsonValue | None + variants: list[AsyncApiSchemaVariantDetail] class AsyncApiActionDetail(TypedDict): diff --git a/src/x2mdx/asyncapi/render.py b/src/x2mdx/asyncapi/render.py index b18ed2d75..6cd6acdfb 100644 --- a/src/x2mdx/asyncapi/render.py +++ b/src/x2mdx/asyncapi/render.py @@ -18,6 +18,7 @@ ReferenceMetaItem, ReferenceOperationPage, ReferencePanel, + ReferenceSchema, ReferenceSection, compact_text, markdown_page_from_template, @@ -109,8 +110,17 @@ def action_schema(action: dict[str, Any], *, anchor: str): message = dict(action.get("message") or {}) sample = message.get("sample") required_fields = list(message.get("required_fields") or []) - if sample is None and not required_fields: + variant_schemas = [schema_from_variant(variant) for variant in message.get("variants") or []] + if sample is None and not required_fields and not variant_schemas: return None + if variant_schemas: + return ReferenceSchema( + name=str(message.get("name") or action["action"]), + summary=str(message.get("payload_schema") or "-"), + description=str(action.get("description") or ""), + anchor=anchor, + variants=variant_schemas, + ) return schema_from_sample( name=str(message.get("name") or action["action"]), sample=sample, @@ -121,6 +131,16 @@ def action_schema(action: dict[str, Any], *, anchor: str): ) +def schema_from_variant(variant: dict[str, Any]) -> ReferenceSchema: + return schema_from_sample( + name=str(variant.get("name") or "Variant"), + sample=variant.get("sample"), + required_fields=list(variant.get("required_fields") or []), + summary=str(variant.get("payload_schema") or "-"), + variants=[schema_from_variant(child) for child in variant.get("variants") or []], + ) + + def wscat_example(action: dict[str, Any]) -> str: sample = action["message"].get("sample") if action["action"] == "publish" and sample is not None: diff --git a/src/x2mdx/reference_pages.py b/src/x2mdx/reference_pages.py index 920dc90cc..53adbf2fb 100644 --- a/src/x2mdx/reference_pages.py +++ b/src/x2mdx/reference_pages.py @@ -55,6 +55,7 @@ class ReferenceSchema: description: str = "" anchor: str | None = None fields: list[ReferenceField] = field(default_factory=list) + variants: list["ReferenceSchema"] = field(default_factory=list) enum_values: list[str] = field(default_factory=list) example: ReferenceExample | None = None @@ -233,6 +234,7 @@ def schema_from_sample( description: str = "", summary: str = "", anchor: str | None = None, + variants: list[ReferenceSchema] | None = None, ) -> ReferenceSchema: required = set(required_fields or []) fields: list[ReferenceField] = [] @@ -261,5 +263,6 @@ def schema_from_sample( description=description, anchor=anchor, fields=fields, + variants=variants or [], example=example, ) diff --git a/src/x2mdx/templates/shared/reference_macros.md.j2 b/src/x2mdx/templates/shared/reference_macros.md.j2 index 4b17d7377..d8a0f0b6d 100644 --- a/src/x2mdx/templates/shared/reference_macros.md.j2 +++ b/src/x2mdx/templates/shared/reference_macros.md.j2 @@ -145,6 +145,22 @@

{{ escape_mdx_html_text(inline_text(schema.description)) }}

{% endif %} {{ fields_table(schema.fields) }} +{%- if schema.variants %} +
+
Variants
+ {% for variant in schema.variants %} +
+
+

{{ escape_mdx_html_text(inline_text(variant.name)) }}

+ {% if variant.summary %} +

{{ escape_mdx_html_text(inline_text(variant.summary)) }}

+ {% endif %} +
+ {{ schema_body(variant, render_example=render_example, render_description=render_description) }} +
+ {% endfor %} +
+{%- endif %} {% if schema.enum_values %}