mikel 0.3.2 → 0.4.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 +128 -2
- package/index.js +39 -10
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -68,7 +68,9 @@ const result = m("{{^isAdmin}}You are not Admin{{/isAdmin}}", data);
|
|
|
68
68
|
// Output: 'You are not Admin'
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
-
### Partials
|
|
71
|
+
### Partials
|
|
72
|
+
|
|
73
|
+
> This feature was added in `v0.3.0`
|
|
72
74
|
|
|
73
75
|
Partials allow you to include separate templates within your main template. Use the greater than symbol `>` followed by the partial name inside double curly braces `{{> partialName }}`.
|
|
74
76
|
|
|
@@ -87,7 +89,9 @@ const result = m("{{> hello}}", data, {partials});
|
|
|
87
89
|
// Output: 'Hello Bob!'
|
|
88
90
|
```
|
|
89
91
|
|
|
90
|
-
#### Custom context in partials
|
|
92
|
+
#### Custom context in partials
|
|
93
|
+
|
|
94
|
+
> This feature was added in `v0.3.1`.
|
|
91
95
|
|
|
92
96
|
You can provide a custom context for the partial by specifying a field of the data: `{{> partialName dataField}}`.
|
|
93
97
|
|
|
@@ -106,6 +110,128 @@ const result = m("User: {{> user currentUser}}", data, {partials});
|
|
|
106
110
|
// Output: 'User: John Doe <john@example.com>'
|
|
107
111
|
```
|
|
108
112
|
|
|
113
|
+
### Built-in helpers
|
|
114
|
+
|
|
115
|
+
> Added in `v0.4.0`.
|
|
116
|
+
|
|
117
|
+
Helpers allows you to execute special functions within blocks or sections of your template. Mikel currently supports the following built-in helpers:
|
|
118
|
+
|
|
119
|
+
#### each
|
|
120
|
+
|
|
121
|
+
The `each` helper iterates over an array and renders the block for each item in the array.
|
|
122
|
+
|
|
123
|
+
Syntax: `{{#each arrayName}} ... {{/each}}`.
|
|
124
|
+
|
|
125
|
+
Example:
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
const data = {
|
|
129
|
+
users: ["John", "Alice", "Bob"],
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
console.log(m("{{#each users}}{{.}}, {{/each}}", data)); // --> 'John, Alice, Bob, '
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
When looping throug arrays, you can use the variable `@index` to access to the current index of the item in the array:
|
|
136
|
+
|
|
137
|
+
```javascript
|
|
138
|
+
const data = {
|
|
139
|
+
users: ["John", "Alice", "Bob"],
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
console.log(m("{{#each users}}{{@index}}: {{.}}, {{/each}}", data)); // --> '0: John, 1: Alice, 2: Bob, '
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The `each` helper can also iterate over objects:
|
|
146
|
+
|
|
147
|
+
```javascript
|
|
148
|
+
const data = {
|
|
149
|
+
values: {
|
|
150
|
+
foo: "bar",
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
console.log(m("{{#each values}}{{.}}{{/each}}", data)); // --> 'bar'
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
When looping throug objects, you can use the variable `@key` to access to the current key in the object, and the variable `@value` to access to the corresponding value:
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
const data = {
|
|
161
|
+
values: {
|
|
162
|
+
foo: "0",
|
|
163
|
+
bar: "1",
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
console.log(m("{{#each values}}{{@key}}: {{@value}}, {{/each}}", data)); // --> 'foo: 0, bar: 1, '
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### if
|
|
171
|
+
|
|
172
|
+
The `if` helper renders the block only if the condition is truthy.
|
|
173
|
+
|
|
174
|
+
Syntax: `{{#if condition}} ... {{/if}}`
|
|
175
|
+
|
|
176
|
+
Example:
|
|
177
|
+
|
|
178
|
+
```javascript
|
|
179
|
+
const data = {
|
|
180
|
+
isAdmin: true,
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
console.log(m("{{#if isAdmin}}Hello admin{{/if}}", data)); // --> 'Hello admin'
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
#### unless
|
|
187
|
+
|
|
188
|
+
The `unless` helper renders the block only if the condition is falsy.
|
|
189
|
+
|
|
190
|
+
Syntax: `{{#unless condition}} ... {{/unless}}`
|
|
191
|
+
|
|
192
|
+
Example:
|
|
193
|
+
|
|
194
|
+
```javascript
|
|
195
|
+
const data = {
|
|
196
|
+
isAdmin: false,
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
console.log(m("{{#unless isAdmin}}Hello guest{{/unless}}", data)); // --> 'Hello guest'
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### At-Variables
|
|
203
|
+
|
|
204
|
+
> Added in `v0.4.0`.
|
|
205
|
+
|
|
206
|
+
At-Variables in Mikel provide convenient access to special values within your templates. These variables, denoted by the `@` symbol, allow users to interact with specific data contexts or values.
|
|
207
|
+
|
|
208
|
+
#### @root
|
|
209
|
+
|
|
210
|
+
The `@root` variable grants access to the root data context provided to the template. It is always defined and enables users to retrieve values from the top-level data object.
|
|
211
|
+
|
|
212
|
+
Example:
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
215
|
+
const data = {
|
|
216
|
+
name: "World",
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
console.log(m("Hello, {{@root.name}}!", data)); // -> 'Hello, World!'
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### @index
|
|
223
|
+
|
|
224
|
+
The `@index` variable facilitates access to the current index of the item when iterating over an array using the `#each` helper. It aids in dynamic rendering and indexing within loops.
|
|
225
|
+
|
|
226
|
+
#### @key
|
|
227
|
+
|
|
228
|
+
The `@key` variable allows users to retrieve the current key of the object entry when looping through an object using the `#each` helper. It provides access to object keys for dynamic rendering and customization.
|
|
229
|
+
|
|
230
|
+
#### @value
|
|
231
|
+
|
|
232
|
+
The `@value` variable allows users to retrieve the current value of the object entry when iterating over an object using the `#each` helper. It simplifies access to object values for dynamic rendering and data manipulation.
|
|
233
|
+
|
|
234
|
+
|
|
109
235
|
## API
|
|
110
236
|
|
|
111
237
|
### `m(template, data[, options])`
|
package/index.js
CHANGED
|
@@ -12,37 +12,66 @@ const escape = str => {
|
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
const get = (ctx, path) => {
|
|
15
|
-
return path === "." ? ctx :
|
|
15
|
+
return (path === "." ? ctx : path.split(".").reduce((p, k) => p?.[k], ctx)) ?? "";
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
const
|
|
18
|
+
const helpers = new Map(Object.entries({
|
|
19
|
+
"#each": (value, options) => {
|
|
20
|
+
return (typeof value === "object" ? Object.entries(value || {}) : [])
|
|
21
|
+
.map((item, index) => options.fn(item[1], {index: index, key: item[0], value: item[1]}))
|
|
22
|
+
.join("");
|
|
23
|
+
},
|
|
24
|
+
"#if": (value, options) => !!value ? options.fn(options.context) : "",
|
|
25
|
+
"#unless": (value, options) => !!!value ? options.fn(options.context) : "",
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
const compile = (tokens, output, context, opt, index = 0, section = "", vars = {}) => {
|
|
19
29
|
let i = index;
|
|
20
30
|
while (i < tokens.length) {
|
|
21
31
|
if (i % 2 === 0) {
|
|
22
32
|
output.push(tokens[i]);
|
|
23
33
|
}
|
|
34
|
+
else if (tokens[i].startsWith("@")) {
|
|
35
|
+
output.push(get(vars || {}, tokens[i].slice(1).trim() ?? "_") ?? "");
|
|
36
|
+
}
|
|
24
37
|
else if (tokens[i].startsWith("!")) {
|
|
25
|
-
output.push(get(
|
|
38
|
+
output.push(get(context, tokens[i].slice(1).trim()));
|
|
39
|
+
}
|
|
40
|
+
else if (tokens[i].startsWith("#") && helpers.has(tokens[i].trim().split(" ")[0])) {
|
|
41
|
+
const [t, v] = tokens[i].slice(1).trim().split(" ");
|
|
42
|
+
const j = i + 1;
|
|
43
|
+
output.push(helpers.get("#" + t)(get(context, v), {
|
|
44
|
+
context: context,
|
|
45
|
+
globalOptions: opt,
|
|
46
|
+
fn: (blockContext = {}, blockVars = {}, blockOutput = []) => {
|
|
47
|
+
i = compile(tokens, blockOutput, blockContext, opt, j, t, {root: vars.root, ...blockVars});
|
|
48
|
+
return blockOutput.join("");
|
|
49
|
+
},
|
|
50
|
+
}));
|
|
51
|
+
// Make sure that this block has been executed
|
|
52
|
+
if (i + 1 === j) {
|
|
53
|
+
i = compile(tokens, [], {}, opt, j, t, vars);
|
|
54
|
+
}
|
|
26
55
|
}
|
|
27
56
|
else if (tokens[i].startsWith("#") || tokens[i].startsWith("^")) {
|
|
28
57
|
const t = tokens[i].slice(1).trim();
|
|
29
|
-
const value = get(
|
|
58
|
+
const value = get(context, t);
|
|
30
59
|
const negate = tokens[i].startsWith("^");
|
|
31
60
|
if (!negate && value && Array.isArray(value)) {
|
|
32
61
|
const j = i + 1;
|
|
33
62
|
(value.length > 0 ? value : [""]).forEach(item => {
|
|
34
|
-
i = compile(tokens, value.length > 0 ? output : [], item, opt, j, t);
|
|
63
|
+
i = compile(tokens, value.length > 0 ? output : [], item, opt, j, t, vars);
|
|
35
64
|
});
|
|
36
65
|
}
|
|
37
66
|
else {
|
|
38
67
|
const includeOutput = (!negate && !!value) || (negate && !!!value);
|
|
39
|
-
i = compile(tokens, includeOutput ? output : [],
|
|
68
|
+
i = compile(tokens, includeOutput ? output : [], context, opt, i + 1, t, vars);
|
|
40
69
|
}
|
|
41
70
|
}
|
|
42
71
|
else if (tokens[i].startsWith(">")) {
|
|
43
72
|
const [t, v] = tokens[i].slice(1).trim().split(" ");
|
|
44
73
|
if (typeof opt?.partials?.[t] === "string") {
|
|
45
|
-
compile(opt.partials[t].split(tags), output, v ? get(
|
|
74
|
+
compile(opt.partials[t].split(tags), output, v ? get(context, v) : context, opt, 0, "", vars);
|
|
46
75
|
}
|
|
47
76
|
}
|
|
48
77
|
else if (tokens[i].startsWith("/")) {
|
|
@@ -52,14 +81,14 @@ const compile = (tokens, output, ctx, opt, index, section) => {
|
|
|
52
81
|
break;
|
|
53
82
|
}
|
|
54
83
|
else {
|
|
55
|
-
output.push(escape(get(
|
|
84
|
+
output.push(escape(get(context, tokens[i].trim())));
|
|
56
85
|
}
|
|
57
86
|
i = i + 1;
|
|
58
87
|
}
|
|
59
88
|
return i;
|
|
60
89
|
};
|
|
61
90
|
|
|
62
|
-
export default (str,
|
|
63
|
-
compile(str.split(tags), output,
|
|
91
|
+
export default (str, context = {}, opt = {}, output = []) => {
|
|
92
|
+
compile(str.split(tags), output, context, opt, 0, "", {root: context});
|
|
64
93
|
return output.join("");
|
|
65
94
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mikel",
|
|
3
3
|
"description": "Micro templating library with zero dependencies",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Josemi Juanes",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"test": "node test.js"
|
|
21
21
|
},
|
|
22
22
|
"keywords": [
|
|
23
|
-
"
|
|
23
|
+
"template",
|
|
24
24
|
"templating"
|
|
25
25
|
],
|
|
26
26
|
"files": [
|