{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Document",
  "description": "Portable AST. Use [`crate::parse`] or [`Document::new`] to create a document.",
  "type": "object",
  "properties": {
    "children": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/Node"
      }
    },
    "limits": {
      "$ref": "#/$defs/Limits"
    },
    "position": {
      "$ref": "#/$defs/Position"
    },
    "tokenizer": {
      "type": "string"
    },
    "version": {
      "type": "string"
    }
  },
  "additionalProperties": false,
  "required": [
    "version",
    "tokenizer",
    "limits",
    "children",
    "position"
  ],
  "$defs": {
    "Limits": {
      "description": "Limits are tokens, stored as expanded integers (`1.5k` becomes 1500).",
      "type": "object",
      "properties": {
        "max_tokens": {
          "type": [
            "integer",
            "null"
          ],
          "format": "uint64",
          "minimum": 0
        },
        "per_item": {
          "description": "Applies to each direct child section; does not change grandchildren.",
          "type": [
            "integer",
            "null"
          ],
          "format": "uint64",
          "minimum": 0
        },
        "reason": {
          "description": "Required, nonblank rationale whenever either limit is declared.",
          "type": [
            "string",
            "null"
          ]
        },
        "sig": {
          "description": "Short budget checksum, generated by `sign`; not an approval or identity.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "additionalProperties": false
    },
    "Node": {
      "description": "Markdown stays literal text. These are the only content node kinds.",
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "kind": {
              "type": "string",
              "const": "text"
            },
            "value": {
              "type": "string"
            }
          },
          "additionalProperties": false,
          "required": [
            "kind",
            "value"
          ]
        },
        {
          "description": "A semantic grouping. IDs have no provider-specific role or trust meaning.",
          "type": "object",
          "properties": {
            "children": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/Node"
              }
            },
            "id": {
              "type": [
                "string",
                "null"
              ]
            },
            "kind": {
              "type": "string",
              "const": "section"
            },
            "limits": {
              "$ref": "#/$defs/Limits"
            },
            "position": {
              "$ref": "#/$defs/Position"
            }
          },
          "additionalProperties": false,
          "required": [
            "kind",
            "limits",
            "children",
            "position"
          ]
        },
        {
          "description": "A named string slot: `{{question}}`. Variables have no limits.\n\n```compile_fail\nuse htmlp::{Variable, Position};\nlet slot = Variable { id: \"question\".into(), max_tokens: 100, position: Position::default() };\n```",
          "type": "object",
          "properties": {
            "id": {
              "type": "string"
            },
            "kind": {
              "type": "string",
              "const": "variable"
            },
            "position": {
              "$ref": "#/$defs/Position"
            }
          },
          "additionalProperties": false,
          "required": [
            "kind",
            "id",
            "position"
          ]
        }
      ]
    },
    "Position": {
      "description": "One-based Unicode-scalar line/column; zero-based UTF-8 byte offset.\nZero line/column denotes an unknown location or an in-memory node.",
      "type": "object",
      "properties": {
        "column": {
          "type": "integer",
          "format": "uint",
          "minimum": 0
        },
        "line": {
          "type": "integer",
          "format": "uint",
          "minimum": 0
        },
        "offset": {
          "type": "integer",
          "format": "uint",
          "minimum": 0
        }
      },
      "required": [
        "line",
        "column",
        "offset"
      ]
    }
  }
}
