feat: bru lang - supporting ~ @ identifiers

This commit is contained in:
Anoop M D 2023-02-05 23:13:18 +05:30
parent 84bd603e11
commit a0cb53445f
5 changed files with 127 additions and 223 deletions

View File

@ -24,9 +24,9 @@ const {
* *
*/ */
const grammar = ohm.grammar(`Bru { const grammar = ohm.grammar(`Bru {
BruFile = (meta | http | querydisabled | query | headersdisabled | headers | bodies | varsandassert | script | tests | docs)* BruFile = (meta | http | query | headers | bodies | varsandassert | script | tests | docs)*
bodies = bodyjson | bodytext | bodyxml | bodygraphql | bodygraphqlvars | bodyforms bodies = bodyjson | bodytext | bodyxml | bodygraphql | bodygraphqlvars | bodyforms
bodyforms = bodyformurlencodeddisabled | bodyformurlencoded | bodymultipartdisabled | bodymultipart bodyforms = bodyformurlencoded | bodymultipart
nl = "\\r"? "\\n" nl = "\\r"? "\\n"
st = " " | "\\t" st = " " | "\\t"
@ -59,18 +59,13 @@ const grammar = ohm.grammar(`Bru {
trace = "trace" dictionary trace = "trace" dictionary
headers = "headers" dictionary headers = "headers" dictionary
headersdisabled = "headers:disabled" dictionary
query = "query" dictionary query = "query" dictionary
querydisabled = "query:disabled" dictionary
varsandassert = vars | varsdisabled | varslocal | varslocaldisabled | assert | assertdisabled varsandassert = vars | varslocal | assert
vars = "vars" dictionary vars = "vars" dictionary
varsdisabled = "vars:disabled" dictionary
varslocal = "vars:local" dictionary varslocal = "vars:local" dictionary
varslocaldisabled = "vars:local:disabled" dictionary
assert = "assert" dictionary assert = "assert" dictionary
assertdisabled = "assert:disabled" dictionary
bodyjson = "body:json" st* "{" nl* textblock tagend bodyjson = "body:json" st* "{" nl* textblock tagend
bodytext = "body:text" st* "{" nl* textblock tagend bodytext = "body:text" st* "{" nl* textblock tagend
@ -79,25 +74,30 @@ const grammar = ohm.grammar(`Bru {
bodygraphqlvars = "body:graphql:vars" st* "{" nl* textblock tagend bodygraphqlvars = "body:graphql:vars" st* "{" nl* textblock tagend
bodyformurlencoded = "body:form-urlencoded" dictionary bodyformurlencoded = "body:form-urlencoded" dictionary
bodyformurlencodeddisabled = "body:form-urlencoded:disabled" dictionary
bodymultipart = "body:multipart-form" dictionary bodymultipart = "body:multipart-form" dictionary
bodymultipartdisabled = "body:multipart-form:disabled" dictionary
script = "script" st* "{" nl* textblock tagend script = "script" st* "{" nl* textblock tagend
tests = "tests" st* "{" nl* textblock tagend tests = "tests" st* "{" nl* textblock tagend
docs = "docs" st* "{" nl* textblock tagend docs = "docs" st* "{" nl* textblock tagend
}`); }`);
const mapPairListToKeyValPairs = (pairList = [], enabled = true) => { const mapPairListToKeyValPairs = (pairList = []) => {
if(!pairList.length) { if(!pairList.length) {
return []; return [];
} }
return _.map(pairList[0], pair => { return _.map(pairList[0], pair => {
const key = _.keys(pair)[0]; let name = _.keys(pair)[0];
let value = pair[name];
let enabled = true;
if (name && name.length && name.charAt(0) === "~") {
name = name.slice(1);
enabled = false;
}
return { return {
name: key, name,
value: pair[key], value,
enabled: enabled enabled
}; };
}); });
}; };
@ -143,6 +143,27 @@ const sem = grammar.createSemantics().addAttribute('ast', {
value(chars) { value(chars) {
return chars.sourceString ? chars.sourceString.trim() : ''; return chars.sourceString ? chars.sourceString.trim() : '';
}, },
textblock(line, _1, rest) {
return [line.ast, ...rest.ast].join('\n');
},
textline(chars) {
return chars.sourceString;
},
textchar(char) {
return char.sourceString;
},
nl(_1, _2) {
return '';
},
st(_) {
return '';
},
tagend(_1 ,_2) {
return '';
},
_iter(...elements) {
return elements.map(e => e.ast);
},
meta(_1, dictionary) { meta(_1, dictionary) {
return { return {
meta: mapPairListToKeyValPair(dictionary.ast) meta: mapPairListToKeyValPair(dictionary.ast)
@ -209,21 +230,11 @@ const sem = grammar.createSemantics().addAttribute('ast', {
query: mapPairListToKeyValPairs(dictionary.ast) query: mapPairListToKeyValPairs(dictionary.ast)
}; };
}, },
querydisabled(_1, dictionary) {
return {
query: mapPairListToKeyValPairs(dictionary.ast, false)
};
},
headers(_1, dictionary) { headers(_1, dictionary) {
return { return {
headers: mapPairListToKeyValPairs(dictionary.ast) headers: mapPairListToKeyValPairs(dictionary.ast)
}; };
}, },
headersdisabled(_1, dictionary) {
return {
headers: mapPairListToKeyValPairs(dictionary.ast, false)
};
},
bodyformurlencoded(_1, dictionary) { bodyformurlencoded(_1, dictionary) {
return { return {
body: { body: {
@ -231,13 +242,6 @@ const sem = grammar.createSemantics().addAttribute('ast', {
} }
}; };
}, },
bodyformurlencodeddisabled(_1, dictionary) {
return {
body: {
formUrlEncoded: mapPairListToKeyValPairs(dictionary.ast, false)
}
};
},
bodymultipart(_1, dictionary) { bodymultipart(_1, dictionary) {
return { return {
body: { body: {
@ -245,13 +249,6 @@ const sem = grammar.createSemantics().addAttribute('ast', {
} }
}; };
}, },
bodymultipartdisabled(_1, dictionary) {
return {
body: {
multipartForm: mapPairListToKeyValPairs(dictionary.ast, false)
}
};
},
bodyjson(_1, _2, _3, _4, textblock, _5) { bodyjson(_1, _2, _3, _4, textblock, _5) {
return { return {
body: { body: {
@ -293,42 +290,25 @@ const sem = grammar.createSemantics().addAttribute('ast', {
}, },
vars(_1, dictionary) { vars(_1, dictionary) {
const vars = mapPairListToKeyValPairs(dictionary.ast); const vars = mapPairListToKeyValPairs(dictionary.ast);
_.each(vars, (val) => { val.local = false; }); _.each(vars, (v) => {
let name = v.name;
if (name && name.length && name.charAt(0) === "@") {
v.name = name.slice(1);
v.local = true;
} else {
v.local = false;
}
});
return { return {
vars vars
}; };
}, },
varsdisabled(_1, dictionary) {
const vars = mapPairListToKeyValPairs(dictionary.ast, false);
_.each(vars, (val) => { val.local = false; });
return {
vars
};
},
varslocal(_1, dictionary) {
const varsLocal = mapPairListToKeyValPairs(dictionary.ast);
_.each(varsLocal, (val) => { val.local = true; });
return {
vars: varsLocal
};
},
varslocaldisabled(_1, dictionary) {
const varsLocal = mapPairListToKeyValPairs(dictionary.ast, false);
_.each(varsLocal, (val) => { val.local = true; });
return {
vars: varsLocal
};
},
assert(_1, dictionary) { assert(_1, dictionary) {
return { return {
assert: mapPairListToKeyValPairs(dictionary.ast) assert: mapPairListToKeyValPairs(dictionary.ast)
}; };
}, },
assertdisabled(_1, dictionary) {
return {
assert: mapPairListToKeyValPairs(dictionary.ast, false)
};
},
script(_1, _2, _3, _4, textblock, _5) { script(_1, _2, _3, _4, textblock, _5) {
return { return {
script: outdentString(textblock.sourceString) script: outdentString(textblock.sourceString)
@ -343,27 +323,6 @@ const sem = grammar.createSemantics().addAttribute('ast', {
return { return {
docs: outdentString(textblock.sourceString) docs: outdentString(textblock.sourceString)
}; };
},
textblock(line, _1, rest) {
return [line.ast, ...rest.ast].join('\n');
},
textline(chars) {
return chars.sourceString;
},
textchar(char) {
return char.sourceString;
},
nl(_1, _2) {
return '';
},
st(_) {
return '';
},
tagend(_1 ,_2) {
return '';
},
_iter(...elements) {
return elements.map(e => e.ast);
} }
}); });

View File

@ -53,36 +53,30 @@ const jsonToBru = (json) => {
`; `;
} }
if(query && query.length && enabled(query).length) { if(query && query.length) {
bru += `query { bru += 'query {';
${indentString(enabled(query).map(item => `${item.name}: ${item.value}`).join('\n'))} if(enabled(query).length) {
} bru += `\n${indentString(enabled(query).map(item => `${item.name}: ${item.value}`).join('\n'))}`;
}
`; if(disabled(query).length) {
bru += `\n${indentString(disabled(query).map(item => `~${item.name}: ${item.value}`).join('\n'))}`;
}
bru += '\n}\n\n';
} }
if(query && query.length && disabled(query).length) { if(headers && headers.length) {
bru += `query:disabled { bru += 'headers {';
${indentString(disabled(query).map(item => `${item.name}: ${item.value}`).join('\n'))} if(enabled(headers).length) {
} bru += `\n${indentString(enabled(headers).map(item => `${item.name}: ${item.value}`).join('\n'))}`;
}
`; if(disabled(headers).length) {
} bru += `\n${indentString(disabled(headers).map(item => `~${item.name}: ${item.value}`).join('\n'))}`;
}
if(headers && headers.length && enabled(headers).length) { bru += '\n}\n\n';
bru += `headers {
${indentString(enabled(headers).map(header => `${header.name}: ${header.value}`).join('\n'))}
}
`;
}
if(headers && headers.length && disabled(headers).length) {
bru += `headers:disabled {
${indentString(disabled(headers).map(header => `${header.name}: ${header.value}`).join('\n'))}
}
`;
} }
if(body && body.json && body.json.length) { if(body && body.json && body.json.length) {
@ -109,52 +103,42 @@ ${indentString(body.xml)}
`; `;
} }
if(body && body.formUrlEncoded && enabled(body.formUrlEncoded).length) { if(body && body.formUrlEncoded) {
bru += `body:form-urlencoded { bru += `body:form-urlencoded {`;
${indentString(enabled(body.formUrlEncoded).map(item => `${item.name}: ${item.value}`).join('\n'))} if(enabled(body.formUrlEncoded).length) {
} bru += `\n${indentString(enabled(body.formUrlEncoded).map(item => `${item.name}: ${item.value}`).join('\n'))}`;
}
`; if(disabled(body.formUrlEncoded).length) {
bru += `\n${indentString(disabled(body.formUrlEncoded).map(item => `~${item.name}: ${item.value}`).join('\n'))}`;
}
bru += '\n}\n\n';
} }
if(body && body.formUrlEncoded && disabled(body.formUrlEncoded).length) { if(body && body.multipartForm) {
bru += `body:form-urlencoded:disabled { bru += `body:multipart-form {`;
${indentString(disabled(body.formUrlEncoded).map(item => `${item.name}: ${item.value}`).join('\n'))} if(enabled(body.multipartForm).length) {
} bru += `\n${indentString(enabled(body.multipartForm).map(item => `${item.name}: ${item.value}`).join('\n'))}`;
}
`; if(disabled(body.multipartForm).length) {
} bru += `\n${indentString(disabled(body.multipartForm).map(item => `~${item.name}: ${item.value}`).join('\n'))}`;
}
if(body && body.multipartForm && enabled(body.multipartForm).length) { bru += '\n}\n\n';
bru += `body:multipart-form {
${indentString(enabled(body.multipartForm).map(item => `${item.name}: ${item.value}`).join('\n'))}
}
`;
}
if(body && body.multipartForm && disabled(body.multipartForm).length) {
bru += `body:multipart-form:disabled {
${indentString(disabled(body.multipartForm).map(item => `${item.name}: ${item.value}`).join('\n'))}
}
`;
} }
if(body && body.graphql && body.graphql.query) { if(body && body.graphql && body.graphql.query) {
bru += `body:graphql { bru += `body:graphql {\n`;
${indentString(body.graphql.query)} bru += `${indentString(body.graphql.query)}`;
} bru += '\n}\n\n';
`;
} }
if(body && body.graphql && body.graphql.variables) { if(body && body.graphql && body.graphql.variables) {
bru += `body:graphql:vars { bru += `body:graphql:vars {\n`;
${indentString(body.graphql.variables)} bru += `${indentString(body.graphql.variables)}`
} bru += '\n}\n\n';
`;
} }
if(vars && vars.length) { if(vars && vars.length) {
@ -163,53 +147,39 @@ ${indentString(body.graphql.variables)}
const varsLocalEnabled = _.filter(vars, (v) => v.enabled && v.local); const varsLocalEnabled = _.filter(vars, (v) => v.enabled && v.local);
const varsLocalDisabled = _.filter(vars, (v) => !v.enabled && v.local); const varsLocalDisabled = _.filter(vars, (v) => !v.enabled && v.local);
bru += `vars {`;
if(varsEnabled.length) { if(varsEnabled.length) {
bru += `vars { bru += `\n${indentString(varsEnabled.map(item => `${item.name}: ${item.value}`).join('\n'))}`;
${indentString(varsEnabled.map(item => `${item.name}: ${item.value}`).join('\n'))}
}
`;
}
if(varsDisabled.length) {
bru += `vars:disabled {
${indentString(varsDisabled.map(item => `${item.name}: ${item.value}`).join('\n'))}
}
`;
} }
if(varsLocalEnabled.length) { if(varsLocalEnabled.length) {
bru += `vars:local { bru += `\n${indentString(varsLocalEnabled.map(item => `@${item.name}: ${item.value}`).join('\n'))}`;
${indentString(varsLocalEnabled.map(item => `${item.name}: ${item.value}`).join('\n'))} }
}
`; if(varsDisabled.length) {
bru += `\n${indentString(varsDisabled.map(item => `~${item.name}: ${item.value}`).join('\n'))}`;
} }
if(varsLocalDisabled.length) { if(varsLocalDisabled.length) {
bru += `vars:local:disabled { bru += `\n${indentString(varsLocalDisabled.map(item => `~@${item.name}: ${item.value}`).join('\n'))}`;
${indentString(varsLocalDisabled.map(item => `${item.name}: ${item.value}`).join('\n'))}
}
`;
} }
bru += '\n}\n\n';
} }
if(assert && enabled(assert).length) { if(assert && assert.length) {
bru += `assert { bru += `assert {`;
${indentString(enabled(assert).map(item => `${item.name}: ${item.value}`).join('\n'))}
}
`; if(enabled(assert).length) {
} bru += `\n${indentString(enabled(assert).map(item => `${item.name}: ${item.value}`).join('\n'))}`;
}
if(assert && disabled(assert).length) { if(disabled(assert).length) {
bru += `assert:disabled { bru += `\n${indentString(disabled(assert).map(item => `~${item.name}: ${item.value}`).join('\n'))}`;
${indentString(disabled(assert).map(item => `${item.name}: ${item.value}`).join('\n'))} }
}
`; bru += '\n}\n\n';
} }
if(script && script.length) { if(script && script.length) {
@ -236,7 +206,6 @@ ${indentString(docs)}
`; `;
} }
return stripLastLine(bru); return stripLastLine(bru);
}; };

View File

@ -101,8 +101,8 @@ headers {
it("should parse disabled headers", () => { it("should parse disabled headers", () => {
const input = ` const input = `
headers:disabled { headers {
content-type: application/json ~content-type: application/json
}`; }`;
const output = parser(input); const output = parser(input);

View File

@ -5,26 +5,20 @@ meta {
} }
get { get {
url: https://api.textlocal.in/send/ url: https://api.textlocal.in/send
body: json body: json
} }
query { query {
apiKey: secret apiKey: secret
numbers: 998877665 numbers: 998877665
} ~message: hello
query:disabled {
message: hello
} }
headers { headers {
content-type: application/json content-type: application/json
Authorization: Bearer 123 Authorization: Bearer 123
} ~transaction-id: {{transactionId}}
headers:disabled {
transaction-id: {{transactionId}}
} }
body:json { body:json {
@ -47,19 +41,13 @@ body:xml {
body:form-urlencoded { body:form-urlencoded {
apikey: secret apikey: secret
numbers: +91998877665 numbers: +91998877665
} ~message: hello
body:form-urlencoded:disabled {
message: hello
} }
body:multipart-form { body:multipart-form {
apikey: secret apikey: secret
numbers: +91998877665 numbers: +91998877665
} ~message: hello
body:multipart-form:disabled {
message: hello
} }
body:graphql { body:graphql {
@ -81,26 +69,14 @@ body:graphql:vars {
vars { vars {
token: $res.body.token token: $res.body.token
} @orderNumber: $res.body.orderNumber
~petId: $res.body.id
vars:disabled { ~@transactionId: $res.body.transactionId
petId: $res.body.id
}
vars:local {
orderNumber: $res.body.orderNumber
}
vars:local:disabled {
transactionId: $res.body.transactionId
} }
assert { assert {
$res.status: 200 $res.status: 200
} ~$res.body.message: success
assert:disabled {
$res.body.message: success
} }
script { script {

View File

@ -6,7 +6,7 @@
}, },
"http": { "http": {
"method": "get", "method": "get",
"url": "https://api.textlocal.in/send/", "url": "https://api.textlocal.in/send",
"body": "json" "body": "json"
}, },
"query": [{ "query": [{
@ -89,18 +89,18 @@
"local": false, "local": false,
"enabled": true "enabled": true
}, },
{
"name": "petId",
"value": "$res.body.id",
"local": false,
"enabled": false
},
{ {
"name": "orderNumber", "name": "orderNumber",
"value": "$res.body.orderNumber", "value": "$res.body.orderNumber",
"local": true, "local": true,
"enabled": true "enabled": true
}, },
{
"name": "petId",
"value": "$res.body.id",
"local": false,
"enabled": false
},
{ {
"name": "transactionId", "name": "transactionId",
"value": "$res.body.transactionId", "value": "$res.body.transactionId",