From 104bd272f9b54eb0fe0cd795c7f6427be7011e34 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Fri, 3 Feb 2023 04:39:45 +0530 Subject: [PATCH 01/10] feat: bru lang - simple parser --- packages/bruno-lang/package.json | 3 +- packages/bruno-lang/v2/src/index.js | 55 ++++++++++++++++++++++ packages/bruno-lang/v2/tests/index.spec.js | 17 +++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 packages/bruno-lang/v2/src/index.js create mode 100644 packages/bruno-lang/v2/tests/index.spec.js diff --git a/packages/bruno-lang/package.json b/packages/bruno-lang/package.json index c243c7980..632aed4c5 100644 --- a/packages/bruno-lang/package.json +++ b/packages/bruno-lang/package.json @@ -10,6 +10,7 @@ "test": "jest" }, "dependencies": { - "arcsecond": "^5.0.0" + "arcsecond": "^5.0.0", + "ohm-js": "^16.6.0" } } diff --git a/packages/bruno-lang/v2/src/index.js b/packages/bruno-lang/v2/src/index.js new file mode 100644 index 000000000..563cdcfc2 --- /dev/null +++ b/packages/bruno-lang/v2/src/index.js @@ -0,0 +1,55 @@ +const ohm = require("ohm-js"); + +const grammar = ohm.grammar(`Bru { + Headers = "headers" "{" PairList "}" + PairList = Pair ("," Pair)* + Pair = Key ":" Value + Key = identifier + Value = stringLiteral + identifier = alnum* + stringLiteral = letter* +}`); + +const sem = grammar.createSemantics().addAttribute('ast', { + Headers(_, _1, PairList, _2) { + return PairList.ast; + }, + PairList(pairs, _, rest) { + return [pairs.ast, ...rest.ast]; + }, + Pair(key, _, value) { + return { key: key.ast, value: value.ast }; + }, + Key(id) { + return id.sourceString; + }, + Value(str) { + return str.sourceString; + }, + identifier(id) { + return id.sourceString; + }, + stringLiteral(str) { + return str.sourceString; + }, + _iter(...elements) { + return elements.map(e => e.ast); + } +}); + +const input = `headers { + hello: world, + foo: bar +}`; + +const parser = (input) => { + const match = grammar.match(input); + + if(match.succeeded()) { + return sem(match).ast; + } else { + throw new Error(match.message); + } +} + +module.exports = parser; diff --git a/packages/bruno-lang/v2/tests/index.spec.js b/packages/bruno-lang/v2/tests/index.spec.js new file mode 100644 index 000000000..e2d701092 --- /dev/null +++ b/packages/bruno-lang/v2/tests/index.spec.js @@ -0,0 +1,17 @@ +const parser = require("../src/index"); + +describe("parser", () => { + it("should parse headers", () => { + const input = `headers { + hello: world, + foo: bar + }`; + + const expected = [ + { key: "hello", value: "world" }, + { key: "foo", value: "bar" } + ]; + + expect(parser(input)).toEqual(expected); + }); +}); From 9d6ba4691ce14ab90924d8a1032c7527bd508e66 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Fri, 3 Feb 2023 08:01:44 +0530 Subject: [PATCH 02/10] feat: bru lang tests, scripts and headers using ohm --- packages/bruno-lang/v2/src/index.js | 80 +++++++++++++++------- packages/bruno-lang/v2/tests/index.spec.js | 28 +++++--- 2 files changed, 73 insertions(+), 35 deletions(-) diff --git a/packages/bruno-lang/v2/src/index.js b/packages/bruno-lang/v2/src/index.js index 563cdcfc2..d4fb543b4 100644 --- a/packages/bruno-lang/v2/src/index.js +++ b/packages/bruno-lang/v2/src/index.js @@ -1,53 +1,81 @@ const ohm = require("ohm-js"); const grammar = ohm.grammar(`Bru { - Headers = "headers" "{" PairList "}" - PairList = Pair ("," Pair)* - Pair = Key ":" Value - Key = identifier - Value = stringLiteral - identifier = alnum* - stringLiteral = letter* + BruFile = (script | test | headers)* + nl = "\\r"? "\\n" + st = " " | "\\t" + tagend = nl "}" + + headers = "headers" st* "{" nl* pairlist tagend + + pairlist = pair (~tagend nl pair)* (~tagend space)* + pair = st* key st* ":" st* val st* + key = alnum* + val = letter* + + script = "script" st* "{" codeblock tagend + test = "test" st* "{" codeblock tagend + + codeblock = codeline (~tagend nl codeline)* + codeline = codechar* + codechar = ~nl any }`); const sem = grammar.createSemantics().addAttribute('ast', { - Headers(_, _1, PairList, _2) { - return PairList.ast; + headers(_1, _2, _3, _4, pairlist, _5) { + return pairlist.ast; }, - PairList(pairs, _, rest) { - return [pairs.ast, ...rest.ast]; + pairlist(pair, _1, rest, _2) { + return [pair.ast, ...rest.ast]; }, - Pair(key, _, value) { - return { key: key.ast, value: value.ast }; + pair(_1, key, _2, _3, _4, val, _5) { + let res = {}; + res[key.ast] = val.ast; + return res; }, - Key(id) { - return id.sourceString; + key(chars) { + return chars.sourceString; }, - Value(str) { - return str.sourceString; + val(chars) { + return chars.sourceString; }, - identifier(id) { - return id.sourceString; + script(_1, _2, _3, codeblock, _4) { + return codeblock.sourceString; }, - stringLiteral(str) { - return str.sourceString; + test(_1, _2, _3, codeblock, _4) { + return codeblock.sourceString; + }, + codeblock(line, _1, rest) { + return [line.ast, ...rest.ast].join('\n'); + }, + codeline(chars) { + return chars.sourceString; + }, + codechar(char) { + return char.sourceString; + }, + nl(_1, _2) { + return ''; + }, + st(_) { + return ''; + }, + tagend(_1 ,_2) { + return ''; }, _iter(...elements) { return elements.map(e => e.ast); } }); -const input = `headers { - hello: world, - foo: bar -}`; - const parser = (input) => { const match = grammar.match(input); if(match.succeeded()) { return sem(match).ast; } else { + console.log('match.message========='); + console.log(match.message); throw new Error(match.message); } } diff --git a/packages/bruno-lang/v2/tests/index.spec.js b/packages/bruno-lang/v2/tests/index.spec.js index e2d701092..1effaa772 100644 --- a/packages/bruno-lang/v2/tests/index.spec.js +++ b/packages/bruno-lang/v2/tests/index.spec.js @@ -2,16 +2,26 @@ const parser = require("../src/index"); describe("parser", () => { it("should parse headers", () => { - const input = `headers { - hello: world, - foo: bar - }`; + const input = ` +headers { + hello: world + foo: bar +}`; - const expected = [ - { key: "hello", value: "world" }, - { key: "foo", value: "bar" } - ]; + const output = parser(input); + console.log(output); + }); - expect(parser(input)).toEqual(expected); + it("should parse script body", () => { + const input = ` +script { + function onResponse(request, response) { + expect(response.status).to.equal(200); + } +} +`; + + const output = parser(input); + console.log(output); }); }); From 2ee2e270b01375585e7310122a5167b8b64e778f Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Fri, 3 Feb 2023 21:08:40 +0530 Subject: [PATCH 03/10] feat: brun lang - ast updates, tests for headers and script tags --- packages/bruno-lang/v2/src/index.js | 56 ++++++++--- packages/bruno-lang/v2/tests/headers.spec.js | 100 +++++++++++++++++++ packages/bruno-lang/v2/tests/index.spec.js | 27 +++-- packages/bruno-lang/v2/tests/script.spec.js | 17 ++++ 4 files changed, 177 insertions(+), 23 deletions(-) create mode 100644 packages/bruno-lang/v2/tests/headers.spec.js create mode 100644 packages/bruno-lang/v2/tests/script.spec.js diff --git a/packages/bruno-lang/v2/src/index.js b/packages/bruno-lang/v2/src/index.js index d4fb543b4..53ba9d452 100644 --- a/packages/bruno-lang/v2/src/index.js +++ b/packages/bruno-lang/v2/src/index.js @@ -1,4 +1,5 @@ const ohm = require("ohm-js"); +const _ = require('lodash'); const grammar = ohm.grammar(`Bru { BruFile = (script | test | headers)* @@ -6,26 +7,51 @@ const grammar = ohm.grammar(`Bru { st = " " | "\\t" tagend = nl "}" - headers = "headers" st* "{" nl* pairlist tagend + headers = "headers" st* "{" pairlist? tagend - pairlist = pair (~tagend nl pair)* (~tagend space)* + pairlist = nl* pair (~tagend nl pair)* (~tagend space)* pair = st* key st* ":" st* val st* - key = alnum* - val = letter* + key = ~tagend alnum* + val = ~tagend letter* - script = "script" st* "{" codeblock tagend + script = "script" st* "{" nl* codeblock tagend test = "test" st* "{" codeblock tagend codeblock = codeline (~tagend nl codeline)* codeline = codechar* - codechar = ~nl any + codechar = ~nl any }`); +const mapPairListToKeyValPairs = (pairList = [], enabled = true) => { + if(!pairList.length) { + return []; + } + return _.map(pairList[0], pair => { + const key = _.keys(pair)[0]; + return { + name: key, + value: pair[key], + enabled: enabled + }; + }); +}; + const sem = grammar.createSemantics().addAttribute('ast', { - headers(_1, _2, _3, _4, pairlist, _5) { - return pairlist.ast; + BruFile(tags) { + if(!tags || !tags.ast || !tags.ast.length) { + return {}; + } + + return _.reduce(tags.ast, (result, item) => { + return _.assign(result, item); + }, {}); }, - pairlist(pair, _1, rest, _2) { + headers(_1, _2, _3, pairlist, _4) { + return { + headers: mapPairListToKeyValPairs(pairlist.ast) + }; + }, + pairlist(_1, pair, _2, rest, _3) { return [pair.ast, ...rest.ast]; }, pair(_1, key, _2, _3, _4, val, _5) { @@ -39,11 +65,15 @@ const sem = grammar.createSemantics().addAttribute('ast', { val(chars) { return chars.sourceString; }, - script(_1, _2, _3, codeblock, _4) { - return codeblock.sourceString; + script(_1, _2, _3, _4, codeblock, _5) { + return { + script: codeblock.sourceString + }; }, test(_1, _2, _3, codeblock, _4) { - return codeblock.sourceString; + return { + test: codeblock.sourceString + };; }, codeblock(line, _1, rest) { return [line.ast, ...rest.ast].join('\n'); @@ -74,8 +104,6 @@ const parser = (input) => { if(match.succeeded()) { return sem(match).ast; } else { - console.log('match.message========='); - console.log(match.message); throw new Error(match.message); } } diff --git a/packages/bruno-lang/v2/tests/headers.spec.js b/packages/bruno-lang/v2/tests/headers.spec.js new file mode 100644 index 000000000..d1c998277 --- /dev/null +++ b/packages/bruno-lang/v2/tests/headers.spec.js @@ -0,0 +1,100 @@ +const bruToJsonV2 = require("../src/index"); + +const assertSingleHeader = (input) => { + const output = bruToJsonV2(input); + + const expected = { + "headers": [{ + "name": "hello", + "value": "world", + "enabled": true + }] + }; + expect(output).toEqual(expected); +}; + +describe("headers parser", () => { + it("should parse empty header", () => { + const input = ` +headers { +}`; + + const output = bruToJsonV2(input); + const expected = { + "headers": [] + }; + expect(output).toEqual(expected); + }); + + it("should parse single header", () => { + const input = ` +headers { + hello: world +}`; + + assertSingleHeader(input); + }); + + it("should parse single header with spaces", () => { + const input = ` +headers { + hello: world +}`; + + assertSingleHeader(input); + }); + + it("should parse single header with spaces and newlines", () => { + const input = ` +headers { + + hello: world + + +}`; + + assertSingleHeader(input); + }); + + it("should parse multi headers", () => { + const input = ` +headers { + hello: world + foo: bar +}`; + + const output = bruToJsonV2(input); + const expected = { + "headers": [{ + "name": "hello", + "value": "world", + "enabled": true + }, { + "name": "foo", + "value": "bar", + "enabled": true + }] + }; + expect(output).toEqual(expected); + }); + + it("should throw error on invalid header", () => { + const input = ` +headers { + hello: world + foo +}`; + + expect(() => bruToJsonV2(input)).toThrow(); + }); + + it("should throw error on invalid header", () => { + const input = ` +headers { + hello: world + foo: bar}`; + + expect(() => bruToJsonV2(input)).toThrow(); + }); +}); + diff --git a/packages/bruno-lang/v2/tests/index.spec.js b/packages/bruno-lang/v2/tests/index.spec.js index 1effaa772..2ad905ed6 100644 --- a/packages/bruno-lang/v2/tests/index.spec.js +++ b/packages/bruno-lang/v2/tests/index.spec.js @@ -1,19 +1,13 @@ const parser = require("../src/index"); describe("parser", () => { - it("should parse headers", () => { + it("should parse the bru file", () => { const input = ` headers { hello: world foo: bar -}`; +} - const output = parser(input); - console.log(output); - }); - - it("should parse script body", () => { - const input = ` script { function onResponse(request, response) { expect(response.status).to.equal(200); @@ -22,6 +16,21 @@ script { `; const output = parser(input); - console.log(output); + const expected = { + "headers": [ + { + "name": "hello", + "value": "world", + "enabled": true + }, + { + "name": "foo", + "value": "bar", + "enabled": true + } + ], + "script": " function onResponse(request, response) {\n expect(response.status).to.equal(200);\n }" + } + expect(output).toEqual(expected); }); }); diff --git a/packages/bruno-lang/v2/tests/script.spec.js b/packages/bruno-lang/v2/tests/script.spec.js new file mode 100644 index 000000000..4adf12a9f --- /dev/null +++ b/packages/bruno-lang/v2/tests/script.spec.js @@ -0,0 +1,17 @@ +const parser = require("../src/index"); + +describe("script parser", () => { + it("should parse script body", () => { + const input = ` +script { + function onResponse(request, response) { + expect(response.status).to.equal(200); + } +} +`; + + const output = parser(input); + const expected = " function onResponse(request, response) {\n expect(response.status).to.equal(200);\n }"; + expect(output.script).toEqual(expected); + }); +}); From a21615a5fbccd18c2c82e7f352080731990cab75 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Fri, 3 Feb 2023 21:44:07 +0530 Subject: [PATCH 04/10] feat: bru lang - keys can support any char except whitespace, values can have any char except newline --- packages/bruno-lang/v2/src/index.js | 40 ++++++++++---------- packages/bruno-lang/v2/tests/headers.spec.js | 12 +++--- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/packages/bruno-lang/v2/src/index.js b/packages/bruno-lang/v2/src/index.js index 53ba9d452..30ba7fec8 100644 --- a/packages/bruno-lang/v2/src/index.js +++ b/packages/bruno-lang/v2/src/index.js @@ -6,20 +6,22 @@ const grammar = ohm.grammar(`Bru { nl = "\\r"? "\\n" st = " " | "\\t" tagend = nl "}" + validkey = ~(st | ":") any + validvalue = ~nl any headers = "headers" st* "{" pairlist? tagend pairlist = nl* pair (~tagend nl pair)* (~tagend space)* - pair = st* key st* ":" st* val st* - key = ~tagend alnum* - val = ~tagend letter* + pair = st* key st* ":" st* value st* + key = ~tagend validkey* + value = ~tagend validvalue* - script = "script" st* "{" nl* codeblock tagend - test = "test" st* "{" codeblock tagend + script = "script" st* "{" nl* textblock tagend + test = "test" st* "{" textblock tagend - codeblock = codeline (~tagend nl codeline)* - codeline = codechar* - codechar = ~nl any + textblock = textline (~tagend nl textline)* + textline = textchar* + textchar = ~nl any }`); const mapPairListToKeyValPairs = (pairList = [], enabled = true) => { @@ -54,34 +56,34 @@ const sem = grammar.createSemantics().addAttribute('ast', { pairlist(_1, pair, _2, rest, _3) { return [pair.ast, ...rest.ast]; }, - pair(_1, key, _2, _3, _4, val, _5) { + pair(_1, key, _2, _3, _4, value, _5) { let res = {}; - res[key.ast] = val.ast; + res[key.ast] = value.ast; return res; }, key(chars) { return chars.sourceString; }, - val(chars) { - return chars.sourceString; + value(chars) { + return chars.sourceString ? chars.sourceString.trim() : ''; }, - script(_1, _2, _3, _4, codeblock, _5) { + script(_1, _2, _3, _4, textblock, _5) { return { - script: codeblock.sourceString + script: textblock.sourceString }; }, - test(_1, _2, _3, codeblock, _4) { + test(_1, _2, _3, textblock, _4) { return { - test: codeblock.sourceString + test: textblock.sourceString };; }, - codeblock(line, _1, rest) { + textblock(line, _1, rest) { return [line.ast, ...rest.ast].join('\n'); }, - codeline(chars) { + textline(chars) { return chars.sourceString; }, - codechar(char) { + textchar(char) { return char.sourceString; }, nl(_1, _2) { diff --git a/packages/bruno-lang/v2/tests/headers.spec.js b/packages/bruno-lang/v2/tests/headers.spec.js index d1c998277..3365bd8b7 100644 --- a/packages/bruno-lang/v2/tests/headers.spec.js +++ b/packages/bruno-lang/v2/tests/headers.spec.js @@ -59,19 +59,19 @@ headers { it("should parse multi headers", () => { const input = ` headers { - hello: world - foo: bar + content-type: application/json + Authorization: JWT secret }`; const output = bruToJsonV2(input); const expected = { "headers": [{ - "name": "hello", - "value": "world", + "name": "content-type", + "value": "application/json", "enabled": true }, { - "name": "foo", - "value": "bar", + "name": "Authorization", + "value": "JWT secret", "enabled": true }] }; From 118ceacf46c508f8fde77dad046816c1cb295ef5 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Fri, 3 Feb 2023 23:02:16 +0530 Subject: [PATCH 05/10] feat: bru lang - allow parsing empty header values --- packages/bruno-lang/v2/src/index.js | 8 ++++---- packages/bruno-lang/v2/tests/headers.spec.js | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/bruno-lang/v2/src/index.js b/packages/bruno-lang/v2/src/index.js index 30ba7fec8..577f46e92 100644 --- a/packages/bruno-lang/v2/src/index.js +++ b/packages/bruno-lang/v2/src/index.js @@ -8,11 +8,11 @@ const grammar = ohm.grammar(`Bru { tagend = nl "}" validkey = ~(st | ":") any validvalue = ~nl any - + headers = "headers" st* "{" pairlist? tagend - + pairlist = nl* pair (~tagend nl pair)* (~tagend space)* - pair = st* key st* ":" st* value st* + pair = st* key st* ":" st* value? st* key = ~tagend validkey* value = ~tagend validvalue* @@ -58,7 +58,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { }, pair(_1, key, _2, _3, _4, value, _5) { let res = {}; - res[key.ast] = value.ast; + res[key.ast] = _.get(value, 'ast[0]', ''); return res; }, key(chars) { diff --git a/packages/bruno-lang/v2/tests/headers.spec.js b/packages/bruno-lang/v2/tests/headers.spec.js index 3365bd8b7..64c729841 100644 --- a/packages/bruno-lang/v2/tests/headers.spec.js +++ b/packages/bruno-lang/v2/tests/headers.spec.js @@ -56,6 +56,23 @@ headers { assertSingleHeader(input); }); + it("should parse single header with empty value", () => { + const input = ` +headers { + hello: +}`; + + const output = bruToJsonV2(input); + const expected = { + "headers": [{ + "name": "hello", + "value": "", + "enabled": true + }] + }; + expect(output).toEqual(expected); + }); + it("should parse multi headers", () => { const input = ` headers { From 7a8e5198ffdca500c0b406106c29533996974de0 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Fri, 3 Feb 2023 23:27:06 +0530 Subject: [PATCH 06/10] feat: bru lang - support disabled headers parsing --- packages/bruno-lang/v2/src/index.js | 26 ++++++++++++++++---- packages/bruno-lang/v2/tests/headers.spec.js | 17 +++++++++++++ packages/bruno-lang/v2/tests/index.spec.js | 22 ++++++++++++----- 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/packages/bruno-lang/v2/src/index.js b/packages/bruno-lang/v2/src/index.js index 577f46e92..3863060d0 100644 --- a/packages/bruno-lang/v2/src/index.js +++ b/packages/bruno-lang/v2/src/index.js @@ -2,15 +2,17 @@ const ohm = require("ohm-js"); const _ = require('lodash'); const grammar = ohm.grammar(`Bru { - BruFile = (script | test | headers)* + BruFile = (script | test | headersdisabled | headers)* nl = "\\r"? "\\n" st = " " | "\\t" tagend = nl "}" validkey = ~(st | ":") any validvalue = ~nl any - headers = "headers" st* "{" pairlist? tagend + headers = "headers" pairblock + headersdisabled = "headers:disabled" pairblock + pairblock = st* "{" pairlist? tagend pairlist = nl* pair (~tagend nl pair)* (~tagend space)* pair = st* key st* ":" st* value? st* key = ~tagend validkey* @@ -38,6 +40,12 @@ const mapPairListToKeyValPairs = (pairList = [], enabled = true) => { }); }; +const concatArrays = (objValue, srcValue) => { + if (_.isArray(objValue) && _.isArray(srcValue)) { + return objValue.concat(srcValue); + } +}; + const sem = grammar.createSemantics().addAttribute('ast', { BruFile(tags) { if(!tags || !tags.ast || !tags.ast.length) { @@ -45,14 +53,22 @@ const sem = grammar.createSemantics().addAttribute('ast', { } return _.reduce(tags.ast, (result, item) => { - return _.assign(result, item); + return _.mergeWith(result, item, concatArrays); }, {}); }, - headers(_1, _2, _3, pairlist, _4) { + headers(_1, pairblock) { return { - headers: mapPairListToKeyValPairs(pairlist.ast) + headers: mapPairListToKeyValPairs(pairblock.ast) }; }, + headersdisabled(_1, pairblock) { + return { + headers: mapPairListToKeyValPairs(pairblock.ast, false) + }; + }, + pairblock(_1, _2, pairlist, _3) { + return pairlist.ast; + }, pairlist(_1, pair, _2, rest, _3) { return [pair.ast, ...rest.ast]; }, diff --git a/packages/bruno-lang/v2/tests/headers.spec.js b/packages/bruno-lang/v2/tests/headers.spec.js index 64c729841..56b0de46a 100644 --- a/packages/bruno-lang/v2/tests/headers.spec.js +++ b/packages/bruno-lang/v2/tests/headers.spec.js @@ -95,6 +95,23 @@ headers { expect(output).toEqual(expected); }); + it("should parse disabled headers", () => { + const input = ` +headers:disabled { + content-type: application/json +}`; + + const output = bruToJsonV2(input); + const expected = { + "headers": [{ + "name": "content-type", + "value": "application/json", + "enabled": false + }] + }; + expect(output).toEqual(expected); + }); + it("should throw error on invalid header", () => { const input = ` headers { diff --git a/packages/bruno-lang/v2/tests/index.spec.js b/packages/bruno-lang/v2/tests/index.spec.js index 2ad905ed6..d260d8b57 100644 --- a/packages/bruno-lang/v2/tests/index.spec.js +++ b/packages/bruno-lang/v2/tests/index.spec.js @@ -4,8 +4,12 @@ describe("parser", () => { it("should parse the bru file", () => { const input = ` headers { - hello: world - foo: bar + content-type: application/json + Authorization: Bearer 123 +} + +headers:disabled { + transaction-id: {{transactionId}} } script { @@ -19,18 +23,24 @@ script { const expected = { "headers": [ { - "name": "hello", - "value": "world", + "name": "content-type", + "value": "application/json", "enabled": true }, { - "name": "foo", - "value": "bar", + "name": "Authorization", + "value": "Bearer 123", "enabled": true + }, + { + "name": "transaction-id", + "value": "{{transactionId}}", + "enabled": false } ], "script": " function onResponse(request, response) {\n expect(response.status).to.equal(200);\n }" } + expect(output).toEqual(expected); }); }); From 689d886e746953b82e6172c9267a4c776f0c7f7f Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Sat, 4 Feb 2023 06:06:02 +0530 Subject: [PATCH 07/10] feat: bru lang - support for body type parsing --- packages/bruno-lang/v2/src/index.js | 95 ++++++++++++++++- packages/bruno-lang/v2/tests/index.spec.js | 118 +++++++++++++++++++++ 2 files changed, 212 insertions(+), 1 deletion(-) diff --git a/packages/bruno-lang/v2/src/index.js b/packages/bruno-lang/v2/src/index.js index 3863060d0..ae10df892 100644 --- a/packages/bruno-lang/v2/src/index.js +++ b/packages/bruno-lang/v2/src/index.js @@ -2,7 +2,9 @@ const ohm = require("ohm-js"); const _ = require('lodash'); const grammar = ohm.grammar(`Bru { - BruFile = (script | test | headersdisabled | headers)* + BruFile = (script | test | querydisabled | query | headersdisabled | headers | bodies )* + bodies = bodyjson | bodytext | bodyxml | bodygraphql | bodygraphqlvars | bodyforms + bodyforms = bodyformurlencodeddisabled | bodyformurlencoded | bodymultipartdisabled | bodymultipart nl = "\\r"? "\\n" st = " " | "\\t" tagend = nl "}" @@ -12,12 +14,26 @@ const grammar = ohm.grammar(`Bru { headers = "headers" pairblock headersdisabled = "headers:disabled" pairblock + query = "query" pairblock + querydisabled = "query:disabled" pairblock + pairblock = st* "{" pairlist? tagend pairlist = nl* pair (~tagend nl pair)* (~tagend space)* pair = st* key st* ":" st* value? st* key = ~tagend validkey* value = ~tagend validvalue* + bodyjson = "body:json" st* "{" nl* textblock tagend + bodytext = "body:text" st* "{" nl* textblock tagend + bodyxml = "body:xml" st* "{" nl* textblock tagend + bodygraphql = "body:graphql" st* "{" nl* textblock tagend + bodygraphqlvars = "body:graphql:vars" st* "{" nl* textblock tagend + + bodyformurlencoded = "body:form-urlencoded" pairblock + bodyformurlencodeddisabled = "body:form-urlencoded:disabled" pairblock + bodymultipart = "body:multipart-form" pairblock + bodymultipartdisabled = "body:multipart-form:disabled" pairblock + script = "script" st* "{" nl* textblock tagend test = "test" st* "{" textblock tagend @@ -56,6 +72,16 @@ const sem = grammar.createSemantics().addAttribute('ast', { return _.mergeWith(result, item, concatArrays); }, {}); }, + query(_1, pairblock) { + return { + query: mapPairListToKeyValPairs(pairblock.ast) + }; + }, + querydisabled(_1, pairblock) { + return { + query: mapPairListToKeyValPairs(pairblock.ast, false) + }; + }, headers(_1, pairblock) { return { headers: mapPairListToKeyValPairs(pairblock.ast) @@ -83,6 +109,73 @@ const sem = grammar.createSemantics().addAttribute('ast', { value(chars) { return chars.sourceString ? chars.sourceString.trim() : ''; }, + bodyformurlencoded(_1, pairblock) { + return { + body: { + formUrlEncoded: mapPairListToKeyValPairs(pairblock.ast) + } + }; + }, + bodyformurlencodeddisabled(_1, pairblock) { + return { + body: { + formUrlEncoded: mapPairListToKeyValPairs(pairblock.ast, false) + } + }; + }, + bodymultipart(_1, pairblock) { + return { + body: { + multipartForm: mapPairListToKeyValPairs(pairblock.ast) + } + }; + }, + bodymultipartdisabled(_1, pairblock) { + return { + body: { + multipartForm: mapPairListToKeyValPairs(pairblock.ast, false) + } + }; + }, + bodyjson(_1, _2, _3, _4, textblock, _5) { + return { + body: { + json: textblock.sourceString + } + }; + }, + bodytext(_1, _2, _3, _4, textblock, _5) { + return { + body: { + text: textblock.sourceString + } + }; + }, + bodyxml(_1, _2, _3, _4, textblock, _5) { + return { + body: { + xml: textblock.sourceString + } + }; + }, + bodygraphql(_1, _2, _3, _4, textblock, _5) { + return { + body: { + graphql: { + query: textblock.sourceString + } + } + }; + }, + bodygraphqlvars(_1, _2, _3, _4, textblock, _5) { + return { + body: { + graphql: { + variables: textblock.sourceString + } + } + }; + }, script(_1, _2, _3, _4, textblock, _5) { return { script: textblock.sourceString diff --git a/packages/bruno-lang/v2/tests/index.spec.js b/packages/bruno-lang/v2/tests/index.spec.js index d260d8b57..ad9e3bfbd 100644 --- a/packages/bruno-lang/v2/tests/index.spec.js +++ b/packages/bruno-lang/v2/tests/index.spec.js @@ -3,6 +3,15 @@ const parser = require("../src/index"); describe("parser", () => { it("should parse the bru file", () => { const input = ` +query { + apiKey: secret + numbers: 998877665 +} + +query:disabled { + message: hello +} + headers { content-type: application/json Authorization: Bearer 123 @@ -12,6 +21,58 @@ headers:disabled { transaction-id: {{transactionId}} } +body:form-urlencoded { + apikey: secret + numbers: +91998877665 +} + +body:form-urlencoded:disabled { + message: hello +} + +body:multipart-form { + apikey: secret + numbers: +91998877665 +} + +body:multipart-form:disabled { + message: hello +} + +body:json { + { + "hello": "world" + } +} + +body:text { + This is a text body +} + +body:xml { + + John + 30 + +} + +body:graphql { + { + launchesPast { + launch_site { + site_name + } + launch_success + } + } +} + +body:graphql:vars { + { + "limit": 5 + } +} + script { function onResponse(request, response) { expect(response.status).to.equal(200); @@ -21,6 +82,19 @@ script { const output = parser(input); const expected = { + "query": [{ + "name": "apiKey", + "value": "secret", + "enabled": true + }, { + "name": "numbers", + "value": "998877665", + "enabled": true + }, { + "name": "message", + "value": "hello", + "enabled": false + }], "headers": [ { "name": "content-type", @@ -38,9 +112,53 @@ script { "enabled": false } ], + "body": { + "json": " {\n \"hello\": \"world\"\n }", + "text": " This is a text body", + "xml": " \n John\n 30\n ", + "graphql": { + "query": " {\n launchesPast {\n launch_site {\n site_name\n }\n launch_success\n }\n }", + "variables": " {\n \"limit\": 5\n }" + }, + "formUrlEncoded": [ + { + "name": "apikey", + "value": "secret", + "enabled": true + }, + { + "name": "numbers", + "value": "+91998877665", + "enabled": true + }, + { + "name": "message", + "value": "hello", + "enabled": false + } + ], + "multipartForm": [ + { + "name": "apikey", + "value": "secret", + "enabled": true + }, + { + "name": "numbers", + "value": "+91998877665", + "enabled": true + }, + { + "name": "message", + "value": "hello", + "enabled": false + } + ] + }, "script": " function onResponse(request, response) {\n expect(response.status).to.equal(200);\n }" } + // console.log(JSON.stringify(output, null, 2)); expect(output).toEqual(expected); }); }); From e7d332c7d7826b9defe3e9a9fb4f369554547de9 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Sat, 4 Feb 2023 16:02:27 +0530 Subject: [PATCH 08/10] feat: bru lang - support for vars, asserts and docs --- packages/bruno-lang/v2/src/index.js | 247 ++++++++++++++++----- packages/bruno-lang/v2/tests/index.spec.js | 90 +++++++- 2 files changed, 285 insertions(+), 52 deletions(-) diff --git a/packages/bruno-lang/v2/src/index.js b/packages/bruno-lang/v2/src/index.js index ae10df892..b21459cc3 100644 --- a/packages/bruno-lang/v2/src/index.js +++ b/packages/bruno-lang/v2/src/index.js @@ -1,45 +1,88 @@ const ohm = require("ohm-js"); const _ = require('lodash'); +/** + * A Bru file is made up of blocks. + * There are two types of blocks + * + * 1. Dictionary Blocks - These are blocks that have key value pairs + * ex: + * headers { + * content-type: application/json + * } + * + * 2. Text Blocks - These are blocks that have text + * ex: + * body:json { + * { + * "username": "John Nash", + * "password": "governingdynamics + * } + * + */ const grammar = ohm.grammar(`Bru { - BruFile = (script | test | querydisabled | query | headersdisabled | headers | bodies )* + BruFile = (meta | http | querydisabled | query | headersdisabled | headers | bodies | varsandassert | script | test | docs)* bodies = bodyjson | bodytext | bodyxml | bodygraphql | bodygraphqlvars | bodyforms bodyforms = bodyformurlencodeddisabled | bodyformurlencoded | bodymultipartdisabled | bodymultipart + nl = "\\r"? "\\n" st = " " | "\\t" tagend = nl "}" validkey = ~(st | ":") any validvalue = ~nl any - headers = "headers" pairblock - headersdisabled = "headers:disabled" pairblock - - query = "query" pairblock - querydisabled = "query:disabled" pairblock - - pairblock = st* "{" pairlist? tagend + // Dictionary Blocks + dictionary = st* "{" pairlist? tagend pairlist = nl* pair (~tagend nl pair)* (~tagend space)* pair = st* key st* ":" st* value? st* key = ~tagend validkey* value = ~tagend validvalue* + // Text Blocks + textblock = textline (~tagend nl textline)* + textline = textchar* + textchar = ~nl any + + meta = "meta" dictionary + + http = get | post | put | delete | options | head | connect | trace + get = "get" dictionary + post = "post" dictionary + put = "put" dictionary + delete = "delete" dictionary + options = "options" dictionary + head = "head" dictionary + connect = "connect" dictionary + trace = "trace" dictionary + + headers = "headers" dictionary + headersdisabled = "headers:disabled" dictionary + + query = "query" dictionary + querydisabled = "query:disabled" dictionary + + varsandassert = vars | varsdisabled | varslocal | varslocaldisabled | assert | assertdisabled + vars = "vars" dictionary + varsdisabled = "vars:disabled" dictionary + varslocal = "vars:local" dictionary + varslocaldisabled = "vars:local:disabled" dictionary + assert = "assert" dictionary + assertdisabled = "assert:disabled" dictionary + bodyjson = "body:json" st* "{" nl* textblock tagend bodytext = "body:text" st* "{" nl* textblock tagend bodyxml = "body:xml" st* "{" nl* textblock tagend bodygraphql = "body:graphql" st* "{" nl* textblock tagend bodygraphqlvars = "body:graphql:vars" st* "{" nl* textblock tagend - bodyformurlencoded = "body:form-urlencoded" pairblock - bodyformurlencodeddisabled = "body:form-urlencoded:disabled" pairblock - bodymultipart = "body:multipart-form" pairblock - bodymultipartdisabled = "body:multipart-form:disabled" pairblock + bodyformurlencoded = "body:form-urlencoded" dictionary + bodyformurlencodeddisabled = "body:form-urlencoded:disabled" dictionary + bodymultipart = "body:multipart-form" dictionary + bodymultipartdisabled = "body:multipart-form:disabled" dictionary script = "script" st* "{" nl* textblock tagend - test = "test" st* "{" textblock tagend - - textblock = textline (~tagend nl textline)* - textline = textchar* - textchar = ~nl any + test = "test" st* "{" nl* textblock tagend + docs = "docs" st* "{" nl* textblock tagend }`); const mapPairListToKeyValPairs = (pairList = [], enabled = true) => { @@ -62,6 +105,14 @@ const concatArrays = (objValue, srcValue) => { } }; +const mapPairListToKeyValPair = (pairList = []) => { + if(!pairList || !pairList.length) { + return {}; + } + + return _.merge({}, ...pairList[0]); +} + const sem = grammar.createSemantics().addAttribute('ast', { BruFile(tags) { if(!tags || !tags.ast || !tags.ast.length) { @@ -72,27 +123,7 @@ const sem = grammar.createSemantics().addAttribute('ast', { return _.mergeWith(result, item, concatArrays); }, {}); }, - query(_1, pairblock) { - return { - query: mapPairListToKeyValPairs(pairblock.ast) - }; - }, - querydisabled(_1, pairblock) { - return { - query: mapPairListToKeyValPairs(pairblock.ast, false) - }; - }, - headers(_1, pairblock) { - return { - headers: mapPairListToKeyValPairs(pairblock.ast) - }; - }, - headersdisabled(_1, pairblock) { - return { - headers: mapPairListToKeyValPairs(pairblock.ast, false) - }; - }, - pairblock(_1, _2, pairlist, _3) { + dictionary(_1, _2, pairlist, _3) { return pairlist.ast; }, pairlist(_1, pair, _2, rest, _3) { @@ -109,31 +140,112 @@ const sem = grammar.createSemantics().addAttribute('ast', { value(chars) { return chars.sourceString ? chars.sourceString.trim() : ''; }, - bodyformurlencoded(_1, pairblock) { + meta(_1, dictionary) { return { - body: { - formUrlEncoded: mapPairListToKeyValPairs(pairblock.ast) + meta: mapPairListToKeyValPair(dictionary.ast) + }; + }, + get(_1, dictionary) { + return { + http: { + method: 'GET', + ...mapPairListToKeyValPair(dictionary.ast) } }; }, - bodyformurlencodeddisabled(_1, pairblock) { + post(_1, dictionary) { return { - body: { - formUrlEncoded: mapPairListToKeyValPairs(pairblock.ast, false) + http: { + method: 'POST', + ...mapPairListToKeyValPair(dictionary.ast) } }; }, - bodymultipart(_1, pairblock) { + put(_1, dictionary) { return { - body: { - multipartForm: mapPairListToKeyValPairs(pairblock.ast) + http: { + method: 'PUT', + ...mapPairListToKeyValPair(dictionary.ast) } }; }, - bodymultipartdisabled(_1, pairblock) { + delete(_1, dictionary) { + return { + http: { + method: 'DELETE', + ...mapPairListToKeyValPair(dictionary.ast) + } + }; + }, + options(_1, dictionary) { + return { + http: { + method: 'OPTIONS', + ...mapPairListToKeyValPair(dictionary.ast) + } + }; + }, + head(_1, dictionary) { + return { + http: { + method: 'HEAD', + ...mapPairListToKeyValPair(dictionary.ast) + } + }; + }, + connect(_1, dictionary) { + return { + http: { + method: 'CONNECT', + ...mapPairListToKeyValPair(dictionary.ast) + } + }; + }, + query(_1, dictionary) { + return { + query: mapPairListToKeyValPairs(dictionary.ast) + }; + }, + querydisabled(_1, dictionary) { + return { + query: mapPairListToKeyValPairs(dictionary.ast, false) + }; + }, + headers(_1, dictionary) { + return { + headers: mapPairListToKeyValPairs(dictionary.ast) + }; + }, + headersdisabled(_1, dictionary) { + return { + headers: mapPairListToKeyValPairs(dictionary.ast, false) + }; + }, + bodyformurlencoded(_1, dictionary) { return { body: { - multipartForm: mapPairListToKeyValPairs(pairblock.ast, false) + formUrlEncoded: mapPairListToKeyValPairs(dictionary.ast) + } + }; + }, + bodyformurlencodeddisabled(_1, dictionary) { + return { + body: { + formUrlEncoded: mapPairListToKeyValPairs(dictionary.ast, false) + } + }; + }, + bodymultipart(_1, dictionary) { + return { + body: { + multipartForm: mapPairListToKeyValPairs(dictionary.ast) + } + }; + }, + bodymultipartdisabled(_1, dictionary) { + return { + body: { + multipartForm: mapPairListToKeyValPairs(dictionary.ast, false) } }; }, @@ -176,16 +288,51 @@ const sem = grammar.createSemantics().addAttribute('ast', { } }; }, + vars(_1, dictionary) { + return { + vars: mapPairListToKeyValPairs(dictionary.ast) + }; + }, + varsdisabled(_1, dictionary) { + return { + vars: mapPairListToKeyValPairs(dictionary.ast, false) + }; + }, + varslocal(_1, dictionary) { + return { + varsLocal: mapPairListToKeyValPairs(dictionary.ast) + }; + }, + varslocaldisabled(_1, dictionary) { + return { + varsLocal: mapPairListToKeyValPairs(dictionary.ast, false) + }; + }, + assert(_1, dictionary) { + return { + assert: mapPairListToKeyValPairs(dictionary.ast) + }; + }, + assertdisabled(_1, dictionary) { + return { + assert: mapPairListToKeyValPairs(dictionary.ast, false) + }; + }, script(_1, _2, _3, _4, textblock, _5) { return { script: textblock.sourceString }; }, - test(_1, _2, _3, textblock, _4) { + test(_1, _2, _3, _4, textblock, _5) { return { test: textblock.sourceString };; }, + docs(_1, _2, _3, _4, textblock, _5) { + return { + docs: textblock.sourceString + }; + }, textblock(line, _1, rest) { return [line.ast, ...rest.ast].join('\n'); }, diff --git a/packages/bruno-lang/v2/tests/index.spec.js b/packages/bruno-lang/v2/tests/index.spec.js index ad9e3bfbd..53ef20d68 100644 --- a/packages/bruno-lang/v2/tests/index.spec.js +++ b/packages/bruno-lang/v2/tests/index.spec.js @@ -3,6 +3,17 @@ const parser = require("../src/index"); describe("parser", () => { it("should parse the bru file", () => { const input = ` +meta { + name: Send Bulk SMS + type: http + seq: 1 +} + +get { + url: https://api.textlocal.in/send/ + body: json +} + query { apiKey: secret numbers: 998877665 @@ -73,15 +84,53 @@ body:graphql:vars { } } -script { +vars { + token: $res.body.token +} + +vars:disabled { + petId: $res.body.id +} + +vars:local { + orderNumber: $res.body.orderNumber +} + +vars:local:disabled { + transactionId: $res.body.transactionId +} + +assert { + $res.status: 200 +} + +assert:disabled { + $res.body.message: success +} + +test { function onResponse(request, response) { expect(response.status).to.equal(200); } } + +docs { + This request needs auth token to be set in the headers. +} `; const output = parser(input); const expected = { + "meta": { + "name": "Send Bulk SMS", + "type": "http", + "seq": "1" + }, + "http": { + "method": "GET", + "url": "https://api.textlocal.in/send/", + "body": "json" + }, "query": [{ "name": "apiKey", "value": "secret", @@ -155,7 +204,44 @@ script { } ] }, - "script": " function onResponse(request, response) {\n expect(response.status).to.equal(200);\n }" + "vars": [ + { + "name": "token", + "value": "$res.body.token", + "enabled": true + }, + { + "name": "petId", + "value": "$res.body.id", + "enabled": false + } + ], + "varsLocal": [ + { + "name": "orderNumber", + "value": "$res.body.orderNumber", + "enabled": true + }, + { + "name": "transactionId", + "value": "$res.body.transactionId", + "enabled": false + } + ], + "assert": [ + { + "name": "$res.status", + "value": "200", + "enabled": true + }, + { + "name": "$res.body.message", + "value": "success", + "enabled": false + } + ], + "test": " function onResponse(request, response) {\n expect(response.status).to.equal(200);\n }", + "docs": " This request needs auth token to be set in the headers." } // console.log(JSON.stringify(output, null, 2)); From 342a39bcb4833d2a530d276b3131485282f9ec11 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Sat, 4 Feb 2023 16:06:32 +0530 Subject: [PATCH 09/10] chore: renamed test files --- .../{headers.spec.js => dictionary.spec.js} | 20 +++++++++++-------- .../v2/tests/{script.spec.js => text.spec.js} | 3 +++ 2 files changed, 15 insertions(+), 8 deletions(-) rename packages/bruno-lang/v2/tests/{headers.spec.js => dictionary.spec.js} (85%) rename packages/bruno-lang/v2/tests/{script.spec.js => text.spec.js} (88%) diff --git a/packages/bruno-lang/v2/tests/headers.spec.js b/packages/bruno-lang/v2/tests/dictionary.spec.js similarity index 85% rename from packages/bruno-lang/v2/tests/headers.spec.js rename to packages/bruno-lang/v2/tests/dictionary.spec.js index 56b0de46a..46d5b31f7 100644 --- a/packages/bruno-lang/v2/tests/headers.spec.js +++ b/packages/bruno-lang/v2/tests/dictionary.spec.js @@ -1,7 +1,11 @@ -const bruToJsonV2 = require("../src/index"); +/** + * This test file is used to test the text parser. + */ + +const parser = require("../src/index"); const assertSingleHeader = (input) => { - const output = bruToJsonV2(input); + const output = parser(input); const expected = { "headers": [{ @@ -19,7 +23,7 @@ describe("headers parser", () => { headers { }`; - const output = bruToJsonV2(input); + const output = parser(input); const expected = { "headers": [] }; @@ -62,7 +66,7 @@ headers { hello: }`; - const output = bruToJsonV2(input); + const output = parser(input); const expected = { "headers": [{ "name": "hello", @@ -80,7 +84,7 @@ headers { Authorization: JWT secret }`; - const output = bruToJsonV2(input); + const output = parser(input); const expected = { "headers": [{ "name": "content-type", @@ -101,7 +105,7 @@ headers:disabled { content-type: application/json }`; - const output = bruToJsonV2(input); + const output = parser(input); const expected = { "headers": [{ "name": "content-type", @@ -119,7 +123,7 @@ headers { foo }`; - expect(() => bruToJsonV2(input)).toThrow(); + expect(() => parser(input)).toThrow(); }); it("should throw error on invalid header", () => { @@ -128,7 +132,7 @@ headers { hello: world foo: bar}`; - expect(() => bruToJsonV2(input)).toThrow(); + expect(() => parser(input)).toThrow(); }); }); diff --git a/packages/bruno-lang/v2/tests/script.spec.js b/packages/bruno-lang/v2/tests/text.spec.js similarity index 88% rename from packages/bruno-lang/v2/tests/script.spec.js rename to packages/bruno-lang/v2/tests/text.spec.js index 4adf12a9f..caefa0874 100644 --- a/packages/bruno-lang/v2/tests/script.spec.js +++ b/packages/bruno-lang/v2/tests/text.spec.js @@ -1,3 +1,6 @@ +/** + * This test file is used to test the text parser. + */ const parser = require("../src/index"); describe("script parser", () => { From cf0ede1a83236136913fc3fa8ed2bc1d47999d0a Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Sat, 4 Feb 2023 16:11:29 +0530 Subject: [PATCH 10/10] chore: using fixtures to cleanup test file --- .../bruno-lang/v2/tests/fixtures/request.bru | 114 ++++++++ .../bruno-lang/v2/tests/fixtures/request.json | 123 +++++++++ packages/bruno-lang/v2/tests/index.spec.js | 244 +----------------- 3 files changed, 241 insertions(+), 240 deletions(-) create mode 100644 packages/bruno-lang/v2/tests/fixtures/request.bru create mode 100644 packages/bruno-lang/v2/tests/fixtures/request.json diff --git a/packages/bruno-lang/v2/tests/fixtures/request.bru b/packages/bruno-lang/v2/tests/fixtures/request.bru new file mode 100644 index 000000000..9db94d4dd --- /dev/null +++ b/packages/bruno-lang/v2/tests/fixtures/request.bru @@ -0,0 +1,114 @@ +meta { + name: Send Bulk SMS + type: http + seq: 1 +} + +get { + url: https://api.textlocal.in/send/ + body: json +} + +query { + apiKey: secret + numbers: 998877665 +} + +query:disabled { + message: hello +} + +headers { + content-type: application/json + Authorization: Bearer 123 +} + +headers:disabled { + transaction-id: {{transactionId}} +} + +body:form-urlencoded { + apikey: secret + numbers: +91998877665 +} + +body:form-urlencoded:disabled { + message: hello +} + +body:multipart-form { + apikey: secret + numbers: +91998877665 +} + +body:multipart-form:disabled { + message: hello +} + +body:json { + { + "hello": "world" + } +} + +body:text { + This is a text body +} + +body:xml { + + John + 30 + +} + +body:graphql { + { + launchesPast { + launch_site { + site_name + } + launch_success + } + } +} + +body:graphql:vars { + { + "limit": 5 + } +} + +vars { + token: $res.body.token +} + +vars:disabled { + petId: $res.body.id +} + +vars:local { + orderNumber: $res.body.orderNumber +} + +vars:local:disabled { + transactionId: $res.body.transactionId +} + +assert { + $res.status: 200 +} + +assert:disabled { + $res.body.message: success +} + +test { + function onResponse(request, response) { + expect(response.status).to.equal(200); + } +} + +docs { + This request needs auth token to be set in the headers. +} \ No newline at end of file diff --git a/packages/bruno-lang/v2/tests/fixtures/request.json b/packages/bruno-lang/v2/tests/fixtures/request.json new file mode 100644 index 000000000..167af5f60 --- /dev/null +++ b/packages/bruno-lang/v2/tests/fixtures/request.json @@ -0,0 +1,123 @@ +{ + "meta": { + "name": "Send Bulk SMS", + "type": "http", + "seq": "1" + }, + "http": { + "method": "GET", + "url": "https://api.textlocal.in/send/", + "body": "json" + }, + "query": [{ + "name": "apiKey", + "value": "secret", + "enabled": true + }, { + "name": "numbers", + "value": "998877665", + "enabled": true + }, { + "name": "message", + "value": "hello", + "enabled": false + }], + "headers": [ + { + "name": "content-type", + "value": "application/json", + "enabled": true + }, + { + "name": "Authorization", + "value": "Bearer 123", + "enabled": true + }, + { + "name": "transaction-id", + "value": "{{transactionId}}", + "enabled": false + } + ], + "body": { + "json": " {\n \"hello\": \"world\"\n }", + "text": " This is a text body", + "xml": " \n John\n 30\n ", + "graphql": { + "query": " {\n launchesPast {\n launch_site {\n site_name\n }\n launch_success\n }\n }", + "variables": " {\n \"limit\": 5\n }" + }, + "formUrlEncoded": [ + { + "name": "apikey", + "value": "secret", + "enabled": true + }, + { + "name": "numbers", + "value": "+91998877665", + "enabled": true + }, + { + "name": "message", + "value": "hello", + "enabled": false + } + ], + "multipartForm": [ + { + "name": "apikey", + "value": "secret", + "enabled": true + }, + { + "name": "numbers", + "value": "+91998877665", + "enabled": true + }, + { + "name": "message", + "value": "hello", + "enabled": false + } + ] + }, + "vars": [ + { + "name": "token", + "value": "$res.body.token", + "enabled": true + }, + { + "name": "petId", + "value": "$res.body.id", + "enabled": false + } + ], + "varsLocal": [ + { + "name": "orderNumber", + "value": "$res.body.orderNumber", + "enabled": true + }, + { + "name": "transactionId", + "value": "$res.body.transactionId", + "enabled": false + } + ], + "assert": [ + { + "name": "$res.status", + "value": "200", + "enabled": true + }, + { + "name": "$res.body.message", + "value": "success", + "enabled": false + } + ], + "test": " function onResponse(request, response) {\n expect(response.status).to.equal(200);\n }", + "docs": " This request needs auth token to be set in the headers." +} \ No newline at end of file diff --git a/packages/bruno-lang/v2/tests/index.spec.js b/packages/bruno-lang/v2/tests/index.spec.js index 53ef20d68..c33cd7630 100644 --- a/packages/bruno-lang/v2/tests/index.spec.js +++ b/packages/bruno-lang/v2/tests/index.spec.js @@ -1,248 +1,12 @@ +const fs = require("fs"); +const path = require("path"); const parser = require("../src/index"); describe("parser", () => { it("should parse the bru file", () => { - const input = ` -meta { - name: Send Bulk SMS - type: http - seq: 1 -} - -get { - url: https://api.textlocal.in/send/ - body: json -} - -query { - apiKey: secret - numbers: 998877665 -} - -query:disabled { - message: hello -} - -headers { - content-type: application/json - Authorization: Bearer 123 -} - -headers:disabled { - transaction-id: {{transactionId}} -} - -body:form-urlencoded { - apikey: secret - numbers: +91998877665 -} - -body:form-urlencoded:disabled { - message: hello -} - -body:multipart-form { - apikey: secret - numbers: +91998877665 -} - -body:multipart-form:disabled { - message: hello -} - -body:json { - { - "hello": "world" - } -} - -body:text { - This is a text body -} - -body:xml { - - John - 30 - -} - -body:graphql { - { - launchesPast { - launch_site { - site_name - } - launch_success - } - } -} - -body:graphql:vars { - { - "limit": 5 - } -} - -vars { - token: $res.body.token -} - -vars:disabled { - petId: $res.body.id -} - -vars:local { - orderNumber: $res.body.orderNumber -} - -vars:local:disabled { - transactionId: $res.body.transactionId -} - -assert { - $res.status: 200 -} - -assert:disabled { - $res.body.message: success -} - -test { - function onResponse(request, response) { - expect(response.status).to.equal(200); - } -} - -docs { - This request needs auth token to be set in the headers. -} -`; - + const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'request.bru'), 'utf8'); + const expected = require("./fixtures/request.json"); const output = parser(input); - const expected = { - "meta": { - "name": "Send Bulk SMS", - "type": "http", - "seq": "1" - }, - "http": { - "method": "GET", - "url": "https://api.textlocal.in/send/", - "body": "json" - }, - "query": [{ - "name": "apiKey", - "value": "secret", - "enabled": true - }, { - "name": "numbers", - "value": "998877665", - "enabled": true - }, { - "name": "message", - "value": "hello", - "enabled": false - }], - "headers": [ - { - "name": "content-type", - "value": "application/json", - "enabled": true - }, - { - "name": "Authorization", - "value": "Bearer 123", - "enabled": true - }, - { - "name": "transaction-id", - "value": "{{transactionId}}", - "enabled": false - } - ], - "body": { - "json": " {\n \"hello\": \"world\"\n }", - "text": " This is a text body", - "xml": " \n John\n 30\n ", - "graphql": { - "query": " {\n launchesPast {\n launch_site {\n site_name\n }\n launch_success\n }\n }", - "variables": " {\n \"limit\": 5\n }" - }, - "formUrlEncoded": [ - { - "name": "apikey", - "value": "secret", - "enabled": true - }, - { - "name": "numbers", - "value": "+91998877665", - "enabled": true - }, - { - "name": "message", - "value": "hello", - "enabled": false - } - ], - "multipartForm": [ - { - "name": "apikey", - "value": "secret", - "enabled": true - }, - { - "name": "numbers", - "value": "+91998877665", - "enabled": true - }, - { - "name": "message", - "value": "hello", - "enabled": false - } - ] - }, - "vars": [ - { - "name": "token", - "value": "$res.body.token", - "enabled": true - }, - { - "name": "petId", - "value": "$res.body.id", - "enabled": false - } - ], - "varsLocal": [ - { - "name": "orderNumber", - "value": "$res.body.orderNumber", - "enabled": true - }, - { - "name": "transactionId", - "value": "$res.body.transactionId", - "enabled": false - } - ], - "assert": [ - { - "name": "$res.status", - "value": "200", - "enabled": true - }, - { - "name": "$res.body.message", - "value": "success", - "enabled": false - } - ], - "test": " function onResponse(request, response) {\n expect(response.status).to.equal(200);\n }", - "docs": " This request needs auth token to be set in the headers." - } // console.log(JSON.stringify(output, null, 2)); expect(output).toEqual(expected);