{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://graphdom.dev/schema/spider.json",
  "title": "Graphdom spider",
  "description": "A spider: a graph of the states a site can be in, whose edges are blocks of steps.",
  "type": "object",
  "properties": {
    "format": {
      "description": "The IR version, \"graphdom-ir@1.<minor>\".",
      "type": "string"
    },
    "spider": {
      "description": "The id of the task the spider does.",
      "type": "string"
    },
    "version": {
      "description": "The spider's version, from 1, never changed once approved.",
      "type": "integer"
    },
    "origins": {
      "description": "The roles: the sites the task acts on, by name; a URL starts with \"{role}\", and a run binds each role to an origin.",
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    },
    "incidental": {
      "description": "Origins the pages only touch (a CDN, analytics), by name; they appear in request patterns and are not assigned at run time.",
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    },
    "inputs": {
      "description": "The values a run takes, by name.",
      "type": "object",
      "additionalProperties": {
        "type": "object",
        "properties": {
          "type": {
            "description": "The type of the value.",
            "type": "string",
            "enum": [
              "string",
              "number",
              "boolean",
              "file"
            ]
          },
          "values": {
            "description": "The values it may take, when they are a fixed set.",
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "number"
                }
              ]
            }
          },
          "example": {
            "description": "A value seen in a recording, or the files a session picked.",
            "anyOf": [
              {
                "$ref": "#/$defs/Expr"
              },
              {
                "type": "array",
                "items": {
                  "$ref": "#/$defs/Expr"
                }
              }
            ]
          }
        },
        "required": [
          "type"
        ],
        "additionalProperties": false
      }
    },
    "secrets": {
      "description": "The secrets a run takes, such as a password, by name; only their labels are in the spider.",
      "type": "object",
      "additionalProperties": {
        "type": "object",
        "properties": {
          "label": {
            "description": "What the secret is, as a person is asked for it.",
            "type": "string"
          }
        },
        "required": [
          "label"
        ],
        "additionalProperties": false
      }
    },
    "outputs": {
      "description": "The values a run returns, by name.",
      "type": "object",
      "additionalProperties": {
        "anyOf": [
          {
            "type": "object",
            "properties": {
              "type": {
                "description": "The type of the value returned.",
                "type": "string",
                "enum": [
                  "string",
                  "number",
                  "file"
                ]
              }
            },
            "required": [
              "type"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "description": "The type of the value returned.",
                "type": "string",
                "const": "list"
              },
              "of": {
                "description": "The fields of each item of the list, by name, with their types.",
                "type": "object",
                "additionalProperties": {
                  "type": "string",
                  "enum": [
                    "string",
                    "number",
                    "string[]"
                  ]
                }
              }
            },
            "required": [
              "type",
              "of"
            ],
            "additionalProperties": false
          }
        ]
      }
    },
    "targets": {
      "description": "The elements the steps act on, by name.",
      "type": "object",
      "additionalProperties": {
        "type": "object",
        "properties": {
          "frames": {
            "description": "The frames the element is in, outermost first; each hop is the ranked locators of an iframe or frame.",
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/Locator"
              },
              "minItems": 1
            }
          },
          "hosts": {
            "description": "The shadow hosts the element is in, outermost first.",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "css": {
                  "description": "A CSS selector for the shadow host.",
                  "type": "string"
                },
                "closed": {
                  "description": "Present when the shadow root is closed.",
                  "type": "boolean",
                  "const": true
                }
              },
              "required": [
                "css"
              ],
              "additionalProperties": false
            }
          },
          "within": {
            "description": "Another target the element is looked for in, such as a table row or a dialog.",
            "type": "string"
          },
          "is": {
            "description": "The role or tag the element found must have.",
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "role": {
                    "description": "The ARIA role the element must have.",
                    "type": "string"
                  }
                },
                "required": [
                  "role"
                ],
                "additionalProperties": false
              },
              {
                "type": "object",
                "properties": {
                  "tag": {
                    "description": "The HTML tag name the element must have.",
                    "type": "string"
                  }
                },
                "required": [
                  "tag"
                ],
                "additionalProperties": false
              }
            ]
          },
          "many": {
            "description": "Present when the target is a list of elements, which only extract reads.",
            "type": "boolean",
            "const": true
          },
          "by": {
            "description": "The locators that find the element, best first, at least one.",
            "type": "array",
            "items": {
              "$ref": "#/$defs/Locator"
            },
            "minItems": 1
          }
        },
        "required": [
          "by"
        ],
        "additionalProperties": false
      }
    },
    "start": {
      "description": "The state the run begins in.",
      "type": "string"
    },
    "entry": {
      "description": "The URL the run goes to first; by default the URL of the start state's recogniser.",
      "type": "string"
    },
    "states": {
      "description": "The states the site can be in, by name.",
      "type": "object",
      "additionalProperties": {
        "type": "object",
        "properties": {
          "recognise": {
            "description": "What tells this state from the others: every rule given must hold.",
            "type": "object",
            "properties": {
              "url": {
                "description": "The URL pattern the page's main frame must match.",
                "type": "string"
              },
              "present": {
                "description": "Targets that must be found.",
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "absent": {
                "description": "Targets that must not be found.",
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "when": {
                "description": "Any other condition, read at once and never waited for.",
                "$ref": "#/$defs/Cond"
              },
              "page": {
                "description": "The page recognised; by default \"main\".",
                "type": "string"
              }
            },
            "required": [],
            "additionalProperties": false
          },
          "edges": {
            "description": "The ways out of the state, in order: the first whose condition holds is taken; none ends the run here.",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "description": "The edge's id, unique in the spider.",
                  "type": "string"
                },
                "when": {
                  "description": "The condition under which the edge is taken; by default always.",
                  "$ref": "#/$defs/Cond"
                },
                "max": {
                  "description": "How many times a run may take the edge; by default 1.",
                  "type": "integer"
                },
                "steps": {
                  "description": "The steps the edge runs, in order.",
                  "type": "array",
                  "items": {
                    "$ref": "#/$defs/BlockStep"
                  }
                },
                "to": {
                  "description": "The states the run may arrive in; none ends the run after the steps.",
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "required": [
                "id",
                "steps",
                "to"
              ],
              "additionalProperties": false
            }
          },
          "note": {
            "description": "A note for the people reading the spider.",
            "type": "string"
          }
        },
        "required": [
          "recognise",
          "edges"
        ],
        "additionalProperties": false
      }
    },
    "interrupts": {
      "description": "Detours that may leave from any state, such as a cookie banner, or end the run, such as a CAPTCHA.",
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "description": "The interrupt's id, unique in the spider.",
            "type": "string"
          },
          "when": {
            "description": "The condition that sets it off, in any state.",
            "$ref": "#/$defs/Cond"
          },
          "steps": {
            "description": "The steps it runs, none of them a submit; then the run goes on from the state it was in.",
            "type": "array",
            "items": {
              "$ref": "#/$defs/BlockStep"
            }
          },
          "stop": {
            "description": "The reason the run ends instead, such as a CAPTCHA or new terms.",
            "type": "string"
          },
          "max": {
            "description": "How many times a run may take it.",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "when"
        ],
        "additionalProperties": false,
        "oneOf": [
          {
            "properties": {
              "steps": true
            },
            "required": [
              "steps"
            ]
          },
          {
            "properties": {
              "stop": true
            },
            "required": [
              "stop"
            ]
          }
        ]
      }
    }
  },
  "required": [
    "format",
    "spider",
    "version",
    "origins",
    "inputs",
    "outputs",
    "targets",
    "start",
    "states"
  ],
  "additionalProperties": false,
  "$defs": {
    "Expr": {
      "description": "A value: a literal, or the value of an input or a secret in this run.",
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "number"
        },
        {
          "type": "boolean"
        },
        {
          "type": "object",
          "properties": {
            "input": {
              "description": "The name of an input: its value in this run.",
              "type": "string"
            }
          },
          "required": [
            "input"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "secret": {
              "description": "The name of a secret: its value in this run, only where a secret may go.",
              "type": "string"
            }
          },
          "required": [
            "secret"
          ],
          "additionalProperties": false
        }
      ]
    },
    "Read": {
      "description": "How an element is read: its text, its form value, or one of its attributes.",
      "anyOf": [
        {
          "type": "string",
          "enum": [
            "text",
            "value"
          ]
        },
        {
          "type": "object",
          "properties": {
            "attr": {
              "description": "The name of the attribute to read.",
              "type": "string"
            }
          },
          "required": [
            "attr"
          ],
          "additionalProperties": false
        }
      ]
    },
    "Cond": {
      "description": "A condition on the page or the inputs, read when it is checked.",
      "anyOf": [
        {
          "type": "object",
          "properties": {
            "input": {
              "description": "The name of the input compared.",
              "type": "string"
            },
            "eq": {
              "description": "Holds when the value equals this one.",
              "$ref": "#/$defs/Expr"
            },
            "ne": {
              "description": "Holds when the value differs from this one.",
              "$ref": "#/$defs/Expr"
            },
            "lt": {
              "description": "Holds when the value is a number less than this one.",
              "type": "number"
            },
            "le": {
              "description": "Holds when the value is a number at most this one.",
              "type": "number"
            },
            "gt": {
              "description": "Holds when the value is a number greater than this one.",
              "type": "number"
            },
            "ge": {
              "description": "Holds when the value is a number at least this one.",
              "type": "number"
            },
            "in": {
              "description": "Holds when the value is one of these.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Expr"
              }
            },
            "contains": {
              "description": "Holds when the value contains this text.",
              "$ref": "#/$defs/Expr"
            },
            "matches": {
              "description": "Holds when the value matches this regular expression.",
              "type": "string"
            },
            "nonEmpty": {
              "description": "Holds when the value is not empty.",
              "type": "boolean",
              "const": true
            }
          },
          "required": [
            "input"
          ],
          "additionalProperties": false,
          "minProperties": 2,
          "maxProperties": 2
        },
        {
          "type": "object",
          "properties": {
            "value": {
              "description": "The target whose form value is compared.",
              "type": "string"
            },
            "eq": {
              "description": "Holds when the value equals this one.",
              "$ref": "#/$defs/Expr"
            },
            "ne": {
              "description": "Holds when the value differs from this one.",
              "$ref": "#/$defs/Expr"
            },
            "lt": {
              "description": "Holds when the value is a number less than this one.",
              "type": "number"
            },
            "le": {
              "description": "Holds when the value is a number at most this one.",
              "type": "number"
            },
            "gt": {
              "description": "Holds when the value is a number greater than this one.",
              "type": "number"
            },
            "ge": {
              "description": "Holds when the value is a number at least this one.",
              "type": "number"
            },
            "in": {
              "description": "Holds when the value is one of these.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Expr"
              }
            },
            "contains": {
              "description": "Holds when the value contains this text.",
              "$ref": "#/$defs/Expr"
            },
            "matches": {
              "description": "Holds when the value matches this regular expression.",
              "type": "string"
            },
            "nonEmpty": {
              "description": "Holds when the value is not empty.",
              "type": "boolean",
              "const": true
            }
          },
          "required": [
            "value"
          ],
          "additionalProperties": false,
          "minProperties": 2,
          "maxProperties": 2
        },
        {
          "type": "object",
          "properties": {
            "text": {
              "description": "The target whose text is compared.",
              "type": "string"
            },
            "eq": {
              "description": "Holds when the value equals this one.",
              "$ref": "#/$defs/Expr"
            },
            "ne": {
              "description": "Holds when the value differs from this one.",
              "$ref": "#/$defs/Expr"
            },
            "lt": {
              "description": "Holds when the value is a number less than this one.",
              "type": "number"
            },
            "le": {
              "description": "Holds when the value is a number at most this one.",
              "type": "number"
            },
            "gt": {
              "description": "Holds when the value is a number greater than this one.",
              "type": "number"
            },
            "ge": {
              "description": "Holds when the value is a number at least this one.",
              "type": "number"
            },
            "in": {
              "description": "Holds when the value is one of these.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Expr"
              }
            },
            "contains": {
              "description": "Holds when the value contains this text.",
              "$ref": "#/$defs/Expr"
            },
            "matches": {
              "description": "Holds when the value matches this regular expression.",
              "type": "string"
            },
            "nonEmpty": {
              "description": "Holds when the value is not empty.",
              "type": "boolean",
              "const": true
            }
          },
          "required": [
            "text"
          ],
          "additionalProperties": false,
          "minProperties": 2,
          "maxProperties": 2
        },
        {
          "type": "object",
          "properties": {
            "url": {
              "description": "Holds when the main frame's URL matches this pattern.",
              "type": "string"
            }
          },
          "required": [
            "url"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "present": {
              "description": "Holds when this target is found on the page.",
              "type": "string"
            }
          },
          "required": [
            "present"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "visible": {
              "description": "Holds when this target is found and visible.",
              "type": "string"
            }
          },
          "required": [
            "visible"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "all": {
              "description": "Holds when every one of these conditions holds.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Cond"
              },
              "minItems": 1
            }
          },
          "required": [
            "all"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "any": {
              "description": "Holds when at least one of these conditions holds.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Cond"
              },
              "minItems": 1
            }
          },
          "required": [
            "any"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "not": {
              "description": "Holds when this condition does not.",
              "$ref": "#/$defs/Cond"
            }
          },
          "required": [
            "not"
          ],
          "additionalProperties": false
        }
      ]
    },
    "Until": {
      "description": "What a step waits for after acting: a condition, a response, or a navigation.",
      "anyOf": [
        {
          "$ref": "#/$defs/Cond"
        },
        {
          "type": "object",
          "properties": {
            "response": {
              "description": "A request, \"METHOD {origin}/path\", whose response arrives.",
              "type": "string"
            },
            "status": {
              "description": "The HTTP status the response must have.",
              "type": "integer"
            }
          },
          "required": [
            "response"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "navigation": {
              "description": "A request, \"METHOD {origin}/path\", whose document the main frame commits and loads.",
              "type": "string"
            }
          },
          "required": [
            "navigation"
          ],
          "additionalProperties": false
        }
      ]
    },
    "Locator": {
      "description": "One way to find an element; a target ranks several, best first.",
      "anyOf": [
        {
          "type": "object",
          "properties": {
            "testId": {
              "description": "The element's test id attribute.",
              "type": "string"
            }
          },
          "required": [
            "testId"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "field": {
              "description": "The name of the form field.",
              "type": "string"
            }
          },
          "required": [
            "field"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "role": {
              "description": "The element's ARIA role.",
              "type": "string"
            },
            "name": {
              "description": "Its accessible name, exact after collapsing whitespace.",
              "$ref": "#/$defs/Expr"
            }
          },
          "required": [
            "role"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "label": {
              "description": "The text of the form field's label.",
              "$ref": "#/$defs/Expr"
            }
          },
          "required": [
            "label"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "id": {
              "description": "The element's id attribute.",
              "type": "string"
            }
          },
          "required": [
            "id"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "css": {
              "description": "A CSS selector.",
              "type": "string"
            },
            "text": {
              "description": "The whole text the element selected must have, whitespace collapsed.",
              "$ref": "#/$defs/Expr"
            },
            "contains": {
              "description": "A part of the text the element selected must have, whitespace collapsed; not with text.",
              "$ref": "#/$defs/Expr"
            }
          },
          "required": [
            "css"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "text": {
              "description": "The element's visible text.",
              "$ref": "#/$defs/Expr"
            }
          },
          "required": [
            "text"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "attr": {
              "description": "Attribute values the element must have, by attribute name.",
              "type": "object",
              "additionalProperties": {
                "$ref": "#/$defs/Expr"
              }
            }
          },
          "required": [
            "attr"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "frameUrl": {
              "description": "The URL of the document a frame committed, only in a frame hop.",
              "type": "string"
            }
          },
          "required": [
            "frameUrl"
          ],
          "additionalProperties": false
        }
      ]
    },
    "Step": {
      "description": "One step of a block: an action on the page, an extract, or closing a page.",
      "anyOf": [
        {
          "type": "object",
          "properties": {
            "do": {
              "description": "The kind of step.",
              "type": "string",
              "const": "goto"
            },
            "id": {
              "description": "The step's id, unique in the spider.",
              "type": "string"
            },
            "url": {
              "description": "The URL to go to.",
              "type": "string"
            },
            "note": {
              "description": "A note for the people reading the spider.",
              "type": "string"
            },
            "effect": {
              "description": "Whether the step only reads or submits something; required, never defaulted.",
              "type": "string",
              "enum": [
                "read",
                "submit"
              ]
            },
            "page": {
              "description": "The page the step acts on; by default \"main\".",
              "type": "string"
            },
            "until": {
              "description": "What the step waits for after acting, every one of them.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Until"
              }
            },
            "timeoutMs": {
              "description": "How long the step waits, in milliseconds.",
              "type": "integer"
            },
            "opens": {
              "description": "The page or the download the step opens.",
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "page": {
                      "description": "The name the page opened goes by in later steps.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "page"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "download": {
                      "description": "The file output the download is saved as.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "download"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "dialog": {
              "description": "The dialog the step opens, and how it is answered.",
              "type": "object",
              "properties": {
                "kind": {
                  "description": "The kind of dialog.",
                  "type": "string",
                  "enum": [
                    "alert",
                    "confirm",
                    "prompt",
                    "beforeunload"
                  ]
                },
                "message": {
                  "description": "The message the dialog shows.",
                  "type": "string"
                },
                "answer": {
                  "description": "Whether the dialog is accepted or dismissed.",
                  "type": "string",
                  "enum": [
                    "accept",
                    "dismiss"
                  ]
                },
                "text": {
                  "description": "The text typed into a prompt before accepting it.",
                  "$ref": "#/$defs/Expr"
                }
              },
              "required": [
                "kind",
                "answer"
              ],
              "additionalProperties": false
            }
          },
          "required": [
            "do",
            "id",
            "url",
            "effect"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "do": {
              "description": "The kind of step.",
              "type": "string",
              "const": "click"
            },
            "id": {
              "description": "The step's id, unique in the spider.",
              "type": "string"
            },
            "target": {
              "description": "The target the step acts on.",
              "type": "string"
            },
            "offset": {
              "description": "Where to click in the element; by default its centre.",
              "type": "object",
              "properties": {
                "x": {
                  "description": "Pixels from the left edge.",
                  "type": "number"
                },
                "y": {
                  "description": "Pixels from the top edge.",
                  "type": "number"
                }
              },
              "required": [
                "x",
                "y"
              ],
              "additionalProperties": false
            },
            "button": {
              "description": "The mouse button; by default left.",
              "type": "string",
              "enum": [
                "left",
                "middle",
                "right"
              ]
            },
            "modifiers": {
              "description": "The keys held down while clicking.",
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "Alt",
                  "Control",
                  "Meta",
                  "Shift"
                ]
              }
            },
            "count": {
              "description": "One click or a double click.",
              "type": "integer",
              "enum": [
                1,
                2
              ]
            },
            "note": {
              "description": "A note for the people reading the spider.",
              "type": "string"
            },
            "effect": {
              "description": "Whether the step only reads or submits something; required, never defaulted.",
              "type": "string",
              "enum": [
                "read",
                "submit"
              ]
            },
            "page": {
              "description": "The page the step acts on; by default \"main\".",
              "type": "string"
            },
            "until": {
              "description": "What the step waits for after acting, every one of them.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Until"
              }
            },
            "timeoutMs": {
              "description": "How long the step waits, in milliseconds.",
              "type": "integer"
            },
            "opens": {
              "description": "The page or the download the step opens.",
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "page": {
                      "description": "The name the page opened goes by in later steps.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "page"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "download": {
                      "description": "The file output the download is saved as.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "download"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "dialog": {
              "description": "The dialog the step opens, and how it is answered.",
              "type": "object",
              "properties": {
                "kind": {
                  "description": "The kind of dialog.",
                  "type": "string",
                  "enum": [
                    "alert",
                    "confirm",
                    "prompt",
                    "beforeunload"
                  ]
                },
                "message": {
                  "description": "The message the dialog shows.",
                  "type": "string"
                },
                "answer": {
                  "description": "Whether the dialog is accepted or dismissed.",
                  "type": "string",
                  "enum": [
                    "accept",
                    "dismiss"
                  ]
                },
                "text": {
                  "description": "The text typed into a prompt before accepting it.",
                  "$ref": "#/$defs/Expr"
                }
              },
              "required": [
                "kind",
                "answer"
              ],
              "additionalProperties": false
            }
          },
          "required": [
            "do",
            "id",
            "target",
            "effect"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "do": {
              "description": "The kind of step.",
              "type": "string",
              "const": "hover"
            },
            "id": {
              "description": "The step's id, unique in the spider.",
              "type": "string"
            },
            "target": {
              "description": "The target the step acts on.",
              "type": "string"
            },
            "note": {
              "description": "A note for the people reading the spider.",
              "type": "string"
            },
            "effect": {
              "description": "Whether the step only reads or submits something; required, never defaulted.",
              "type": "string",
              "enum": [
                "read",
                "submit"
              ]
            },
            "page": {
              "description": "The page the step acts on; by default \"main\".",
              "type": "string"
            },
            "until": {
              "description": "What the step waits for after acting, every one of them.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Until"
              }
            },
            "timeoutMs": {
              "description": "How long the step waits, in milliseconds.",
              "type": "integer"
            },
            "opens": {
              "description": "The page or the download the step opens.",
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "page": {
                      "description": "The name the page opened goes by in later steps.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "page"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "download": {
                      "description": "The file output the download is saved as.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "download"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "dialog": {
              "description": "The dialog the step opens, and how it is answered.",
              "type": "object",
              "properties": {
                "kind": {
                  "description": "The kind of dialog.",
                  "type": "string",
                  "enum": [
                    "alert",
                    "confirm",
                    "prompt",
                    "beforeunload"
                  ]
                },
                "message": {
                  "description": "The message the dialog shows.",
                  "type": "string"
                },
                "answer": {
                  "description": "Whether the dialog is accepted or dismissed.",
                  "type": "string",
                  "enum": [
                    "accept",
                    "dismiss"
                  ]
                },
                "text": {
                  "description": "The text typed into a prompt before accepting it.",
                  "$ref": "#/$defs/Expr"
                }
              },
              "required": [
                "kind",
                "answer"
              ],
              "additionalProperties": false
            }
          },
          "required": [
            "do",
            "id",
            "target",
            "effect"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "do": {
              "description": "The kind of step.",
              "type": "string",
              "const": "fill"
            },
            "id": {
              "description": "The step's id, unique in the spider.",
              "type": "string"
            },
            "target": {
              "description": "The target the step acts on.",
              "type": "string"
            },
            "value": {
              "description": "The value put in the field.",
              "$ref": "#/$defs/Expr"
            },
            "note": {
              "description": "A note for the people reading the spider.",
              "type": "string"
            },
            "effect": {
              "description": "Whether the step only reads or submits something; required, never defaulted.",
              "type": "string",
              "enum": [
                "read",
                "submit"
              ]
            },
            "page": {
              "description": "The page the step acts on; by default \"main\".",
              "type": "string"
            },
            "until": {
              "description": "What the step waits for after acting, every one of them.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Until"
              }
            },
            "timeoutMs": {
              "description": "How long the step waits, in milliseconds.",
              "type": "integer"
            },
            "opens": {
              "description": "The page or the download the step opens.",
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "page": {
                      "description": "The name the page opened goes by in later steps.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "page"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "download": {
                      "description": "The file output the download is saved as.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "download"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "dialog": {
              "description": "The dialog the step opens, and how it is answered.",
              "type": "object",
              "properties": {
                "kind": {
                  "description": "The kind of dialog.",
                  "type": "string",
                  "enum": [
                    "alert",
                    "confirm",
                    "prompt",
                    "beforeunload"
                  ]
                },
                "message": {
                  "description": "The message the dialog shows.",
                  "type": "string"
                },
                "answer": {
                  "description": "Whether the dialog is accepted or dismissed.",
                  "type": "string",
                  "enum": [
                    "accept",
                    "dismiss"
                  ]
                },
                "text": {
                  "description": "The text typed into a prompt before accepting it.",
                  "$ref": "#/$defs/Expr"
                }
              },
              "required": [
                "kind",
                "answer"
              ],
              "additionalProperties": false
            }
          },
          "required": [
            "do",
            "id",
            "target",
            "value",
            "effect"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "do": {
              "description": "The kind of step.",
              "type": "string",
              "const": "type"
            },
            "id": {
              "description": "The step's id, unique in the spider.",
              "type": "string"
            },
            "target": {
              "description": "The target the step acts on.",
              "type": "string"
            },
            "value": {
              "description": "The value put in the field.",
              "$ref": "#/$defs/Expr"
            },
            "cadenceMs": {
              "description": "The time between keys, in milliseconds.",
              "type": "number"
            },
            "note": {
              "description": "A note for the people reading the spider.",
              "type": "string"
            },
            "effect": {
              "description": "Whether the step only reads or submits something; required, never defaulted.",
              "type": "string",
              "enum": [
                "read",
                "submit"
              ]
            },
            "page": {
              "description": "The page the step acts on; by default \"main\".",
              "type": "string"
            },
            "until": {
              "description": "What the step waits for after acting, every one of them.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Until"
              }
            },
            "timeoutMs": {
              "description": "How long the step waits, in milliseconds.",
              "type": "integer"
            },
            "opens": {
              "description": "The page or the download the step opens.",
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "page": {
                      "description": "The name the page opened goes by in later steps.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "page"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "download": {
                      "description": "The file output the download is saved as.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "download"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "dialog": {
              "description": "The dialog the step opens, and how it is answered.",
              "type": "object",
              "properties": {
                "kind": {
                  "description": "The kind of dialog.",
                  "type": "string",
                  "enum": [
                    "alert",
                    "confirm",
                    "prompt",
                    "beforeunload"
                  ]
                },
                "message": {
                  "description": "The message the dialog shows.",
                  "type": "string"
                },
                "answer": {
                  "description": "Whether the dialog is accepted or dismissed.",
                  "type": "string",
                  "enum": [
                    "accept",
                    "dismiss"
                  ]
                },
                "text": {
                  "description": "The text typed into a prompt before accepting it.",
                  "$ref": "#/$defs/Expr"
                }
              },
              "required": [
                "kind",
                "answer"
              ],
              "additionalProperties": false
            }
          },
          "required": [
            "do",
            "id",
            "target",
            "value",
            "cadenceMs",
            "effect"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "do": {
              "description": "The kind of step.",
              "type": "string",
              "const": "press"
            },
            "id": {
              "description": "The step's id, unique in the spider.",
              "type": "string"
            },
            "target": {
              "description": "The target focused before pressing; by default the element in focus.",
              "type": "string"
            },
            "keys": {
              "description": "The keys pressed in turn, such as \"Enter\" or \"Control+a\".",
              "type": "array",
              "items": {
                "type": "string"
              },
              "minItems": 1
            },
            "note": {
              "description": "A note for the people reading the spider.",
              "type": "string"
            },
            "effect": {
              "description": "Whether the step only reads or submits something; required, never defaulted.",
              "type": "string",
              "enum": [
                "read",
                "submit"
              ]
            },
            "page": {
              "description": "The page the step acts on; by default \"main\".",
              "type": "string"
            },
            "until": {
              "description": "What the step waits for after acting, every one of them.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Until"
              }
            },
            "timeoutMs": {
              "description": "How long the step waits, in milliseconds.",
              "type": "integer"
            },
            "opens": {
              "description": "The page or the download the step opens.",
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "page": {
                      "description": "The name the page opened goes by in later steps.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "page"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "download": {
                      "description": "The file output the download is saved as.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "download"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "dialog": {
              "description": "The dialog the step opens, and how it is answered.",
              "type": "object",
              "properties": {
                "kind": {
                  "description": "The kind of dialog.",
                  "type": "string",
                  "enum": [
                    "alert",
                    "confirm",
                    "prompt",
                    "beforeunload"
                  ]
                },
                "message": {
                  "description": "The message the dialog shows.",
                  "type": "string"
                },
                "answer": {
                  "description": "Whether the dialog is accepted or dismissed.",
                  "type": "string",
                  "enum": [
                    "accept",
                    "dismiss"
                  ]
                },
                "text": {
                  "description": "The text typed into a prompt before accepting it.",
                  "$ref": "#/$defs/Expr"
                }
              },
              "required": [
                "kind",
                "answer"
              ],
              "additionalProperties": false
            }
          },
          "required": [
            "do",
            "id",
            "keys",
            "effect"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "do": {
              "description": "The kind of step.",
              "type": "string",
              "const": "select"
            },
            "id": {
              "description": "The step's id, unique in the spider.",
              "type": "string"
            },
            "target": {
              "description": "The target the step acts on.",
              "type": "string"
            },
            "label": {
              "description": "The label of the option selected.",
              "$ref": "#/$defs/Expr"
            },
            "value": {
              "description": "The value of the option selected.",
              "$ref": "#/$defs/Expr"
            },
            "note": {
              "description": "A note for the people reading the spider.",
              "type": "string"
            },
            "effect": {
              "description": "Whether the step only reads or submits something; required, never defaulted.",
              "type": "string",
              "enum": [
                "read",
                "submit"
              ]
            },
            "page": {
              "description": "The page the step acts on; by default \"main\".",
              "type": "string"
            },
            "until": {
              "description": "What the step waits for after acting, every one of them.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Until"
              }
            },
            "timeoutMs": {
              "description": "How long the step waits, in milliseconds.",
              "type": "integer"
            },
            "opens": {
              "description": "The page or the download the step opens.",
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "page": {
                      "description": "The name the page opened goes by in later steps.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "page"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "download": {
                      "description": "The file output the download is saved as.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "download"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "dialog": {
              "description": "The dialog the step opens, and how it is answered.",
              "type": "object",
              "properties": {
                "kind": {
                  "description": "The kind of dialog.",
                  "type": "string",
                  "enum": [
                    "alert",
                    "confirm",
                    "prompt",
                    "beforeunload"
                  ]
                },
                "message": {
                  "description": "The message the dialog shows.",
                  "type": "string"
                },
                "answer": {
                  "description": "Whether the dialog is accepted or dismissed.",
                  "type": "string",
                  "enum": [
                    "accept",
                    "dismiss"
                  ]
                },
                "text": {
                  "description": "The text typed into a prompt before accepting it.",
                  "$ref": "#/$defs/Expr"
                }
              },
              "required": [
                "kind",
                "answer"
              ],
              "additionalProperties": false
            }
          },
          "required": [
            "do",
            "id",
            "target",
            "effect"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "do": {
              "description": "The kind of step.",
              "type": "string",
              "const": "check"
            },
            "id": {
              "description": "The step's id, unique in the spider.",
              "type": "string"
            },
            "target": {
              "description": "The target the step acts on.",
              "type": "string"
            },
            "checked": {
              "description": "Whether the box ends up checked.",
              "$ref": "#/$defs/Expr"
            },
            "note": {
              "description": "A note for the people reading the spider.",
              "type": "string"
            },
            "effect": {
              "description": "Whether the step only reads or submits something; required, never defaulted.",
              "type": "string",
              "enum": [
                "read",
                "submit"
              ]
            },
            "page": {
              "description": "The page the step acts on; by default \"main\".",
              "type": "string"
            },
            "until": {
              "description": "What the step waits for after acting, every one of them.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Until"
              }
            },
            "timeoutMs": {
              "description": "How long the step waits, in milliseconds.",
              "type": "integer"
            },
            "opens": {
              "description": "The page or the download the step opens.",
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "page": {
                      "description": "The name the page opened goes by in later steps.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "page"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "download": {
                      "description": "The file output the download is saved as.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "download"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "dialog": {
              "description": "The dialog the step opens, and how it is answered.",
              "type": "object",
              "properties": {
                "kind": {
                  "description": "The kind of dialog.",
                  "type": "string",
                  "enum": [
                    "alert",
                    "confirm",
                    "prompt",
                    "beforeunload"
                  ]
                },
                "message": {
                  "description": "The message the dialog shows.",
                  "type": "string"
                },
                "answer": {
                  "description": "Whether the dialog is accepted or dismissed.",
                  "type": "string",
                  "enum": [
                    "accept",
                    "dismiss"
                  ]
                },
                "text": {
                  "description": "The text typed into a prompt before accepting it.",
                  "$ref": "#/$defs/Expr"
                }
              },
              "required": [
                "kind",
                "answer"
              ],
              "additionalProperties": false
            }
          },
          "required": [
            "do",
            "id",
            "target",
            "checked",
            "effect"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "do": {
              "description": "The kind of step.",
              "type": "string",
              "const": "choose"
            },
            "id": {
              "description": "The step's id, unique in the spider.",
              "type": "string"
            },
            "target": {
              "description": "The target the step acts on.",
              "type": "string"
            },
            "query": {
              "description": "The text typed into the field to show the suggestions.",
              "$ref": "#/$defs/Expr"
            },
            "cadenceMs": {
              "description": "The time between keys, in milliseconds.",
              "type": "number"
            },
            "option": {
              "description": "The target of the option to commit.",
              "type": "string"
            },
            "commit": {
              "description": "How the option is committed: a click, or arrow keys then Enter.",
              "type": "string",
              "enum": [
                "click",
                "keys"
              ]
            },
            "match": {
              "description": "How the option is picked among the suggestions shown.",
              "type": "object",
              "properties": {
                "value": {
                  "description": "The value the option chosen must match.",
                  "$ref": "#/$defs/Expr"
                },
                "rule": {
                  "description": "How texts are compared: as text, an Italian address, or an Italian comune.",
                  "type": "string",
                  "enum": [
                    "text",
                    "address-it",
                    "comune-it"
                  ]
                },
                "check": {
                  "description": "The target whose value must match too after the commit; by default the field.",
                  "type": "string"
                }
              },
              "required": [
                "value",
                "rule"
              ],
              "additionalProperties": false
            },
            "note": {
              "description": "A note for the people reading the spider.",
              "type": "string"
            },
            "effect": {
              "description": "Whether the step only reads or submits something; required, never defaulted.",
              "type": "string",
              "enum": [
                "read",
                "submit"
              ]
            },
            "page": {
              "description": "The page the step acts on; by default \"main\".",
              "type": "string"
            },
            "until": {
              "description": "What the step waits for after acting, every one of them.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Until"
              }
            },
            "timeoutMs": {
              "description": "How long the step waits, in milliseconds.",
              "type": "integer"
            },
            "opens": {
              "description": "The page or the download the step opens.",
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "page": {
                      "description": "The name the page opened goes by in later steps.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "page"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "download": {
                      "description": "The file output the download is saved as.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "download"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "dialog": {
              "description": "The dialog the step opens, and how it is answered.",
              "type": "object",
              "properties": {
                "kind": {
                  "description": "The kind of dialog.",
                  "type": "string",
                  "enum": [
                    "alert",
                    "confirm",
                    "prompt",
                    "beforeunload"
                  ]
                },
                "message": {
                  "description": "The message the dialog shows.",
                  "type": "string"
                },
                "answer": {
                  "description": "Whether the dialog is accepted or dismissed.",
                  "type": "string",
                  "enum": [
                    "accept",
                    "dismiss"
                  ]
                },
                "text": {
                  "description": "The text typed into a prompt before accepting it.",
                  "$ref": "#/$defs/Expr"
                }
              },
              "required": [
                "kind",
                "answer"
              ],
              "additionalProperties": false
            }
          },
          "required": [
            "do",
            "id",
            "target",
            "query",
            "cadenceMs",
            "option",
            "commit",
            "effect"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "do": {
              "description": "The kind of step.",
              "type": "string",
              "const": "upload"
            },
            "id": {
              "description": "The step's id, unique in the spider.",
              "type": "string"
            },
            "target": {
              "description": "The target the step acts on.",
              "type": "string"
            },
            "files": {
              "description": "The files uploaded.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Expr"
              },
              "minItems": 1
            },
            "note": {
              "description": "A note for the people reading the spider.",
              "type": "string"
            },
            "effect": {
              "description": "Whether the step only reads or submits something; required, never defaulted.",
              "type": "string",
              "enum": [
                "read",
                "submit"
              ]
            },
            "page": {
              "description": "The page the step acts on; by default \"main\".",
              "type": "string"
            },
            "until": {
              "description": "What the step waits for after acting, every one of them.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Until"
              }
            },
            "timeoutMs": {
              "description": "How long the step waits, in milliseconds.",
              "type": "integer"
            },
            "opens": {
              "description": "The page or the download the step opens.",
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "page": {
                      "description": "The name the page opened goes by in later steps.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "page"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "download": {
                      "description": "The file output the download is saved as.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "download"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "dialog": {
              "description": "The dialog the step opens, and how it is answered.",
              "type": "object",
              "properties": {
                "kind": {
                  "description": "The kind of dialog.",
                  "type": "string",
                  "enum": [
                    "alert",
                    "confirm",
                    "prompt",
                    "beforeunload"
                  ]
                },
                "message": {
                  "description": "The message the dialog shows.",
                  "type": "string"
                },
                "answer": {
                  "description": "Whether the dialog is accepted or dismissed.",
                  "type": "string",
                  "enum": [
                    "accept",
                    "dismiss"
                  ]
                },
                "text": {
                  "description": "The text typed into a prompt before accepting it.",
                  "$ref": "#/$defs/Expr"
                }
              },
              "required": [
                "kind",
                "answer"
              ],
              "additionalProperties": false
            }
          },
          "required": [
            "do",
            "id",
            "target",
            "files",
            "effect"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "do": {
              "description": "The kind of step.",
              "type": "string",
              "const": "scroll"
            },
            "id": {
              "description": "The step's id, unique in the spider.",
              "type": "string"
            },
            "target": {
              "description": "The target to scroll to, or to scroll within to its end.",
              "type": "string"
            },
            "to": {
              "description": "Where to scroll: to the end of the page or to the target.",
              "type": "string",
              "enum": [
                "end",
                "target"
              ]
            },
            "note": {
              "description": "A note for the people reading the spider.",
              "type": "string"
            },
            "effect": {
              "description": "Whether the step only reads or submits something; required, never defaulted.",
              "type": "string",
              "enum": [
                "read",
                "submit"
              ]
            },
            "page": {
              "description": "The page the step acts on; by default \"main\".",
              "type": "string"
            },
            "until": {
              "description": "What the step waits for after acting, every one of them.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Until"
              }
            },
            "timeoutMs": {
              "description": "How long the step waits, in milliseconds.",
              "type": "integer"
            },
            "opens": {
              "description": "The page or the download the step opens.",
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "page": {
                      "description": "The name the page opened goes by in later steps.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "page"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "download": {
                      "description": "The file output the download is saved as.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "download"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "dialog": {
              "description": "The dialog the step opens, and how it is answered.",
              "type": "object",
              "properties": {
                "kind": {
                  "description": "The kind of dialog.",
                  "type": "string",
                  "enum": [
                    "alert",
                    "confirm",
                    "prompt",
                    "beforeunload"
                  ]
                },
                "message": {
                  "description": "The message the dialog shows.",
                  "type": "string"
                },
                "answer": {
                  "description": "Whether the dialog is accepted or dismissed.",
                  "type": "string",
                  "enum": [
                    "accept",
                    "dismiss"
                  ]
                },
                "text": {
                  "description": "The text typed into a prompt before accepting it.",
                  "$ref": "#/$defs/Expr"
                }
              },
              "required": [
                "kind",
                "answer"
              ],
              "additionalProperties": false
            }
          },
          "required": [
            "do",
            "id",
            "to",
            "effect"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "do": {
              "description": "The kind of step.",
              "type": "string",
              "const": "extract"
            },
            "id": {
              "description": "The step's id, unique in the spider.",
              "type": "string"
            },
            "target": {
              "description": "The target the step acts on.",
              "type": "string"
            },
            "into": {
              "description": "The output the value read goes into.",
              "type": "string"
            },
            "page": {
              "description": "The page read; by default \"main\".",
              "type": "string"
            },
            "read": {
              "description": "How the element is read; by default its text.",
              "$ref": "#/$defs/Read"
            },
            "fields": {
              "description": "The fields read from each element of a list target, by output field name.",
              "type": "object",
              "additionalProperties": {
                "type": "object",
                "properties": {
                  "css": {
                    "description": "A CSS selector for the field within each element.",
                    "type": "string"
                  },
                  "read": {
                    "description": "How the field is read; by default its text.",
                    "$ref": "#/$defs/Read"
                  },
                  "all": {
                    "description": "Present when the field is a list of every match.",
                    "type": "boolean",
                    "const": true
                  }
                },
                "required": [
                  "css"
                ],
                "additionalProperties": false
              }
            },
            "note": {
              "description": "A note for the people reading the spider.",
              "type": "string"
            }
          },
          "required": [
            "do",
            "id",
            "target",
            "into"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "do": {
              "description": "The kind of step.",
              "type": "string",
              "const": "close"
            },
            "id": {
              "description": "The step's id, unique in the spider.",
              "type": "string"
            },
            "page": {
              "description": "The page closed.",
              "type": "string"
            },
            "note": {
              "description": "A note for the people reading the spider.",
              "type": "string"
            }
          },
          "required": [
            "do",
            "id",
            "page"
          ],
          "additionalProperties": false
        }
      ]
    },
    "BlockStep": {
      "description": "One step of a block: a step, or an if that runs steps of the other kinds when its condition holds.",
      "anyOf": [
        {
          "$ref": "#/$defs/Step"
        },
        {
          "type": "object",
          "properties": {
            "do": {
              "description": "The kind of step.",
              "type": "string",
              "const": "if"
            },
            "id": {
              "description": "The step's id, unique in the spider.",
              "type": "string"
            },
            "when": {
              "description": "The condition read when the step is reached.",
              "$ref": "#/$defs/Cond"
            },
            "then": {
              "description": "The steps run when the condition holds, none of them an if; skipped when it does not.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Step"
              },
              "minItems": 1
            },
            "note": {
              "description": "A note for the people reading the spider.",
              "type": "string"
            }
          },
          "required": [
            "do",
            "id",
            "when",
            "then"
          ],
          "additionalProperties": false
        }
      ]
    }
  }
}
