{# Bengal OpenAPI Schema Component Library (Kida) ============================================== Recursive {% def %} component for displaying JSON Schema / OpenAPI schema objects. Migrated from partials/schema-viewer.html (kept as a reference/fallback) to an explicit, importable component with no ambient {% let %} context. Usage: {% from 'autodoc/openapi/_schema.html' import schema_viewer %} {{ schema_viewer(schema, name=schema_name, depth=0) }} Parameters: - schema: OpenAPISchemaMetadata or dict (schema_type/type, properties, required, enum, example, items, description, and — for advanced specs — oneOf/anyOf/allOf, discriminator, additionalProperties, and per-property constraints/flags). - name: Schema name for display (optional, default none) - depth: Nesting depth for indentation + recursion guard (default 0) Advanced rendering (#285) is driven by template-function filters so the same recursion handles top-level schemas and nested raw property schemas: schema_composition / schema_constraints / schema_flags / schema_additional_properties. Each returns an empty/None result when its construct is absent, so simple schemas render exactly as before. Kida Features (confirmed against installed kida-templates): - {% def name(param=default) %} with recursive self-invocation - {% cache %} for expensive recursive rendering - {% with %} for nil-safe optional sections - Optional chaining (?.) and null coalescing (??) #} {% def schema_viewer(schema, name=none, depth=0) %} {% let schema_name = name | default('') %} {% let schema_type = schema?.schema_type ?? schema?.type ?? 'object' %} {% let properties = schema?.properties ?? {} %} {% let required_props = schema?.required ?? () %} {% let enum_vals = schema?.enum ?? none %} {% let items_schema = schema?.items ?? none %} {% let description = schema?.description ?? '' %} {% let current_depth = depth ?? 0 %} {% let max_depth = 4 %} {% let composition = schema | schema_composition %} {% let constraints = schema | schema_constraints %} {% let flags = schema | schema_flags %} {% let additional = schema | schema_additional_properties %} {% let ref_name = schema | schema_ref %} {# Distinct cache namespace ('oa-schema-def-') so this {% def %} never collides with the legacy partials/schema-viewer.html {% include %} (key prefix 'schema-viewer-') that list/responses/request-body still use. The legacy partial keys only on (name, depth); sharing that namespace caused anonymous nested schemas to return each other's cached fragments. #} {% cache 'oa-schema-def-' ~ (schema_name or 'anon') ~ '-' ~ current_depth %} {% if ref_name is not none %} {# Cyclic $ref left by the extractor: show a readable indicator, not an empty box. #}
{{ schema_name }}
{{ schema_type }}
{% if flags?.nullable %}nullable{% end %}
{% if flags?.deprecated %}deprecated{% end %}
{{ clabel }}{% if cvalue %}: {{ cvalue }}{% end %}
{% end %}
{{ composition.discriminator.property_name }}
{% if composition.discriminator.mapping | length > 0 %}
{{ row.value }} {{ row.target }}{{ branch.label }} {{ branch.schema_type }}
{% elif current_depth < max_depth %}
{{ prop_name }}
{{ prop_type }}
{% if is_required %}required{% end %}
{% if prop_flags?.nullable %}nullable{% end %}
{% if prop_flags?.readOnly %}read-only{% end %}
{% if prop_flags?.writeOnly %}write-only{% end %}
{% if prop_flags?.deprecated %}deprecated{% end %}
{{ clabel }}{% if cvalue %}: {{ cvalue }}{% end %}
{% end %}
{{ val }}
{% end %}
{{ default }}
{{ additional.schema_type }}{% end %}
{% elif additional?.allowed %}
Allows additional properties
{% else %}
No additional properties
{% end %}
{{ val }}
{% end %}
{{ ex.value | tojson(indent=2) }}