-
Notifications
You must be signed in to change notification settings - Fork 3
/
parser.js
92 lines (73 loc) · 2.45 KB
/
parser.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
const _ = require('lodash');
const constants = require('./constants');
const numberRegex = /\d+/;
function isNumber(str) {
return str && (str.match(numberRegex) || '').length;
}
function parseStringValue(input) {
let start = input.i;
while (input.buf.readUInt8(input.i) !== constants.special.stringEnd) {
input.i++;
}
let value = input.buf.toString('utf8', start, input.i);
input.i++;
return value;
}
// LE 32 bit number
function parseIntValue(input) {
let value = input.buf.readInt32LE(input.i);
input.i += 4;
return value;
}
function parseObjectValue(input) {
let obj = {};
//should have properties, with type and value
do {
let type = input.buf.readUInt8(input.i);
input.i++;
//handle empty objects/arrays
if (type === constants.special.objectEnd) {
break;
}
let propName = parseStringValue(input);
try {
let val;
switch (type) {
case constants.types.object:
val = parseObjectValue(input);
break;
case constants.types.string:
val = parseStringValue(input);
break;
case constants.types.int:
val = parseIntValue(input);
if (input.options.dateProperties && _.includes(input.options.dateProperties, propName)) {
val = new Date(val * 1000);
} else if (input.options.autoConvertBooleans && (val === 1 || val === 0)) {
val = !!val;
}
break;
}
obj[propName] = val;
} catch (err) {
throw new Error(`encountered error while handling property: ${propName} ${err}`);
}
} while (input.i < input.buf.length);
if (input.options.autoConvertArrays) {
//check if we should convert to an array instead
let keys = Object.keys(obj);
if (_.every(keys, isNumber)) {
let arr = new Array(keys.length);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
arr[key] = obj[key];
}
obj = arr;
}
}
return obj;
}
function topLevel(buffer, opts) {
return parseObjectValue({ buf: buffer, i: 0, options: opts || { autoConvertArrays: true, autoConvertBooleans: true } });
}
module.exports = topLevel;