feat: generic key val line parser

This commit is contained in:
Anoop M D 2023-02-01 08:00:10 +05:30
parent b88848f0dc
commit d9ef1692fe
6 changed files with 308 additions and 134 deletions

View File

@ -1,16 +1,9 @@
const {
between,
regex,
everyCharUntil,
digit,
whitespace,
optionalWhitespace,
endOfInput,
choice,
many,
sepBy,
sequenceOf
everyCharUntil
} = require("arcsecond");
const keyvalLines = require('./key-val-lines');
// body(type=json)
const bodyJsonBegin = regex(/^body\s*\(\s*type\s*=\s*json\s*\)\s*\r?\n/);
@ -60,32 +53,6 @@ const bodyXmlTag = between(bodyXmlBegin)(bodyEnd)(everyCharUntil(bodyEnd)).map((
}
});
// generic key value parser
const newline = regex(/^\r?\n/);
const newLineOrEndOfInput = choice([newline, endOfInput]);
const wordWithoutWhitespace = regex(/^[^\s\t\r?\n]+/g);
const wordWithWhitespace = regex(/^[^\r?\n]+/g);
const line = sequenceOf([
optionalWhitespace,
digit,
whitespace,
wordWithoutWhitespace,
whitespace,
wordWithWhitespace,
newLineOrEndOfInput
]).map(([_, enabled, __, key, ___, value]) => {
return {
"enabled": Number(enabled) ? true : false,
"name": key,
"value": value
};
});
const lines = many(line);
const keyvalLines = sepBy(newline)(lines);
/**
* We have deprecated form-url-encoded type in body tag, it was a misspelling on my part
* The new type is form-urlencoded

View File

@ -1,44 +1,18 @@
const {
sequenceOf,
whitespace,
optionalWhitespace,
choice,
endOfInput,
between,
digit,
many,
regex,
sepBy
} = require("arcsecond");
const newline = regex(/^\r?\n/);
const newLineOrEndOfInput = choice([newline, endOfInput]);
const { each } = require('lodash');
const keyValLines = require('./key-val-lines');
const begin = regex(/^vars\s*\r?\n/);
const end = regex(/^[\r?\n]*\/vars\s*[\r?\n]*/);
const wordWithoutWhitespace = regex(/^[^\s\r?\t\n]+/g);
const wordWithWhitespace = regex(/^[^\r?\n]+/g);
const line = sequenceOf([
optionalWhitespace,
digit,
whitespace,
wordWithoutWhitespace,
whitespace,
wordWithWhitespace,
newLineOrEndOfInput
]).map(([_, enabled, __, key, ___, value]) => {
return {
"enabled": Number(enabled) ? true : false,
"name": key,
"value": value,
"type": "text"
};
});
const envVarsTag = between(begin)(end)(keyValLines).map(([variables]) => {
each(variables, (variable) => {
variable.type = "text"
});
const lines = many(line);
const envVarsLines = sepBy(newline)(lines);
const envVarsTag = between(begin)(end)(envVarsLines).map(([variables]) => {
return {
variables
};

View File

@ -1,43 +1,13 @@
const {
sequenceOf,
whitespace,
optionalWhitespace,
choice,
endOfInput,
between,
digit,
many,
regex,
sepBy
regex
} = require("arcsecond");
const newline = regex(/^\r?\n/);
const newLineOrEndOfInput = choice([newline, endOfInput]);
const keyValLines = require('./key-val-lines');
const begin = regex(/^headers\s*\r?\n/);
const end = regex(/^[\r?\n]*\/headers\s*[\r?\n]*/);
const wordWithoutWhitespace = regex(/^[^\s\t\n]+/g);
const wordWithWhitespace = regex(/^[^\r?\n]+/g);
const line = sequenceOf([
optionalWhitespace,
digit,
whitespace,
wordWithoutWhitespace,
whitespace,
wordWithWhitespace,
newLineOrEndOfInput
]).map(([_, enabled, __, key, ___, value]) => {
return {
"enabled": Number(enabled) ? true : false,
"name": key,
"value": value
};
});
const lines = many(line);
const headersLines = sepBy(newline)(lines);
const headersTag = between(begin)(end)(headersLines).map(([headers]) => {
const headersTag = between(begin)(end)(keyValLines).map(([headers]) => {
return {
headers
};

View File

@ -0,0 +1,64 @@
const {
sequenceOf,
whitespace,
optionalWhitespace,
choice,
digit,
many,
regex,
sepBy,
} = require("arcsecond");
const newline = regex(/^\r?\n/);
const wordWithoutWhitespace = regex(/^[^\s\r?\t\n]+/g);
const wordWithWhitespace = regex(/^[^\r?\n]+/g);
// matching lines like: 1 key value
const line = sequenceOf([
optionalWhitespace,
digit,
whitespace,
wordWithoutWhitespace,
whitespace,
wordWithWhitespace
]).map(([_, enabled, __, key, ___, value]) => {
return {
"enabled": Number(enabled) ? true : false,
"name": key ? key.trim() : "",
"value": value ? value.trim() : ""
};
});
// matching lines like: 1 key follows by [whitespaces] and a newline
const line2 = sequenceOf([
optionalWhitespace,
digit,
whitespace,
wordWithoutWhitespace,
regex(/^\s*\r?\n/)
]).map(([_, enabled, __, key]) => {
return {
"enabled": Number(enabled) ? true : false,
"name": key,
"value": ""
};
});
// matching lines like: 1 followed by [whitespaces] and a newline
const line3 = sequenceOf([
optionalWhitespace,
digit,
regex(/^\s*\r?\n/)
]).map(([_, enabled]) => {
return {
"enabled": Number(enabled) ? true : false,
"name": "",
"value": ""
};
});
const lines = many(choice([line3, line2, line]));
const keyValLines = sepBy(newline)(lines);
module.exports = keyValLines;

View File

@ -1,44 +1,13 @@
const {
sequenceOf,
whitespace,
optionalWhitespace,
choice,
endOfInput,
everyCharUntil,
between,
digit,
many,
regex,
sepBy
regex
} = require("arcsecond");
const newline = regex(/^\r?\n/);
const newLineOrEndOfInput = choice([newline, endOfInput]);
const keyValLines = require('./key-val-lines');
const begin = regex(/^params\s*\r?\n/);
const end = regex(/^[\r?\n]*\/params\s*[\r?\n]*/);
const wordWithoutWhitespace = regex(/^[^\s\t\r?\n]+/g);
const wordWithWhitespace = regex(/^[^\r?\n]+/g);
const line = sequenceOf([
optionalWhitespace,
digit,
whitespace,
wordWithoutWhitespace,
whitespace,
wordWithWhitespace,
newLineOrEndOfInput
]).map(([_, enabled, __, key, ___, value]) => {
return {
"enabled": Number(enabled) ? true : false,
"name": key,
"value": value
};
});
const lines = many(line);
const paramsLines = sepBy(newline)(lines);
const paramsTag = between(begin)(end)(paramsLines).map(([params]) => {
const paramsTag = between(begin)(end)(keyValLines).map(([params]) => {
return {
params
};

View File

@ -0,0 +1,230 @@
const {
between,
regex,
anyChar,
many,
choice
} = require("arcsecond");
const _ = require('lodash');
const keyValLines = require('../src/key-val-lines');
const begin = regex(/^vars\s*\r?\n/);
const end = regex(/^[\r?\n]*\/vars\s*[\r?\n]*/);
const varsTag = between(begin)(end)(keyValLines).map(([variables]) => {
return {
variables
};
});
const toJson = (fileContents) => {
const parser = many(choice([
varsTag,
anyChar
]));
const parsed = parser
.run(fileContents)
.result
.reduce((acc, item) => _.merge(acc, item), {});
const json = {
variables: parsed.variables || []
};
return json;
};
describe('bool-key-val', () => {
it('should parse bool-key-val - case 1', () => {
const file = `
vars
1 host https://www.google.com
/vars
`;
const result = toJson(file);
expect(result).toEqual({
variables: [{
enabled: true,
name: 'host',
value: 'https://www.google.com'
}]
});
});
it('should parse bool-key-val - case 2', () => {
const file = `
vars
1 host https://www.google.com
1 auth jwt secret
/vars
`;
const result = toJson(file);
expect(result).toEqual({
variables: [{
enabled: true,
name: 'host',
value: 'https://www.google.com'
}, {
enabled: true,
name: 'auth',
value: 'jwt secret'
}]
});
});
// following test cases are for edge cases
// one line with just enabled flag
it('should parse bool-key-val - case 3', () => {
const file = `
vars
1
/vars
`;
const result = toJson(file);
expect(result).toEqual({
variables: [{
enabled: true,
name: '',
value: ''
}]
});
});
// one line with just enabled flag and a space
it('should parse bool-key-val - case 4', () => {
const file = `
vars
1
/vars
`;
const result = toJson(file);
expect(result).toEqual({
variables: [{
enabled: true,
name: '',
value: ''
}]
});
});
// one line with just enabled flag and a space and a name
it('should parse bool-key-val - case 5', () => {
const file = `
vars
1 host
/vars
`;
const result = toJson(file);
expect(result).toEqual({
variables: [{
enabled: true,
name: 'host',
value: ''
}]
});
});
// one line with just enabled flag and a space and a name and a space
it('should parse bool-key-val - case 6', () => {
const file = `
vars
1 host
/vars
`;
const result = toJson(file);
expect(result).toEqual({
variables: [{
enabled: true,
name: 'host',
value: ''
}]
});
});
// three lines, second line with just enabled flag
it('should parse bool-key-val - case 7', () => {
const file = `
vars
1 host https://www.google.com
1
0 Content-type application/json
/vars
`;
const result = toJson(file);
expect(result).toEqual({
variables: [{
enabled: true,
name: 'host',
value: 'https://www.google.com'
}, {
enabled: true,
name: '',
value: ''
}, {
enabled: false,
name: 'Content-type',
value: 'application/json'
}]
});
});
// three lines, second line with just enabled flag and a space
it('should parse bool-key-val - case 8', () => {
const file = `
vars
1 host https://www.google.com
1
0 Content-type application/json
/vars
`;
const result = toJson(file);
expect(result).toEqual({
variables: [{
enabled: true,
name: 'host',
value: 'https://www.google.com'
}, {
enabled: true,
name: '',
value: ''
}, {
enabled: false,
name: 'Content-type',
value: 'application/json'
}]
});
});
// three lines, second line with just enabled flag and a space and a name
it('should parse bool-key-val - case 9', () => {
const file = `
vars
1 host https://www.google.com
1 auth
0 Content-type application/json
/vars
`;
const result = toJson(file);
expect(result).toEqual({
variables: [{
enabled: true,
name: 'host',
value: 'https://www.google.com'
}, {
enabled: true,
name: 'auth',
value: ''
}, {
enabled: false,
name: 'Content-type',
value: 'application/json'
}]
});
});
});