{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://bnd.by/fapl/examples/fapl-1.0.schema.json",
  "title": "FAPL 1.0",
  "description": "Синтаксическая схема модуля Frontend Architecture & Process Language версии 1.0. Семантические правила согласованности имён описаны в спецификации.",
  "type": "object",
  "additionalProperties": false,
  "required": ["version", "module", "components", "workflows", "services"],
  "properties": {
    "version": {
      "const": "1.0",
      "description": "Версия языка."
    },
    "module": {
      "type": "string",
      "minLength": 1,
      "description": "Имя модуля."
    },
    "description": {
      "type": "string",
      "description": "Назначение модуля человеческим языком."
    },
    "components": {
      "type": "array",
      "items": { "$ref": "#/$defs/component" }
    },
    "workflows": {
      "type": "object",
      "minProperties": 1,
      "propertyNames": { "$ref": "#/$defs/ident" },
      "additionalProperties": { "$ref": "#/$defs/workflow" }
    },
    "services": {
      "type": "object",
      "propertyNames": { "$ref": "#/$defs/ident" },
      "additionalProperties": { "$ref": "#/$defs/service" }
    }
  },
  "$defs": {
    "ident": {
      "type": "string",
      "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
    },
    "scalarType": {
      "type": "string",
      "enum": ["String", "ID"]
    },
    "typeExpr": {
      "description": "Скалярный тип либо объект «поле → тип».",
      "oneOf": [
        { "$ref": "#/$defs/scalarType" },
        {
          "type": "object",
          "minProperties": 1,
          "propertyNames": { "$ref": "#/$defs/ident" },
          "additionalProperties": { "$ref": "#/$defs/typeExpr" }
        }
      ]
    },
    "refString": {
      "type": "string",
      "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)?$",
      "description": "Локальное действие (имя) или ссылка Service.method / Workflow.symbol."
    },
    "action": {
      "oneOf": [
        { "$ref": "#/$defs/refString" },
        {
          "type": "array",
          "minItems": 1,
          "items": { "$ref": "#/$defs/refString" }
        }
      ]
    },
    "component": {
      "type": "object",
      "additionalProperties": false,
      "required": ["name", "type"],
      "properties": {
        "name": { "$ref": "#/$defs/ident" },
        "type": { "enum": ["Page", "Component"] },
        "route": {
          "type": "string",
          "pattern": "^/\\S*$"
        },
        "children": {
          "type": "array",
          "minItems": 1,
          "items": { "$ref": "#/$defs/ident" }
        },
        "inputs": {
          "type": "array",
          "minItems": 1,
          "items": { "$ref": "#/$defs/input" }
        },
        "outputs": {
          "type": "array",
          "minItems": 1,
          "items": { "$ref": "#/$defs/output" }
        }
      },
      "allOf": [
        {
          "if": {
            "properties": { "type": { "const": "Page" } },
            "required": ["type"]
          },
          "then": { "required": ["route"] }
        },
        {
          "if": {
            "properties": { "type": { "const": "Component" } },
            "required": ["type"]
          },
          "then": {
            "properties": { "route": false }
          }
        }
      ]
    },
    "input": {
      "type": "object",
      "additionalProperties": false,
      "required": ["name", "type"],
      "properties": {
        "name": { "$ref": "#/$defs/ident" },
        "type": { "$ref": "#/$defs/typeExpr" }
      }
    },
    "output": {
      "type": "object",
      "additionalProperties": false,
      "required": ["name", "action"],
      "properties": {
        "name": { "$ref": "#/$defs/ident" },
        "action": { "$ref": "#/$defs/action" }
      }
    },
    "workflow": {
      "type": "object",
      "additionalProperties": false,
      "required": ["initial_state", "states"],
      "properties": {
        "description": { "type": "string" },
        "initial_state": { "$ref": "#/$defs/ident" },
        "states": {
          "type": "object",
          "minProperties": 1,
          "propertyNames": { "$ref": "#/$defs/ident" },
          "additionalProperties": { "$ref": "#/$defs/state" }
        }
      }
    },
    "state": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "type": { "const": "Final" },
        "entry": { "$ref": "#/$defs/refString" },
        "on": {
          "type": "object",
          "minProperties": 1,
          "propertyNames": { "$ref": "#/$defs/ident" },
          "additionalProperties": { "$ref": "#/$defs/transition" }
        }
      },
      "anyOf": [
        { "required": ["type"] },
        { "required": ["on"] }
      ],
      "allOf": [
        {
          "if": {
            "properties": { "type": { "const": "Final" } },
            "required": ["type"]
          },
          "then": {
            "allOf": [
              { "not": { "required": ["on"] } },
              { "not": { "required": ["entry"] } }
            ]
          }
        }
      ]
    },
    "transition": {
      "type": "object",
      "additionalProperties": false,
      "required": ["target"],
      "properties": {
        "target": { "$ref": "#/$defs/ident" },
        "payload": { "$ref": "#/$defs/typeExpr" },
        "action": { "$ref": "#/$defs/action" }
      }
    },
    "service": {
      "type": "object",
      "additionalProperties": false,
      "required": ["methods"],
      "properties": {
        "methods": {
          "type": "array",
          "minItems": 1,
          "items": { "$ref": "#/$defs/method" }
        }
      }
    },
    "method": {
      "type": "object",
      "additionalProperties": false,
      "required": ["name", "params", "returns"],
      "properties": {
        "name": { "$ref": "#/$defs/ident" },
        "async": { "type": "boolean" },
        "params": { "$ref": "#/$defs/typeExpr" },
        "returns": { "$ref": "#/$defs/typeExpr" },
        "error": { "$ref": "#/$defs/typeExpr" }
      }
    }
  }
}
