hurl/docs/spec/hurl.grammar
2023-02-14 13:34:17 +01:00

493 lines
8.4 KiB
Plaintext

# General
hurl-file: entry*
lt*
entry: request
response?
request:
lt*
method sp value-string lt
header*
request-section*
body?
response:
lt*
version sp status lt
header*
response-section*
body?
method:
"GET"
| "HEAD"
| "POST"
| "PUT"
| "DELETE"
| "CONNECT"
| "OPTIONS"
| "TRACE"
| "PATCH"
| "LINK"
| "UNLINK"
| "PURGE"
| "LOCK"
| "UNLOCK"
| "PROPFIND"
| "VIEW"
version:
"HTTP/1.0"
| "HTTP/1.1"
| "HTTP/2"
| "HTTP"
status: [0-9]+
header:
lt*
key-value lt
body:
lt*
bytes lt
# Sections
request-section:
query-string-params-section
| form-params-section
| multipart-form-data-section
| cookies-section
| options-section
response-section:
captures-section
| asserts-section
query-string-params-section:
lt*
"[QueryStringParams]" lt
key-value*
form-params-section:
lt*
"[FormParams]" lt
key-value*
multipart-form-data-section:
lt*
"[MultipartFormData]" lt
multipart-form-data-param*
cookies-section:
lt*
"[Cookies]" lt
key-value*
captures-section:
lt*
"[Captures]" lt
capture*
asserts-section:
lt*
"[Asserts]" lt
assert*
options-section:
lt*
"[Options]" lt
option*
key-value: key-string ":" value-string
multipart-form-data-param: file-param | key-value
file-param :
lt*
key-string ":" file-value lt
file-value: "file," filename ";" (file-contenttype)?
file-contenttype: [a-zA-Z0-9/+-]+
capture:
lt*
key-string ":" query (sp filter)* lt
assert:
lt*
query (sp filter)* sp predicate lt
option:
lt*
( ca-certificate-option
| follow-redirect-option
| insecure-option
| max-redirs-option
| retry-option
| retry-interval-option
| retry-max-count-option
| variable-option
| verbose-option
| very-verbose-option
)
ca-certificate-option: "cacert" ":" filename lt
follow-redirect-option: "location" ":" boolean lt
insecure-option: "insecure" ":" boolean lt
max-redirs-option: "max-redirs" ":" integer lt
retry-option: "retry" ":" boolean lt
retry-interval-option: "retry-interval" ":" integer lt
retry-max-count-option: "retry-max-count" ":" integer lt
variable-option: "variable" ":" variable-definition lt
verbose-option: "verbose" ":" boolean lt
very-verbose-option: "very-verbose" ":" boolean lt
variable-definition: variable-name "=" variable-value
variable-value:
null
| boolean
| integer
| float
| key-string
| quoted-string
# Query
query:
status-query
| url-query
| header-query
| certificate-query
| cookie-query
| body-query
| xpath-query
| jsonpath-query
| regex-query
| variable-query
| duration-query
| bytes-query
| sha256-query
| md5-query
status-query: "status"
url-query: "url"
header-query: "header" sp quoted-string
certificate-query: "certificate" sp ("Subject" | "Issuer" | "Start date" | "Expire date" | "Serial Number")
cookie-query: "cookie" sp quoted-string
body-query: "body"
xpath-query: "xpath" sp quoted-string
jsonpath-query: "jsonpath" sp quoted-string
regex-query: "regex" sp (quoted-string | regex)
variable-query: "variable" sp quoted-string
duration-query: "duration"
sha256-query: "sha256"
md5-query: "md5"
bytes-query: "bytes"
# Predicates
predicate: ("not" sp )? predicate-func
predicate-func:
equal-predicate
| not-equal-predicate
| greater-predicate
| greater-or-equal-predicate
| less-predicate
| less-or-equal-predicate
| start-with-predicate
| end-with-predicate
| contain-predicate
| match-predicate
| exist-predicate
| include-predicate
| integer-predicate
| float-predicate
| boolean-predicate
| string-predicate
| collection-predicate
equal-predicate: ("equals" | "==") sp predicate-value
not-equal-predicate: ("notEquals" | "!=") sp predicate-value
greater-predicate: ("greaterThan" | ">") sp (integer | float | quoted-string)
greater-or-equal-predicate: ("greaterThanOrEquals" | ">=") sp sp* (integer | float | quoted-string)
less-predicate: ("lessThan" | "<") sp (integer | float | quoted-string)
less-or-equal-predicate: ("lessThanOrEquals" | "<=") sp (integer | float | quoted-string)
start-with-predicate: "startsWith" sp (quoted-string | oneline-hex | oneline-base64)
end-with-predicate: "endsWith" sp (quoted-string | oneline-hex | oneline-base64)
contain-predicate: "contains" sp quoted-string
match-predicate: "matches" sp (quoted-string | regex)
exist-predicate: "exists"
include-predicate: "includes" sp predicate-value
integer-predicate: "isInteger"
float-predicate: "isFloat"
boolean-predicate: "isBoolean"
string-predicate: "isString"
collection-predicate: "isCollection"
predicate-value:
null
| boolean
| integer
| float
| quoted-string
| oneline-hex
| oneline-base64
| oneline-file
| multiline-string
| template
# Bytes
bytes:
json-value
| xml
| multiline-string
| oneline-string
| oneline-base64
| oneline-file
| oneline-hex
xml: "<" "To Be Defined" ">"
oneline-base64: "base64," [A-Z0-9+-= \n]+ ";"
oneline-file: "file," filename ";"
oneline-hex: "hex," hexdigit* ";"
# Strings
quoted-string: "\"" (quoted-string-content | template)* "\""
quoted-string-content: (quoted-string-text | quoted-string-escaped-char)*
quoted-string-text: ~["\\]+
quoted-string-escaped-char: "\\" ("\"" | "\\" | "\b" | "\f" | "\n" | "\r" | "\t" | "\u" unicode-char)
key-string: (key-string-content | template)+
key-string-content: (key-string-text | key-string-escaped-char)*
key-string-text: (alphanum | "_" | "-" | "." | "[" | "]" | "@" | "$") +
key-string-escaped-char: "\\" ("#" | ":" | "\\" | "\b" | "\f" | "\n" | "\r" | "\t" | "\u" unicode-char )
value-string: (value-string-content | template)*
value-string-content: (value-string-text | value-string-escaped-char)*
value-string-text: ~[#\n\\]+
value-string-escaped-char: "\\" ("#" | "\\" | "\b" | "\f" | "\n" | "\r" | "\t" | "\u" unicode-char )
oneline-string: "`" (oneline-string-content | template)* "`"
oneline-string-content: (oneline-string-text | oneline-string-escaped-char)*
oneline-string-text: ~[#\n\\] ~"`"
oneline-string-escaped-char: "\\" ("`" | "#" | "\\" | "b" | "f" | "u" unicode-char )
multiline-string:
"```" multiline-string-type? lt
(multiline-string-content | template)* lt
"```"
multiline-string-type:
"base64"
| "hex"
| "json"
| "xml"
| "graphql"
multiline-string-content: (multiline-string-text | multiline-string-escaped-char)*
multiline-string-text: ~[\\]+ ~"```"
multiline-string-escaped-char: "\\" ( "\\" | "b" | "f" | "n" | "r" | "t" | "`" | "u" unicode-char)
filename: (filename-content | template)*
filename-content: (filename-text | filename-escaped-char)*
filename-text: ~[#; \n\\]+
filename-escaped-char: "\\" (";" | "#" | [ ])
unicode-char: "{" hexdigit+ "}"
# JSON
json-value:
template
| json-object
| json-array
| json-string
| json-number
| boolean
| null
json-object: "{" json-key-value ("," json-key-value)* "}"
json-key-value: json-string ":" json-value
json-array: "[" json-value ("," json-value)* "]"
json-string: "\"" (json-string-content | template)* "\""
json-string-content: json-string-text | json-string-escaped-char
json-string-text: ~["\\]
json-string-escaped-char:
"\\" ("\"" | "\\" | "b" | "f" | "n" | "r" | "t" | "u" hexdigit hexdigit hexdigit hexdigit)
json-number: integer fraction? exponent?
# Template / Expression
template: "{{" expr "}}"
expr: variable-name (sp filter)*
variable-name: [A-Za-z] [A-Za-z_-0-9]*
# Filter
filter:
count-filter
| format-filter
| html-escape-filter
| html-unescape-filter
| nth-filter
| regex-filter
| replace-filter
| split-filter
| to-date-filter
| to-int-filter
| url-decode-filter
| url-encode-filter
count-filter: "count"
format-filter: "format"
html-escape-filter: "htmlEscape"
html-unescape-filter: "htmlUnescape"
nth-filter: "nth" sp integer
regex-filter: "regex" sp (quoted-string | regex)
replace-filter: "replace" sp (quoted-string | regex) sp quoted-string
split-filter: "split" sp quoted-string
to-date-filter: "toDate"
to-int-filter: "toInt"
url-decode-filter: "urlDecode"
url-encode-filter: "urlEncode"
# Lexical Grammar
boolean: "true" | "false"
null: "null"
alphanum: [A-Za-z0-9]
integer: digit+
float: integer fraction
digit: [0-9]
hexdigit: [0-9A-Fa-f]
fraction: "." digit+
exponent: ("e" | "E") ("+"|"-")? digit+
sp: [ \t]
lt: sp* comment? [\n]?
comment: "#" ~[\n]*
regex: "/" regex-content "/"
regex-content: (regex-text|regex-escaped-char)*
regex-text: ~[\n\/]+
regex-escaped-char: "\\" ~[\n]