mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-11 09:51:30 +00:00
fix: Support @contentType for multiline values (#6217)
* fix: Support @contentType for multiline values Fixes the issue where the @contentType annotation broke the parsing of multiline values. * chore: add dotall flag to fileExtractContentType Not strictly needed since body:file uses single-line values in practice, but doesn't hurt and matches what multipartExtractContentType does. --------- Co-authored-by: Márk Dániel Seres <markdaniel.seres@tesco.com>
This commit is contained in:
@@ -52,7 +52,8 @@ const grammar = ohm.grammar(`Bru {
|
||||
|
||||
// Multiline text block surrounded by '''
|
||||
multilinetextblockdelimiter = "'''"
|
||||
multilinetextblock = multilinetextblockdelimiter (~multilinetextblockdelimiter any)* multilinetextblockdelimiter
|
||||
multilinetextblock = multilinetextblockdelimiter (~multilinetextblockdelimiter any)* multilinetextblockdelimiter st* contenttypeannotation?
|
||||
contenttypeannotation = "@contentType(" (~")" any)* ")"
|
||||
|
||||
// Dictionary Blocks
|
||||
dictionary = st* "{" pairlist? tagend
|
||||
@@ -65,7 +66,8 @@ const grammar = ohm.grammar(`Bru {
|
||||
quoted_key_char = ~(quote_char | esc_quote_char | nl) any
|
||||
quoted_key = disable_char? quote_char (esc_quote_char | quoted_key_char)* quote_char
|
||||
key = keychar*
|
||||
value = list | multilinetextblock | valuechar*
|
||||
value = list | multilinetextblock | singlelinevalue
|
||||
singlelinevalue = valuechar*
|
||||
|
||||
// Dictionary for Assert Block
|
||||
assertdictionary = st* "{" assertpairlist? tagend
|
||||
@@ -211,7 +213,7 @@ const mapRequestParams = (pairList = [], type) => {
|
||||
|
||||
const multipartExtractContentType = (pair) => {
|
||||
if (_.isString(pair.value)) {
|
||||
const match = pair.value.match(/^(.*?)\s*@contentType\((.*?)\)\s*$/);
|
||||
const match = pair.value.match(/^(.*?)\s*@contentType\((.*?)\)\s*$/s);
|
||||
if (match != null && match.length > 2) {
|
||||
pair.value = match[1];
|
||||
pair.contentType = match[2];
|
||||
@@ -223,7 +225,7 @@ const multipartExtractContentType = (pair) => {
|
||||
|
||||
const fileExtractContentType = (pair) => {
|
||||
if (_.isString(pair.value)) {
|
||||
const match = pair.value.match(/^(.*?)\s*@contentType\((.*?)\)\s*$/);
|
||||
const match = pair.value.match(/^(.*?)\s*@contentType\((.*?)\)\s*$/s);
|
||||
if (match && match.length > 2) {
|
||||
pair.value = match[1].trim();
|
||||
pair.contentType = match[2].trim();
|
||||
@@ -369,25 +371,6 @@ const sem = grammar.createSemantics().addAttribute('ast', {
|
||||
key(chars) {
|
||||
return chars.sourceString ? chars.sourceString.trim() : '';
|
||||
},
|
||||
value(chars) {
|
||||
if (chars.ctorName === 'list') {
|
||||
return chars.ast;
|
||||
}
|
||||
try {
|
||||
let isMultiline = chars.sourceString?.startsWith(`'''`) && chars.sourceString?.endsWith(`'''`);
|
||||
if (isMultiline) {
|
||||
const multilineString = chars.sourceString?.replace(/^'''|'''$/g, '');
|
||||
return multilineString
|
||||
.split('\n')
|
||||
.map((line) => line.slice(4))
|
||||
.join('\n');
|
||||
}
|
||||
return chars.sourceString ? chars.sourceString.trim() : '';
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
return chars.sourceString ? chars.sourceString.trim() : '';
|
||||
},
|
||||
assertdictionary(_1, _2, pairlist, _3) {
|
||||
return pairlist.ast;
|
||||
},
|
||||
@@ -435,9 +418,19 @@ const sem = grammar.createSemantics().addAttribute('ast', {
|
||||
multilinetextblockdelimiter(_) {
|
||||
return '';
|
||||
},
|
||||
multilinetextblock(_1, content, _2) {
|
||||
// Join all the content between the triple quotes and trim it
|
||||
return content.sourceString.trim();
|
||||
multilinetextblock(_1, content, _2, _3, contentType) {
|
||||
const multilineString = content.sourceString
|
||||
.split('\n')
|
||||
.map((line) => line.slice(4))
|
||||
.join('\n');
|
||||
|
||||
if (!contentType.sourceString) {
|
||||
return multilineString;
|
||||
}
|
||||
return `${multilineString} ${contentType.sourceString}`;
|
||||
},
|
||||
singlelinevalue(chars) {
|
||||
return chars.sourceString?.trim() || '';
|
||||
},
|
||||
_iter(...elements) {
|
||||
return elements.map((e) => e.ast);
|
||||
|
||||
@@ -175,5 +175,33 @@ vars:pre-request {
|
||||
const output = parser(input);
|
||||
expect(output).toEqual(expected);
|
||||
});
|
||||
|
||||
it('parses multiline body parts with content type annotation', () => {
|
||||
const input = `
|
||||
body:multipart-form {
|
||||
filePart: '''
|
||||
Line1
|
||||
Line2
|
||||
''' @contentType(text/plain)
|
||||
}
|
||||
`;
|
||||
|
||||
const expected = {
|
||||
body: {
|
||||
multipartForm: [
|
||||
{
|
||||
name: 'filePart',
|
||||
value: 'Line1\nLine2',
|
||||
enabled: true,
|
||||
type: 'text',
|
||||
contentType: 'text/plain'
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
const output = parser(input);
|
||||
expect(output).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,6 +12,9 @@ post {
|
||||
|
||||
body:multipart-form {
|
||||
foo: {"bar":"baz"} @contentType(application/json--test)
|
||||
multiline: '''
|
||||
"multiline-test"
|
||||
''' @contentType(application/json--multiline--test)
|
||||
form-data-key: {{form-data-key}}
|
||||
form-data-stringified-object: {{form-data-stringified-object}}
|
||||
file: @file(bruno.png)
|
||||
@@ -21,6 +24,7 @@ assert {
|
||||
res.body: contains form-data-value
|
||||
res.body: contains {"foo":123}
|
||||
res.body: contains Content-Type: application/json--test
|
||||
res.body: contains Content-Type: application/json--multiline--test
|
||||
}
|
||||
|
||||
script:pre-request {
|
||||
|
||||
Reference in New Issue
Block a user