mikel 0.11.1 → 0.12.0
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 +28 -9
- package/index.js +28 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -167,6 +167,17 @@ const data = {
|
|
|
167
167
|
console.log(m("{{#each values}}{{@key}}: {{@value}}, {{/each}}", data)); // --> 'foo: 0, bar: 1, '
|
|
168
168
|
```
|
|
169
169
|
|
|
170
|
+
The `each` helper also supports the following options, provided as keyword arguments:
|
|
171
|
+
- `skip`: number of first items to skip (default is `0`).
|
|
172
|
+
- `limit`: allows to limit the number of items to display (default equals to the length of the items list).
|
|
173
|
+
|
|
174
|
+
Example:
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
console.log(m("{{each values limit=2}}{{.}}{{/each}}", {values: [0, 1, 2, 3]})); // --> '01'
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
|
|
170
181
|
#### if
|
|
171
182
|
|
|
172
183
|
The `if` helper renders the block only if the condition is truthy.
|
|
@@ -239,6 +250,7 @@ console.log(m("{{#with autor}}{{name}} <{{email}}>{{/with}}", data)); // --> 'Bo
|
|
|
239
250
|
### Custom Helpers
|
|
240
251
|
|
|
241
252
|
> Added in `v0.5.0`.
|
|
253
|
+
> Breaking change introduced in `v0.12.0`.
|
|
242
254
|
|
|
243
255
|
Custom helpers should be provided as an object in the `options.helpers` field, where each key represents the name of the helper and the corresponding value is a function defining the helper's behavior.
|
|
244
256
|
|
|
@@ -251,8 +263,8 @@ const data = {
|
|
|
251
263
|
};
|
|
252
264
|
const options = {
|
|
253
265
|
helpers: {
|
|
254
|
-
customHelper:
|
|
255
|
-
return `Hello, ${
|
|
266
|
+
customHelper: params => {
|
|
267
|
+
return `Hello, ${params.args[0]}!`;
|
|
256
268
|
},
|
|
257
269
|
},
|
|
258
270
|
};
|
|
@@ -261,8 +273,10 @@ const result = m(template, data, options);
|
|
|
261
273
|
console.log(result); // Output: "Hello, World!"
|
|
262
274
|
```
|
|
263
275
|
|
|
264
|
-
Custom helper functions receive
|
|
276
|
+
Custom helper functions receive a single object as argument, containing the following keys:
|
|
265
277
|
|
|
278
|
+
- `args`: an array containing the variables with the helper is called in the template.
|
|
279
|
+
- `opt`: an object containing the keyword arguments provided to the helper.
|
|
266
280
|
- `context`: the current context (data) where the helper has been executed.
|
|
267
281
|
- `fn`: a function that executes the template provided in the helper block and returns a string with the evaluated template in the provided context.
|
|
268
282
|
|
|
@@ -278,8 +292,8 @@ const data = {
|
|
|
278
292
|
};
|
|
279
293
|
const options = {
|
|
280
294
|
helpers: {
|
|
281
|
-
customEach: (
|
|
282
|
-
return
|
|
295
|
+
customEach: ({args, fn}) => {
|
|
296
|
+
return args[0].map((item, index) => fn({ ...item, index: index})).join("");
|
|
283
297
|
},
|
|
284
298
|
},
|
|
285
299
|
};
|
|
@@ -343,11 +357,18 @@ The `@last` variable allows to check if the current iteration using the `#each`
|
|
|
343
357
|
### Functions
|
|
344
358
|
|
|
345
359
|
> Added in `v0.8.0`.
|
|
360
|
+
> Breaking change introduced in `v0.12.0`.
|
|
346
361
|
|
|
347
362
|
Mikel allows users to define custom functions that can be used within templates to perform dynamic operations. Functions can be invoked in the template using the `=` character, followed by the function name and the variables to be provided to the function. Variables should be separated by spaces.
|
|
348
363
|
|
|
349
364
|
Functions should be provided in the `options.functions` field of the options object when rendering a template. Each function is defined by a name and a corresponding function that performs the desired operation.
|
|
350
365
|
|
|
366
|
+
Functions will receive a single object as argument, containing the following keys:
|
|
367
|
+
|
|
368
|
+
- `args`: an array containing the variables with the function is called in the template.
|
|
369
|
+
- `opt`: an object containing the keyword arguments provided to the function.
|
|
370
|
+
- `context`: the current context (data) where the function has been executed.
|
|
371
|
+
|
|
351
372
|
Example:
|
|
352
373
|
|
|
353
374
|
```javascript
|
|
@@ -359,8 +380,8 @@ const data = {
|
|
|
359
380
|
};
|
|
360
381
|
const options = {
|
|
361
382
|
functions: {
|
|
362
|
-
fullName: (
|
|
363
|
-
return `${
|
|
383
|
+
fullName: ({args}) => {
|
|
384
|
+
return `${args[0]} ${args[1]}`;
|
|
364
385
|
}
|
|
365
386
|
},
|
|
366
387
|
};
|
|
@@ -369,8 +390,6 @@ const result = m("My name is: {{=fullName user.firstName user.lastName}}", data,
|
|
|
369
390
|
console.log(result); // --> "My name is: John Doe"
|
|
370
391
|
```
|
|
371
392
|
|
|
372
|
-
In this example, the custom function `fullName` is defined to take two arguments, `firstName` and `lastName`, and return the full name. The template then uses this function to concatenate and render the full name.
|
|
373
|
-
|
|
374
393
|
|
|
375
394
|
## API
|
|
376
395
|
|
package/index.js
CHANGED
|
@@ -11,6 +11,18 @@ const escape = s => s.toString().replace(/[&<>\"']/g, m => escapedChars[m]);
|
|
|
11
11
|
|
|
12
12
|
const get = (c, p) => (p === "." ? c : p.split(".").reduce((x, k) => x?.[k], c)) ?? "";
|
|
13
13
|
|
|
14
|
+
// @description parse string arguments
|
|
15
|
+
const parseArgs = (argString = "", context = {}, vars = {}) => {
|
|
16
|
+
const [t, ...args] = argString.trim().match(/(?:[^\s"]+|"[^"]*")+/g);
|
|
17
|
+
const argv = args.filter(a => !a.includes("=")).map(a => parse(a, context, vars));
|
|
18
|
+
const opt = Object.fromEntries(args.filter(a => a.includes("=")).map(a => {
|
|
19
|
+
const [k, v] = a.split("=");
|
|
20
|
+
return [k, parse(v, context, vars)];
|
|
21
|
+
}));
|
|
22
|
+
return [t, argv, opt];
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// @description parse a string value to a native type
|
|
14
26
|
const parse = (v, context = {}, vars = {}) => {
|
|
15
27
|
if ((v.startsWith(`"`) && v.endsWith(`"`)) || /^-?\d+\.?\d*$/.test(v) || v === "true" || v === "false" || v === "null") {
|
|
16
28
|
return JSON.parse(v);
|
|
@@ -32,16 +44,18 @@ const frontmatter = (str = "", parser = null) => {
|
|
|
32
44
|
|
|
33
45
|
// @description default helpers
|
|
34
46
|
const defaultHelpers = {
|
|
35
|
-
"each":
|
|
36
|
-
|
|
37
|
-
|
|
47
|
+
"each": p => {
|
|
48
|
+
const items = typeof p.args[0] === "object" ? Object.entries(p.args[0] || {}) : [];
|
|
49
|
+
const limit = Math.min(items.length - (p.opt.skip || 0), p.opt.limit || items.length);
|
|
50
|
+
return items.slice(p.opt.skip || 0, (p.opt.skip || 0) + limit)
|
|
51
|
+
.map((item, index) => p.fn(item[1], {index: index, key: item[0], value: item[1], first: index === 0, last: index === items.length - 1}))
|
|
38
52
|
.join("");
|
|
39
53
|
},
|
|
40
|
-
"if":
|
|
41
|
-
"unless":
|
|
42
|
-
"eq":
|
|
43
|
-
"ne":
|
|
44
|
-
"with":
|
|
54
|
+
"if": p => !!p.args[0] ? p.fn(p.context) : "",
|
|
55
|
+
"unless": p => !!!p.args[0] ? p.fn(p.context) : "",
|
|
56
|
+
"eq": p => p.args[0] === p.args[1] ? p.fn(p.context) : "",
|
|
57
|
+
"ne": p => p.args[0] !== p.args[1] ? p.fn(p.context) : "",
|
|
58
|
+
"with": p => p.fn(p.args[0]),
|
|
45
59
|
};
|
|
46
60
|
|
|
47
61
|
// @description create a new instance of mikel
|
|
@@ -64,9 +78,11 @@ const create = (template = "", options = {}) => {
|
|
|
64
78
|
output.push(get(context, tokens[i].slice(1).trim()));
|
|
65
79
|
}
|
|
66
80
|
else if (tokens[i].startsWith("#") && typeof helpers[tokens[i].slice(1).trim().split(" ")[0]] === "function") {
|
|
67
|
-
const [t,
|
|
81
|
+
const [t, args, opt] = parseArgs(tokens[i].slice(1), context, vars);
|
|
68
82
|
const j = i + 1;
|
|
69
|
-
output.push(helpers[t](
|
|
83
|
+
output.push(helpers[t]({
|
|
84
|
+
args: args,
|
|
85
|
+
opt: opt,
|
|
70
86
|
context: context,
|
|
71
87
|
fn: (blockContext = {}, blockVars = {}, blockOutput = []) => {
|
|
72
88
|
i = compile(tokens, blockOutput, blockContext, {...vars, ...blockVars, root: vars.root}, j, t);
|
|
@@ -100,9 +116,9 @@ const create = (template = "", options = {}) => {
|
|
|
100
116
|
}
|
|
101
117
|
}
|
|
102
118
|
else if (tokens[i].startsWith("=")) {
|
|
103
|
-
const [t,
|
|
119
|
+
const [t, args, opt] = parseArgs(tokens[i].slice(1), context, vars);
|
|
104
120
|
if (typeof functions[t] === "function") {
|
|
105
|
-
output.push(functions[t](
|
|
121
|
+
output.push(functions[t]({args, opt, context}) || "");
|
|
106
122
|
}
|
|
107
123
|
}
|
|
108
124
|
else if (tokens[i].startsWith("/")) {
|