feat: with json body

Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
Kasper Juul Hermansen 2023-07-04 22:34:31 +02:00
parent c34df2ccaa
commit 20ea4b66b9
Signed by: kjuulh
GPG Key ID: 57B6E1465221F912
10 changed files with 3426 additions and 1037 deletions

20
corpus/assertions.txt Normal file
View File

@ -0,0 +1,20 @@
===
Assertion
===
GET https://somewhere.com
HTTP 200
[Asserts]
---
(source_file
(request_declaration
(request_literal)
(url))
(response
(scheme_literal)
(status_code_pattern))
(assert_declaration
(assert_literal)))

View File

@ -1,21 +1,22 @@
=== ===
Comments Comments
=== ===
GET https://somewhere.com # some comment
GET https://somewhere.com # some comment
# comment # comment
HTTP 200 # comment HTTP 200
# comment
--- ---
(source_file (source_file
(request_declaration (request_declaration
(request_literal) (request_literal)
(url)) (url))
(comment) (comment)
(comment) (comment)
(response (response
(scheme_literal) (scheme_literal)
(status_code_pattern)) (status_code_pattern))
(comment)) (comment))

View File

@ -116,3 +116,27 @@ HTTP 302
(response (response
(scheme_literal) (scheme_literal)
(status_code_pattern))) (status_code_pattern)))
===
Request body json
===
POST https://somewhere.com?query=something
{
"some-name": "some-value"
}
HTTP 302
---
(source_file
(request_declaration
(request_literal)
(url))
(body
(json_request_declaration))
(response
(scheme_literal)
(status_code_pattern)))

View File

@ -1,9 +1,21 @@
const NL = token.immediate(/[\r\n]+/);
const PREC = {
comment: 1,
request: 2,
header: 3,
param: 4,
body: 5,
var: 6,
whitespace: 7,
new_line: 8,
}
module.exports = grammar({ module.exports = grammar({
name: "hurl", name: "hurl",
extras: $ => [ extras: $ => [
$.comment, $.comment,
/\s/
], ],
rules: { rules: {
@ -12,32 +24,48 @@ module.exports = grammar({
// statements // statements
_statement: ($) => _statement: ($) =>
choice($._declaration_statement), choice($._declaration_statement, NL),
_declaration_statement: ($) => _declaration_statement: ($) => seq(
choice( choice(
$.request_declaration, $.request_declaration,
$.header_declaration, $.header_declaration,
alias($.http_response_declaration, $.response), alias($.http_response_declaration, $.response),
$.assert_declaration,
alias($.request_body_declaration, $.body),
), ),
prec.left(PREC.whitespace, optional($._whitespace)),
),
// declarations // declarations
request_declaration: ($) => request_declaration: ($) =>
seq($._literal, field("url", $.url)), prec.left(PREC.request,
seq($._literal, $._whitespace, field("url", $.url)),
),
request_body_declaration: $ => choice(
$.json_request_declaration
),
json_request_declaration: $ => prec.left(PREC.body, seq(/\{/, optional(repeat(choice(/\n/))), repeat(seq($._line, NL)), /\}\n\n/)),
header_declaration: ($) => header_declaration: ($) =>
seq( seq(
field("header_name", $.header_name), field("header_name", $.header_name),
":", ":",
optional($._whitespace),
field("header_value", $.header_value) field("header_value", $.header_value)
), ),
http_response_declaration: $ => seq($.scheme_literal, $.status_code_pattern), http_response_declaration: $ => seq($.scheme_literal, $._whitespace, $.status_code_pattern),
assert_declaration: $ => seq('[', $.assert_literal, ']'),
// literals // literals
_literal: ($) => choice($.request_literal), _literal: ($) => choice($.request_literal, $.assert_literal),
request_literal: (_$) => request_literal: (_$) =>
choice( choice(
@ -58,18 +86,31 @@ module.exports = grammar({
"VIEW" "VIEW"
), ),
assert_literal: $ => choice(
"QueryStringParams",
"FormParams",
"MultipartFormData",
"Cookies",
"Captures",
"Asserts",
"Options",
),
scheme_literal: $ => "HTTP", scheme_literal: $ => "HTTP",
// patterns // patterns
comment: $ => token(prec(-10, /#.*/)), //comment: _ => prec.left(PREC.comment, token(seq("#", /.*/, optional(NL)))),
//comment_raw: _ => token(seq("#", /.*/, optional(NL))),
comment: _ => prec.left(PREC.comment, token(seq("#", /.*/, NL))),
status_code_pattern: $ => /[\d]{3}/, status_code_pattern: $ => /[\d]{3}/,
header_name: ($) => /[a-zA-Z-_0-9]+/, header_name: ($) => /[a-zA-Z-_0-9]+/,
header_value: ($) => header_value: ($) =>
/[a-zA-Z\-_0-9\/\\]+/, /[a-zA-Z\-_0-9\/\\]+/,
url: ($) => /\S+/, url: ($) => /\S+/,
_line: _ => /[^\n]+/,
_whitespace: _ => repeat1(/[\t\v ]/),
}, },
}); });

12
package-lock.json generated
View File

@ -9,7 +9,8 @@
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"nan": "^2.17.0" "nan": "^2.17.0",
"tree-sitter-json": "^0.20.0"
}, },
"devDependencies": { "devDependencies": {
"prettier": "^2.8.8", "prettier": "^2.8.8",
@ -45,6 +46,15 @@
"bin": { "bin": {
"tree-sitter": "cli.js" "tree-sitter": "cli.js"
} }
},
"node_modules/tree-sitter-json": {
"version": "0.20.0",
"resolved": "https://registry.npmjs.org/tree-sitter-json/-/tree-sitter-json-0.20.0.tgz",
"integrity": "sha512-PteOLH+Tx6Bz4ZA/d40/DbkiSXXRM/gKahhHI8hQ1lWNfFvdknnz9k3Mz84ol5srRyLboJ8wp8GSkhZ6ht9EGQ==",
"hasInstallScript": true,
"dependencies": {
"nan": "^2.14.1"
}
} }
} }
} }

