{
  "id": "http://www.jsonscript.org/schema/evaluate.json#",
  "$schema": "https://raw.githubusercontent.com/epoberezkin/ajv/master/lib/refs/json-schema-v5.json#",
  "title": "JSONScript evaluation schema",
  "description": "Schema with custom keywords that evaluates JSON script. It assumes that the script is valid",
  "allOf": [
    {
      "switch": [
        {
          "if": {
            "type": "object"
          },
          "then": {
            "switch": [
              {
                "if": {
                  "required": [
                    "$exec"
                  ]
                },
                "then": {
                  "title": "instruction $exec",
                  "allOf": [
                    {
                      "title": "evaluate properties",
                      "description": "evaluates all or some keywords using this (full) schema, properties-scripts are replaced with returned synchronous or asynchronous value",
                      "additionalProperties": {
                        "$ref": "#"
                      }
                    },
                    {
                      "title": "object to [async] value",
                      "description": "Merge object properties into a single [asynchronous] object value",
                      "objectToAsync": true
                    },
                    {
                      "title": "execute instruction",
                      "description": "executes supported script instructions",
                      "validateAsync": {
                        "allOf": [
                          {
                            "description": "validate evaluated instruction keywords",
                            "properties": {
                              "$exec": {
                                "type": "string",
                                "anyOf": [
                                  {
                                    "pattern": "^[A-Za-z_$][A-Za-z_$0-9]+$"
                                  },
                                  {
                                    "format": "uuid"
                                  }
                                ]
                              },
                              "$method": {
                                "type": "string",
                                "pattern": "^[A-Za-z_$][A-Za-z_$0-9]+$"
                              }
                            }
                          },
                          {
                            "description": "execute instruction using custom keyword",
                            "eval$exec": true
                          }
                        ]
                      }
                    }
                  ]
                }
              },
              {
                "if": {
                  "required": [
                    "$ref"
                  ]
                },
                "then": {
                  "title": "instruction $ref",
                  "allOf": [
                    {
                      "title": "evaluate properties",
                      "description": "evaluates all or some keywords using this (full) schema, properties-scripts are replaced with returned synchronous or asynchronous value",
                      "additionalProperties": {
                        "$ref": "#"
                      }
                    },
                    {
                      "title": "object to [async] value",
                      "description": "Merge object properties into a single [asynchronous] object value",
                      "objectToAsync": true
                    },
                    {
                      "title": "execute instruction",
                      "description": "executes supported script instructions",
                      "validateAsync": {
                        "allOf": [
                          {
                            "description": "validate evaluated instruction keywords",
                            "properties": {
                              "$ref": {
                                "type": "string",
                                "anyOf": [
                                  {
                                    "format": "json-pointer"
                                  },
                                  {
                                    "format": "relative-json-pointer"
                                  }
                                ]
                              }
                            }
                          },
                          {
                            "description": "execute instruction using custom keyword",
                            "eval$ref": true
                          }
                        ]
                      }
                    }
                  ]
                }
              },
              {
                "if": {
                  "required": [
                    "$data"
                  ]
                },
                "then": {
                  "title": "instruction $data",
                  "allOf": [
                    {
                      "title": "evaluate properties",
                      "description": "evaluates all or some keywords using this (full) schema, properties-scripts are replaced with returned synchronous or asynchronous value",
                      "additionalProperties": {
                        "$ref": "#"
                      }
                    },
                    {
                      "title": "object to [async] value",
                      "description": "Merge object properties into a single [asynchronous] object value",
                      "objectToAsync": true
                    },
                    {
                      "title": "execute instruction",
                      "description": "executes supported script instructions",
                      "validateAsync": {
                        "allOf": [
                          {
                            "description": "validate evaluated instruction keywords",
                            "properties": {
                              "$data": {
                                "type": "string",
                                "format": "json-pointer"
                              }
                            }
                          },
                          {
                            "description": "execute instruction using custom keyword",
                            "eval$data": true
                          }
                        ]
                      }
                    }
                  ]
                }
              },
              {
                "if": {
                  "required": [
                    "$if"
                  ]
                },
                "then": {
                  "title": "instruction $if",
                  "allOf": [
                    {
                      "title": "evaluate properties",
                      "description": "evaluates all or some keywords using this (full) schema, properties-scripts are replaced with returned synchronous or asynchronous value",
                      "properties": {
                        "$if": {
                          "$ref": "#"
                        }
                      }
                    },
                    {
                      "title": "object to [async] value",
                      "description": "Merge object properties into a single [asynchronous] object value",
                      "objectToAsync": true
                    },
                    {
                      "title": "execute instruction",
                      "description": "executes supported script instructions",
                      "validateAsync": {
                        "allOf": [
                          {
                            "description": "validate evaluated instruction keywords",
                            "properties": {
                              "$if": {
                                "type": "boolean"
                              },
                              "$else": {
                                "default": null
                              }
                            }
                          },
                          {
                            "description": "execute instruction using custom keyword",
                            "eval$if": true
                          }
                        ]
                      }
                    }
                  ]
                }
              },
              {
                "if": {
                  "required": [
                    "$delay"
                  ]
                },
                "then": {
                  "title": "instruction $delay",
                  "allOf": [
                    {
                      "title": "evaluate properties",
                      "description": "evaluates all or some keywords using this (full) schema, properties-scripts are replaced with returned synchronous or asynchronous value",
                      "properties": {
                        "$wait": {
                          "$ref": "#"
                        }
                      }
                    },
                    {
                      "title": "object to [async] value",
                      "description": "Merge object properties into a single [asynchronous] object value",
                      "objectToAsync": true
                    },
                    {
                      "title": "execute instruction",
                      "description": "executes supported script instructions",
                      "validateAsync": {
                        "allOf": [
                          {
                            "description": "validate evaluated instruction keywords",
                            "properties": {
                              "$wait": {
                                "type": "integer",
                                "default": 0
                              }
                            }
                          },
                          {
                            "description": "execute instruction using custom keyword",
                            "eval$delay": true
                          }
                        ]
                      }
                    }
                  ]
                }
              },
              {
                "if": {
                  "required": [
                    "$func"
                  ]
                },
                "then": {
                  "title": "instruction $func",
                  "allOf": [
                    {
                      "title": "evaluate properties",
                      "description": "evaluates all or some keywords using this (full) schema, properties-scripts are replaced with returned synchronous or asynchronous value",
                      "properties": {
                        "$name": {
                          "$ref": "#"
                        },
                        "$args": {
                          "$ref": "#"
                        }
                      }
                    },
                    {
                      "title": "object to [async] value",
                      "description": "Merge object properties into a single [asynchronous] object value",
                      "objectToAsync": true
                    },
                    {
                      "title": "execute instruction",
                      "description": "executes supported script instructions",
                      "validateAsync": {
                        "allOf": [
                          {
                            "description": "validate evaluated instruction keywords",
                            "properties": {
                              "$name": {
                                "type": "string",
                                "anyOf": [
                                  {
                                    "pattern": "^[A-Za-z_$][A-Za-z_$0-9]+$"
                                  },
                                  {
                                    "format": "uuid"
                                  }
                                ]
                              },
                              "$args": {
                                "type": "array",
                                "minItems": 1,
                                "items": {
                                  "anyOf": [
                                    {
                                      "type": "string",
                                      "pattern": "^[A-Za-z_$][A-Za-z_$0-9]+$"
                                    },
                                    {
                                      "type": "object",
                                      "minProperties": 1,
                                      "maxProperties": 1,
                                      "patternProperties": {
                                        "^[A-Za-z_$][A-Za-z_$0-9]+$": {
                                          "$ref": "http://json-schema.org/draft-04/schema#"
                                        }
                                      }
                                    }
                                  ]
                                }
                              }
                            }
                          },
                          {
                            "description": "execute instruction using custom keyword",
                            "eval$func": true
                          }
                        ]
                      }
                    }
                  ]
                }
              },
              {
                "if": {
                  "required": [
                    "$call"
                  ]
                },
                "then": {
                  "title": "instruction $call",
                  "allOf": [
                    {
                      "title": "evaluate properties",
                      "description": "evaluates all or some keywords using this (full) schema, properties-scripts are replaced with returned synchronous or asynchronous value",
                      "additionalProperties": {
                        "$ref": "#"
                      }
                    },
                    {
                      "title": "object to [async] value",
                      "description": "Merge object properties into a single [asynchronous] object value",
                      "objectToAsync": true
                    },
                    {
                      "title": "execute instruction",
                      "description": "executes supported script instructions",
                      "validateAsync": {
                        "allOf": [
                          {
                            "description": "validate evaluated instruction keywords",
                            "properties": {
                              "$call": {
                                "anyOf": [
                                  {
                                    "type": "string",
                                    "anyOf": [
                                      {
                                        "pattern": "^[A-Za-z_$][A-Za-z_$0-9]+$"
                                      },
                                      {
                                        "format": "uuid"
                                      }
                                    ]
                                  },
                                  {
                                    "description": "custom keyword to validate that value is a function",
                                    "function": true
                                  }
                                ]
                              }
                            }
                          },
                          {
                            "description": "execute instruction using custom keyword",
                            "eval$call": true
                          }
                        ]
                      }
                    }
                  ]
                }
              },
              {
                "if": {
                  "required": [
                    "$quote"
                  ]
                },
                "then": {
                  "title": "instruction $quote",
                  "allOf": [
                    {
                      "title": "execute instruction",
                      "description": "executes supported script instructions",
                      "validateAsync": {
                        "description": "execute instruction using custom keyword",
                        "eval$quote": true
                      }
                    }
                  ]
                }
              },
              {
                "then": {
                  "title": "parallel execution",
                  "allOf": [
                    {
                      "title": "evaluate properties",
                      "description": "evaluates all properties using the same schema, properties-scripts are replaced with returned synchronous or asynchronous value",
                      "additionalProperties": {
                        "$ref": "#"
                      }
                    },
                    {
                      "title": "object to [async] value",
                      "description": "Merge object properties into a single [asynchronous] object value",
                      "objectToAsync": true
                    }
                  ]
                }
              }
            ]
          }
        },
        {
          "if": {
            "type": "array"
          },
          "then": {
            "title": "sequential execution",
            "description": "queues items so that the next items is executed only after the previous asynchronous value receives data",
            "itemsSerial": {
              "$ref": "#"
            }
          }
        },
        {
          "then": {
            "title": "scalar values",
            "description": "convert scalar values to asynchronouse values",
            "valueToAsync": true
          }
        }
      ]
    },
    {
      "description": "store pointer to evaluted object and resolve pending references",
      "resolvePendingRefs": true
    }
  ]
}