{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://cratly.io/schema/section-types/v0.json",
  "title": "Cratly section-type manifest",
  "description": "Grammar for a section-type manifest (conventionally emitted to `.cratly/sections.json` in a website repository by a theme framework adapter such as Scavold). The manifest tells the cratly editor which section kinds a site offers and which typed properties each one accepts, so the editor can render appropriate controls (text inputs, checkboxes, media pickers, page pickers, selects) when an author inserts or edits a section. This file is framework-agnostic: any adapter (VitePress/Scavold, Next.js, Astro, …) may produce a conforming manifest. The grammar is a stable, versioned contract — tools SHOULD bundle the version(s) they understand rather than fetch this document at runtime.",
  "type": "object",
  "required": [ "specVersion", "sections" ],
  "additionalProperties": false,
  "properties": {
    "$schema": {
      "type": "string",
      "description": "Optional pointer back to this grammar. When present it SHOULD be the canonical URL of the grammar version the manifest conforms to."
    },
    "specVersion": {
      "type": "integer",
      "description": "Version of this grammar the manifest conforms to. Tools reject or warn on versions they do not support.",
      "enum": [ 0 ]
    },
    "adapter": {
      "type": "object",
      "description": "Identifies the tool that produced this manifest. Informational; the editor does not need it to render controls, but it is useful for diagnostics and cache-busting.",
      "additionalProperties": true,
      "properties": {
        "name": { "type": "string", "description": "Adapter identifier, e.g. \"scavold\"." },
        "version": { "type": "string", "description": "Adapter package version that generated this manifest." }
      }
    },
    "sections": {
      "type": "object",
      "description": "Map of section kind → its definition. The key is the container name as it appears in Markdown after the opening `:::` (e.g. \"section\", \"video\", \"hero\").",
      "propertyNames": {
        "type": "string",
        "pattern": "^[A-Za-z][A-Za-z0-9_-]*$"
      },
      "additionalProperties": { "$ref": "#/$defs/sectionDefinition" }
    }
  },
  "$defs": {
    "sectionDefinition": {
      "type": "object",
      "description": "Editor-facing description of a single section kind.",
      "additionalProperties": false,
      "properties": {
        "label": {
          "type": "string",
          "description": "Human-readable name shown in the editor's section-type picker. When absent, editors fall back to the raw container name."
        },
        "hint": {
          "type": "string",
          "description": "Short explanatory text describing what this section is for, shown in the editor."
        },
        "props": {
          "type": "object",
          "description": "Map of property name → its definition. The property name is the key an author writes in the section's opening line (a bare flag for boolean props, or `name=value` for all other types).",
          "propertyNames": {
            "type": "string",
            "pattern": "^[A-Za-z][A-Za-z0-9_-]*$"
          },
          "additionalProperties": { "$ref": "#/$defs/propDefinition" }
        }
      }
    },
    "propDefinition": {
      "type": "object",
      "description": "A single customizable property of a section. `type` selects both the editor widget and the value's processing rules.",
      "required": [ "type" ],
      "additionalProperties": false,
      "properties": {
        "type": {
          "type": "string",
          "description": "Determines the editor widget and how adapters process the value.",
          "enum": [ "text", "textarea", "boolean", "number", "media-file", "page-ref", "enum" ]
        },
        "label": {
          "type": "string",
          "description": "Human-readable label shown next to the control. When absent, editors derive one from the property name."
        },
        "hint": {
          "type": "string",
          "description": "Short explanatory text shown below the control."
        },
        "required": {
          "type": "boolean",
          "description": "When true, editors should require a value before the section is considered valid.",
          "default": false
        },
        "default": {
          "description": "Default value the editor pre-fills. Its JSON type should match `type` (boolean for boolean, number for number, string otherwise)."
        },
        "values": {
          "type": "array",
          "description": "Allowed choices. REQUIRED when `type` is \"enum\" and ignored otherwise. Each entry is either a bare string value, or an object pairing a value with a display label.",
          "minItems": 1,
          "items": {
            "oneOf": [
              { "type": "string" },
              {
                "type": "object",
                "required": [ "value" ],
                "additionalProperties": false,
                "properties": {
                  "value": { "type": "string", "description": "The stored value written to Markdown." },
                  "label": { "type": "string", "description": "Display text shown in the select control." }
                }
              }
            ]
          }
        }
      },
      "allOf": [
        {
          "if": { "properties": { "type": { "const": "enum" } } },
          "then": { "required": [ "values" ] },
          "else": { "not": { "required": [ "values" ] } }
        }
      ]
    }
  }
}