View File

@ -12,7 +12,8 @@
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"nan": "^2.17.0" "nan": "^2.17.0",
"tree-sitter-json": "^0.20.0"
}, },
"devDependencies": { "devDependencies": {
"prettier": "^2.8.8", "prettier": "^2.8.8",

1
queries/injections.scm Normal file
View File

@ -0,0 +1 @@
(json_request_declaration) @json

View File

@ -14,48 +14,162 @@
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "_declaration_statement" "name": "_declaration_statement"
},
{
"type": "IMMEDIATE_TOKEN",
"content": {
"type": "PATTERN",
"value": "[\\r\\n]+"
}
} }
] ]
}, },
"_declaration_statement": { "_declaration_statement": {
"type": "CHOICE", "type": "SEQ",
"members": [ "members": [
{ {
"type": "SYMBOL", "type": "CHOICE",
"name": "request_declaration" "members": [
{
"type": "SYMBOL",
"name": "request_declaration"
},
{
"type": "SYMBOL",
"name": "header_declaration"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "http_response_declaration"
},
"named": true,
"value": "response"
},
{
"type": "SYMBOL",
"name": "assert_declaration"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "request_body_declaration"
},
"named": true,
"value": "body"
}
]
}, },
{ {
"type": "SYMBOL", "type": "PREC_LEFT",
"name": "header_declaration" "value": 7,
},
{
"type": "ALIAS",
"content": { "content": {
"type": "SYMBOL", "type": "CHOICE",
"name": "http_response_declaration" "members": [
}, {
"named": true, "type": "SYMBOL",
"value": "response" "name": "_whitespace"
},
{
"type": "BLANK"
}
]
}
} }
] ]
}, },
"request_declaration": { "request_declaration": {
"type": "SEQ", "type": "PREC_LEFT",
"value": 2,
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_literal"
},
{
"type": "SYMBOL",
"name": "_whitespace"
},
{
"type": "FIELD",
"name": "url",
"content": {
"type": "SYMBOL",
"name": "url"
}
}
]
}
},
"request_body_declaration": {
"type": "CHOICE",
"members": [ "members": [
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "_literal" "name": "json_request_declaration"
},
{
"type": "FIELD",
"name": "url",
"content": {
"type": "SYMBOL",
"name": "url"
}
} }
] ]
}, },
"json_request_declaration": {
"type": "PREC_LEFT",
"value": 5,
"content": {
"type": "SEQ",
"members": [
{
"type": "PATTERN",
"value": "\\{"
},
{
"type": "CHOICE",
"members": [
{
"type": "REPEAT",
"content": {
"type": "CHOICE",
"members": [
{
"type": "PATTERN",
"value": "\\n"
}
]
}
},
{
"type": "BLANK"
}
]
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_line"
},
{
"type": "IMMEDIATE_TOKEN",
"content": {
"type": "PATTERN",
"value": "[\\r\\n]+"
}
}
]
}
},
{
"type": "PATTERN",
"value": "\\}\\n\\n"
}
]
}
},
"header_declaration": { "header_declaration": {
"type": "SEQ", "type": "SEQ",
"members": [ "members": [
@ -71,6 +185,18 @@
"type": "STRING", "type": "STRING",
"value": ":" "value": ":"
}, },
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_whitespace"
},
{
"type": "BLANK"
}
]
},
{ {
"type": "FIELD", "type": "FIELD",
"name": "header_value", "name": "header_value",
@ -88,18 +214,43 @@
"type": "SYMBOL", "type": "SYMBOL",
"name": "scheme_literal" "name": "scheme_literal"
}, },
{
"type": "SYMBOL",
"name": "_whitespace"
},
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "status_code_pattern" "name": "status_code_pattern"
} }
] ]
}, },
"assert_declaration": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "["
},
{
"type": "SYMBOL",
"name": "assert_literal"
},
{
"type": "STRING",
"value": "]"
}
]
},
"_literal": { "_literal": {
"type": "CHOICE", "type": "CHOICE",
"members": [ "members": [
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "request_literal" "name": "request_literal"
},
{
"type": "SYMBOL",
"name": "assert_literal"
} }
] ]
}, },
@ -168,18 +319,67 @@
} }
] ]
}, },
"assert_literal": {
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "QueryStringParams"
},
{
"type": "STRING",
"value": "FormParams"
},
{
"type": "STRING",
"value": "MultipartFormData"
},
{
"type": "STRING",
"value": "Cookies"
},
{
"type": "STRING",
"value": "Captures"
},
{
"type": "STRING",
"value": "Asserts"
},
{
"type": "STRING",
"value": "Options"
}
]
},
"scheme_literal": { "scheme_literal": {
"type": "STRING", "type": "STRING",
"value": "HTTP" "value": "HTTP"
}, },
"comment": { "comment": {
"type": "TOKEN", "type": "PREC_LEFT",
"value": 1,
"content": { "content": {
"type": "PREC", "type": "TOKEN",
"value": -10,
"content": { "content": {
"type": "PATTERN", "type": "SEQ",
"value": "#.*" "members": [
{
"type": "STRING",
"value": "#"
},
{
"type": "PATTERN",
"value": ".*"
},
{
"type": "IMMEDIATE_TOKEN",
"content": {
"type": "PATTERN",
"value": "[\\r\\n]+"
}
}
]
} }
} }
}, },
@ -198,16 +398,23 @@
"url": { "url": {
"type": "PATTERN", "type": "PATTERN",
"value": "\\S+" "value": "\\S+"
},
"_line": {
"type": "PATTERN",
"value": "[^\\n]+"
},
"_whitespace": {
"type": "REPEAT1",
"content": {
"type": "PATTERN",
"value": "[\\t\\v ]"
}
} }
}, },
"extras": [ "extras": [
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "comment" "name": "comment"
},
{
"type": "PATTERN",
"value": "\\s"
} }
], ],
"conflicts": [], "conflicts": [],

