mikel 0.14.1 → 0.16.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 +32 -0
  2. package/index.js +25 -6
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -142,6 +142,38 @@ const result = m("User: {{>user userName=name userEmail=email }}", data, {partia
142
142
 
143
143
  Please note that providing keyword arguments and a custom context to a partial is not supported. On this situation, the partial will be evaluated only with the custom context.
144
144
 
145
+ #### Partial blocks
146
+
147
+ > This feature was added in `v0.16.0`.
148
+
149
+ You can pass a block to a partial using a greather than symbol `>>` followed by the partial name to start the partial block, and a slash followed by the partial name to end the partial block. The provided block content will be available in the `@content` variable.
150
+
151
+ Example:
152
+
153
+ ```javascript
154
+ const options = {
155
+ partials: {
156
+ foo: "Hello {{@content}}!",
157
+ },
158
+ };
159
+
160
+ const result = m("{{>>foo}}Bob{{/foo}}", {}, options);
161
+ // Output: 'Hello Bob!'
162
+ ```
163
+
164
+ ### Inline partials
165
+
166
+ > This feature was added in `v0.16.0`.
167
+
168
+ Inline partials allows you to define partials directly in your template. Use the plus symbol `+` followed by the partial name to start the partial definition, and end the partial definition with a slash `/` followed by the partial name. For example, `{{<foo}}` begins a partial definition called `foo`, and `{{/foo}}` ends it.
169
+
170
+ Example:
171
+
172
+ ```javascript
173
+ const result = m(`{{<foo}}Hello {{name}}!{{/foo}}{{>foo name="Bob"}}`, {});
174
+ // Output: 'Hello Bob!'
175
+ ```
176
+
145
177
  ### Built-in helpers
146
178
 
147
179
  > Added in `v0.4.0`.
package/index.js CHANGED
@@ -1,4 +1,3 @@
1
- const tags = /\{\{|\}\}/;
2
1
  const escapedChars = {
3
2
  "&": "&amp;",
4
3
  "<": "&lt;",
@@ -11,6 +10,12 @@ const escape = s => s.toString().replace(/[&<>\"']/g, m => escapedChars[m]);
11
10
 
12
11
  const get = (c, p) => (p === "." ? c : p.split(".").reduce((x, k) => x?.[k], c)) ?? "";
13
12
 
13
+ // @description tokenize and untokenize methods
14
+ const tokenize = (str = "") => str.split(/\{\{|\}\}/);
15
+ const untokenize = (ts = [], s = "{{", e = "}}") => {
16
+ return ts.reduce((p, t, i) => p + (i % 2 === 0 ? e : s) + t);
17
+ };
18
+
14
19
  // @description parse string arguments
15
20
  const parseArgs = (argString = "", context = {}, vars = {}) => {
16
21
  const [t, ...args] = argString.trim().match(/(?:[^\s"]+|"[^"]*")+/g);
@@ -60,9 +65,8 @@ const defaultHelpers = {
60
65
 
61
66
  // @description create a new instance of mikel
62
67
  const create = (template = "", options = {}) => {
63
- // initialize internal context
64
68
  const helpers = Object.assign({}, defaultHelpers, options?.helpers || {});
65
- const partials = options?.partials || {};
69
+ const partials = Object.assign({}, options?.partials || {});
66
70
  const functions = options?.functions || {};
67
71
  // internal method to compile the template
68
72
  const compile = (tokens, output, context, vars, index = 0, section = "") => {
@@ -103,11 +107,26 @@ const create = (template = "", options = {}) => {
103
107
  i = compile(tokens, includeOutput ? output : [], context, vars, i + 1, t);
104
108
  }
105
109
  }
110
+ else if (tokens[i].startsWith("<")) {
111
+ const t = tokens[i].slice(1).trim(), partialTokens = tokens.slice(i + 1);
112
+ const lastIndex = partialTokens.findIndex((token, j) => {
113
+ return j % 2 !== 0 && token.trim().startsWith("/") && token.trim().endsWith(t);
114
+ });
115
+ if (typeof partials[t] === "undefined") {
116
+ partials[t] = untokenize(partialTokens.slice(0, lastIndex));
117
+ }
118
+ i = i + lastIndex + 1;
119
+ }
106
120
  else if (tokens[i].startsWith(">")) {
107
- const [t, args, opt] = parseArgs(tokens[i].slice(1), context, vars);
121
+ const [t, args, opt] = parseArgs(tokens[i].replace(/^>{1,2}/, ""), context, vars);
122
+ const blockContent = []; // to store partial block content
123
+ if (tokens[i].startsWith(">>")) {
124
+ i = compile(tokens, blockContent, context, vars, i + 1, t);
125
+ }
108
126
  if (typeof partials[t] === "string") {
109
127
  const newCtx = args.length > 0 ? args[0] : (Object.keys(opt).length > 0 ? opt : context);
110
- compile(partials[t].split(tags), output, newCtx, vars, 0, "");
128
+ const newVars = {...vars, content: blockContent.join("")};
129
+ compile(tokenize(partials[t]), output, newCtx, newVars, 0, "");
111
130
  }
112
131
  }
113
132
  else if (tokens[i].startsWith("=")) {
@@ -139,7 +158,7 @@ const create = (template = "", options = {}) => {
139
158
  };
140
159
  // entry method to compile the template with the provided data object
141
160
  const compileTemplate = (data = {}, output = []) => {
142
- compile(template.split(tags), output, data, {root: data}, 0, "");
161
+ compile(tokenize(template), output, data, {root: data}, 0, "");
143
162
  return output.join("");
144
163
  };
145
164
  // assign api methods and return method to compile the template
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.14.1",
4
+ "version": "0.16.0",
5
5
  "type": "module",
6
6
  "author": {
7
7
  "name": "Josemi Juanes",