feat: brun lang - ast updates, tests for headers and script tags

This commit is contained in:
Anoop M D 2023-02-03 21:08:40 +05:30
parent 9d6ba4691c
commit 2ee2e270b0
4 changed files with 177 additions and 23 deletions

View File

@ -1,4 +1,5 @@
const ohm = require("ohm-js"); const ohm = require("ohm-js");
const _ = require('lodash');
const grammar = ohm.grammar(`Bru { const grammar = ohm.grammar(`Bru {
BruFile = (script | test | headers)* BruFile = (script | test | headers)*
@ -6,14 +7,14 @@ const grammar = ohm.grammar(`Bru {
st = " " | "\\t" st = " " | "\\t"
tagend = nl "}" 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* pair = st* key st* ":" st* val st*
key = alnum* key = ~tagend alnum*
val = letter* val = ~tagend letter*
script = "script" st* "{" codeblock tagend script = "script" st* "{" nl* codeblock tagend
test = "test" st* "{" codeblock tagend test = "test" st* "{" codeblock tagend
codeblock = codeline (~tagend nl codeline)* codeblock = codeline (~tagend nl codeline)*
@ -21,11 +22,36 @@ const grammar = ohm.grammar(`Bru {
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', { const sem = grammar.createSemantics().addAttribute('ast', {
headers(_1, _2, _3, _4, pairlist, _5) { BruFile(tags) {
return pairlist.ast; 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]; return [pair.ast, ...rest.ast];
}, },
pair(_1, key, _2, _3, _4, val, _5) { pair(_1, key, _2, _3, _4, val, _5) {
@ -39,11 +65,15 @@ const sem = grammar.createSemantics().addAttribute('ast', {
val(chars) { val(chars) {
return chars.sourceString; return chars.sourceString;
}, },
script(_1, _2, _3, codeblock, _4) { script(_1, _2, _3, _4, codeblock, _5) {
return codeblock.sourceString; return {
script: codeblock.sourceString
};
}, },
test(_1, _2, _3, codeblock, _4) { test(_1, _2, _3, codeblock, _4) {
return codeblock.sourceString; return {
test: codeblock.sourceString
};;
}, },
codeblock(line, _1, rest) { codeblock(line, _1, rest) {
return [line.ast, ...rest.ast].join('\n'); return [line.ast, ...rest.ast].join('\n');
@ -74,8 +104,6 @@ const parser = (input) => {
if(match.succeeded()) { if(match.succeeded()) {
return sem(match).ast; return sem(match).ast;
} else { } else {
console.log('match.message=========');
console.log(match.message);
throw new Error(match.message); throw new Error(match.message);
} }
} }

View File

@ -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();
});
});

View File

@ -1,19 +1,13 @@
const parser = require("../src/index"); const parser = require("../src/index");
describe("parser", () => { describe("parser", () => {
it("should parse headers", () => { it("should parse the bru file", () => {
const input = ` const input = `
headers { headers {
hello: world hello: world
foo: bar foo: bar
}`; }
const output = parser(input);
console.log(output);
});
it("should parse script body", () => {
const input = `
script { script {
function onResponse(request, response) { function onResponse(request, response) {
expect(response.status).to.equal(200); expect(response.status).to.equal(200);
@ -22,6 +16,21 @@ script {
`; `;
const output = parser(input); 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);
}); });
}); });

View File

@ -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);
});
});