View File

@ -1,4 +1,44 @@
[ [
{
"type": "assert_declaration",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "assert_literal",
"named": true
}
]
}
},
{
"type": "assert_literal",
"named": true,
"fields": {}
},
{
"type": "body",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "json_request_declaration",
"named": true
}
]
}
},
{
"type": "comment",
"named": true,
"fields": {}
},
{ {
"type": "header_declaration", "type": "header_declaration",
"named": true, "named": true,
@ -25,6 +65,11 @@
} }
} }
}, },
{
"type": "json_request_declaration",
"named": true,
"fields": {}
},
{ {
"type": "request_declaration", "type": "request_declaration",
"named": true, "named": true,
@ -44,6 +89,10 @@
"multiple": false, "multiple": false,
"required": true, "required": true,
"types": [ "types": [
{
"type": "assert_literal",
"named": true
},
{ {
"type": "request_literal", "type": "request_literal",
"named": true "named": true
@ -83,6 +132,14 @@
"multiple": true, "multiple": true,
"required": false, "required": false,
"types": [ "types": [
{
"type": "assert_declaration",
"named": true
},
{
"type": "body",
"named": true
},
{ {
"type": "header_declaration", "type": "header_declaration",
"named": true "named": true
@ -102,14 +159,30 @@
"type": ":", "type": ":",
"named": false "named": false
}, },
{
"type": "Asserts",
"named": false
},
{ {
"type": "CONNECT", "type": "CONNECT",
"named": false "named": false
}, },
{
"type": "Captures",
"named": false
},
{
"type": "Cookies",
"named": false
},
{ {
"type": "DELETE", "type": "DELETE",
"named": false "named": false
}, },
{
"type": "FormParams",
"named": false
},
{ {
"type": "GET", "type": "GET",
"named": false "named": false
@ -122,10 +195,18 @@
"type": "LOCK", "type": "LOCK",
"named": false "named": false
}, },
{
"type": "MultipartFormData",
"named": false
},
{ {
"type": "OPTIONS", "type": "OPTIONS",
"named": false "named": false
}, },
{
"type": "Options",
"named": false
},
{ {
"type": "PATCH", "type": "PATCH",
"named": false "named": false
@ -146,6 +227,10 @@
"type": "PUT", "type": "PUT",
"named": false "named": false
}, },
{
"type": "QueryStringParams",
"named": false
},
{ {
"type": "TRACE", "type": "TRACE",
"named": false "named": false
@ -163,8 +248,12 @@
"named": false "named": false
}, },
{ {
"type": "comment", "type": "[",
"named": true "named": false
},
{
"type": "]",
"named": false
}, },
{ {
"type": "header_name", "type": "header_name",

File diff suppressed because it is too large Load Diff