mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-11-22 15:42:20 +03:00
Add lang identifier to multiline.
This commit is contained in:
parent
f3bf0b7618
commit
3b3483a997
7
integration/tests_error_parser/multiline.err
Normal file
7
integration/tests_error_parser/multiline.err
Normal file
@ -0,0 +1,7 @@
|
||||
error: Parsing multine
|
||||
--> tests_error_parser/multiline.hurl:2:4
|
||||
|
|
||||
2 | ```foo
|
||||
| ^ the multiline is not valid
|
||||
|
|
||||
|
2
integration/tests_error_parser/multiline.exit
Normal file
2
integration/tests_error_parser/multiline.exit
Normal file
@ -0,0 +1,2 @@
|
||||
2
|
||||
|
6
integration/tests_error_parser/multiline.hurl
Normal file
6
integration/tests_error_parser/multiline.hurl
Normal file
@ -0,0 +1,6 @@
|
||||
GET http://localhost:8000/invalid-multiline
|
||||
```foo
|
||||
bar
|
||||
baz
|
||||
```
|
||||
HTTP 200
|
@ -1,8 +1,8 @@
|
||||
error: Assert body value
|
||||
--> tests_failed/assert_newline.hurl:9:4
|
||||
--> tests_failed/assert_newline.hurl:10:1
|
||||
|
|
||||
9 | ```<p>Hello</p>
|
||||
| ^ actual value is <<p>Hello</p>
|
||||
10 | <p>Hello</p>
|
||||
| ^ actual value is <<p>Hello</p>
|
||||
|
||||
>
|
||||
|
|
||||
|
@ -6,7 +6,8 @@
|
||||
<span class="line"></span><span class="comment"># It should produce an assert error</span>
|
||||
<span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/error-assert-newline</span></span>
|
||||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||||
<span class="raw"><span class="line">```<p>Hello</p></span>
|
||||
<span class="raw"><span class="line">```</span>
|
||||
<span class="line"><p>Hello</p></span>
|
||||
<span class="line">```</span></span>
|
||||
</span></span><span class="line"></span>
|
||||
<span class="line"></span><span class="comment"># TODO</span>
|
||||
|
@ -6,7 +6,8 @@
|
||||
# It should produce an assert error
|
||||
GET http://localhost:8000/error-assert-newline
|
||||
HTTP 200
|
||||
```<p>Hello</p>
|
||||
```
|
||||
<p>Hello</p>
|
||||
```
|
||||
|
||||
# TODO
|
||||
|
@ -1,15 +1,80 @@
|
||||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/multilines</span></span>
|
||||
</span><span class="response"><span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||||
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/multilines/plain-text</span></span>
|
||||
</span><span class="response"><span class="line"></span>
|
||||
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||||
<span class="line section-header">[Asserts]</span>
|
||||
<span class="line"><span class="query-type">body</span> <span class="predicate-type">==</span> <span class="string">"line1\nline2\nline3\n"</span></span>
|
||||
<span class="line"><span class="query-type">body</span> <span class="predicate-type">==</span> <span class="raw"><span class="line">```line1</span>
|
||||
<span class="line">line2</span>
|
||||
<span class="line">line3</span>
|
||||
<span class="line">```</span></span></span>
|
||||
<span class="line"><span class="query-type">body</span> <span class="predicate-type">==</span> <span class="raw"><span class="line">```</span>
|
||||
<span class="line">line1</span>
|
||||
<span class="line">line2</span>
|
||||
<span class="line">line3</span>
|
||||
<span class="line">```</span></span></span>
|
||||
</span></span><span class="line"></span>
|
||||
</code></pre>
|
||||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/multilines/base64</span></span>
|
||||
</span><span class="response"><span class="line"></span>
|
||||
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||||
<span class="raw"><span class="line">```base64</span>
|
||||
<span class="line">TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwg</span>
|
||||
<span class="line">c2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu</span>
|
||||
<span class="line">YSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlzIG5vc3RydWQgZXhlcmNpdGF0</span>
|
||||
<span class="line">aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1aXAgZXggZWEgY29tbW9kbyBjb25zZXF1</span>
|
||||
<span class="line">YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBpbiByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2</span>
|
||||
<span class="line">ZWxpdCBlc3NlIGNpbGx1bSBkb2xvcmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRl</span>
|
||||
<span class="line">dXIgc2ludCBvY2NhZWNhdCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1</span>
|
||||
<span class="line">aSBvZmZpY2lhIGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg==</span>
|
||||
<span class="line">```</span></span>
|
||||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/multilines/hex</span></span>
|
||||
</span><span class="response"><span class="line"></span>
|
||||
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||||
<span class="raw"><span class="line">```hex</span>
|
||||
<span class="line">039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81</span>
|
||||
<span class="line">```</span></span>
|
||||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/multilines/json</span></span>
|
||||
</span><span class="response"><span class="line"></span>
|
||||
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||||
<span class="raw"><span class="line">```json</span>
|
||||
<span class="line">{</span>
|
||||
<span class="line"> "foo": "bar"</span>
|
||||
<span class="line"> "baz": 123456</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line">```</span></span>
|
||||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/multilines/xml</span></span>
|
||||
</span><span class="response"><span class="line"></span>
|
||||
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||||
<span class="raw"><span class="line">```xml</span>
|
||||
<span class="line"><?xml version="1.0"?></span>
|
||||
<span class="line"><catalog></span>
|
||||
<span class="line"> <book id="bk101"></span>
|
||||
<span class="line"> <author>Gambardella, Matthew</author></span>
|
||||
<span class="line"> <title>XML Developer's Guide</title></span>
|
||||
<span class="line"> <genre>Computer</genre></span>
|
||||
<span class="line"> <price>44.95</price></span>
|
||||
<span class="line"> <publish_date>2000-10-01</publish_date></span>
|
||||
<span class="line"> <description>An in-depth look at creating applications</span>
|
||||
<span class="line"> with XML.</description></span>
|
||||
<span class="line"> </book></span>
|
||||
<span class="line"></catalog></span>
|
||||
<span class="line">```</span></span>
|
||||
</span></span><span class="hurl-entry"><span class="request"><span class="line"></span>
|
||||
<span class="line"></span>
|
||||
<span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/multilines/graphql</span></span>
|
||||
</span><span class="response"><span class="line"></span>
|
||||
<span class="line"><span class="version">HTTP</span> <span class="number">200</span></span>
|
||||
<span class="raw"><span class="line">```graphql</span>
|
||||
<span class="line">{</span>
|
||||
<span class="line"> hero {</span>
|
||||
<span class="line"> name</span>
|
||||
<span class="line"> # Queries can have comments!</span>
|
||||
<span class="line"> friends {</span>
|
||||
<span class="line"> name</span>
|
||||
<span class="line"> }</span>
|
||||
<span class="line"> }</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line">```</span></span>
|
||||
</span></span></code></pre>
|
||||
|
@ -1,14 +1,79 @@
|
||||
GET http://localhost:8000/multilines
|
||||
GET http://localhost:8000/multilines/plain-text
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
body == "line1\nline2\nline3\n"
|
||||
body == ```line1
|
||||
line2
|
||||
line3
|
||||
```
|
||||
body == ```
|
||||
line1
|
||||
line2
|
||||
line3
|
||||
```
|
||||
|
||||
|
||||
GET http://localhost:8000/multilines/base64
|
||||
|
||||
HTTP 200
|
||||
```base64
|
||||
TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwg
|
||||
c2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu
|
||||
YSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlzIG5vc3RydWQgZXhlcmNpdGF0
|
||||
aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1aXAgZXggZWEgY29tbW9kbyBjb25zZXF1
|
||||
YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBpbiByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2
|
||||
ZWxpdCBlc3NlIGNpbGx1bSBkb2xvcmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRl
|
||||
dXIgc2ludCBvY2NhZWNhdCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1
|
||||
aSBvZmZpY2lhIGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg==
|
||||
```
|
||||
|
||||
|
||||
GET http://localhost:8000/multilines/hex
|
||||
|
||||
HTTP 200
|
||||
```hex
|
||||
039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81
|
||||
```
|
||||
|
||||
|
||||
GET http://localhost:8000/multilines/json
|
||||
|
||||
HTTP 200
|
||||
```json
|
||||
{
|
||||
"foo": "bar"
|
||||
"baz": 123456
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
GET http://localhost:8000/multilines/xml
|
||||
|
||||
HTTP 200
|
||||
```xml
|
||||
<?xml version="1.0"?>
|
||||
<catalog>
|
||||
<book id="bk101">
|
||||
<author>Gambardella, Matthew</author>
|
||||
<title>XML Developer's Guide</title>
|
||||
<genre>Computer</genre>
|
||||
<price>44.95</price>
|
||||
<publish_date>2000-10-01</publish_date>
|
||||
<description>An in-depth look at creating applications
|
||||
with XML.</description>
|
||||
</book>
|
||||
</catalog>
|
||||
```
|
||||
|
||||
|
||||
GET http://localhost:8000/multilines/graphql
|
||||
|
||||
HTTP 200
|
||||
```graphql
|
||||
{
|
||||
hero {
|
||||
name
|
||||
# Queries can have comments!
|
||||
friends {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -1 +1 @@
|
||||
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/multilines"},"response":{"status":200,"asserts":[{"query":{"type":"body"},"predicate":{"type":"equal","value":"line1\nline2\nline3\n"}},{"query":{"type":"body"},"predicate":{"type":"equal","value":"line1\nline2\nline3\n"}},{"query":{"type":"body"},"predicate":{"type":"equal","value":"line1\nline2\nline3\n"}}]}}]}
|
||||
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/multilines/plain-text"},"response":{"status":200,"asserts":[{"query":{"type":"body"},"predicate":{"type":"equal","value":"line1\nline2\nline3\n"}},{"query":{"type":"body"},"predicate":{"type":"equal","value":"line1\nline2\nline3\n"}}]}},{"request":{"method":"GET","url":"http://localhost:8000/multilines/base64"},"response":{"status":200,"body":{"type":"base64","value":"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwg\nc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu\nYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlzIG5vc3RydWQgZXhlcmNpdGF0\naW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1aXAgZXggZWEgY29tbW9kbyBjb25zZXF1\nYXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBpbiByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2\nZWxpdCBlc3NlIGNpbGx1bSBkb2xvcmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRl\ndXIgc2ludCBvY2NhZWNhdCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1\naSBvZmZpY2lhIGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg==\n"}}},{"request":{"method":"GET","url":"http://localhost:8000/multilines/hex"},"response":{"status":200,"body":{"type":"hex","value":"039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81\n"}}},{"request":{"method":"GET","url":"http://localhost:8000/multilines/json"},"response":{"status":200,"body":{"type":"json","value":"{\n \"foo\": \"bar\"\n \"baz\": 123456\n}\n"}}},{"request":{"method":"GET","url":"http://localhost:8000/multilines/xml"},"response":{"status":200,"body":{"type":"xml","value":"<?xml version=\"1.0\"?>\n<catalog>\n <book id=\"bk101\">\n <author>Gambardella, Matthew</author>\n <title>XML Developer's Guide</title>\n <genre>Computer</genre>\n <price>44.95</price>\n <publish_date>2000-10-01</publish_date>\n <description>An in-depth look at creating applications\n with XML.</description>\n </book>\n</catalog>\n"}}},{"request":{"method":"GET","url":"http://localhost:8000/multilines/graphql"},"response":{"status":200,"body":{"type":"graphql","value":"{\n hero {\n name\n # Queries can have comments!\n friends {\n name\n }\n }\n}\n"}}}]}
|
||||
|
@ -1,6 +1,68 @@
|
||||
from app import app
|
||||
|
||||
|
||||
@app.route("/multilines")
|
||||
def multilines():
|
||||
@app.route("/multilines/plain-text")
|
||||
def multilines_plain_text():
|
||||
return "line1\nline2\nline3\n"
|
||||
|
||||
|
||||
@app.route("/multilines/base64")
|
||||
def multilines_base64():
|
||||
return """\
|
||||
TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwg
|
||||
c2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu
|
||||
YSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlzIG5vc3RydWQgZXhlcmNpdGF0
|
||||
aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1aXAgZXggZWEgY29tbW9kbyBjb25zZXF1
|
||||
YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBpbiByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2
|
||||
ZWxpdCBlc3NlIGNpbGx1bSBkb2xvcmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRl
|
||||
dXIgc2ludCBvY2NhZWNhdCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1
|
||||
aSBvZmZpY2lhIGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg==
|
||||
"""
|
||||
|
||||
|
||||
@app.route("/multilines/json")
|
||||
def multilines_json():
|
||||
return """\
|
||||
{
|
||||
"foo": "bar"
|
||||
"baz": 123456
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
@app.route("/multilines/hex")
|
||||
def multilines_hex():
|
||||
return "039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81\n"
|
||||
|
||||
|
||||
@app.route("/multilines/xml")
|
||||
def multilines_xml():
|
||||
return """\
|
||||
<?xml version="1.0"?>
|
||||
<catalog>
|
||||
<book id="bk101">
|
||||
<author>Gambardella, Matthew</author>
|
||||
<title>XML Developer's Guide</title>
|
||||
<genre>Computer</genre>
|
||||
<price>44.95</price>
|
||||
<publish_date>2000-10-01</publish_date>
|
||||
<description>An in-depth look at creating applications
|
||||
with XML.</description>
|
||||
</book>
|
||||
</catalog>
|
||||
"""
|
||||
|
||||
|
||||
@app.route("/multilines/graphql")
|
||||
def multilines_graphql():
|
||||
return """\
|
||||
{
|
||||
hero {
|
||||
name
|
||||
# Queries can have comments!
|
||||
friends {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
@ -482,10 +482,26 @@ pub enum PredicateFuncValue {
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct RawString {
|
||||
pub newline: Whitespace,
|
||||
pub lang: Option<Lang>,
|
||||
pub value: Template,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Lang {
|
||||
pub value: Option<LangValue>,
|
||||
pub space: Whitespace,
|
||||
pub newline: Whitespace,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum LangValue {
|
||||
Base64,
|
||||
Hex,
|
||||
Json,
|
||||
Xml,
|
||||
GraphQl,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Base64 {
|
||||
pub space0: Whitespace,
|
||||
|
@ -128,6 +128,19 @@ impl fmt::Display for CookieAttribute {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for LangValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let s = match self {
|
||||
LangValue::Base64 => "base64",
|
||||
LangValue::Hex => "hex",
|
||||
LangValue::Json => "json",
|
||||
LangValue::Xml => "xml",
|
||||
LangValue::GraphQl => "graphql",
|
||||
};
|
||||
write!(f, "{}", s)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Hex {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
|
@ -58,6 +58,7 @@ impl Error for parser::Error {
|
||||
ParseError::InvalidCookieAttribute { .. } => "Parsing cookie attribute".to_string(),
|
||||
ParseError::OddNumberOfHexDigits { .. } => "Parsing hex bytearray".to_string(),
|
||||
ParseError::UrlIllegalCharacter(_) => "Parsing URL".to_string(),
|
||||
ParseError::Multiline => "Parsing multine".to_string(),
|
||||
_ => format!("{:?}", self),
|
||||
}
|
||||
}
|
||||
@ -109,7 +110,9 @@ impl Error for parser::Error {
|
||||
"expecting an even number of hex digits".to_string()
|
||||
}
|
||||
ParseError::UrlIllegalCharacter(c) => format!("illegal character <{}>", c),
|
||||
ParseError::Multiline => "the multiline is not valid".to_string(),
|
||||
_ => format!("{:?}", self),
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -859,7 +859,12 @@ impl Htmlable for RawString {
|
||||
let mut buffer = "".to_string();
|
||||
buffer.push_str("<span class=\"raw\">");
|
||||
let mut s = "```".to_string();
|
||||
s.push_str(self.newline.value.as_str());
|
||||
if let Some(lang) = &self.lang {
|
||||
if let Some(lang_value) = &lang.value {
|
||||
s.push_str(format!("{}", lang_value).as_str());
|
||||
}
|
||||
s.push('\n');
|
||||
}
|
||||
s.push_str(self.value.to_string().as_str());
|
||||
s.push_str("```");
|
||||
buffer.push_str(multilines(s).as_str());
|
||||
@ -1073,10 +1078,7 @@ mod tests {
|
||||
fn test_raw_string() {
|
||||
// ``````
|
||||
let raw_string = RawString {
|
||||
newline: Whitespace {
|
||||
value: "".to_string(),
|
||||
source_info: SourceInfo::new(0, 0, 0, 0),
|
||||
},
|
||||
lang: None,
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![TemplateElement::String {
|
||||
@ -1093,10 +1095,7 @@ mod tests {
|
||||
|
||||
// ```hello```
|
||||
let raw_string = RawString {
|
||||
newline: Whitespace {
|
||||
value: "".to_string(),
|
||||
source_info: SourceInfo::new(0, 0, 0, 0),
|
||||
},
|
||||
lang: None,
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![TemplateElement::String {
|
||||
@ -1116,10 +1115,23 @@ mod tests {
|
||||
// line2
|
||||
// ```
|
||||
let raw_string = RawString {
|
||||
newline: Whitespace {
|
||||
value: "\n".to_string(),
|
||||
source_info: SourceInfo::new(0, 0, 0, 0),
|
||||
},
|
||||
lang: Some(Lang {
|
||||
value: None,
|
||||
space: Whitespace {
|
||||
value: "".to_string(),
|
||||
source_info: SourceInfo {
|
||||
start: Pos { line: 1, column: 4 },
|
||||
end: Pos { line: 1, column: 4 },
|
||||
},
|
||||
},
|
||||
newline: Whitespace {
|
||||
value: "\n".to_string(),
|
||||
source_info: SourceInfo {
|
||||
start: Pos { line: 1, column: 4 },
|
||||
end: Pos { line: 2, column: 1 },
|
||||
},
|
||||
},
|
||||
}),
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![TemplateElement::String {
|
||||
@ -1133,27 +1145,6 @@ mod tests {
|
||||
raw_string.to_html(),
|
||||
"<span class=\"raw\"><span class=\"line\">```</span>\n<span class=\"line\">line1</span>\n<span class=\"line\">line2</span>\n<span class=\"line\">```</span></span>".to_string()
|
||||
);
|
||||
|
||||
// ```Hello
|
||||
// ```
|
||||
let raw_string = RawString {
|
||||
newline: Whitespace {
|
||||
value: "".to_string(),
|
||||
source_info: SourceInfo::new(0, 0, 0, 0),
|
||||
},
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "Hello\n".to_string(),
|
||||
encoded: "unused".to_string(),
|
||||
}],
|
||||
source_info: SourceInfo::new(0, 0, 0, 0),
|
||||
},
|
||||
};
|
||||
assert_eq!(
|
||||
raw_string.to_html(),
|
||||
"<span class=\"raw\"><span class=\"line\">```Hello</span>\n<span class=\"line\">```</span></span>".to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -16,6 +16,7 @@
|
||||
*
|
||||
*/
|
||||
use crate::ast::*;
|
||||
use crate::parser::multiline::multiline_string;
|
||||
|
||||
use super::combinators::*;
|
||||
use super::json::parse as parse_json;
|
||||
@ -25,10 +26,9 @@ use super::xml;
|
||||
use super::ParseResult;
|
||||
|
||||
pub fn bytes(reader: &mut Reader) -> ParseResult<'static, Bytes> {
|
||||
//let start = p.state.clone();
|
||||
choice(
|
||||
&[
|
||||
raw_string_bytes,
|
||||
multiline_string_bytes,
|
||||
json_bytes,
|
||||
xml_bytes,
|
||||
base64_bytes,
|
||||
@ -38,9 +38,6 @@ pub fn bytes(reader: &mut Reader) -> ParseResult<'static, Bytes> {
|
||||
reader,
|
||||
)
|
||||
}
|
||||
fn raw_string_bytes(reader: &mut Reader) -> ParseResult<'static, Bytes> {
|
||||
raw_string(reader).map(Bytes::RawString)
|
||||
}
|
||||
|
||||
fn xml_bytes(reader: &mut Reader) -> ParseResult<'static, Bytes> {
|
||||
match xml::parse(reader) {
|
||||
@ -68,9 +65,12 @@ fn hex_bytes(reader: &mut Reader) -> ParseResult<'static, Bytes> {
|
||||
hex(reader).map(Bytes::Hex)
|
||||
}
|
||||
|
||||
pub fn multiline_string_bytes(reader: &mut Reader) -> ParseResult<'static, Bytes> {
|
||||
multiline_string(reader).map(Bytes::RawString)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::super::error::*;
|
||||
use super::*;
|
||||
|
||||
|
@ -61,6 +61,7 @@ pub enum ParseError {
|
||||
OddNumberOfHexDigits,
|
||||
UrlIllegalCharacter(char),
|
||||
InvalidOption,
|
||||
Multiline,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
|
@ -42,6 +42,7 @@ mod expr;
|
||||
mod filename;
|
||||
mod filter;
|
||||
mod json;
|
||||
mod multiline;
|
||||
mod parsers;
|
||||
mod predicate;
|
||||
mod predicate_value;
|
||||
|
537
packages/hurl_core/src/parser/multiline.rs
Normal file
537
packages/hurl_core/src/parser/multiline.rs
Normal file
@ -0,0 +1,537 @@
|
||||
/*
|
||||
* Hurl (https://hurl.dev)
|
||||
* Copyright (C) 2022 Orange
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
use super::combinators::*;
|
||||
use super::reader::Reader;
|
||||
use super::ParseResult;
|
||||
use crate::ast::*;
|
||||
use crate::parser::primitives::*;
|
||||
use crate::parser::{template, Error, ParseError};
|
||||
|
||||
pub fn multiline_string(reader: &mut Reader) -> ParseResult<'static, RawString> {
|
||||
try_literal("```", reader)?;
|
||||
let save = reader.state.clone();
|
||||
|
||||
match choice(
|
||||
&[
|
||||
base64_lang,
|
||||
hex_lang,
|
||||
json_lang,
|
||||
xml_lang,
|
||||
graphql_lang,
|
||||
undefined_lang,
|
||||
],
|
||||
reader,
|
||||
) {
|
||||
Ok(lang) => {
|
||||
let value = multiline_string_value(reader)?;
|
||||
Ok(RawString {
|
||||
value,
|
||||
lang: Some(lang),
|
||||
})
|
||||
}
|
||||
Err(_) => {
|
||||
reader.state = save;
|
||||
let value = oneline_string_value(reader)?;
|
||||
Ok(RawString { value, lang: None })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn multiline_string_value(reader: &mut Reader) -> ParseResult<'static, Template> {
|
||||
let mut chars = vec![];
|
||||
|
||||
let start = reader.state.pos.clone();
|
||||
while !reader.remaining().starts_with("```") && !reader.is_eof() {
|
||||
let pos = reader.state.pos.clone();
|
||||
let c = reader.read().unwrap();
|
||||
chars.push((c, c.to_string(), pos));
|
||||
}
|
||||
let end = reader.state.pos.clone();
|
||||
literal("```", reader)?;
|
||||
|
||||
let encoded_string = template::EncodedString {
|
||||
source_info: SourceInfo {
|
||||
start: start.clone(),
|
||||
end: end.clone(),
|
||||
},
|
||||
chars,
|
||||
};
|
||||
|
||||
let elements = template::templatize(encoded_string)?;
|
||||
|
||||
Ok(Template {
|
||||
quotes: false,
|
||||
elements,
|
||||
source_info: SourceInfo { start, end },
|
||||
})
|
||||
}
|
||||
|
||||
fn oneline_string_value(reader: &mut Reader) -> ParseResult<'static, Template> {
|
||||
let mut chars = vec![];
|
||||
|
||||
let start = reader.state.pos.clone();
|
||||
while !reader.remaining().starts_with("```") && !reader.is_eof() {
|
||||
let pos = reader.state.pos.clone();
|
||||
let c = reader.read().unwrap();
|
||||
if c == '\n' {
|
||||
return Err(Error {
|
||||
pos: start,
|
||||
recoverable: false,
|
||||
inner: ParseError::Multiline,
|
||||
});
|
||||
}
|
||||
chars.push((c, c.to_string(), pos));
|
||||
}
|
||||
let end = reader.state.pos.clone();
|
||||
literal("```", reader)?;
|
||||
|
||||
let encoded_string = template::EncodedString {
|
||||
source_info: SourceInfo {
|
||||
start: start.clone(),
|
||||
end: end.clone(),
|
||||
},
|
||||
chars,
|
||||
};
|
||||
|
||||
let elements = template::templatize(encoded_string)?;
|
||||
|
||||
Ok(Template {
|
||||
quotes: false,
|
||||
elements,
|
||||
source_info: SourceInfo { start, end },
|
||||
})
|
||||
}
|
||||
|
||||
fn undefined_lang(reader: &mut Reader) -> ParseResult<'static, Lang> {
|
||||
let space = zero_or_more_spaces(reader)?;
|
||||
let newline = newline(reader)?;
|
||||
Ok(Lang {
|
||||
value: None,
|
||||
space,
|
||||
newline,
|
||||
})
|
||||
}
|
||||
|
||||
fn base64_lang(reader: &mut Reader) -> ParseResult<'static, Lang> {
|
||||
try_literal("base64", reader)?;
|
||||
let space = zero_or_more_spaces(reader)?;
|
||||
let newline = newline(reader)?;
|
||||
Ok(Lang {
|
||||
value: Some(LangValue::Base64),
|
||||
space,
|
||||
newline,
|
||||
})
|
||||
}
|
||||
|
||||
fn hex_lang(reader: &mut Reader) -> ParseResult<'static, Lang> {
|
||||
try_literal("hex", reader)?;
|
||||
let space = zero_or_more_spaces(reader)?;
|
||||
let newline = newline(reader)?;
|
||||
Ok(Lang {
|
||||
value: Some(LangValue::Hex),
|
||||
space,
|
||||
newline,
|
||||
})
|
||||
}
|
||||
|
||||
fn json_lang(reader: &mut Reader) -> ParseResult<'static, Lang> {
|
||||
try_literal("json", reader)?;
|
||||
let space = zero_or_more_spaces(reader)?;
|
||||
let newline = newline(reader)?;
|
||||
Ok(Lang {
|
||||
value: Some(LangValue::Json),
|
||||
space,
|
||||
newline,
|
||||
})
|
||||
}
|
||||
|
||||
fn xml_lang(reader: &mut Reader) -> ParseResult<'static, Lang> {
|
||||
try_literal("xml", reader)?;
|
||||
let space = zero_or_more_spaces(reader)?;
|
||||
let newline = newline(reader)?;
|
||||
Ok(Lang {
|
||||
value: Some(LangValue::Xml),
|
||||
space,
|
||||
newline,
|
||||
})
|
||||
}
|
||||
|
||||
fn graphql_lang(reader: &mut Reader) -> ParseResult<'static, Lang> {
|
||||
try_literal("graphql", reader)?;
|
||||
let space = zero_or_more_spaces(reader)?;
|
||||
let newline = newline(reader)?;
|
||||
Ok(Lang {
|
||||
value: Some(LangValue::GraphQl),
|
||||
space,
|
||||
newline,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_base64_multiline_string_type() {
|
||||
let mut reader = Reader::init("base64\nxxxx");
|
||||
assert_eq!(
|
||||
base64_lang(&mut reader).unwrap(),
|
||||
Lang {
|
||||
value: Some(LangValue::Base64),
|
||||
space: Whitespace {
|
||||
value: String::from(""),
|
||||
source_info: SourceInfo::new(1, 7, 1, 7),
|
||||
},
|
||||
newline: Whitespace {
|
||||
value: "\n".to_string(),
|
||||
source_info: SourceInfo::new(1, 7, 2, 1)
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_base64_multiline_string_type_with_padding() {
|
||||
let mut reader = Reader::init("base64 \nxxxx");
|
||||
assert_eq!(
|
||||
base64_lang(&mut reader).unwrap(),
|
||||
Lang {
|
||||
value: Some(LangValue::Base64),
|
||||
space: Whitespace {
|
||||
value: String::from(" "),
|
||||
source_info: SourceInfo::new(1, 7, 1, 13),
|
||||
},
|
||||
newline: Whitespace {
|
||||
value: "\n".to_string(),
|
||||
source_info: SourceInfo::new(1, 13, 2, 1)
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiline_string_ok() {
|
||||
let datas = [
|
||||
(
|
||||
"```\nline1\nline2\nline3\n```",
|
||||
None,
|
||||
"line1\nline2\nline3\n",
|
||||
),
|
||||
(
|
||||
"``` \nline1\nline2\nline3\n```",
|
||||
None,
|
||||
"line1\nline2\nline3\n",
|
||||
),
|
||||
(
|
||||
"```base64\nline1\nline2\nline3\n```",
|
||||
Some(LangValue::Base64),
|
||||
"line1\nline2\nline3\n",
|
||||
),
|
||||
(
|
||||
"```hex\nline1\nline2\nline3\n```",
|
||||
Some(LangValue::Hex),
|
||||
"line1\nline2\nline3\n",
|
||||
),
|
||||
(
|
||||
"```json\nline1\nline2\nline3\n```",
|
||||
Some(LangValue::Json),
|
||||
"line1\nline2\nline3\n",
|
||||
),
|
||||
(
|
||||
"```graphql\nline1\nline2\nline3\n```",
|
||||
Some(LangValue::GraphQl),
|
||||
"line1\nline2\nline3\n",
|
||||
),
|
||||
(
|
||||
"```graphql \nline1\nline2\nline3\n```",
|
||||
Some(LangValue::GraphQl),
|
||||
"line1\nline2\nline3\n",
|
||||
),
|
||||
];
|
||||
|
||||
for (text, lang, value) in datas.iter() {
|
||||
let mut reader = Reader::init(text);
|
||||
let multiline = multiline_string(&mut reader).unwrap();
|
||||
assert_eq!(multiline.lang.unwrap().value, *lang);
|
||||
assert_eq!(multiline.value.elements[0].to_string(), value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiline_string_failed() {
|
||||
let datas = [
|
||||
"```hexaaa\nline1\nline2\nline3\n```",
|
||||
"```aaa\nline1\nline2\nline3\n```",
|
||||
];
|
||||
|
||||
for text in datas.iter() {
|
||||
let mut reader = Reader::init(text);
|
||||
assert!(multiline_string(&mut reader).is_err())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiline_string_empty() {
|
||||
let mut reader = Reader::init("``````");
|
||||
assert_eq!(
|
||||
multiline_string(&mut reader).unwrap(),
|
||||
RawString {
|
||||
lang: None,
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![],
|
||||
source_info: SourceInfo::new(1, 4, 1, 4),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
let mut reader = Reader::init("```\n```");
|
||||
assert_eq!(
|
||||
multiline_string(&mut reader).unwrap(),
|
||||
RawString {
|
||||
lang: Some(Lang {
|
||||
value: None,
|
||||
space: Whitespace {
|
||||
value: "".to_string(),
|
||||
source_info: SourceInfo::new(1, 4, 1, 4)
|
||||
},
|
||||
newline: Whitespace {
|
||||
value: "\n".to_string(),
|
||||
source_info: SourceInfo::new(1, 4, 2, 1)
|
||||
}
|
||||
}),
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![],
|
||||
source_info: SourceInfo::new(2, 1, 2, 1),
|
||||
},
|
||||
}
|
||||
);
|
||||
let mut reader = Reader::init("```\r\n```");
|
||||
assert_eq!(
|
||||
multiline_string(&mut reader).unwrap(),
|
||||
RawString {
|
||||
lang: Some(Lang {
|
||||
value: None,
|
||||
space: Whitespace {
|
||||
value: "".to_string(),
|
||||
source_info: SourceInfo::new(1, 4, 1, 4)
|
||||
},
|
||||
newline: Whitespace {
|
||||
value: "\r\n".to_string(),
|
||||
source_info: SourceInfo::new(1, 4, 2, 1)
|
||||
}
|
||||
}),
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![],
|
||||
source_info: SourceInfo::new(2, 1, 2, 1),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_string_hello() {
|
||||
let mut reader = Reader::init("```Hello World!```");
|
||||
assert_eq!(
|
||||
multiline_string(&mut reader).unwrap(),
|
||||
RawString {
|
||||
lang: None,
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "Hello World!".to_string(),
|
||||
encoded: "Hello World!".to_string(),
|
||||
}],
|
||||
source_info: SourceInfo::new(1, 4, 1, 16),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_string_base64_prefix() {
|
||||
let mut reader = Reader::init("```base64_inline```");
|
||||
assert_eq!(
|
||||
multiline_string(&mut reader).unwrap(),
|
||||
RawString {
|
||||
lang: None,
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "base64_inline".to_string(),
|
||||
encoded: "base64_inline".to_string(),
|
||||
}],
|
||||
source_info: SourceInfo::new(1, 4, 1, 17),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_string_csv() {
|
||||
let mut reader = Reader::init("```\nline1\nline2\nline3\n```");
|
||||
assert_eq!(
|
||||
multiline_string(&mut reader).unwrap(),
|
||||
RawString {
|
||||
lang: Some(Lang {
|
||||
value: None,
|
||||
space: Whitespace {
|
||||
value: "".to_string(),
|
||||
source_info: SourceInfo::new(1, 4, 1, 4),
|
||||
},
|
||||
newline: Whitespace {
|
||||
value: "\n".to_string(),
|
||||
source_info: SourceInfo::new(1, 4, 2, 1),
|
||||
}
|
||||
}),
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "line1\nline2\nline3\n".to_string(),
|
||||
encoded: "line1\nline2\nline3\n".to_string(),
|
||||
}],
|
||||
source_info: SourceInfo::new(2, 1, 5, 1),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_string_one_emptyline() {
|
||||
// one newline
|
||||
// the value takes the value of the newline??
|
||||
let mut reader = Reader::init("```\n\n```");
|
||||
assert_eq!(
|
||||
multiline_string(&mut reader).unwrap(),
|
||||
RawString {
|
||||
lang: Some(Lang {
|
||||
value: None,
|
||||
space: Whitespace {
|
||||
value: "".to_string(),
|
||||
source_info: SourceInfo::new(1, 4, 1, 4),
|
||||
},
|
||||
newline: Whitespace {
|
||||
value: "\n".to_string(),
|
||||
source_info: SourceInfo::new(1, 4, 2, 1),
|
||||
}
|
||||
}),
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "\n".to_string(),
|
||||
encoded: "\n".to_string(),
|
||||
}],
|
||||
source_info: SourceInfo::new(2, 1, 3, 1),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// one cr
|
||||
let mut reader = Reader::init("```\n\r\n````");
|
||||
assert_eq!(
|
||||
multiline_string(&mut reader).unwrap(),
|
||||
RawString {
|
||||
lang: Some(Lang {
|
||||
value: None,
|
||||
space: Whitespace {
|
||||
value: "".to_string(),
|
||||
source_info: SourceInfo::new(1, 4, 1, 4),
|
||||
},
|
||||
newline: Whitespace {
|
||||
value: "\n".to_string(),
|
||||
source_info: SourceInfo::new(1, 4, 2, 1),
|
||||
}
|
||||
}),
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "\r\n".to_string(),
|
||||
encoded: "\r\n".to_string(),
|
||||
}],
|
||||
source_info: SourceInfo::new(2, 1, 3, 1),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_string_error() {
|
||||
let mut reader = Reader::init("xxx");
|
||||
let error = multiline_string(&mut reader).err().unwrap();
|
||||
assert_eq!(error.pos, Pos { line: 1, column: 1 });
|
||||
assert_eq!(
|
||||
error.inner,
|
||||
ParseError::Expecting {
|
||||
value: String::from("```")
|
||||
}
|
||||
);
|
||||
assert!(error.recoverable);
|
||||
|
||||
let mut reader = Reader::init("```\nxxx");
|
||||
let error = multiline_string(&mut reader).err().unwrap();
|
||||
assert_eq!(error.pos, Pos { line: 2, column: 4 });
|
||||
assert_eq!(
|
||||
error.inner,
|
||||
ParseError::Expecting {
|
||||
value: String::from("```")
|
||||
}
|
||||
);
|
||||
assert!(!error.recoverable);
|
||||
|
||||
let mut reader = Reader::init("```xxx");
|
||||
let error = multiline_string(&mut reader).err().unwrap();
|
||||
assert_eq!(error.pos, Pos { line: 1, column: 7 });
|
||||
assert_eq!(
|
||||
error.inner,
|
||||
ParseError::Expecting {
|
||||
value: String::from("```")
|
||||
}
|
||||
);
|
||||
assert!(!error.recoverable);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_string_value() {
|
||||
let mut reader = Reader::init("```");
|
||||
assert_eq!(
|
||||
multiline_string_value(&mut reader).unwrap(),
|
||||
Template {
|
||||
quotes: false,
|
||||
elements: vec![],
|
||||
source_info: SourceInfo::new(1, 1, 1, 1),
|
||||
}
|
||||
);
|
||||
assert_eq!(reader.state.cursor, 3);
|
||||
|
||||
let mut reader = Reader::init("hello```");
|
||||
assert_eq!(
|
||||
multiline_string_value(&mut reader).unwrap(),
|
||||
Template {
|
||||
quotes: false,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "hello".to_string(),
|
||||
encoded: "hello".to_string(),
|
||||
}],
|
||||
source_info: SourceInfo::new(1, 1, 1, 6),
|
||||
}
|
||||
);
|
||||
assert_eq!(reader.state.cursor, 8);
|
||||
}
|
||||
}
|
@ -407,10 +407,17 @@ mod tests {
|
||||
source_info: SourceInfo::new(2, 1, 2, 1),
|
||||
},
|
||||
value: Bytes::RawString(RawString {
|
||||
newline: Whitespace {
|
||||
value: "\n".to_string(),
|
||||
source_info: SourceInfo::new(2, 4, 3, 1),
|
||||
},
|
||||
lang: Some(Lang {
|
||||
value: None,
|
||||
space: Whitespace {
|
||||
value: "".to_string(),
|
||||
source_info: SourceInfo::new(2, 4, 2, 4),
|
||||
},
|
||||
newline: Whitespace {
|
||||
source_info: SourceInfo::new(2, 4, 3, 1),
|
||||
value: "\n".to_string(),
|
||||
}
|
||||
}),
|
||||
value: Template {
|
||||
elements: vec![TemplateElement::String {
|
||||
value: String::from("Hello World!\n"),
|
||||
|
@ -24,6 +24,7 @@ use super::primitives::*;
|
||||
use super::reader::Reader;
|
||||
use super::string::*;
|
||||
use super::ParseResult;
|
||||
use crate::parser::multiline::multiline_string;
|
||||
use crate::parser::{Error, ParseError};
|
||||
|
||||
pub fn predicate_value(reader: &mut Reader) -> ParseResult<'static, PredicateValue> {
|
||||
@ -61,7 +62,7 @@ pub fn predicate_value(reader: &mut Reader) -> ParseResult<'static, PredicateVal
|
||||
Ok(value) => Ok(PredicateValue::String(value)),
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
|p1| match raw_string(p1) {
|
||||
|p1| match multiline_string(p1) {
|
||||
Ok(value) => Ok(PredicateValue::Raw(value)),
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
|
@ -23,7 +23,6 @@ use super::error::*;
|
||||
use super::filename;
|
||||
use super::reader::Reader;
|
||||
use super::string::*;
|
||||
use super::template;
|
||||
use super::ParseResult;
|
||||
|
||||
pub fn space(reader: &mut Reader) -> ParseResult<'static, Whitespace> {
|
||||
@ -502,60 +501,6 @@ pub fn float(reader: &mut Reader) -> ParseResult<'static, Float> {
|
||||
Ok(Float { value, encoded })
|
||||
}
|
||||
|
||||
pub fn raw_string(reader: &mut Reader) -> ParseResult<'static, RawString> {
|
||||
// one value without newline or multiline mode
|
||||
// includes the last newline (consistent with bash EOL)
|
||||
try_literal("```", reader)?;
|
||||
let save = reader.state.clone();
|
||||
match newline(reader) {
|
||||
Ok(newline) => {
|
||||
let value = raw_string_value(reader)?;
|
||||
Ok(RawString { newline, value })
|
||||
}
|
||||
Err(_) => {
|
||||
reader.state = save;
|
||||
let newline = Whitespace {
|
||||
value: String::from(""),
|
||||
source_info: SourceInfo {
|
||||
start: reader.state.clone().pos,
|
||||
end: reader.state.clone().pos,
|
||||
},
|
||||
};
|
||||
let value = raw_string_value(reader)?;
|
||||
Ok(RawString { newline, value })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn raw_string_value(reader: &mut Reader) -> ParseResult<'static, Template> {
|
||||
let mut chars = vec![];
|
||||
|
||||
let start = reader.state.pos.clone();
|
||||
while !reader.remaining().starts_with("```") && !reader.is_eof() {
|
||||
let pos = reader.state.pos.clone();
|
||||
let c = reader.read().unwrap();
|
||||
chars.push((c, c.to_string(), pos));
|
||||
}
|
||||
let end = reader.state.pos.clone();
|
||||
literal("```", reader)?;
|
||||
|
||||
let encoded_string = template::EncodedString {
|
||||
source_info: SourceInfo {
|
||||
start: start.clone(),
|
||||
end: end.clone(),
|
||||
},
|
||||
chars,
|
||||
};
|
||||
|
||||
let elements = template::templatize(encoded_string)?;
|
||||
|
||||
Ok(Template {
|
||||
quotes: false,
|
||||
elements,
|
||||
source_info: SourceInfo { start, end },
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn file(reader: &mut Reader) -> ParseResult<'static, File> {
|
||||
let _start = reader.state.clone();
|
||||
try_literal("file", reader)?;
|
||||
@ -1120,226 +1065,6 @@ mod tests {
|
||||
assert!(!error.recoverable);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_string_empty() {
|
||||
let mut reader = Reader::init("``````");
|
||||
assert_eq!(
|
||||
raw_string(&mut reader).unwrap(),
|
||||
RawString {
|
||||
newline: Whitespace {
|
||||
value: String::from(""),
|
||||
source_info: SourceInfo::new(1, 4, 1, 4),
|
||||
},
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![],
|
||||
source_info: SourceInfo::new(1, 4, 1, 4),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
let mut reader = Reader::init("```\n```");
|
||||
assert_eq!(
|
||||
raw_string(&mut reader).unwrap(),
|
||||
RawString {
|
||||
newline: Whitespace {
|
||||
value: String::from("\n"),
|
||||
source_info: SourceInfo::new(1, 4, 2, 1),
|
||||
},
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![],
|
||||
source_info: SourceInfo::new(2, 1, 2, 1),
|
||||
},
|
||||
}
|
||||
);
|
||||
let mut reader = Reader::init("```\r\n```");
|
||||
assert_eq!(
|
||||
raw_string(&mut reader).unwrap(),
|
||||
RawString {
|
||||
newline: Whitespace {
|
||||
value: String::from("\r\n"),
|
||||
source_info: SourceInfo::new(1, 4, 2, 1),
|
||||
},
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![],
|
||||
source_info: SourceInfo::new(2, 1, 2, 1),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_string_hello() {
|
||||
let mut reader = Reader::init("```Hello World!```");
|
||||
assert_eq!(
|
||||
raw_string(&mut reader).unwrap(),
|
||||
RawString {
|
||||
newline: Whitespace {
|
||||
value: String::from(""),
|
||||
source_info: SourceInfo::new(1, 4, 1, 4),
|
||||
},
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "Hello World!".to_string(),
|
||||
encoded: "Hello World!".to_string(),
|
||||
}],
|
||||
source_info: SourceInfo::new(1, 4, 1, 16),
|
||||
},
|
||||
}
|
||||
);
|
||||
let mut reader = Reader::init("```Hello\nWorld!\n```");
|
||||
assert_eq!(
|
||||
raw_string(&mut reader).unwrap(),
|
||||
RawString {
|
||||
newline: Whitespace {
|
||||
value: String::from(""),
|
||||
source_info: SourceInfo::new(1, 4, 1, 4),
|
||||
},
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "Hello\nWorld!\n".to_string(),
|
||||
encoded: "Hello\nWorld!\n".to_string(),
|
||||
}],
|
||||
source_info: SourceInfo::new(1, 4, 3, 1),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_string_csv() {
|
||||
let mut reader = Reader::init("```\nline1\nline2\nline3\n```");
|
||||
assert_eq!(
|
||||
raw_string(&mut reader).unwrap(),
|
||||
RawString {
|
||||
newline: Whitespace {
|
||||
value: String::from("\n"),
|
||||
source_info: SourceInfo::new(1, 4, 2, 1),
|
||||
},
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "line1\nline2\nline3\n".to_string(),
|
||||
encoded: "line1\nline2\nline3\n".to_string(),
|
||||
}],
|
||||
source_info: SourceInfo::new(2, 1, 5, 1),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_string_one_emptyline() {
|
||||
// one newline
|
||||
// the value takes the value of the newline??
|
||||
let mut reader = Reader::init("```\n\n```");
|
||||
assert_eq!(
|
||||
raw_string(&mut reader).unwrap(),
|
||||
RawString {
|
||||
newline: Whitespace {
|
||||
value: String::from("\n"),
|
||||
source_info: SourceInfo::new(1, 4, 2, 1),
|
||||
},
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "\n".to_string(),
|
||||
encoded: "\n".to_string(),
|
||||
}],
|
||||
source_info: SourceInfo::new(2, 1, 3, 1),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// one cr
|
||||
let mut reader = Reader::init("```\n\r\n````");
|
||||
assert_eq!(
|
||||
raw_string(&mut reader).unwrap(),
|
||||
RawString {
|
||||
newline: Whitespace {
|
||||
value: String::from("\n"),
|
||||
source_info: SourceInfo::new(1, 4, 2, 1),
|
||||
},
|
||||
value: Template {
|
||||
quotes: false,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "\r\n".to_string(),
|
||||
encoded: "\r\n".to_string(),
|
||||
}],
|
||||
source_info: SourceInfo::new(2, 1, 3, 1),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_string_error() {
|
||||
let mut reader = Reader::init("xxx");
|
||||
let error = raw_string(&mut reader).err().unwrap();
|
||||
assert_eq!(error.pos, Pos { line: 1, column: 1 });
|
||||
assert_eq!(
|
||||
error.inner,
|
||||
ParseError::Expecting {
|
||||
value: String::from("```")
|
||||
}
|
||||
);
|
||||
assert!(error.recoverable);
|
||||
|
||||
let mut reader = Reader::init("```\nxxx");
|
||||
let error = raw_string(&mut reader).err().unwrap();
|
||||
assert_eq!(error.pos, Pos { line: 2, column: 4 });
|
||||
assert_eq!(
|
||||
error.inner,
|
||||
ParseError::Expecting {
|
||||
value: String::from("```")
|
||||
}
|
||||
);
|
||||
assert!(!error.recoverable);
|
||||
|
||||
let mut reader = Reader::init("```xxx");
|
||||
let error = raw_string(&mut reader).err().unwrap();
|
||||
assert_eq!(error.pos, Pos { line: 1, column: 7 });
|
||||
assert_eq!(
|
||||
error.inner,
|
||||
ParseError::Expecting {
|
||||
value: String::from("```")
|
||||
}
|
||||
);
|
||||
assert!(!error.recoverable);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_string_value() {
|
||||
let mut reader = Reader::init("```");
|
||||
assert_eq!(
|
||||
raw_string_value(&mut reader).unwrap(),
|
||||
Template {
|
||||
quotes: false,
|
||||
elements: vec![],
|
||||
source_info: SourceInfo::new(1, 1, 1, 1),
|
||||
}
|
||||
);
|
||||
assert_eq!(reader.state.cursor, 3);
|
||||
|
||||
let mut reader = Reader::init("hello```");
|
||||
assert_eq!(
|
||||
raw_string_value(&mut reader).unwrap(),
|
||||
Template {
|
||||
quotes: false,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "hello".to_string(),
|
||||
encoded: "hello".to_string(),
|
||||
}],
|
||||
source_info: SourceInfo::new(1, 1, 1, 6),
|
||||
}
|
||||
);
|
||||
assert_eq!(reader.state.cursor, 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hex_digit() {
|
||||
let mut reader = Reader::init("0");
|
||||
|
@ -141,10 +141,20 @@ impl ToJson for Bytes {
|
||||
("type".to_string(), JValue::String("xml".to_string())),
|
||||
("value".to_string(), JValue::String(value.clone())),
|
||||
]),
|
||||
Bytes::RawString(value) => JValue::Object(vec![
|
||||
("type".to_string(), JValue::String("raw-string".to_string())),
|
||||
("value".to_string(), JValue::String(value.value.to_string())),
|
||||
]),
|
||||
Bytes::RawString(value) => {
|
||||
let lang = match &value.lang {
|
||||
// TODO: change raw-string for undefined
|
||||
None | Some(Lang { value: None, .. }) => "raw-string".to_string(),
|
||||
Some(Lang {
|
||||
value: Some(lang_value),
|
||||
..
|
||||
}) => lang_value.to_string(),
|
||||
};
|
||||
JValue::Object(vec![
|
||||
("type".to_string(), JValue::String(lang)),
|
||||
("value".to_string(), JValue::String(value.value.to_string())),
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,5 +121,6 @@ pub fn format_token(token: Token, color: bool) -> String {
|
||||
value
|
||||
}
|
||||
}
|
||||
Token::Lang(value) => value,
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ pub enum Token {
|
||||
String(String),
|
||||
CodeDelimiter(String),
|
||||
CodeVariable(String),
|
||||
Lang(String),
|
||||
}
|
||||
|
||||
pub trait Tokenizable {
|
||||
@ -605,16 +606,35 @@ impl Tokenizable for PredicateValue {
|
||||
|
||||
impl Tokenizable for RawString {
|
||||
fn tokenize(&self) -> Vec<Token> {
|
||||
let mut tokens: Vec<Token> = vec![
|
||||
Token::Keyword("```".to_string()),
|
||||
Token::Whitespace(self.newline.value.clone()),
|
||||
];
|
||||
let mut tokens: Vec<Token> = vec![Token::Keyword("```".to_string())];
|
||||
if let Some(kind) = &self.lang {
|
||||
tokens.append(&mut kind.tokenize())
|
||||
}
|
||||
tokens.append(&mut self.value.tokenize());
|
||||
tokens.push(Token::Keyword("```".to_string()));
|
||||
tokens
|
||||
}
|
||||
}
|
||||
|
||||
impl Tokenizable for Lang {
|
||||
fn tokenize(&self) -> Vec<Token> {
|
||||
let mut tokens: Vec<Token> = vec![];
|
||||
if let Some(value) = &self.value {
|
||||
tokens.append(&mut value.tokenize());
|
||||
}
|
||||
tokens.append(&mut self.space.tokenize());
|
||||
tokens.append(&mut self.newline.tokenize());
|
||||
tokens
|
||||
}
|
||||
}
|
||||
|
||||
impl Tokenizable for LangValue {
|
||||
fn tokenize(&self) -> Vec<Token> {
|
||||
let token = Token::Lang(self.to_string());
|
||||
vec![token]
|
||||
}
|
||||
}
|
||||
|
||||
impl Tokenizable for EncodedString {
|
||||
fn tokenize(&self) -> Vec<Token> {
|
||||
let mut tokens: Vec<Token> = vec![];
|
||||
|
@ -520,7 +520,7 @@ impl Lintable<RawString> for RawString {
|
||||
|
||||
fn lint(&self) -> RawString {
|
||||
RawString {
|
||||
newline: self.newline.clone(),
|
||||
lang: None,
|
||||
value: self.value.lint(),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user