mikel 0.8.1 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/index.js +78 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -199,6 +199,26 @@ const data = {
|
|
|
199
199
|
console.log(m("{{#unless isAdmin}}Hello guest{{/unless}}", data)); // --> 'Hello guest'
|
|
200
200
|
```
|
|
201
201
|
|
|
202
|
+
#### eq
|
|
203
|
+
|
|
204
|
+
> Added in `v0.9.0`.
|
|
205
|
+
|
|
206
|
+
The `eq` helper renders the blocks only if the two values provided as argument are equal. Example:
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
console.log(m(`{{#eq name "bob"}}Hello bob{{/eq}}`, {name: "bob"})); // --> 'Hello bob'
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
#### ne
|
|
213
|
+
|
|
214
|
+
> Added in `v0.9.0`.
|
|
215
|
+
|
|
216
|
+
The `ne` helper renders the block only if the two values provided as argument are not equal. Example:
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
console.log(m(`{{#ne name "bob"}}Not bob{{/ne}}`, {name: "John"})); // --> 'Not bob'
|
|
220
|
+
```
|
|
221
|
+
|
|
202
222
|
### Custom Helpers
|
|
203
223
|
|
|
204
224
|
> Added in `v0.5.0`.
|
package/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const tags = /\{\{|\}\}/;
|
|
2
|
+
const endl = "\n";
|
|
2
3
|
const escapedChars = {
|
|
3
4
|
"&": "&",
|
|
4
5
|
"<": "<",
|
|
@@ -11,6 +12,74 @@ const escape = s => s.toString().replace(/[&<>\"']/g, m => escapedChars[m]);
|
|
|
11
12
|
|
|
12
13
|
const get = (c, p) => (p === "." ? c : p.split(".").reduce((x, k) => x?.[k], c)) ?? "";
|
|
13
14
|
|
|
15
|
+
const parse = (v, context = {}, vars = {}) => {
|
|
16
|
+
if ((v.startsWith(`"`) && v.endsWith(`"`)) || /^-?\d*\.?\d*$/.test(v) || v === "true" || v === "false" || v === "null") {
|
|
17
|
+
return JSON.parse(v);
|
|
18
|
+
}
|
|
19
|
+
return (v || "").startsWith("@") ? get(vars, v.slice(1)) : get(context, v || ".");
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// @description tiny yaml parser
|
|
23
|
+
const yamlParser = (str = "") => {
|
|
24
|
+
const lines = str.split(endl), result = {}, levels = [{ctx: result, indent: 0}];
|
|
25
|
+
let level = 0, i = 0;
|
|
26
|
+
while (i < lines.length) {
|
|
27
|
+
const line = lines[i] || "";
|
|
28
|
+
if (!!line.trim() && !line.trim().startsWith("#")) {
|
|
29
|
+
const indent = (line.match(/^( *)/m)?.[0] || "").length;
|
|
30
|
+
while(level > 0 && indent < levels[level].indent) {
|
|
31
|
+
levels.pop();
|
|
32
|
+
level = level - 1;
|
|
33
|
+
}
|
|
34
|
+
const isArrayItem = line.trim().startsWith("-");
|
|
35
|
+
let [key, value] = line.trim().split(":").map(v => v.trim());
|
|
36
|
+
// Check if is a new item of the array
|
|
37
|
+
if (isArrayItem) {
|
|
38
|
+
key = key.replace(/^(- *)/m, "");
|
|
39
|
+
if (typeof value === "undefined") {
|
|
40
|
+
value = key;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
const newIndent = (line.slice(0, line.indexOf(key))).length;
|
|
44
|
+
levels[level].ctx.push({});
|
|
45
|
+
levels.push({ctx: levels[level].ctx[levels[level].ctx.length - 1], indent: newIndent});
|
|
46
|
+
level = level + 1;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Check for empty value --> entering into a nested object or array
|
|
50
|
+
if (!value) {
|
|
51
|
+
const nextLine = lines[i + 1] || "";
|
|
52
|
+
const nextIndent = (nextLine.match(/^( *)/m)?.[0] || "").length;
|
|
53
|
+
levels[level].ctx[key] = nextLine.trim().startsWith("-") ? [] : {};
|
|
54
|
+
if (nextIndent > levels[level].indent) {
|
|
55
|
+
levels.push({ctx: levels[level].ctx[key], indent: nextIndent});
|
|
56
|
+
level = level + 1;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else if(value && Array.isArray(levels[level].ctx)) {
|
|
60
|
+
levels[level].ctx.push(JSON.parse(value));
|
|
61
|
+
}
|
|
62
|
+
else if (value) {
|
|
63
|
+
levels[level].ctx[key] = JSON.parse(value);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
i = i + 1;
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// @description tiny front-matter parser
|
|
72
|
+
const frontmatter = (str = "", parser = null) => {
|
|
73
|
+
let body = (str || "").trim(), data = {};
|
|
74
|
+
const matches = Array.from(body.matchAll(/^(--- *)/gm))
|
|
75
|
+
if (matches?.length === 2 && matches[0].index === 0) {
|
|
76
|
+
const front = body.substring(0 + matches[0][1].length, matches[1].index).trim();
|
|
77
|
+
body = body.substring(matches[1].index + matches[1][1].length).trim();
|
|
78
|
+
data = typeof parser === "function" ? parser(front) : yamlParser(front);
|
|
79
|
+
}
|
|
80
|
+
return {body, data};
|
|
81
|
+
};
|
|
82
|
+
|
|
14
83
|
const defaultHelpers = {
|
|
15
84
|
"each": (value, opt) => {
|
|
16
85
|
return (typeof value === "object" ? Object.entries(value || {}) : [])
|
|
@@ -19,6 +88,8 @@ const defaultHelpers = {
|
|
|
19
88
|
},
|
|
20
89
|
"if": (value, opt) => !!value ? opt.fn(opt.context) : "",
|
|
21
90
|
"unless": (value, opt) => !!!value ? opt.fn(opt.context) : "",
|
|
91
|
+
"eq": (a, b, opt) => a === b ? opt.fn(opt.context) : "",
|
|
92
|
+
"ne": (a, b, opt) => a !== b ? opt.fn(opt.context) : "",
|
|
22
93
|
};
|
|
23
94
|
|
|
24
95
|
const compile = (tokens, output, context, partials, helpers, vars, fn = {}, index = 0, section = "") => {
|
|
@@ -34,9 +105,9 @@ const compile = (tokens, output, context, partials, helpers, vars, fn = {}, inde
|
|
|
34
105
|
output.push(get(context, tokens[i].slice(1).trim()));
|
|
35
106
|
}
|
|
36
107
|
else if (tokens[i].startsWith("#") && typeof helpers[tokens[i].slice(1).trim().split(" ")[0]] === "function") {
|
|
37
|
-
const [t, ...args] = tokens[i].slice(1).trim().
|
|
108
|
+
const [t, ...args] = tokens[i].slice(1).trim().match(/(?:[^\s"]+|"[^"]*")+/g);
|
|
38
109
|
const j = i + 1;
|
|
39
|
-
output.push(helpers[t](...args.map(v => (v
|
|
110
|
+
output.push(helpers[t](...args.map(v => parse(v, context, vars)), {
|
|
40
111
|
context: context,
|
|
41
112
|
fn: (blockContext = {}, blockVars = {}, blockOutput = []) => {
|
|
42
113
|
i = compile(tokens, blockOutput, blockContext, partials, helpers, {...vars, ...blockVars, root: vars.root}, fn, j, t);
|
|
@@ -70,9 +141,9 @@ const compile = (tokens, output, context, partials, helpers, vars, fn = {}, inde
|
|
|
70
141
|
}
|
|
71
142
|
}
|
|
72
143
|
else if (tokens[i].startsWith("=")) {
|
|
73
|
-
const [t, ...args] = tokens[i].slice(1).trim().
|
|
144
|
+
const [t, ...args] = tokens[i].slice(1).trim().match(/(?:[^\s"]+|"[^"]*")+/g);
|
|
74
145
|
if (typeof fn[t] === "function") {
|
|
75
|
-
output.push(fn[t](...args.map(v => (v
|
|
146
|
+
output.push(fn[t](...args.map(v => parse(v, context, vars))) || "");
|
|
76
147
|
}
|
|
77
148
|
}
|
|
78
149
|
else if (tokens[i].startsWith("/")) {
|
|
@@ -101,5 +172,8 @@ const mikel = (str, context = {}, opt = {}, output = []) => {
|
|
|
101
172
|
// @description assign utilities
|
|
102
173
|
mikel.escape = escape;
|
|
103
174
|
mikel.get = get;
|
|
175
|
+
mikel.parse = parse;
|
|
176
|
+
mikel.yaml = yamlParser;
|
|
177
|
+
mikel.frontmatter = frontmatter;
|
|
104
178
|
|
|
105
179
|
export default mikel;
|