mikel 0.4.0 → 0.6.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.
Files changed (3) hide show
  1. package/README.md +70 -5
  2. package/index.js +32 -25
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -199,11 +199,46 @@ const data = {
199
199
  console.log(m("{{#unless isAdmin}}Hello guest{{/unless}}", data)); // --> 'Hello guest'
200
200
  ```
201
201
 
202
- ### At-Variables
202
+ ### Custom Helpers
203
+
204
+ > Added in `v0.5.0`.
205
+
206
+ 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.
207
+
208
+ Example:
209
+
210
+ ```javascript
211
+ const template = "{{#greeting name}}{{/greeting}}";
212
+ const data = {
213
+ name: "World!",
214
+ };
215
+ const options = {
216
+ helpers: {
217
+ customHelper: ({context, value, key, options, fn}) => {
218
+ return `Hello, ${value}!`;
219
+ },
220
+ },
221
+ };
222
+
223
+ const result = m(template, data, options);
224
+ console.log(result); // Output: "Hello, World!"
225
+ ```
226
+
227
+ Custom helper functions receive a single object parameter containing the following fields:
228
+
229
+ - `context`: The current context (data) where the helper has been executed.
230
+ - `value`: The current value passed to the helper.
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.
234
+
235
+ The helper function must return a string, which will be injected into the result string.
236
+
237
+ ### Variables
203
238
 
204
239
  > Added in `v0.4.0`.
205
240
 
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.
241
+ Data 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
242
 
208
243
  #### @root
209
244
 
@@ -231,10 +266,30 @@ The `@key` variable allows users to retrieve the current key of the object entry
231
266
 
232
267
  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
268
 
269
+ ### Custom variables
270
+
271
+ > Added in `v0.5.0`
272
+
273
+ 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.
274
+
275
+ Custom data variables should be provided in the `options.variables` field of the options object when rendering a template. Each custom data variable should be defined as a key-value pair, where the key represents the variable name and the value represents the data associated with that variable.
276
+
277
+ Example:
278
+
279
+ ```javascript
280
+ const result = m("Hello, {{@customVariable}}!", {}, {
281
+ variables: {
282
+ customVariable: "World",
283
+ },
284
+ });
285
+ console.log(result); // --> 'Hello, World!'
286
+ ```
287
+
288
+ In this example, the custom data variable `customVariable` is defined with the value `"World"`, and it can be accessed in the template using `@customVariable`.
234
289
 
235
290
  ## API
236
291
 
237
- ### `m(template, data[, options])`
292
+ ### `mikel(template, data[, options])`
238
293
 
239
294
  Render the given template string with the provided data object.
240
295
 
@@ -242,20 +297,30 @@ Render the given template string with the provided data object.
242
297
  - `data` (object): The data object containing the values to render.
243
298
  - `options` (object): An object containing the following optional values:
244
299
  - `partials` (object): An object containing the available partials.
300
+ - `variables` (object): An object containing custom data variables.
301
+ - `helpers` (object): An object containing custom helpers.
245
302
 
246
303
  Returns: A string with the rendered output.
247
304
 
248
305
  ```javascript
249
- import m from "mikel";
306
+ import mikel from "mikel";
250
307
 
251
308
  const data = {
252
309
  name: "World",
253
310
  };
254
311
 
255
- const result = m("Hello, {{name}}!", data);
312
+ const result = mikel("Hello, {{name}}!", data);
256
313
  console.log(result); // Output: "Hello, World!"
257
314
  ```
258
315
 
316
+ ### `mikel.escape(str)`
317
+
318
+ This function converts special HTML characters `&`, `<`, `>`, `"`, and `'` to their corresponding HTML entities.
319
+
320
+ ### `mikel.get(object, path)`
321
+
322
+ This function returns the value in `object` following the provided `path` string.
323
+
259
324
  ## License
260
325
 
261
326
  This project is licensed under the [MIT License](LICENSE).
package/index.js CHANGED
@@ -7,50 +7,47 @@ const escapedChars = {
7
7
  "'": "&#039;",
8
8
  };
9
9
 
10
- const escape = str => {
11
- return str.toString().replace(/[&<>\"']/g, m => escapedChars[m]);
12
- };
10
+ const escape = s => s.toString().replace(/[&<>\"']/g, m => escapedChars[m]);
13
11
 
14
- const get = (ctx, path) => {
15
- return (path === "." ? ctx : path.split(".").reduce((p, k) => p?.[k], ctx)) ?? "";
16
- };
12
+ const get = (c, p) => (p === "." ? c : p.split(".").reduce((x, k) => x?.[k], c)) ?? "";
17
13
 
18
- const helpers = new Map(Object.entries({
19
- "#each": (value, options) => {
14
+ const defaultHelpers = {
15
+ "each": ({value, fn}) => {
20
16
  return (typeof value === "object" ? Object.entries(value || {}) : [])
21
- .map((item, index) => options.fn(item[1], {index: index, key: item[0], value: item[1]}))
17
+ .map((item, index) => fn(item[1], {index: index, key: item[0], value: item[1]}))
22
18
  .join("");
23
19
  },
24
- "#if": (value, options) => !!value ? options.fn(options.context) : "",
25
- "#unless": (value, options) => !!!value ? options.fn(options.context) : "",
26
- }));
20
+ "if": ({value, fn, context}) => !!value ? fn(context) : "",
21
+ "unless": ({value, fn, context}) => !!!value ? fn(context) : "",
22
+ };
27
23
 
28
- const compile = (tokens, output, context, opt, index = 0, section = "", vars = {}) => {
24
+ const compile = (tokens, output, context, partials, helpers, vars, index = 0, section = "") => {
29
25
  let i = index;
30
26
  while (i < tokens.length) {
31
27
  if (i % 2 === 0) {
32
28
  output.push(tokens[i]);
33
29
  }
34
30
  else if (tokens[i].startsWith("@")) {
35
- output.push(get(vars || {}, tokens[i].slice(1).trim() ?? "_") ?? "");
31
+ output.push(get(vars, tokens[i].slice(1).trim() ?? "_") ?? "");
36
32
  }
37
33
  else if (tokens[i].startsWith("!")) {
38
34
  output.push(get(context, tokens[i].slice(1).trim()));
39
35
  }
40
- else if (tokens[i].startsWith("#") && helpers.has(tokens[i].trim().split(" ")[0])) {
36
+ else if (tokens[i].startsWith("#") && typeof helpers[tokens[i].slice(1).trim().split(" ")[0]] === "function") {
41
37
  const [t, v] = tokens[i].slice(1).trim().split(" ");
42
38
  const j = i + 1;
43
- output.push(helpers.get("#" + t)(get(context, v), {
39
+ output.push(helpers[t]({
44
40
  context: context,
45
- globalOptions: opt,
41
+ key: v || ".",
42
+ value: get(context, v || "."),
46
43
  fn: (blockContext = {}, blockVars = {}, blockOutput = []) => {
47
- i = compile(tokens, blockOutput, blockContext, opt, j, t, {root: vars.root, ...blockVars});
44
+ i = compile(tokens, blockOutput, blockContext, partials, helpers, {...vars, ...blockVars, root: vars.root}, j, t);
48
45
  return blockOutput.join("");
49
46
  },
50
47
  }));
51
48
  // Make sure that this block has been executed
52
49
  if (i + 1 === j) {
53
- i = compile(tokens, [], {}, opt, j, t, vars);
50
+ i = compile(tokens, [], {}, partials, helpers, vars, j, t);
54
51
  }
55
52
  }
56
53
  else if (tokens[i].startsWith("#") || tokens[i].startsWith("^")) {
@@ -60,18 +57,18 @@ const compile = (tokens, output, context, opt, index = 0, section = "", vars = {
60
57
  if (!negate && value && Array.isArray(value)) {
61
58
  const j = i + 1;
62
59
  (value.length > 0 ? value : [""]).forEach(item => {
63
- i = compile(tokens, value.length > 0 ? output : [], item, opt, j, t, vars);
60
+ i = compile(tokens, value.length > 0 ? output : [], item, partials, helpers, vars, j, t);
64
61
  });
65
62
  }
66
63
  else {
67
64
  const includeOutput = (!negate && !!value) || (negate && !!!value);
68
- i = compile(tokens, includeOutput ? output : [], context, opt, i + 1, t, vars);
65
+ i = compile(tokens, includeOutput ? output : [], context, partials, helpers, vars, i + 1, t);
69
66
  }
70
67
  }
71
68
  else if (tokens[i].startsWith(">")) {
72
69
  const [t, v] = tokens[i].slice(1).trim().split(" ");
73
- if (typeof opt?.partials?.[t] === "string") {
74
- compile(opt.partials[t].split(tags), output, v ? get(context, v) : context, opt, 0, "", vars);
70
+ if (typeof partials[t] === "string") {
71
+ compile(partials[t].split(tags), output, v ? get(context, v) : context, partials, helpers, vars, 0, "");
75
72
  }
76
73
  }
77
74
  else if (tokens[i].startsWith("/")) {
@@ -88,7 +85,17 @@ const compile = (tokens, output, context, opt, index = 0, section = "", vars = {
88
85
  return i;
89
86
  };
90
87
 
91
- export default (str, context = {}, opt = {}, output = []) => {
92
- compile(str.split(tags), output, context, opt, 0, "", {root: context});
88
+ // @description main compiler function
89
+ const mikel = (str, context = {}, opt = {}, output = []) => {
90
+ const partials = Object.assign({}, opt.partials || {});
91
+ const helpers = Object.assign({}, defaultHelpers, opt.helpers || {});
92
+ const variables = Object.assign({}, opt.variables || {}, {root: context});
93
+ compile(str.split(tags), output, context, partials, helpers, variables, 0, "");
93
94
  return output.join("");
94
95
  };
96
+
97
+ // @description assign utilities
98
+ mikel.escape = escape;
99
+ mikel.get = get;
100
+
101
+ export default mikel;
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.0",
4
+ "version": "0.6.0",
5
5
  "type": "module",
6
6
  "author": {
7
7
  "name": "Josemi Juanes",