feat: bru lang - parse env files

This commit is contained in:
Anoop M D 2023-02-05 19:06:48 +05:30
parent c3236d4eb1
commit 84bd603e11
5 changed files with 277 additions and 1 deletions

View File

@ -138,7 +138,7 @@ const sem = grammar.createSemantics().addAttribute('ast', {
return res;
},
key(chars) {
return chars.sourceString;
return chars.sourceString ? chars.sourceString.trim() : '';
},
value(chars) {
return chars.sourceString ? chars.sourceString.trim() : '';

View File

@ -0,0 +1,108 @@
const ohm = require("ohm-js");
const _ = require('lodash');
const grammar = ohm.grammar(`Bru {
BruEnvFile = (vars)*
nl = "\\r"? "\\n"
st = " " | "\\t"
tagend = nl "}"
validkey = ~(st | ":") any
validvalue = ~nl any
// 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*
vars = "vars" dictionary
}`);
const mapPairListToKeyValPairs = (pairList = []) => {
if(!pairList.length) {
return [];
}
return _.map(pairList[0], pair => {
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 {
name,
value,
enabled
};
});
};
const concatArrays = (objValue, srcValue) => {
if (_.isArray(objValue) && _.isArray(srcValue)) {
return objValue.concat(srcValue);
}
};
const sem = grammar.createSemantics().addAttribute('ast', {
BruEnvFile(tags) {
if(!tags || !tags.ast || !tags.ast.length) {
return {};
}
return _.reduce(tags.ast, (result, item) => {
return _.mergeWith(result, item, concatArrays);
}, {});
},
dictionary(_1, _2, pairlist, _3) {
return pairlist.ast;
},
pairlist(_1, pair, _2, rest, _3) {
return [pair.ast, ...rest.ast];
},
pair(_1, key, _2, _3, _4, value, _5) {
let res = {};
res[key.ast] = _.get(value, 'ast[0]', '');
return res;
},
key(chars) {
return chars.sourceString ? chars.sourceString.trim() : '';
},
value(chars) {
return chars.sourceString ? chars.sourceString.trim() : '';
},
nl(_1, _2) {
return '';
},
st(_) {
return '';
},
tagend(_1 ,_2) {
return '';
},
_iter(...elements) {
return elements.map(e => e.ast);
},
vars(_1, dictionary) {
const vars = mapPairListToKeyValPairs(dictionary.ast);
return {
variables: vars
};
}
});
const parser = (input) => {
const match = grammar.match(input);
if(match.succeeded()) {
return sem(match).ast;
} else {
throw new Error(match.message);
}
}
module.exports = parser;

View File

@ -0,0 +1,25 @@
const _ = require('lodash');
const envToJson = (json) => {
const variables = _.get(json, 'variables', []);
const vars = variables.map((variable) => {
const { name, value, enabled } = variable;
const prefix = enabled ? '' : '~';
return ` ${prefix}${name}: ${value}`;
});
if(!vars || !vars.length) {
return `vars {
}
`;
}
const output = `vars {
${vars.join('\n')}
}
`;
return output;
};
module.exports = envToJson;

View File

@ -0,0 +1,88 @@
const parser = require("../src/envToJson");
describe("env parser", () => {
it("should parse empty vars", () => {
const input = `
vars {
}`;
const output = parser(input);
const expected = {
"variables": []
};
expect(output).toEqual(expected);
});
it("should parse single var line", () => {
const input = `
vars {
url: http://localhost:3000
}`;
const output = parser(input);
const expected = {
"variables": [{
"name": "url",
"value": "http://localhost:3000",
"enabled" : true,
}]
};
expect(output).toEqual(expected);
});
it("should parse multiple var lines", () => {
const input = `
vars {
url: http://localhost:3000
port: 3000
~token: secret
}`;
const output = parser(input);
const expected = {
"variables": [{
"name": "url",
"value": "http://localhost:3000",
"enabled" : true
}, {
"name": "port",
"value": "3000",
"enabled" : true
}, {
"name": "token",
"value": "secret",
"enabled" : false
}]
};
expect(output).toEqual(expected);
});
it("should gracefully handle empty lines and spaces", () => {
const input = `
vars {
url: http://localhost:3000
port: 3000
}
`;
const output = parser(input);
const expected = {
"variables": [{
"name": "url",
"value": "http://localhost:3000",
"enabled" : true,
}, {
"name": "port",
"value": "3000",
"enabled" : true,
}]
};
expect(output).toEqual(expected);
});
});

View File

@ -0,0 +1,55 @@
const parser = require("../src/jsonToEnv");
describe("env parser", () => {
it("should parse empty vars", () => {
const input = {
"variables": []
};
const output = parser(input);
const expected = `vars {
}
`;
expect(output).toEqual(expected);
});
it("should parse single var line", () => {
const input = {
"variables": [{
"name": "url",
"value": "http://localhost:3000",
"enabled" : true,
}]
};
const output = parser(input);
const expected = `vars {
url: http://localhost:3000
}
`;
expect(output).toEqual(expected);
});
it("should parse multiple var lines", () => {
const input = {
"variables": [{
"name": "url",
"value": "http://localhost:3000",
"enabled" : true
}, {
"name": "port",
"value": "3000",
"enabled" : false
}]
};
const expected = `vars {
url: http://localhost:3000
~port: 3000
}
`;
const output = parser(input);
expect(output).toEqual(expected);
});
});