bruno/packages/bruno-lang/v2/src/envToJson.js

168 lines
3.5 KiB
JavaScript

const ohm = require('ohm-js');
const _ = require('lodash');
const grammar = ohm.grammar(`Bru {
BruEnvFile = (vars | secretvars)*
nl = "\\r"? "\\n"
st = " " | "\\t"
stnl = st | nl
tagend = nl "}"
optionalnl = ~tagend nl
keychar = ~(tagend | st | nl | ":") any
valuechar = ~(nl | tagend) any
// Dictionary Blocks
dictionary = st* "{" pairlist? tagend
pairlist = optionalnl* pair (~tagend stnl* pair)* (~tagend space)*
pair = st* key st* ":" st* value st*
key = keychar*
value = valuechar*
// Array Blocks
array = st* "[" stnl* valuelist stnl* "]"
valuelist = stnl* arrayvalue stnl* ("," stnl* arrayvalue)*
arrayvalue = arrayvaluechar*
arrayvaluechar = ~(nl | st | "[" | "]" | ",") any
secretvars = "vars:secret" array
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 mapArrayListToKeyValPairs = (arrayList = []) => {
arrayList = arrayList.filter((v) => v && v.length);
if (!arrayList.length) {
return [];
}
return _.map(arrayList, (value) => {
let name = value;
let enabled = true;
if (name && name.length && name.charAt(0) === '~') {
name = name.slice(1);
enabled = false;
}
return {
name,
value: null,
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 {
variables: []
};
}
return _.reduce(
tags.ast,
(result, item) => {
return _.mergeWith(result, item, concatArrays);
},
{}
);
},
array(_1, _2, _3, valuelist, _4, _5) {
return valuelist.ast;
},
arrayvalue(chars) {
return chars.sourceString ? chars.sourceString.trim() : '';
},
valuelist(_1, value, _2, _3, _4, rest) {
return [value.ast, ...rest.ast];
},
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] = value.ast ? value.ast.trim() : '';
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);
_.each(vars, (v) => {
v.secret = false;
});
return {
variables: vars
};
},
secretvars: (_1, array) => {
const vars = mapArrayListToKeyValPairs(array.ast);
_.each(vars, (v) => {
v.secret = true;
});
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;