{
  "$schema": "http://json-schema.org/draft-07/schema",
  "oneOf": [
    {
      "$ref": "#/definitions/Scenario"
    },
    {
      "$ref": "#/definitions/allOfSteps"
    }
  ],
  "definitions": {
    "Script": {
      "type": "object",
      "properties": {
        "Script/Js": {
          "description": "Run javascript in scenario",
          "oneOf": [
            {
              "$ref": "#/definitions/getVarString",
              "description": "Content script",
              "examples": [
                "Vars.name = 'hello'"
              ]
            },
            {
              "type": "object",
              "required": [
                "content"
              ],
              "properties": {
                "content": {
                  "$ref": "#/definitions/getVarString",
                  "description": "Content script",
                  "examples": [
                    "Vars.name = 'hello'"
                  ]
                },
                "async": {
                  "description": "Run asynchronized",
                  "$ref": "#/definitions/getVarBooleanString",
                  "examples": [
                    "true",
                    "false",
                    "${isAsync}"
                  ]
                },
                "loop": {
                  "description": "Conditional to check before loop steps. ($.loopValue, $.loopKey)",
                  "$ref": "#/definitions/getVarAny",
                  "examples": [
                    "${[1,2,3,4]}",
                    "${{key1: value1, key2: value2}}",
                    "${list}",
                    "${isRun}"
                  ]
                },
                "logLevel": {
                  "description": "How to show log",
                  "$ref": "#/definitions/logLevel"
                },
                "delay": {
                  "description": "Delay in specific time before keep playing the next",
                  "$ref": "#/definitions/time"
                },
                "if": {
                  "description": "Check conditional to decide to run it or NOT",
                  "$ref": "#/definitions/getVarBooleanString"
                },
                "->": {
                  "description": "Expose for others extends",
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  ]
                },
                "<-": {
                  "description": "Extends others which is exposed by '->'",
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  ]
                }
              }
            }
          ]
        },
        "Script/Sh": {
          "description": "Run shell script in scenario",
          "oneOf": [
            {
              "$ref": "#/definitions/getVarString",
              "description": "Content script",
              "examples": [
                "Echo \"${user}\""
              ]
            },
            {
              "type": "object",
              "required": [
                "content"
              ],
              "properties": {
                "content": {
                  "$ref": "#/definitions/getVarString",
                  "description": "Content script",
                  "examples": [
                    "Echo \"${user}\""
                  ]
                },
                "async": {
                  "description": "Run asynchronized",
                  "$ref": "#/definitions/getVarBooleanString",
                  "examples": [
                    "true",
                    "false",
                    "${isAsync}"
                  ]
                },
                "loop": {
                  "description": "Conditional to check before loop steps. ($.loopValue, $.loopKey)",
                  "$ref": "#/definitions/getVarAny",
                  "examples": [
                    "${[1,2,3,4]}",
                    "${{key1: value1, key2: value2}}",
                    "${list}",
                    "${isRun}"
                  ]
                },
                "logLevel": {
                  "description": "How to show log",
                  "$ref": "#/definitions/logLevel"
                },
                "delay": {
                  "description": "Delay in specific time before keep playing the next",
                  "$ref": "#/definitions/time"
                },
                "if": {
                  "description": "Check conditional to decide to run it or NOT",
                  "$ref": "#/definitions/getVarBooleanString"
                },
                "->": {
                  "description": "Expose for others extends",
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  ]
                },
                "<-": {
                  "description": "Extends others which is exposed by '->'",
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  ]
                }
              }
            }
          ]
        }
      }
    },
    "Pause": {
      "type": "object",
      "properties": {
        "Pause": {
          "title": "Pause or sleep the current step",
          "oneOf": [
            {
              "type": "object",
              "description": "Pause",
              "properties": {
                "title": {
                  "$ref": "#/definitions/getVarString",
                  "description": "Description"
                },
                "time": {
                  "$ref": "#/definitions/time",
                  "description": "Delay time"
                }
              },
              "async": {
                "description": "Run asynchronized",
                "$ref": "#/definitions/getVarBooleanString",
                "examples": [
                  "true",
                  "false",
                  "${isAsync}"
                ]
              },
              "loop": {
                "description": "Conditional to check before loop steps. ($.loopValue, $.loopKey)",
                "$ref": "#/definitions/getVarAny",
                "examples": [
                  "${[1,2,3,4]}",
                  "${{key1: value1, key2: value2}}",
                  "${list}",
                  "${isRun}"
                ]
              },
              "logLevel": {
                "description": "How to show log",
                "$ref": "#/definitions/logLevel"
              },
              "delay": {
                "description": "Delay in specific time before keep playing the next",
                "$ref": "#/definitions/time"
              },
              "if": {
                "description": "Check conditional to decide to run it or NOT",
                "$ref": "#/definitions/getVarBooleanString"
              },
              "->": {
                "description": "Expose for others extends",
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                ]
              },
              "<-": {
                "description": "Extends others which is exposed by '->'",
                "oneOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                ]
              }
            },
            {
              "$ref": "#/definitions/time",
              "description": "Delay time"
            },
            {
              "type": "null",
              "description": "Pause"
            }
          ]
        }
      }
    },
    "UserInput": {
      "type": "object",
      "properties": {
        "UserInput": {
          "description": "Get input from user keyboard",
          "type": "array",
          "items": {
            "$ref": "#/definitions/userinput"
          }
        }
      }
    },
    "Exec": {
      "type": "object",
      "properties": {
        "Exec": {
          "type": "object",
          "description": "Execute external command",
          "required": [
            "args"
          ],
          "properties": {
            "title": {
              "$ref": "#/definitions/getVarString"
            },
            "var": {
              "description": "Set result after execution",
              "$ref": "#/definitions/setVar"
            },
            "args": {
              "type": "array",
              "description": "The first is command name, then are agrs",
              "items": {
                "$ref": "#/definitions/getVar"
              }
            },
            "async": {
              "description": "Run asynchronized",
              "$ref": "#/definitions/getVarBooleanString",
              "examples": [
                "true",
                "false",
                "${isAsync}"
              ]
            },
            "loop": {
              "description": "Conditional to check before loop steps. ($.loopValue, $.loopKey)",
              "$ref": "#/definitions/getVarAny",
              "examples": [
                "${[1,2,3,4]}",
                "${{key1: value1, key2: value2}}",
                "${list}",
                "${isRun}"
              ]
            },
            "logLevel": {
              "description": "How to show log",
              "$ref": "#/definitions/logLevel"
            },
            "delay": {
              "description": "Delay in specific time before keep playing the next",
              "$ref": "#/definitions/time"
            },
            "if": {
              "description": "Check conditional to decide to run it or NOT",
              "$ref": "#/definitions/getVarBooleanString"
            },
            "->": {
              "description": "Expose for others extends",
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              ]
            },
            "<-": {
              "description": "Extends others which is exposed by '->'",
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              ]
            }
          }
        }
      }
    },
    "Validate": {
      "type": "object",
      "properties": {
        "Validate": {
          "description": "Use an existed validation or method from https://www.chaijs.com/",
          "properties": {
            "title": {
              "$ref": "#/definitions/getVarString",
              "description": "Validation name"
            },
            "chai": {
              "description": "ChaiJS validator",
              "$ref": "#/definitions/getVar",
              "examples": [
                "${expect(userInfo).to.have.property('display_name')}",
                "${userInfo.display_name.should.equal('thanh')}",
                "${assert.equal(userInfo.display_name, 'thanh')}"
              ]
            }
          },
          "type": "object",
          "required": [
            "title",
            "chai"
          ]
        }
      }
    },
    "Scenario": {
      "type": "object",
      "description": "Includes all of steps in scenario",
      "required": [
        "steps"
      ],
      "properties": {
        "title": {
          "type": "string",
          "description": "Scenario title"
        },
        "description": {
          "type": "string",
          "description": "Scenario description"
        },
        "password": {
          "description": "Password to encrypt scenario file to share to someone",
          "type": "string"
        },
        "vars": {
          "type": "object",
          "description": "Expose the variables to environment variables for override purpose"
        },
        "install": {
          "description": "Install these packages before start",
          "properties": {
            "local": {
              "description": "Install npm packages in local path",
              "type": "object",
              "properties": {
                "dependencies": {
                  "type": "array",
                  "description": "NPM Packages name",
                  "items": {
                    "type": "string"
                  }
                },
                "path": {
                  "type": "string",
                  "description": "Location install NPM Packages"
                }
              }
            },
            "global": {
              "description": "Install npm packages in global",
              "type": "object",
              "properties": {
                "dependencies": {
                  "type": "array",
                  "description": "NPM Packages name",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "logLevel": {
          "description": "Set log level to global",
          "$ref": "#/definitions/logLevel"
        },
        "extensions": {
          "type": "object",
          "description": "Map extension from source code in local",
          "examples": [
            {
              "yas-http": "./yas-http/src",
              "yas-grpc": "./yas-grpc/src",
              "my-ext": "./src"
            }
          ]
        },
        "steps": {
          "$ref": "#/definitions/allOfSteps"
        }
      }
    },
    "Fragment": {
      "type": "object",
      "properties": {
        "Fragment": {
          "description": "Load and execute scenario from a scenario file",
          "anyOf": [
            {
              "description": "Path or URL of scenario file",
              "$ref": "#/definitions/getVarString"
            },
            {
              "type": "object",
              "required": [
                "file"
              ],
              "properties": {
                "title": {
                  "type": "string",
                  "description": "Group title"
                },
                "description": {
                  "type": "string",
                  "description": "Group description"
                },
                "file": {
                  "description": "Path or URL of scenario file",
                  "$ref": "#/definitions/getVarString"
                },
                "password": {
                  "description": "Password to encrypt scenario file to share to someone",
                  "type": "string"
                },
                "vars": {
                  "type": "object",
                  "description": "Override vars in scenario"
                },
                "logLevel": {
                  "description": "Set log level",
                  "$ref": "#/definitions/logLevel"
                }
              }
            }
          ]
        }
      }
    },
    "File": {
      "type": "object",
      "properties": {
        "File/Reader": {
          "type": "object",
          "required": [
            "path",
            "var"
          ],
          "properties": {
            "adapters": {
              "description": "Adapter to parse content after read file",
              "$ref": "#/definitions/fileAdapter"
            },
            "path": {
              "type": "string",
              "description": "Path of input file"
            },
            "title": {
              "$ref": "#/definitions/getVarString",
              "description": "Description"
            },
            "var": {
              "description": "Assign file content which after parsed to global variable",
              "$ref": "#/definitions/setVar"
            },
            "async": {
              "description": "Run asynchronized",
              "$ref": "#/definitions/getVarBooleanString",
              "examples": [
                "true",
                "false",
                "${isAsync}"
              ]
            },
            "loop": {
              "description": "Conditional to check before loop steps. ($.loopValue, $.loopKey)",
              "$ref": "#/definitions/getVarAny",
              "examples": [
                "${[1,2,3,4]}",
                "${{key1: value1, key2: value2}}",
                "${list}",
                "${isRun}"
              ]
            },
            "logLevel": {
              "description": "How to show log",
              "$ref": "#/definitions/logLevel"
            },
            "delay": {
              "description": "Delay in specific time before keep playing the next",
              "$ref": "#/definitions/time"
            },
            "if": {
              "description": "Check conditional to decide to run it or NOT",
              "$ref": "#/definitions/getVarBooleanString"
            },
            "->": {
              "description": "Expose for others extends",
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              ]
            },
            "<-": {
              "description": "Extends others which is exposed by '->'",
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              ]
            }
          }
        },
        "File/Writer": {
          "type": "object",
          "required": [
            "path",
            "content"
          ],
          "properties": {
            "adapters": {
              "description": "Adapter to parse content before write to file",
              "$ref": "#/definitions/fileAdapter"
            },
            "path": {
              "type": "string",
              "description": "Path of output file"
            },
            "title": {
              "$ref": "#/definitions/getVarString",
              "description": "Description"
            },
            "content": {
              "$ref": "#/definitions/getVarAny",
              "description": "File content which is parsed by adapters before write to file"
            },
            "async": {
              "description": "Run asynchronized",
              "$ref": "#/definitions/getVarBooleanString",
              "examples": [
                "true",
                "false",
                "${isAsync}"
              ]
            },
            "loop": {
              "description": "Conditional to check before loop steps. ($.loopValue, $.loopKey)",
              "$ref": "#/definitions/getVarAny",
              "examples": [
                "${[1,2,3,4]}",
                "${{key1: value1, key2: value2}}",
                "${list}",
                "${isRun}"
              ]
            },
            "logLevel": {
              "description": "How to show log",
              "$ref": "#/definitions/logLevel"
            },
            "delay": {
              "description": "Delay in specific time before keep playing the next",
              "$ref": "#/definitions/time"
            },
            "if": {
              "description": "Check conditional to decide to run it or NOT",
              "$ref": "#/definitions/getVarBooleanString"
            },
            "->": {
              "description": "Expose for others extends",
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              ]
            },
            "<-": {
              "description": "Extends others which is exposed by '->'",
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              ]
            }
          }
        }
      }
    },
    "Vars": {
      "type": "object",
      "properties": {
        "Vars": {
          "type": "object",
          "description": "Assign value to global variables"
        }
      }
    },
    "Templates": {
      "type": "object",
      "properties": {
        "Templates": {
          "description": "Declare steps which not used to run, just declared",
          "$ref": "#/definitions/allOfSteps"
        }
      }
    },
    "Group": {
      "type": "object",
      "properties": {
        "Group": {
          "required": [
            "steps"
          ],
          "type": "object",
          "description": "Group steps",
          "properties": {
            "title": {
              "$ref": "#/definitions/getVarString",
              "description": "Group title"
            },
            "description": {
              "$ref": "#/definitions/getVarString",
              "description": "Group description"
            },
            "steps": {
              "$ref": "#/definitions/allOfSteps"
            },
            "async": {
              "description": "Run asynchronized",
              "$ref": "#/definitions/getVarBooleanString",
              "examples": [
                "true",
                "false",
                "${isAsync}"
              ]
            },
            "loop": {
              "description": "Conditional to check before loop steps. ($.loopValue, $.loopKey)",
              "$ref": "#/definitions/getVarAny",
              "examples": [
                "${[1,2,3,4]}",
                "${{key1: value1, key2: value2}}",
                "${list}",
                "${isRun}"
              ]
            },
            "logLevel": {
              "description": "How to show log",
              "$ref": "#/definitions/logLevel"
            },
            "delay": {
              "description": "Delay in specific time before keep playing the next",
              "$ref": "#/definitions/time"
            },
            "if": {
              "description": "Check conditional to decide to run it or NOT",
              "$ref": "#/definitions/getVarBooleanString"
            },
            "->": {
              "description": "Expose for others extends",
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              ]
            },
            "<-": {
              "description": "Extends others which is exposed by '->'",
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              ]
            }
          }
        }
      }
    },
    "echo": {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "title": {
              "$ref": "#/definitions/getVarString",
              "description": "Description"
            },
            "pretty": {
              "type": "boolean",
              "description": "Format object with breakline"
            },
            "schema": {
              "type": "boolean",
              "description": "Print object schema (NOT value)"
            },
            "color": {
              "type": "string",
              "description": "Set text color",
              "examples": [
                "red",
                "blue",
                "cyan",
                "green",
                "gray",
                "yellow"
              ]
            },
            "transforms": {
              "type": [
                "object",
                "string"
              ],
              "description": "Customize output by your code"
            },
            "message": {
              "description": "Message which is printed to screen",
              "$ref": "#/definitions/getVarAny"
            },
            "async": {
              "description": "Run asynchronized",
              "$ref": "#/definitions/getVarBooleanString",
              "examples": [
                "true",
                "false",
                "${isAsync}"
              ]
            },
            "loop": {
              "description": "Conditional to check before loop steps. ($.loopValue, $.loopKey)",
              "$ref": "#/definitions/getVarAny",
              "examples": [
                "${[1,2,3,4]}",
                "${{key1: value1, key2: value2}}",
                "${list}",
                "${isRun}"
              ]
            },
            "logLevel": {
              "description": "How to show log",
              "$ref": "#/definitions/logLevel"
            },
            "delay": {
              "description": "Delay in specific time before keep playing the next",
              "$ref": "#/definitions/time"
            },
            "if": {
              "description": "Check conditional to decide to run it or NOT",
              "$ref": "#/definitions/getVarBooleanString"
            },
            "->": {
              "description": "Expose for others extends",
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              ]
            },
            "<-": {
              "description": "Extends others which is exposed by '->'",
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              ]
            }
          }
        },
        {
          "$ref": "#/definitions/getVar"
        }
      ],
      "examples": [
        "${varName}"
      ]
    },
    "Echo": {
      "type": "object",
      "description": "Print data to screen",
      "properties": {
        "Echo/Schema": {
          "description": "Print object schema to screen",
          "$ref": "#/definitions/echo"
        },
        "Echo/Green": {
          "description": "Print data to screen with text color is Green",
          "$ref": "#/definitions/echo"
        },
        "Echo/Blue": {
          "description": "Print data to screen with text color is Blue",
          "$ref": "#/definitions/echo"
        },
        "Echo/Red": {
          "description": "Print data to screen with text color is Red",
          "$ref": "#/definitions/echo"
        },
        "Echo/Cyan": {
          "description": "Print data to screen with text color is Cyan",
          "$ref": "#/definitions/echo"
        },
        "Echo/Yellow": {
          "description": "Print data to screen with text color is Yellow",
          "$ref": "#/definitions/echo"
        },
        "Echo/Gray": {
          "description": "Print data to screen with text color is Gray",
          "$ref": "#/definitions/echo"
        },
        "Echo": {
          "$ref": "#/definitions/echo"
        }
      }
    },
    "Clear": {
      "type": "object",
      "properties": {
        "Clear": {
          "description": "Clear screen",
          "type": "null"
        }
      }
    },
    "DocGuideMD": {
      "type": "object",
      "properties": {
        "Doc/Guide/MD": {
          "required": [
            "includes",
            "includePattern",
            "outFile"
          ],
          "description": "Auto scan file to detect the comment format which is generated to markdown document",
          "type": "object",
          "properties": {
            "includes": {
              "description": "Only scan files in these locations",
              "type": "array",
              "items": {
                "type": "string"
              },
              "default": [
                "src"
              ]
            },
            "excludes": {
              "description": "Scan files except these locations",
              "type": "array",
              "items": {
                "type": "string"
              },
              "default": [
                "node_modules"
              ]
            },
            "includePattern": {
              "description": "Regex pattern to validate file name before scan it",
              "type": "string",
              "default": ".+\\.ts$"
            },
            "outFile": {
              "description": "Path of guideline file",
              "type": "string"
            },
            "pattern": {
              "type": "object",
              "description": "Mark a guideline block in code",
              "properties": {
                "begin": {
                  "type": "string",
                  "description": "Regex pattern to mark to begin store information"
                },
                "end": {
                  "type": "string",
                  "description": "Regex pattern to mark to end store information"
                }
              }
            }
          }
        }
      }
    },
    "time": {
      "$ref": "#/definitions/getVarNumberString",
      "examples": [
        "1000",
        "1000ms",
        "1s",
        "1m",
        "1h"
      ]
    },
    "allOfSteps": {
      "type": "array",
      "description": "Steps",
      "items": {
        "anyOf": [
          {
            "type": "string"
          },
          {
            "$ref": "#/definitions/Clear"
          },
          {
            "$ref": "#/definitions/DocGuideMD"
          },
          {
            "$ref": "#/definitions/Echo"
          },
          {
            "$ref": "#/definitions/Exec"
          },
          {
            "$ref": "#/definitions/File"
          },
          {
            "$ref": "#/definitions/Group"
          },
          {
            "$ref": "#/definitions/Pause"
          },
          {
            "$ref": "#/definitions/Script"
          },
          {
            "$ref": "#/definitions/Templates"
          },
          {
            "$ref": "#/definitions/UserInput"
          },
          {
            "$ref": "#/definitions/Validate"
          },
          {
            "$ref": "#/definitions/Vars"
          },
          {
            "$ref": "#/definitions/Fragment"
          }
        ]
      }
    },
    "functional": {
      "type": "string",
      "description": "JS code in a function"
    },
    "getVarBooleanString": {
      "description": "Eval string to object value",
      "type": [
        "string",
        "boolean"
      ]
    },
    "getVarNumberString": {
      "description": "Eval string to object value",
      "type": [
        "string",
        "number"
      ]
    },
    "getVarObjectString": {
      "description": "Eval string to object value",
      "type": [
        "string",
        "object"
      ]
    },
    "getVarString": {
      "description": "Eval string to object value",
      "type": [
        "string"
      ]
    },
    "getVar": {
      "description": "Eval string to object value",
      "type": [
        "string",
        "number",
        "boolean"
      ]
    },
    "getVarAny": {
      "description": "Eval string to object value",
      "type": [
        "string",
        "number",
        "boolean",
        "object",
        "array",
        "null"
      ]
    },
    "logLevel": {
      "type": "string",
      "enum": [
        "trace",
        "debug",
        "info",
        "warn",
        "error",
        "slient"
      ]
    },
    "setVar": {
      "description": "Set value to a variable",
      "oneOf": [
        {
          "type": "string",
          "description": "Set value to this",
          "examples": [
            "${var2}"
          ],
          "default": "${varName}"
        },
        {
          "type": "object",
          "description": "Set a part of data to this"
        }
      ]
    },
    "fileAdapter": {
      "type": "array",
      "items": {
        "anyOf": [
          {
            "description": "Adapter name",
            "type": "string",
            "enum": [
              "Password",
              "Json",
              "Xml",
              "Yaml",
              "Csv",
              "Text"
            ]
          },
          {
            "description": "Adapter name and configuration",
            "type": "object",
            "examples": [
              {
                "json": {
                  "pretty": true
                }
              },
              {
                "Password": "my password"
              }
            ]
          },
          {
            "description": "Adapter name",
            "type": "string"
          }
        ]
      }
    },
    "userinput": {
      "type": "object",
      "required": [
        "title",
        "var"
      ],
      "properties": {
        "title": {
          "$ref": "#/definitions/getVarString",
          "description": "Question title"
        },
        "var": {
          "description": "Assign user input value to",
          "$ref": "#/definitions/setVar"
        },
        "required": {
          "description": "User input must be required",
          "$ref": "#/definitions/getVarBooleanString"
        },
        "pattern": {
          "description": "Pattern to validate",
          "$ref": "#/definitions/getVarString"
        },
        "format": {
          "type": "string",
          "examples": [
            "vl => vl.toUpperCase()"
          ]
        },
        "mask": {
          "type": "string",
          "examples": [
            "YYYY-MM-DD HH:mm:ss",
            "HH:mm:ss"
          ]
        },
        "type": {
          "description": "UserInput type",
          "enum": [
            "text",
            "password",
            "invisible",
            "number",
            "confirm",
            "toggle",
            "select",
            "multiselect",
            "autocompleteMultiselect",
            "autocomplete",
            "date"
          ]
        },
        "default": {
          "description": "Init value",
          "$ref": "#/definitions/getVar"
        },
        "choices": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "title",
              "value"
            ],
            "properties": {
              "title": {
                "$ref": "#/definitions/getVarString"
              },
              "description": {
                "$ref": "#/definitions/getVarString"
              },
              "disabled": {
                "$ref": "#/definitions/getVarBooleanString"
              },
              "value": {
                "$ref": "#/definitions/getVar"
              }
            }
          }
        },
        "async": {
          "description": "Run asynchronized",
          "$ref": "#/definitions/getVarBooleanString",
          "examples": [
            "true",
            "false",
            "${isAsync}"
          ]
        },
        "loop": {
          "description": "Conditional to check before loop steps. ($.loopValue, $.loopKey)",
          "$ref": "#/definitions/getVarAny",
          "examples": [
            "${[1,2,3,4]}",
            "${{key1: value1, key2: value2}}",
            "${list}",
            "${isRun}"
          ]
        },
        "logLevel": {
          "description": "How to show log",
          "$ref": "#/definitions/logLevel"
        },
        "delay": {
          "description": "Delay in specific time before keep playing the next",
          "$ref": "#/definitions/time"
        },
        "if": {
          "description": "Check conditional to decide to run it or NOT",
          "$ref": "#/definitions/getVarBooleanString"
        },
        "->": {
          "description": "Expose for others extends",
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          ]
        },
        "<-": {
          "description": "Extends others which is exposed by '->'",
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          ]
        }
      }
    }
  },
  "templates": {
    "validate": {
      "type": "object",
      "required": [
        "title",
        "chai"
      ],
      "properties": {
        "title": {
          "$ref": "#/definitions/getVarString",
          "description": "Validation name"
        },
        "chai": {
          "description": "ChaiJS validator",
          "$ref": "#/definitions/getVar",
          "examples": [
            "${expect(userInfo).to.have.property('display_name')}",
            "${userInfo.display_name.should.equal('thanh')}",
            "${assert.equal(userInfo.display_name, 'thanh')}"
          ]
        }
      }
    },
    "defaultAttrs": {
      "async": {
        "description": "Run asynchronized",
        "$ref": "#/definitions/getVarBooleanString",
        "examples": [
          "true",
          "false",
          "${isAsync}"
        ]
      },
      "loop": {
        "description": "Conditional to check before loop steps. ($.loopValue, $.loopKey)",
        "$ref": "#/definitions/getVarAny",
        "examples": [
          "${[1,2,3,4]}",
          "${{key1: value1, key2: value2}}",
          "${list}",
          "${isRun}"
        ]
      },
      "logLevel": {
        "description": "How to show log",
        "$ref": "#/definitions/logLevel"
      },
      "delay": {
        "description": "Delay in specific time before keep playing the next",
        "$ref": "#/definitions/time"
      },
      "if": {
        "description": "Check conditional to decide to run it or NOT",
        "$ref": "#/definitions/getVarBooleanString"
      },
      "->": {
        "description": "Expose for others extends",
        "oneOf": [
          {
            "type": "string"
          },
          {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        ]
      },
      "<-": {
        "description": "Extends others which is exposed by '->'",
        "oneOf": [
          {
            "type": "string"
          },
          {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        ]
      }
    }
  }
}