-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
133 lines (95 loc) · 2.51 KB
/
index.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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
const safeeval = require('safe-eval');
const ObjectId = require('bson/lib/bson/objectid');
const XRegExp = require('xregexp');
const JSONT = {};
const operators = [ '+', '-', '*', '/' ];
const r = String.raw.bind(String.raw);
/* Removed temporarily because of no support on node<6.
See: https://github.com/codefeathers/jsont/issues/1 */
// const esc = r`(?<!\\)`;
const esc = '';
const t = {};
t['1m'] = 1000 * 60;
t['1h'] = t['1m'] * 60;
t['1d'] = t['1h'] * 24;
const opRegex = XRegExp(
'^['
+ operators
.reduce((acc, cur, i) =>
(i === 1 ? '\\' : '') + acc + '\\' + cur)
+ ']'
);
const last = list =>
list[list.length - 1];
const stringReplaceByIndex = (s, [start, end], r) =>
s.slice(0, start) + r + s.slice(end);
const getOp = str =>
str.match(opRegex) && str[0];
const getDate = {
'+': (n, seg) => new Date(new Date().valueOf() + (t['1' + seg] * n)),
'-': (n, seg) => new Date(new Date().valueOf() - (t['1' + seg] * n)),
};
const stdlib = {
date(str) {
let returnable;
if (str === 'now') returnable = new Date();
else {
const op = getOp(str);
if (op) {
returnable =
getDate[op](str.slice(1, str.length - 1), last(str));
}
else throw new Error(str + ' cannot be cast as a date');
}
return returnable.toISOString();
},
oid (str) {
return (str === 'new') ? new ObjectId() : new ObjectId(str);
}
};
const stdJS = {
/* Inline JS support is removed.
See: https://github.com/codefeathers/jsont/issues/1
js: (str) => safeeval(str.replace(XRegExp(esc + ''), ''), {}), */
};
const ExecSTD = (test, string, STD) => {
const regexp = new XRegExp(
esc + r`\$`
+ esc + r`\[`
+ test
+ esc + ':'
+ r`(?<arguments>((\\\])|[^\]])*)`
+ esc + r`\]`, 'g');
let match;
while((match = XRegExp.exec(string, regexp)) !== null) {
const stdReplaceable = STD[test](match.arguments);
string = stringReplaceByIndex(
string,
[ match.index, match.index + match[0].length ],
stdReplaceable
);
}
return string;
};
JSONT.parse = (text, ENV = {}, STD = {}, options = {}) => {
Object.assign(STD, stdlib);
if (options.js) Object.assign(STD, stdJS);
// Replace plain values from ENV
let string =
Object.keys(ENV)
.reduce(
(acc, key) => {
const re = new XRegExp(`\\$\\[${key}\\]`, 'g');
return XRegExp.replace(acc, re, ENV[key]);
},
text
);
return Object.keys(STD)
.reduce(
/* For every stdlib item */
(str, stdKey) => ExecSTD(stdKey, str, STD),
string
).replace(/\\/g, '');
};
JSONT.toJSON = str => JSON.parse(str);
module.exports = JSONT;