mikel-frontmatter 0.31.0 → 0.32.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 (4) hide show
  1. package/README.md +79 -295
  2. package/index.d.ts +9 -1
  3. package/index.js +123 -52
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -3,11 +3,11 @@
3
3
  ![npm version](https://badgen.net/npm/v/mikel-frontmatter?labelColor=1d2734&color=21bf81)
4
4
  ![license](https://badgen.net/github/license/jmjuanes/mikel?labelColor=1d2734&color=21bf81)
5
5
 
6
- A [mikel](https://github.com/jmjuanes/mikel) plugin to define new data inside templates using a frontmatter-like syntax. Supports both **YAML** and **JSON** formats.
6
+ A [mikel](https://github.com/jmjuanes/mikel) plugin to define new data inside templates using a frontmatter-like syntax. Supports **YAML**, **JSON**, and **TOML** formats.
7
7
 
8
8
  ## Installation
9
9
 
10
- You can install Mikel via npm or yarn:
10
+ You can install it via npm or yarn:
11
11
 
12
12
  ```bash
13
13
  ## Install using npm
@@ -19,362 +19,146 @@ $ yarn add mikel mikel-frontmatter
19
19
 
20
20
  ## Usage
21
21
 
22
- This plugin provides a `{{#frontmatter}}` helper that allows you to define metadata at the beginning of your templates, similar to frontmatter in Markdown files. The parsed data is stored as a variable accessible via `@frontmatter` (or a custom variable name).
23
-
24
- The plugin automatically detects the format:
25
- - **YAML format**: When the content doesn't start with `{`
26
- - **JSON format**: When the content starts with `{` and ends with `}`
27
-
28
- ### YAML Example
22
+ Import the `mikel-frontmatter` package:
29
23
 
30
24
  ```javascript
31
25
  import mikel from "mikel";
32
26
  import mikelFrontmatter from "mikel-frontmatter";
27
+ ```
33
28
 
34
- const template = `
35
- {{#frontmatter}}
36
- title: My Page Title
37
- author: John Doe
38
- date: 2026-02-03
39
- tags:
40
- - javascript
41
- - templating
42
- settings:
43
- published: true
44
- featured: false
45
- {{/frontmatter}}
46
-
47
- <h1>{{@frontmatter.title}}</h1>
48
- <p>By {{@frontmatter.author}} on {{@frontmatter.date}}</p>
49
-
50
- {{#if @frontmatter.settings.published}}
51
- <span class="badge">Published</span>
52
- {{/if}}
53
-
54
- <ul>
55
- {{#each @frontmatter.tags}}
56
- <li>{{this}}</li>
57
- {{/each}}
58
- </ul>
59
- `;
29
+ Include the plugin using the `use` method of mikel:
60
30
 
61
- const render = mikel.create();
62
- render.use(mikelFrontmatter());
31
+ ```javascript
32
+ const m = mikel.create();
63
33
 
64
- const result = render(template, {});
65
- console.log(result);
34
+ m.use(mikelFrontmatter({ ... }));
66
35
  ```
67
36
 
68
- ### JSON Example
37
+ In your template, the `{{#frontmatter}}` helper allows you to define metadata at the beginning of your templates, similar to frontmatter in Markdown files. The parsed data is stored as a variable accessible via `@frontmatter` (or a custom variable name, see below).
69
38
 
70
- ```javascript
71
- import mikel from "mikel";
72
- import mikelFrontmatter from "mikel-frontmatter";
39
+ Example:
73
40
 
74
- const template = `
41
+ ```html
75
42
  {{#frontmatter}}
76
- {
77
- "title": "My Page Title",
78
- "author": "John Doe",
79
- "date": "2026-02-03",
80
- "tags": ["javascript", "templating"],
81
- "settings": {
82
- "published": true,
83
- "featured": false
84
- }
85
- }
43
+ title: My Page Title
44
+ author: John Doe
45
+ date: 2026-02-03
46
+ tags:
47
+ - javascript
48
+ - templating
86
49
  {{/frontmatter}}
87
-
88
50
  <h1>{{@frontmatter.title}}</h1>
89
51
  <p>By {{@frontmatter.author}} on {{@frontmatter.date}}</p>
90
-
91
- {{#if @frontmatter.settings.published}}
92
- <span class="badge">Published</span>
93
- {{/if}}
94
-
95
52
  <ul>
96
- {{#each @frontmatter.tags}}
97
- <li>{{this}}</li>
98
- {{/each}}
53
+ {{#each @frontmatter.tags}}
54
+ <li>{{this}}</li>
55
+ {{/each}}
99
56
  </ul>
100
- `;
101
-
102
- const render = mikel.create();
103
- render.use(mikelFrontmatter());
104
-
105
- const result = render(template, {});
106
- console.log(result);
107
57
  ```
108
58
 
109
- ## Features
110
-
111
- ### Format Auto-Detection
112
-
113
- The plugin automatically detects whether your frontmatter is in YAML or JSON format:
114
-
115
- ```javascript
116
- // YAML format (default)
117
- {{#frontmatter}}
118
- title: My Title
119
- author: John Doe
120
- {{/frontmatter}}
121
-
122
- // JSON format (automatically detected)
123
- {{#frontmatter}}
124
- {
125
- "title": "My Title",
126
- "author": "John Doe"
127
- }
128
- {{/frontmatter}}
129
- ```
130
-
131
- ### Basic Key-Value Pairs
132
-
133
- ```javascript
134
- const template = `
135
- {{#frontmatter}}
136
- title: Hello World
137
- author: Jane Smith
138
- version: 1.0.0
139
- {{/frontmatter}}
140
-
141
- Title: {{@frontmatter.title}}
142
- `;
143
- ```
144
-
145
- ### Data Types
146
-
147
- The plugin supports common data types in both YAML and JSON:
59
+ Note that this helper doesn't produce any output in the rendered template.
148
60
 
149
- **YAML:**
150
- - **Strings**: `name: John Doe` or `name: "John Doe"` or `name: 'John Doe'`
151
- - **Numbers**: `age: 25` or `price: 19.99`
152
- - **Booleans**: `published: true` or `active: false` (also `yes/no`, `on/off`)
153
- - **Null**: `value: null` or `value: ~` or `value:`
61
+ ### Customization
154
62
 
155
- **JSON:**
156
- - **Strings**: `"name": "John Doe"`
157
- - **Numbers**: `"age": 25` or `"price": 19.99`
158
- - **Booleans**: `"published": true` or `"active": false`
159
- - **Null**: `"value": null`
63
+ The `{{#frontmatter}}` helper accepts the following arguments:
160
64
 
161
- ### Nested Objects
65
+ #### as
162
66
 
163
- Both YAML and JSON support nested objects:
67
+ Custom variable name to save parsed metadata. If not provided, parsed metadata will be saved in `@frontmatter`. Example:
164
68
 
165
- **YAML:**
166
- ```javascript
167
- const template = `
168
- {{#frontmatter}}
169
- author:
170
- name: John Doe
171
- email: john@example.com
172
- social:
173
- twitter: @johndoe
174
- github: johndoe
175
- {{/frontmatter}}
176
-
177
- Author: {{@frontmatter.author.name}} ({{@frontmatter.author.email}})
178
- Twitter: {{@frontmatter.author.social.twitter}}
179
- `;
180
- ```
181
-
182
- **JSON:**
183
- ```javascript
184
- const template = `
185
- {{#frontmatter}}
186
- {
187
- "author": {
188
- "name": "John Doe",
189
- "email": "john@example.com",
190
- "social": {
191
- "twitter": "@johndoe",
192
- "github": "johndoe"
193
- }
194
- }
195
- }
196
- {{/frontmatter}}
197
-
198
- Author: {{@frontmatter.author.name}} ({{@frontmatter.author.email}})
199
- Twitter: {{@frontmatter.author.social.twitter}}
200
- `;
201
- ```
202
-
203
- ### Arrays
204
-
205
- Both formats support arrays:
206
-
207
- **YAML:**
208
- ```javascript
209
- const template = `
210
- {{#frontmatter}}
211
- tags:
212
- - javascript
213
- - nodejs
214
- - template
215
- colors:
216
- - red
217
- - green
218
- - blue
219
- {{/frontmatter}}
220
-
221
- Tags: {{#each @frontmatter.tags}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}
222
- `;
223
- ```
224
-
225
- **JSON:**
226
- ```javascript
227
- const template = `
228
- {{#frontmatter}}
229
- {
230
- "tags": ["javascript", "nodejs", "template"],
231
- "colors": ["red", "green", "blue"]
232
- }
69
+ ```html
70
+ {{#frontmatter as="meta"}}
71
+ name: Bob
233
72
  {{/frontmatter}}
234
-
235
- Tags: {{#each @frontmatter.tags}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}
236
- `;
73
+ <div>Hello {{@meta.name}}</div>
237
74
  ```
238
75
 
239
- ### Arrays of Objects
76
+ #### format
240
77
 
241
- **YAML:**
242
- ```javascript
243
- const template = `
244
- {{#frontmatter}}
245
- contributors:
246
- - name: Alice
247
- role: Developer
248
- - name: Bob
249
- role: Designer
250
- - name: Carol
251
- role: Manager
252
- {{/frontmatter}}
78
+ The format of the frontmatter content. Supported values are `yaml` (default), `json`, and `toml`.
253
79
 
254
- {{#each @frontmatter.contributors}}
255
- <div>{{name}} - {{role}}</div>
256
- {{/each}}
257
- `;
258
- ```
80
+ Example using JSON:
259
81
 
260
- **JSON:**
261
- ```javascript
262
- const template = `
263
- {{#frontmatter}}
82
+ ```html
83
+ {{#frontmatter format="json"}}
264
84
  {
265
- "contributors": [
266
- { "name": "Alice", "role": "Developer" },
267
- { "name": "Bob", "role": "Designer" },
268
- { "name": "Carol", "role": "Manager" }
269
- ]
85
+ "title": "My JSON Page",
86
+ "tags": ["json", "mikel"]
270
87
  }
271
88
  {{/frontmatter}}
272
-
273
- {{#each @frontmatter.contributors}}
274
- <div>{{name}} - {{role}}</div>
275
- {{/each}}
276
- `;
277
89
  ```
278
90
 
279
- ### Custom Variable Name
91
+ Example using TOML:
280
92
 
281
- Use the `as` option to store the frontmatter data in a custom variable:
93
+ ```html
94
+ {{#frontmatter format="toml"}}
95
+ title = "My TOML Page"
96
+ tags = ["toml", "mikel"]
282
97
 
283
- ```javascript
284
- const template = `
285
- {{#frontmatter as="meta"}}
286
- title: My Page
287
- description: A great page
98
+ [author]
99
+ name = "John Doe"
288
100
  {{/frontmatter}}
289
-
290
- <title>{{@meta.title}}</title>
291
- <meta name="description" content="{{@meta.description}}">
292
- `;
293
- ```
294
-
295
- ### Multiple Frontmatter Blocks
296
-
297
- You can have multiple `{{#frontmatter}}` blocks in a template. Later blocks will overwrite earlier ones:
298
-
299
- ```javascript
300
- const template = `
301
- {{#frontmatter}}
302
- title: Original Title
303
- author: John
304
- {{/frontmatter}}
305
-
306
- {{#frontmatter}}
307
- title: Updated Title
308
- status: draft
309
- {{/frontmatter}}
310
-
311
- Title: {{@frontmatter.title}}
312
- Author: {{@frontmatter.author}}
313
- Status: {{@frontmatter.status}}
314
- `;
315
-
316
- // Output:
317
- // Title: Updated Title
318
- // Author: (empty, overwritten)
319
- // Status: draft
320
101
  ```
321
102
 
322
103
  ## API
323
104
 
324
105
  ### mikelFrontmatter(options?)
325
106
 
326
- Creates a new instance of the frontmatter plugin.
327
-
328
- **Parameters:**
329
- - `options` (optional): Configuration options for the plugin.
330
- - `parser` (Function): Custom parser function to override the default YAML/JSON parser.
331
-
332
- **Returns:** A plugin object with a `frontmatter` helper.
333
-
334
- ### Helper: `{{#frontmatter}}...{{/frontmatter}}`
107
+ Creates a new instance of the frontmatter plugin. It accepts an `options` parameters containing the following fields:
108
+ - `parser` (Function): Custom parser function to override the default YAML/JSON/TOML parser.
335
109
 
336
- Parses the content inside the block as YAML or JSON (auto-detected) and stores it as a variable.
337
110
 
338
- **Options:**
339
- - `as`: Custom variable name (default: `"frontmatter"`). Example: `{{#frontmatter as="meta"}}`
340
-
341
- **Output:** This helper doesn't produce any output in the rendered template.
342
-
343
- ### Custom Parser
111
+ ## Custom Parser
344
112
 
345
113
  You can provide a custom parser function if you need special parsing logic:
346
114
 
347
115
  ```javascript
348
- const customParser = (content) => {
349
- // Your custom parsing logic
116
+ const customParser = (content, format) => {
117
+ // Your custom parsing logic based on content and format
350
118
  return parsedData;
351
119
  };
352
120
 
353
121
  const render = mikel.create();
354
- render.use(mikelFrontmatter({ parser: customParser }));
122
+ render.use(mikelFrontmatter({
123
+ parser: customParser,
124
+ }));
355
125
  ```
356
126
 
357
127
  ## YAML Syntax Support
358
128
 
359
129
  This plugin includes a basic YAML parser that supports:
360
130
 
361
- - ✅ Key-value pairs
362
- - ✅ Nested objects (with indentation)
363
- - ✅ Arrays (using `- item` syntax)
364
- - ✅ Arrays of objects
365
- - ✅ Strings, numbers, booleans, null
366
- - ✅ Quoted strings (`"..."` or `'...'`)
367
- - ✅ Comments (lines starting with `#`)
368
- - Boolean variants (`yes/no`, `on/off`, `true/false`)
369
- - ❌ Multi-line strings (with `|` or `>`)
370
- - ❌ Anchors and aliases (`&anchor`, `*alias`)
371
- - ❌ Complex YAML features
372
-
373
- For most common use cases, this subset is sufficient.
131
+ - ✅ Key-value pairs.
132
+ - ✅ Nested objects (with indentation).
133
+ - ✅ Arrays (using `- item` syntax).
134
+ - ✅ Arrays of objects.
135
+ - ✅ Inline arrays `[item1, item2, ...]`.
136
+ - ✅ Inline objects `{key1: value1, key2: value2, ...}`.
137
+ - ✅ Boolean variants (`yes/no`, `on/off`, `true/false`).
138
+ - Multi-line strings (with `|` or `>`).
139
+ - ❌ Multi-document syntax (`---`).
140
+ - ❌ Anchors and aliases (`&anchor`, `*alias`).
141
+ - ❌ Complex YAML features (e.g., tags, merge keys).
142
+
143
+ ## TOML Support
144
+
145
+ The plugin includes a basic TOML parser that supports:
146
+
147
+ - ✅ Key-value pairs (`key = "value"`).
148
+ - ✅ Tables (`[section]`).
149
+ - ✅ Nested tables (`[section.subsection]`).
150
+ - ✅ Array of Tables (`[[table]]`).
151
+ - ✅ Inline arrays and objects.
152
+ - ✅ Strings, integers, floats, booleans, and null.
153
+ - ✅ Comments (starting with `#`).
154
+ - ❌ Multi-line strings (`"""` or `'''`).
155
+ - ❌ Date and time values.
156
+ - ❌ Dotted keys (e.g. `a.b = "val"`) in a single line.
157
+ - ❌ Hex, octal, binary, and scientific notation.
374
158
 
375
159
  ## JSON Support
376
160
 
377
- The plugin fully supports standard JSON syntax through the native `JSON.parse()` method. If the frontmatter content starts with `{` and ends with `}`, it will be automatically parsed as JSON.
161
+ The plugin fully supports standard JSON syntax through the native `JSON.parse()` method.
378
162
 
379
163
  ## License
380
164
 
package/index.d.ts CHANGED
@@ -7,7 +7,7 @@ export interface MikelFrontmatterOptions {
7
7
  * @param content - The raw frontmatter content string
8
8
  * @returns Parsed data object
9
9
  */
10
- parser?: (content: string) => Record<string, any>;
10
+ parser?: (content: string, format: string) => Record<string, any>;
11
11
  }
12
12
 
13
13
  /**
@@ -17,6 +17,13 @@ export interface MikelFrontmatterOptions {
17
17
  */
18
18
  export type YamlParser = (yaml: string) => Record<string, any>;
19
19
 
20
+ /**
21
+ * TOML parser function
22
+ * @param toml - TOML string to parse
23
+ * @returns Parsed object
24
+ */
25
+ export type TomlParser = (toml: string) => Record<string, any>;
26
+
20
27
  /**
21
28
  * Mikel frontmatter plugin
22
29
  * @param options - Plugin configuration options
@@ -41,6 +48,7 @@ declare function mikelFrontmatter(options?: MikelFrontmatterOptions): {
41
48
  */
42
49
  declare namespace mikelFrontmatter {
43
50
  export const yamlParser: YamlParser;
51
+ export const tomlParser: TomlParser;
44
52
  }
45
53
 
46
54
  export default mikelFrontmatter;
package/index.js CHANGED
@@ -1,17 +1,42 @@
1
+ // @description split a string by separator, ignoring separators inside quotes
2
+ const splitSafe = (str = "", separator = ",") => {
3
+ const result = [];
4
+ let current = "", inQuotes = false, quoteChar = null;
5
+ for (let i = 0; i < str.length; i++) {
6
+ const char = str[i];
7
+ if ((char === '"' || char === "'")) {
8
+ if (!inQuotes) {
9
+ inQuotes = true;
10
+ quoteChar = char;
11
+ } else if (char === quoteChar) {
12
+ inQuotes = false;
13
+ quoteChar = null;
14
+ }
15
+ }
16
+ if (char === separator && !inQuotes) {
17
+ result.push(current);
18
+ current = "";
19
+ } else {
20
+ current = current + char;
21
+ }
22
+ }
23
+ result.push(current);
24
+ return result;
25
+ };
26
+
1
27
  // @description parse a single value from YAML
2
28
  const parseValue = (str = "") => {
3
- // str = str.trim();
4
29
  // 1. quoted strings
5
30
  if ((str.startsWith(`"`) && str.endsWith(`"`)) || (str.startsWith(`'`) && str.endsWith(`'`))) {
6
31
  return str.slice(1, -1);
7
32
  }
8
33
  // 2. inline array
9
34
  if (str.startsWith("[") && str.endsWith("]")) {
10
- return str.slice(1, -1).split(",").map(item => parseValue(item.trim()));
35
+ return splitSafe(str.slice(1, -1), ",").map(item => parseValue(item.trim()));
11
36
  }
12
37
  // 3. inline object
13
38
  if (str.startsWith("{") && str.endsWith("}")) {
14
- return str.slice(1, -1).split(",").reduce((result, pair) => {
39
+ return splitSafe(str.slice(1, -1), ",").reduce((result, pair) => {
15
40
  const [key, value] = pair.split(":");
16
41
  if (key && value) {
17
42
  result[key.trim()] = parseValue(value.trim());
@@ -43,77 +68,72 @@ const getIndent = (line = "") => {
43
68
  return line.length - line.trimStart().length;
44
69
  };
45
70
 
71
+ // @description extract a key-value pair from a line
72
+ const extractKeyValue = (line = "", separator = ":") => {
73
+ const separatorIndex = line.indexOf(separator);
74
+ return [
75
+ line.slice(0, separatorIndex).trim(),
76
+ line.slice(separatorIndex + 1).trim(),
77
+ ];
78
+ };
79
+
46
80
  // @description parse a simple YAML string into an object
47
81
  const parseYaml = (yaml = "") => {
48
- const lines = yaml.split("\n");
82
+ const lines = yaml.split("\n").filter(line => {
83
+ return line.trim() !== "" && !line.trim().startsWith("#");
84
+ });
49
85
  let i = 0;
50
86
  const parse = (minIndent = 0, result = {}) => {
51
87
  while (i < lines.length) {
52
- const line = lines[i];
53
- const trimmed = line.trim();
54
- const indent = getIndent(line);
55
-
56
- // skip empty and comments
57
- if (!trimmed || trimmed[0] === "#") {
58
- i++;
59
- continue;
60
- }
61
- // Return if dedented
88
+ const line = lines[i].trim();
89
+ const indent = getIndent(lines[i]);
90
+ // 1. return if dedented
62
91
  if (indent < minIndent) {
63
92
  return result;
64
93
  }
65
- // Array item
66
- if (trimmed.startsWith("- ")) {
67
- // First array item - initialize array
94
+ // 2. array item
95
+ else if (line.startsWith("- ")) {
96
+ // first array item - initialize array
68
97
  if (!Array.isArray(result)) {
69
98
  result = [];
70
99
  }
71
- const content = trimmed.slice(2).trim();
100
+ const content = line.slice(2).trim();
72
101
  i++;
102
+ // check for nested content on next lines
73
103
  if (!content) {
74
- // Nested content on next lines
75
104
  result.push(parse(indent + 2, {}));
76
105
  }
77
106
  // inline content with key:value (object)
78
107
  else if (content.includes(":")) {
79
108
  const obj = {};
80
- const colonIdx = content.indexOf(":");
81
- if (colonIdx > 0) {
82
- obj[content.slice(0, colonIdx).trim()] = parseValue(content.slice(colonIdx + 1).trim());
83
- }
84
- // Check for nested content on following lines
109
+ const [key, value] = extractKeyValue(content, ":");
110
+ obj[key] = !!value ? parseValue(value) : null;
111
+ // check for nested content on following lines
85
112
  if (i < lines.length && getIndent(lines[i]) > indent) {
86
113
  Object.assign(obj, parse(indent + 2, {}));
87
114
  }
88
115
  result.push(obj);
89
116
  }
117
+ // simple value
90
118
  else {
91
- // Simple value
92
119
  result.push(parseValue(content));
93
120
  }
94
121
  }
95
- // Key-value pair
96
- else if (trimmed.includes(":")) {
97
- const colonIdx = trimmed.indexOf(":");
98
- const key = trimmed.slice(0, colonIdx).trim();
99
- const value = trimmed.slice(colonIdx + 1).trim();
122
+ // 3. key-value pair
123
+ else if (line.includes(":")) {
124
+ const [key, value] = extractKeyValue(line, ":");
100
125
  i++;
101
- if (!value) {
102
- // Check if next line is an array or object
103
- if (i < lines.length && getIndent(lines[i]) > indent) {
104
- const nextLine = lines[i].trim();
105
- if (nextLine.startsWith("- ")) {
106
- result[key] = parse(indent + 2, []);
107
- } else {
108
- result[key] = parse(indent + 2, {});
109
- }
110
- } else {
111
- result[key] = null;
112
- }
113
- } else {
126
+ result[key] = null;
127
+ // check for inline content with key: value (object)
128
+ if (value) {
114
129
  result[key] = parseValue(value);
115
130
  }
131
+ // check if the next line is an array or object
132
+ else if (!value && i < lines.length && getIndent(lines[i]) > indent) {
133
+ result[key] = parse(indent + 2, lines[i].trim().startsWith("- ") ? [] : {});
134
+ }
116
135
  }
136
+ // 4. other case??
117
137
  else {
118
138
  i++;
119
139
  }
@@ -123,17 +143,68 @@ const parseYaml = (yaml = "") => {
123
143
  return parse(0, {});
124
144
  };
125
145
 
146
+ // @description parse a simple TOML string into an object
147
+ const parseToml = (toml = "") => {
148
+ const lines = toml.split("\n");
149
+ const result = {};
150
+ let currentTable = result;
151
+ for (let i = 0; i < lines.length; i++) {
152
+ const line = lines[i].trim();
153
+ if (!!line && !line.startsWith("#")) {
154
+ // 1. table header [section] or [[array]]
155
+ if (line.startsWith("[") && line.endsWith("]")) {
156
+ const isArray = line.startsWith("[[") && line.endsWith("]]");
157
+ const path = isArray ? line.slice(2, -2).trim() : line.slice(1, -1).trim();
158
+ currentTable = result;
159
+ path.split(".").forEach((part, index, parts) => {
160
+ const isLast = index === parts.length - 1;
161
+ // 1.1. if is an array of tables and is the last part
162
+ if (isLast && isArray) {
163
+ if (!Array.isArray(currentTable[part])) {
164
+ currentTable[part] = [];
165
+ }
166
+ currentTable[part].push({});
167
+ currentTable = currentTable[part][currentTable[part].length - 1];
168
+ }
169
+ // 1.2. other cases
170
+ else {
171
+ if (!currentTable[part]) {
172
+ currentTable[part] = {};
173
+ }
174
+ if (Array.isArray(currentTable[part])) {
175
+ currentTable = currentTable[part][currentTable[part].length - 1];
176
+ }
177
+ else {
178
+ currentTable = currentTable[part];
179
+ }
180
+ }
181
+ });
182
+ }
183
+ // 2. key-value pair: key = value
184
+ else if (line.includes("=")) {
185
+ const [key, value] = extractKeyValue(line, "=");
186
+ currentTable[key] = parseValue(value);
187
+ }
188
+ }
189
+ }
190
+ return result;
191
+ };
192
+
193
+
126
194
  // @description internal method to parse the content of the frontmatter block
127
- const parseFrontmatterBlock = (content = "", parser = null) => {
195
+ const parseFrontmatterBlock = (content = "", format = "yaml", parser = null) => {
128
196
  // 1. use custom parser if provided
129
197
  if (typeof parser === "function") {
130
- return parser(content);
198
+ return parser(content, format);
199
+ }
200
+ // 2. use the appropriate parser based on the format
201
+ if (format === "json") {
202
+ return JSON.parse(content.trim());
131
203
  }
132
- // 2. guess format (YAML or JSON)
133
- const trimmed = content.trim();
134
- if ((trimmed.startsWith("{") && trimmed.endsWith("}")) || (trimmed.startsWith("[") && trimmed.endsWith("]"))) {
135
- return JSON.parse(content);
204
+ if (format === "toml") {
205
+ return parseToml(content);
136
206
  }
207
+ // 3. fallback to YAML
137
208
  return parseYaml(content);
138
209
  };
139
210
 
@@ -145,11 +216,10 @@ const mikelFrontmatter = (options = {}) => {
145
216
  helpers: {
146
217
  frontmatter: params => {
147
218
  const variableName = params.options.as || "frontmatter";
148
- // const format = params.options.format || "yaml";
149
- const content = parseFrontmatterBlock(params.fn(params.data) || "", options.parser);
219
+ const format = params.options.format || "yaml";
150
220
  // register the variable (overwrite if it already exists)
151
221
  Object.assign(params.variables, {
152
- [variableName]: content,
222
+ [variableName]: parseFrontmatterBlock(params.fn(params.data) || "", format, options.parser),
153
223
  });
154
224
  // don't render anything
155
225
  return "";
@@ -160,6 +230,7 @@ const mikelFrontmatter = (options = {}) => {
160
230
 
161
231
  // assign additional metadata to the plugin function
162
232
  mikelFrontmatter.yamlParser = parseYaml;
233
+ mikelFrontmatter.tomlParser = parseToml;
163
234
 
164
235
  // export the plugin as default
165
236
  export default mikelFrontmatter;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mikel-frontmatter",
3
3
  "description": "A mikel plugin to define new data inside templates using a frontmatter-like syntax.",
4
- "version": "0.31.0",
4
+ "version": "0.32.0",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": "Josemi Juanes",