mikel 0.7.0 → 0.8.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 +66 -16
- package/index.js +21 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -214,7 +214,7 @@ const data = {
|
|
|
214
214
|
};
|
|
215
215
|
const options = {
|
|
216
216
|
helpers: {
|
|
217
|
-
customHelper:
|
|
217
|
+
customHelper: value => {
|
|
218
218
|
return `Hello, ${value}!`;
|
|
219
219
|
},
|
|
220
220
|
},
|
|
@@ -224,15 +224,32 @@ const result = m(template, data, options);
|
|
|
224
224
|
console.log(result); // Output: "Hello, World!"
|
|
225
225
|
```
|
|
226
226
|
|
|
227
|
-
Custom helper functions receive
|
|
227
|
+
Custom helper functions receive multiple arguments, where the first N arguments are the variables with the helper is called in the template, and the last argument is an options object containing the following keys:
|
|
228
228
|
|
|
229
|
-
- `context`:
|
|
230
|
-
- `
|
|
231
|
-
- `key`: The field used to extract the value from the current context.
|
|
232
|
-
- `options`: The global options object.
|
|
233
|
-
- `fn`: A function that executes the template provided in the helper block and returns a string with the evaluated template in the provided context.
|
|
229
|
+
- `context`: the current context (data) where the helper has been executed.
|
|
230
|
+
- `fn`: a function that executes the template provided in the helper block and returns a string with the evaluated template in the provided context.
|
|
234
231
|
|
|
235
|
-
The helper function must return a string, which will be injected into the result string.
|
|
232
|
+
The helper function must return a string, which will be injected into the result string. Example:
|
|
233
|
+
|
|
234
|
+
```javascript
|
|
235
|
+
const data = {
|
|
236
|
+
items: [
|
|
237
|
+
{ name: "John" },
|
|
238
|
+
{ name: "Alice" },
|
|
239
|
+
{ name: "Bob" },
|
|
240
|
+
],
|
|
241
|
+
};
|
|
242
|
+
const options = {
|
|
243
|
+
helpers: {
|
|
244
|
+
customEach: (items, opt) => {
|
|
245
|
+
return items.map((item, index) => opt.fn({ ...item, index: index})).join("");
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const result = m("{{#customEach items}}{{index}}: {{name}}, {{/customEach}}", data, options);
|
|
251
|
+
console.log(result); // --> "0: John, 1: Alice, 2: Bob,"
|
|
252
|
+
```
|
|
236
253
|
|
|
237
254
|
### Runtime Variables
|
|
238
255
|
|
|
@@ -288,7 +305,7 @@ The `@last` variable allows to check if the current iteration using the `#each`
|
|
|
288
305
|
|
|
289
306
|
### Custom runtime variables
|
|
290
307
|
|
|
291
|
-
> Added in `v0.5.0
|
|
308
|
+
> Added in `v0.5.0`.
|
|
292
309
|
|
|
293
310
|
Mikel allows users to define custom data variables, providing enhanced flexibility and customization options for templates. These custom data variables can be accessed within the template using the `@` character.
|
|
294
311
|
|
|
@@ -307,18 +324,51 @@ console.log(result); // --> 'Hello, World!'
|
|
|
307
324
|
|
|
308
325
|
In this example, the custom data variable `customVariable` is defined with the value `"World"`, and it can be accessed in the template using `@customVariable`.
|
|
309
326
|
|
|
327
|
+
### Functions
|
|
328
|
+
|
|
329
|
+
> Added in `v0.8.0`.
|
|
330
|
+
|
|
331
|
+
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.
|
|
332
|
+
|
|
333
|
+
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.
|
|
334
|
+
|
|
335
|
+
Example:
|
|
336
|
+
|
|
337
|
+
```javascript
|
|
338
|
+
const data = {
|
|
339
|
+
user: {
|
|
340
|
+
firstName: "John",
|
|
341
|
+
lastName: "Doe",
|
|
342
|
+
},
|
|
343
|
+
};
|
|
344
|
+
const options = {
|
|
345
|
+
functions: {
|
|
346
|
+
fullName: (firstName, lastName) => {
|
|
347
|
+
return `${firstName} ${lastName}`;
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
const result = m("My name is: {{=fullName user.firstName user.lastName}}", data, options);
|
|
353
|
+
console.log(result); // --> "My name is: John Doe"
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
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.
|
|
357
|
+
|
|
358
|
+
|
|
310
359
|
## API
|
|
311
360
|
|
|
312
361
|
### `mikel(template, data[, options])`
|
|
313
362
|
|
|
314
|
-
Render the given template string with the provided data object.
|
|
363
|
+
Render the given template string with the provided data object and options.
|
|
315
364
|
|
|
316
|
-
- `template` (string):
|
|
317
|
-
- `data` (object):
|
|
318
|
-
- `options` (object):
|
|
319
|
-
- `partials` (object):
|
|
320
|
-
- `variables` (object):
|
|
321
|
-
- `helpers` (object):
|
|
365
|
+
- `template` (string): the template string.
|
|
366
|
+
- `data` (object): the data object containing the values to render.
|
|
367
|
+
- `options` (object): an object containing the following optional values:
|
|
368
|
+
- `partials` (object): an object containing the available partials.
|
|
369
|
+
- `variables` (object): an object containing custom data variables.
|
|
370
|
+
- `helpers` (object): an object containing custom helpers.
|
|
371
|
+
- `functions` (object): and object containing custom functions.
|
|
322
372
|
|
|
323
373
|
Returns: A string with the rendered output.
|
|
324
374
|
|
package/index.js
CHANGED
|
@@ -12,17 +12,16 @@ const escape = s => s.toString().replace(/[&<>\"']/g, m => escapedChars[m]);
|
|
|
12
12
|
const get = (c, p) => (p === "." ? c : p.split(".").reduce((x, k) => x?.[k], c)) ?? "";
|
|
13
13
|
|
|
14
14
|
const defaultHelpers = {
|
|
15
|
-
"each": (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
.map((item, index) => fn(item[1], {index: index, key: item[0], value: item[1], first: index === 0, last: index === items.length - 1}))
|
|
15
|
+
"each": (value, opt) => {
|
|
16
|
+
return (typeof value === "object" ? Object.entries(value || {}) : [])
|
|
17
|
+
.map((item, index, items) => opt.fn(item[1], {index: index, key: item[0], value: item[1], first: index === 0, last: index === items.length - 1}))
|
|
19
18
|
.join("");
|
|
20
19
|
},
|
|
21
|
-
"if": (
|
|
22
|
-
"unless": (
|
|
20
|
+
"if": (value, opt) => !!value ? opt.fn(opt.context) : "",
|
|
21
|
+
"unless": (value, opt) => !!!value ? opt.fn(opt.context) : "",
|
|
23
22
|
};
|
|
24
23
|
|
|
25
|
-
const compile = (tokens, output, context, partials, helpers, vars, index = 0, section = "") => {
|
|
24
|
+
const compile = (tokens, output, context, partials, helpers, vars, fn = {}, index = 0, section = "") => {
|
|
26
25
|
let i = index;
|
|
27
26
|
while (i < tokens.length) {
|
|
28
27
|
if (i % 2 === 0) {
|
|
@@ -35,20 +34,18 @@ const compile = (tokens, output, context, partials, helpers, vars, index = 0, se
|
|
|
35
34
|
output.push(get(context, tokens[i].slice(1).trim()));
|
|
36
35
|
}
|
|
37
36
|
else if (tokens[i].startsWith("#") && typeof helpers[tokens[i].slice(1).trim().split(" ")[0]] === "function") {
|
|
38
|
-
const [t,
|
|
37
|
+
const [t, ...args] = tokens[i].slice(1).trim().split(" ");
|
|
39
38
|
const j = i + 1;
|
|
40
|
-
output.push(helpers[t]({
|
|
39
|
+
output.push(helpers[t](...args.map(v => (v || "").startsWith("@") ? get(vars, v.slice(1)) : get(context, v || ".")), {
|
|
41
40
|
context: context,
|
|
42
|
-
key: v || ".",
|
|
43
|
-
value: (v || "").startsWith("@") ? get(vars, v.slice(1)) : get(context, v || "."),
|
|
44
41
|
fn: (blockContext = {}, blockVars = {}, blockOutput = []) => {
|
|
45
|
-
i = compile(tokens, blockOutput, blockContext, partials, helpers, {...vars, ...blockVars, root: vars.root}, j, t);
|
|
42
|
+
i = compile(tokens, blockOutput, blockContext, partials, helpers, {...vars, ...blockVars, root: vars.root}, fn, j, t);
|
|
46
43
|
return blockOutput.join("");
|
|
47
44
|
},
|
|
48
45
|
}));
|
|
49
|
-
// Make sure that this block
|
|
46
|
+
// Make sure that this block is executed at least once
|
|
50
47
|
if (i + 1 === j) {
|
|
51
|
-
i = compile(tokens, [], {},
|
|
48
|
+
i = compile(tokens, [], {}, {}, {}, {}, {}, j, t);
|
|
52
49
|
}
|
|
53
50
|
}
|
|
54
51
|
else if (tokens[i].startsWith("#") || tokens[i].startsWith("^")) {
|
|
@@ -58,18 +55,24 @@ const compile = (tokens, output, context, partials, helpers, vars, index = 0, se
|
|
|
58
55
|
if (!negate && value && Array.isArray(value)) {
|
|
59
56
|
const j = i + 1;
|
|
60
57
|
(value.length > 0 ? value : [""]).forEach(item => {
|
|
61
|
-
i = compile(tokens, value.length > 0 ? output : [], item, partials, helpers, vars, j, t);
|
|
58
|
+
i = compile(tokens, value.length > 0 ? output : [], item, partials, helpers, vars, fn, j, t);
|
|
62
59
|
});
|
|
63
60
|
}
|
|
64
61
|
else {
|
|
65
62
|
const includeOutput = (!negate && !!value) || (negate && !!!value);
|
|
66
|
-
i = compile(tokens, includeOutput ? output : [], context, partials, helpers, vars, i + 1, t);
|
|
63
|
+
i = compile(tokens, includeOutput ? output : [], context, partials, helpers, vars, fn, i + 1, t);
|
|
67
64
|
}
|
|
68
65
|
}
|
|
69
66
|
else if (tokens[i].startsWith(">")) {
|
|
70
67
|
const [t, v] = tokens[i].slice(1).trim().split(" ");
|
|
71
68
|
if (typeof partials[t] === "string") {
|
|
72
|
-
compile(partials[t].split(tags), output, v ? get(context, v) : context, partials, helpers, vars, 0, "");
|
|
69
|
+
compile(partials[t].split(tags), output, v ? get(context, v) : context, partials, helpers, vars, fn, 0, "");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else if (tokens[i].startsWith("=")) {
|
|
73
|
+
const [t, ...args] = tokens[i].slice(1).trim().split(" ");
|
|
74
|
+
if (typeof fn[t] === "function") {
|
|
75
|
+
output.push(fn[t](...args.map(v => (v || "").startsWith("@") ? get(vars, v.slice(1)) : get(context, v || "."))) || "");
|
|
73
76
|
}
|
|
74
77
|
}
|
|
75
78
|
else if (tokens[i].startsWith("/")) {
|
|
@@ -91,7 +94,7 @@ const mikel = (str, context = {}, opt = {}, output = []) => {
|
|
|
91
94
|
const partials = Object.assign({}, opt.partials || {});
|
|
92
95
|
const helpers = Object.assign({}, defaultHelpers, opt.helpers || {});
|
|
93
96
|
const variables = Object.assign({}, opt.variables || {}, {root: context});
|
|
94
|
-
compile(str.split(tags), output, context, partials, helpers, variables, 0, "");
|
|
97
|
+
compile(str.split(tags), output, context, partials, helpers, variables, opt.functions || {}, 0, "");
|
|
95
98
|
return output.join("");
|
|
96
99
|
};
|
|
97
100
|
|