diff --git a/packages/bruno-lang/v2/src/bruToJson.js b/packages/bruno-lang/v2/src/bruToJson.js index 17c9bf97d..0538cc048 100644 --- a/packages/bruno-lang/v2/src/bruToJson.js +++ b/packages/bruno-lang/v2/src/bruToJson.js @@ -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); diff --git a/packages/bruno-lang/v2/tests/bruToJson.spec.js b/packages/bruno-lang/v2/tests/bruToJson.spec.js index 718ce6e1b..b9b27a685 100644 --- a/packages/bruno-lang/v2/tests/bruToJson.spec.js +++ b/packages/bruno-lang/v2/tests/bruToJson.spec.js @@ -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); + }); }); }); diff --git a/packages/bruno-tests/collection/echo/echo multipart.bru b/packages/bruno-tests/collection/echo/echo multipart.bru index 09176d74f..989db8f42 100644 --- a/packages/bruno-tests/collection/echo/echo multipart.bru +++ b/packages/bruno-tests/collection/echo/echo multipart.bru @@ -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 {