{
  "$schema": "http://json-schema.org/draft-07/schema",
  "$id": "typeSchema.json",
  "definitions": {
    "root": {
      "type": "object",
      "patternProperties": {
        "(\\$schema)": {
          "type": "string"
        },
        "(\\$types)": {
          "type": "object",
          "patternProperties": {
            "(^\\$)": {
              "$ref": "#/definitions/typesAll"
            }
          },
          "additionalProperties": false
        },
        "(.*?)": {
          "$ref": "#/definitions/typesAll"
        }
      },
      "additionalProperties": false
    },
    "objectMetaType": {
      "description": "meta type",
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "name": {
          "type": "string"
        },
        "description": {
          "type": "string"
        },
        "$type": {
          "anyOf": [
            {
              "$ref": "#/definitions/objectType"
            },
            {
              "$ref": "#/definitions/objectMetaType"
            }
          ]
        }
      },
      "required": [
        "$type"
      ]
    },
    "objectType": {
      "description": "Object type, can have any properties with any types, but properties should not start with $",
      "type": "object",
      "patternProperties": {
        "^(?!\\$).*": {
          "$ref": "#/definitions/typesAll"
        }
      },
      "additionalProperties": false,
      "not": {
        "oneOf": [
          {
            "properties": {
              "$enum": {}
            },
            "additionalProperties": false,
            "required": [
              "$enum"
            ]
          },
          {
            "properties": {
              "$array": {}
            },
            "additionalProperties": false,
            "required": [
              "$array"
            ]
          }
        ]
      }
    },
    "metaData": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "description": {
          "type": "string"
        }
      }
    },
    "valueTypes": {
      "oneOf": [
        {
          "$ref": "#/definitions/objectType"
        },
        {
          "description": "enum type",
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "name": {
              "type": "string"
            },
            "description": {
              "type": "string"
            },
            "$enum": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "minItems": 1
            }
          },
          "required": [
            "$enum"
          ]
        },
        {
          "description": "array type",
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "name": {
              "type": "string"
            },
            "description": {
              "type": "string"
            },
            "minLength" : {
              "type":"number"
            },
            "maxLength" : {
              "type":"number"
            },
            "$array": {
              "$ref": "#/definitions/typesAll"
            }
          },
          "required": [
            "$array"
          ]
        },
        {
          "description": "number type",
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "name": {
              "type": "string"
            },
            "description": {
              "type": "string"
            },
            "onlyIn": {
              "type": "string",
              "enum": [
                "request",
                "response"
              ]
            },
            "postfix": {
              "type": "string"
            },
            "$number": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "min": {
                  "type": "number"
                },
                "max": {
                  "type": "number"
                }
              }
            }
          },
          "required": [
            "$number"
          ]
        },
        {
          "description": "and type",
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "$and": {
              "$type": "array",
              "items": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/objectMetaType"
                  },
                  {
                    "$ref": "#/definitions/objectType"
                  },
                  {
                    "type": "string",
                    "pattern": "^\\$"
                  }
                ]
              }
            }
          },
          "required": [
            "$and"
          ]
        },
        {
          "description": "map type",
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "name": {
              "type": "string"
            },
            "description": {
              "type": "string"
            },
            "regex": {
              "type": "string"
            },
            "minLength" : {
              "type":"number"
            },
            "maxLength" : {
              "type":"number"
            },
            "$map": {
              "$ref": "#/definitions/typesAll"
            }
          },
          "required": [
            "$map"
          ]
        },
        {
          "description": "string type",
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "name": {
              "type": "string"
            },
            "description": {
              "type": "string"
            },
            "$string": {
              "type": "object",
              "properties": {
                "minLength": {
                  "type": "integer"
                },
                "maxLength": {
                  "type": "integer"
                },
                "regex": {
                  "type": "string"
                }
              }
            }
          },
          "required": [
            "$string"
          ]
        },
        {
          "description": "meta type",
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "name": {
              "type": "string"
            },
            "description": {
              "type": "string"
            },
            "$type": {
              "$ref": "#/definitions/typesAll"
            }
          },
          "required": [
            "$type"
          ]
        },
        {
          "type": "string",
          "enum": [
            "boolean",
            "string",
            "number",
            "integer",
            "null",
            "?"
          ]
        },
        {
          "type": "string",
          "pattern": "^\\$"
        }
      ]
    },
    "typesAll": {
      "oneOf": [
        {
          "$ref": "#/definitions/valueTypes"
        },
        {
          "type": "array",
          "items": {
            "$ref": "#/definitions/valueTypes"
          },
          "minItems": 1,
          "description": "If the value can have multiple types, at least one type needs to be specified"
        }
      ]
    }
  },
  "$ref": "#/definitions/root"
}
