{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://olejbondahl.github.io/symdef/symbol.schema.json",
  "title": "symdef symbol file",
  "description": "A symbol source file (atomic or composite, TOML decoded to JSON) or a resolved symbol. Structural only: the id pattern, the drawing and wiring grids, positive sizes and the number pattern are lint rules, not schema rules. The one bound on values: every number is at most 1e6 in absolute value.",
  "type": "object",
  "required": ["schema", "name", "kind", "status", "reference"],
  "anyOf": [{ "required": ["elements"] }, { "required": ["parts"] }],
  "if": {
    "description": "Guide section 4: slots is required when kind is symbol; an empty table satisfies it.",
    "properties": { "kind": { "const": "symbol" } },
    "required": ["kind"]
  },
  "then": { "required": ["slots"] },
  "additionalProperties": false,
  "properties": {
    "schema": { "const": 1 },
    "name": { "type": "string" },
    "kind": { "enum": ["symbol", "element", "qualifier"] },
    "status": { "enum": ["unverified", "verified"] },
    "reference": {
      "type": "object",
      "required": ["standard", "number"],
      "additionalProperties": false,
      "properties": {
        "standard": { "type": "string" },
        "number": { "type": "string" },
        "edition": { "type": "string" },
        "form": { "type": "string" }
      }
    },
    "ports": {
      "description": "An array of port tables (atomic and resolved) or a rename map new_id -> \"part.port\" (composite).",
      "oneOf": [
        { "type": "array", "items": { "$ref": "#/$defs/port" } },
        { "type": "object", "additionalProperties": { "type": "string" } }
      ]
    },
    "nodes": { "type": "array", "items": { "$ref": "#/$defs/node" } },
    "paths": { "type": "array", "items": { "$ref": "#/$defs/path" } },
    "anchors": { "type": "array", "items": { "$ref": "#/$defs/anchor" } },
    "elements": { "type": "array", "items": { "$ref": "#/$defs/element" } },
    "parts": { "type": "array", "items": { "$ref": "#/$defs/part" } },
    "slots": {
      "description": "Slot id -> slot table, or in a composite a string reference to a part's slot.",
      "type": "object",
      "additionalProperties": {
        "oneOf": [{ "type": "string" }, { "$ref": "#/$defs/slot" }]
      }
    },
    "pole_pitch": { "$ref": "#/$defs/integer" },
    "lint_allow": { "type": "array", "items": { "$ref": "#/$defs/allow" } },
    "stretch": { "type": "array", "items": { "$ref": "#/$defs/stretch" } },
    "body_box": { "$ref": "#/$defs/box" },
    "keepout_box": { "$ref": "#/$defs/box" }
  },
  "$defs": {
    "number": {
      "description": "A finite number with absolute value at most 1e6 (module units). Written as the negation of beyond the limit so that NaN, which a TOML file can carry, is rejected too.",
      "type": "number",
      "not": { "anyOf": [{ "exclusiveMinimum": 1000000 }, { "exclusiveMaximum": -1000000 }] }
    },
    "integer": {
      "description": "An integer with absolute value at most 1e6, written like number.",
      "type": "integer",
      "not": { "anyOf": [{ "exclusiveMinimum": 1000000 }, { "exclusiveMaximum": -1000000 }] }
    },
    "point": {
      "type": "array",
      "items": { "$ref": "#/$defs/number" },
      "minItems": 2,
      "maxItems": 2
    },
    "box": {
      "description": "[[min_x, min_y], [max_x, max_y]]; present in resolved output only.",
      "type": "array",
      "items": { "$ref": "#/$defs/point" },
      "minItems": 2,
      "maxItems": 2
    },
    "direction": { "enum": ["N", "E", "S", "W"] },
    "slot_side": {
      "description": "A direction the box grows towards, or C for a box centred on the slot point.",
      "enum": ["N", "E", "S", "W", "C"]
    },
    "weight": { "enum": ["normal", "thick"] },
    "style": { "enum": ["solid", "dashed", "dash_dot"] },
    "fill": { "enum": ["none", "solid"] },
    "polyline_fill": { "enum": ["none", "solid", "tint"] },
    "port": {
      "type": "object",
      "required": ["id", "at", "dir"],
      "additionalProperties": false,
      "properties": {
        "id": { "type": "string" },
        "at": { "$ref": "#/$defs/point" },
        "dir": { "$ref": "#/$defs/direction" },
        "description": { "type": "string" }
      }
    },
    "node": {
      "type": "object",
      "required": ["ports"],
      "additionalProperties": false,
      "properties": {
        "ports": { "type": "array", "items": { "type": "string" } },
        "potential": { "type": "string" }
      }
    },
    "path": {
      "type": "object",
      "required": ["from", "to", "kind"],
      "additionalProperties": false,
      "properties": {
        "from": { "type": "string" },
        "to": { "type": "string" },
        "kind": { "type": "string" },
        "through": { "type": "boolean" }
      }
    },
    "anchor": {
      "type": "object",
      "required": ["id", "at", "dir"],
      "additionalProperties": false,
      "properties": {
        "id": { "type": "string" },
        "at": { "$ref": "#/$defs/point" },
        "dir": { "$ref": "#/$defs/direction" }
      }
    },
    "slot": {
      "type": "object",
      "required": ["at", "side", "box"],
      "additionalProperties": false,
      "properties": {
        "at": { "$ref": "#/$defs/point" },
        "side": { "$ref": "#/$defs/slot_side" },
        "box": {
          "description": "[width, height]; the text stays upright, so the box never rotates.",
          "type": "array",
          "items": { "$ref": "#/$defs/number" },
          "minItems": 2,
          "maxItems": 2
        },
        "turn": { "type": "boolean" }
      }
    },
    "part": {
      "type": "object",
      "required": ["as", "use"],
      "additionalProperties": false,
      "properties": {
        "as": { "type": "string" },
        "use": { "type": "string" },
        "orient": {
          "enum": ["R0", "R90", "R180", "R270", "MR0", "MR90", "MR180", "MR270"]
        },
        "attach": { "type": "string" },
        "to": { "type": "string" },
        "length": { "$ref": "#/$defs/number" },
        "via": { "type": "string" },
        "at": { "$ref": "#/$defs/point" },
        "repeat": { "$ref": "#/$defs/integer" }
      }
    },
    "stretch": {
      "description": "A cut line across the body: the axis the symbol grows along and the cut's coordinate.",
      "type": "object",
      "required": ["axis", "at"],
      "additionalProperties": false,
      "properties": {
        "axis": { "enum": ["x", "y"] },
        "at": { "$ref": "#/$defs/number" },
        "weight": {
          "description": "The cut's share of the growth against the other cuts on its axis; above zero, 1 when absent.",
          "allOf": [{ "$ref": "#/$defs/number" }, { "exclusiveMinimum": 0 }]
        }
      }
    },
    "allow": {
      "type": "object",
      "required": ["rule", "reason"],
      "additionalProperties": false,
      "properties": {
        "rule": { "type": "string" },
        "reason": { "type": "string" }
      }
    },
    "element": {
      "description": "Exactly one shape key. weight is allowed on every shape, style on line, polyline and arc, fill on polyline and circle, closed on polyline, between on line and polyline.",
      "oneOf": [
        {
          "type": "object",
          "required": ["line"],
          "additionalProperties": false,
          "properties": {
            "line": {
              "type": "array",
              "items": { "$ref": "#/$defs/point" },
              "minItems": 2,
              "maxItems": 2
            },
            "weight": { "$ref": "#/$defs/weight" },
            "style": { "$ref": "#/$defs/style" },
            "port": { "type": "string" },
            "between": { "type": "boolean" }
          }
        },
        {
          "type": "object",
          "required": ["polyline"],
          "additionalProperties": false,
          "properties": {
            "polyline": { "type": "array", "items": { "$ref": "#/$defs/point" } },
            "closed": { "type": "boolean" },
            "fill": { "$ref": "#/$defs/polyline_fill" },
            "weight": { "$ref": "#/$defs/weight" },
            "style": { "$ref": "#/$defs/style" },
            "between": { "type": "boolean" }
          },
          "if": { "properties": { "fill": { "const": "tint" } }, "required": ["fill"] },
          "then": { "required": ["closed"], "properties": { "closed": { "const": true } } }
        },
        {
          "type": "object",
          "required": ["circle", "r"],
          "additionalProperties": false,
          "properties": {
            "circle": { "$ref": "#/$defs/point" },
            "r": { "$ref": "#/$defs/number" },
            "fill": { "$ref": "#/$defs/fill" },
            "weight": { "$ref": "#/$defs/weight" }
          }
        },
        {
          "type": "object",
          "required": ["arc", "r", "start", "end"],
          "additionalProperties": false,
          "properties": {
            "arc": { "$ref": "#/$defs/point" },
            "r": { "$ref": "#/$defs/number" },
            "start": { "$ref": "#/$defs/number" },
            "end": { "$ref": "#/$defs/number" },
            "weight": { "$ref": "#/$defs/weight" },
            "style": { "$ref": "#/$defs/style" }
          }
        },
        {
          "type": "object",
          "required": ["text", "at", "height"],
          "additionalProperties": false,
          "properties": {
            "text": { "type": "string" },
            "at": { "$ref": "#/$defs/point" },
            "height": { "$ref": "#/$defs/number" },
            "weight": { "$ref": "#/$defs/weight" }
          }
        }
      ]
    }
  }
}
