@gmag11/nodered-mcp-server 1.0.1
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/LICENSE +201 -0
- package/README.md +162 -0
- package/index.js +133 -0
- package/package.json +58 -0
- package/resources/skills/nodered-flow-builder/SKILL.md +659 -0
- package/resources/skills/nodered-flow-layout/SKILL.md +395 -0
- package/resources/skills/nodered-flowfuse-dashboard/SKILL.md +941 -0
- package/resources/skills/nodered-fundamentals/SKILL.md +323 -0
- package/resources/skills/nodered-jsonata/SKILL.md +1039 -0
- package/resources/skills/nodered-mustache/SKILL.md +588 -0
- package/resources/skills/nodered-node-reference/SKILL.md +1020 -0
- package/resources/skills/nodered-node-reference/examples/common.json +113 -0
- package/resources/skills/nodered-node-reference/examples/network.json +107 -0
- package/resources/skills/nodered-node-reference/examples/parser.json +147 -0
- package/resources/skills/nodered-node-reference/examples/sequence.json +141 -0
- package/resources/skills/nodered-node-reference/examples/storage.json +104 -0
- package/resources/skills/nodered-patterns/SKILL.md +414 -0
- package/resources/skills/nodered-patterns/examples/error-handler.json +72 -0
- package/resources/skills/nodered-patterns/examples/http-endpoint.json +42 -0
- package/resources/skills/nodered-patterns/examples/mqtt-subscriber.json +47 -0
- package/resources/skills/nodered-patterns/examples/timer-flow.json +50 -0
- package/resources/skills/nodered-subflows/SKILL.md +261 -0
- package/resources/skills/nodered-uibuilder/SKILL.md +500 -0
- package/src/auth/api-key-verifier.js +36 -0
- package/src/auth/composite-verifier.js +59 -0
- package/src/auth/config.js +106 -0
- package/src/auth/oauth-clients-store.js +107 -0
- package/src/auth/oauth-provider.js +149 -0
- package/src/auth/oauth-token-store.js +312 -0
- package/src/nodered/auth.js +158 -0
- package/src/nodered/client.js +199 -0
- package/src/nodered/comms-client.js +500 -0
- package/src/renderer/colors.js +161 -0
- package/src/renderer/geometry.js +115 -0
- package/src/renderer/html-builder.js +571 -0
- package/src/renderer/index.js +51 -0
- package/src/renderer/ir-builder.js +161 -0
- package/src/renderer/layout.js +126 -0
- package/src/renderer/mermaid-builder.js +109 -0
- package/src/renderer/svg-builder.js +228 -0
- package/src/schemas/responses.js +283 -0
- package/src/server.js +844 -0
- package/src/skills/loader.js +84 -0
- package/src/staging-store.js +258 -0
- package/src/tools/add-nodes-to-group.js +216 -0
- package/src/tools/connect-nodes.js +115 -0
- package/src/tools/constants.js +45 -0
- package/src/tools/create-flow.js +87 -0
- package/src/tools/create-node.js +126 -0
- package/src/tools/create-subflow-instance.js +123 -0
- package/src/tools/create-subflow.js +101 -0
- package/src/tools/delete-context.js +60 -0
- package/src/tools/delete-flow.js +81 -0
- package/src/tools/delete-group.js +116 -0
- package/src/tools/delete-node.js +73 -0
- package/src/tools/delete-subflow.js +103 -0
- package/src/tools/deploy.js +94 -0
- package/src/tools/disconnect-nodes.js +158 -0
- package/src/tools/export-flow.js +161 -0
- package/src/tools/export-subflow.js +78 -0
- package/src/tools/flow-utils.js +376 -0
- package/src/tools/get-config-nodes.js +86 -0
- package/src/tools/get-context.js +76 -0
- package/src/tools/get-flow-diagram.js +99 -0
- package/src/tools/get-flow-nodes.js +116 -0
- package/src/tools/get-flows.js +74 -0
- package/src/tools/get-node-detail.js +77 -0
- package/src/tools/get-node-type-detail.js +92 -0
- package/src/tools/get-palette-nodes.js +63 -0
- package/src/tools/get-staging-status.js +34 -0
- package/src/tools/get-subflow-detail.js +110 -0
- package/src/tools/get-subflows.js +105 -0
- package/src/tools/import-flow.js +310 -0
- package/src/tools/inject-message.js +117 -0
- package/src/tools/install-node.js +31 -0
- package/src/tools/read-debug-messages.js +155 -0
- package/src/tools/refresh-staging.js +62 -0
- package/src/tools/remove-nodes-from-group.js +162 -0
- package/src/tools/render-staging.js +69 -0
- package/src/tools/response-utils.js +42 -0
- package/src/tools/search-nodes.js +134 -0
- package/src/tools/uninstall-node.js +31 -0
- package/src/tools/update-flow.js +95 -0
- package/src/tools/update-group.js +77 -0
- package/src/tools/update-node.js +132 -0
- package/src/tools/update-subflow.js +84 -0
- package/src/transport/http.js +252 -0
- package/src/transport/stdio.js +16 -0
- package/src/transport/ws-server.js +223 -0
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nodered-mustache
|
|
3
|
+
description: >-
|
|
4
|
+
Comprehensive reference for the Mustache templating language (v1.3.0).
|
|
5
|
+
Covers all tag types: variables (escaped and unescaped), sections, inverted sections,
|
|
6
|
+
comments, partials, blocks, parents, and set delimiters. Documents dotted-name resolution,
|
|
7
|
+
implicit iterator, lambdas, and the inheritance extension (blocks/parents).
|
|
8
|
+
Includes Node-RED-specific usage notes for the template node.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Mustache Templating Language Reference
|
|
12
|
+
|
|
13
|
+
Comprehensive reference for Mustache — a **logic-less templating language** that works by expanding tags in a template using values provided in a hash or object. Mustache is one of the supported formats in Node-RED's "template" node.
|
|
14
|
+
|
|
15
|
+
Mustache can be used for HTML, config files, source code — anything. It is called "logic-less" because there are no if statements, else clauses, or for loops. Instead there are only **tags**. Some tags are replaced with a value, some nothing, and others a series of values.
|
|
16
|
+
|
|
17
|
+
> **Version:** Mustache spec v1.3.0 (including optional extensions for lambdas and inheritance)
|
|
18
|
+
> **Try it:** [mustache.github.io](http://mustache.github.io/)
|
|
19
|
+
> **Docs:** [mustache(5) man page](https://mustache.github.io/mustache.5.html)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Quick Example
|
|
24
|
+
|
|
25
|
+
A typical Mustache template:
|
|
26
|
+
|
|
27
|
+
```mustache
|
|
28
|
+
Hello {{name}}
|
|
29
|
+
You have just won {{value}} dollars!
|
|
30
|
+
{{#in_ca}}
|
|
31
|
+
Well, {{taxed_value}} dollars, after taxes.
|
|
32
|
+
{{/in_ca}}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Given the following hash:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"name": "Chris",
|
|
40
|
+
"value": 10000,
|
|
41
|
+
"taxed_value": 6000,
|
|
42
|
+
"in_ca": true
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Will produce:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
Hello Chris
|
|
50
|
+
You have just won 10000 dollars!
|
|
51
|
+
Well, 6000 dollars, after taxes.
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Tag Types
|
|
57
|
+
|
|
58
|
+
Tags are indicated by double mustaches. `{{person}}` is a tag, as is `{{#person}}`. In both examples, `person` is the key or tag key.
|
|
59
|
+
|
|
60
|
+
### Variables
|
|
61
|
+
|
|
62
|
+
The most basic tag type. A `{{name}}` tag will try to find the `name` key in the current context. If there is no `name` key, parent contexts are checked recursively. If the top context is reached and the key is still not found, nothing is rendered (empty string).
|
|
63
|
+
|
|
64
|
+
**HTML Escaping:** All variables are HTML escaped by default. Use triple mustache `{{{name}}}` or ampersand syntax `{{&name}}` for raw unescaped output.
|
|
65
|
+
|
|
66
|
+
```mustache
|
|
67
|
+
* {{name}}
|
|
68
|
+
* {{age}}
|
|
69
|
+
* {{company}}
|
|
70
|
+
* {{{company}}}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"name": "Chris",
|
|
76
|
+
"company": "<b>GitHub</b>"
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Output:
|
|
81
|
+
```
|
|
82
|
+
* Chris
|
|
83
|
+
*
|
|
84
|
+
* <b>GitHub</b>
|
|
85
|
+
* <b>GitHub</b>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
> **Note:** The `age` key is missing, so nothing is rendered for `{{age}}`.
|
|
89
|
+
|
|
90
|
+
#### Dotted Names
|
|
91
|
+
|
|
92
|
+
If the key contains dots, it is split on the dots to obtain multiple keys. Each key is looked up in sequence through nested contexts. If any intermediate key is not found, nothing is rendered.
|
|
93
|
+
|
|
94
|
+
```mustache
|
|
95
|
+
* {{client.name}}
|
|
96
|
+
* {{age}}
|
|
97
|
+
* {{client.company.name}}
|
|
98
|
+
* {{{company.name}}}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"client": {
|
|
104
|
+
"name": "Chris & Friends",
|
|
105
|
+
"age": 50
|
|
106
|
+
},
|
|
107
|
+
"company": {
|
|
108
|
+
"name": "<b>GitHub</b>"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Output:
|
|
114
|
+
```
|
|
115
|
+
* Chris & Friends
|
|
116
|
+
*
|
|
117
|
+
*
|
|
118
|
+
* <b>GitHub</b>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
#### Implicit Iterator (`{{.}}`)
|
|
122
|
+
|
|
123
|
+
If the name consists of only a dot (`.`), the current context value is interpolated as a whole. This is especially useful inside sections iterating over lists of scalars (see Sections below).
|
|
124
|
+
|
|
125
|
+
```mustache
|
|
126
|
+
* {{.}}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Current context:
|
|
130
|
+
```
|
|
131
|
+
"Hello!"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Output:
|
|
135
|
+
```
|
|
136
|
+
* Hello!
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
#### Variable Lambdas
|
|
140
|
+
|
|
141
|
+
If any value found during lookup is a callable object (function/lambda), it is invoked with zero arguments. If the lambda returns a string, that string is rendered as a Mustache template before interpolation (using default delimiters against the current context).
|
|
142
|
+
|
|
143
|
+
```mustache
|
|
144
|
+
* {{time.hour}}
|
|
145
|
+
* {{today}}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"time": {
|
|
151
|
+
"hour": 0,
|
|
152
|
+
"minute": 0,
|
|
153
|
+
"second": 0
|
|
154
|
+
},
|
|
155
|
+
"today": "{{year}}-{{month}}-{{day}}",
|
|
156
|
+
"year": 1970,
|
|
157
|
+
"month": 1,
|
|
158
|
+
"day": 1
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Output:
|
|
163
|
+
```
|
|
164
|
+
* 0
|
|
165
|
+
* 1970-1-1
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### Sections
|
|
171
|
+
|
|
172
|
+
Sections render blocks of text zero or more times, depending on the value of the key in the current context. A section begins with a pound (`#`) and ends with a slash (`/`): `{{#person}}...{{/person}}`.
|
|
173
|
+
|
|
174
|
+
The behavior is determined by the value of the key lookup:
|
|
175
|
+
|
|
176
|
+
#### False Values or Empty Lists
|
|
177
|
+
|
|
178
|
+
If the key exists and has a value of `false` or an empty list, the content between the tags is **not displayed**.
|
|
179
|
+
|
|
180
|
+
```mustache
|
|
181
|
+
Shown.
|
|
182
|
+
{{#person}}
|
|
183
|
+
Never shown!
|
|
184
|
+
{{/person}}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```json
|
|
188
|
+
{ "person": false }
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Output:
|
|
192
|
+
```
|
|
193
|
+
Shown.
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
#### Non-Empty Lists
|
|
197
|
+
|
|
198
|
+
If the key value is a non-empty list, the block is rendered **once for each item**. The context inside the block is set to the current item. This is how you loop over collections.
|
|
199
|
+
|
|
200
|
+
```mustache
|
|
201
|
+
{{#repo}}
|
|
202
|
+
<b>{{name}}</b>
|
|
203
|
+
{{/repo}}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"repo": [
|
|
209
|
+
{ "name": "resque" },
|
|
210
|
+
{ "name": "hub" },
|
|
211
|
+
{ "name": "rip" }
|
|
212
|
+
]
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Output:
|
|
217
|
+
```
|
|
218
|
+
<b>resque</b>
|
|
219
|
+
<b>hub</b>
|
|
220
|
+
<b>rip</b>
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Using the implicit iterator with a list of scalars:
|
|
224
|
+
|
|
225
|
+
```mustache
|
|
226
|
+
{{#repo}}
|
|
227
|
+
<b>{{.}}</b>
|
|
228
|
+
{{/repo}}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
```json
|
|
232
|
+
{ "repo": ["resque", "hub", "rip"] }
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Output:
|
|
236
|
+
```
|
|
237
|
+
<b>resque</b>
|
|
238
|
+
<b>hub</b>
|
|
239
|
+
<b>rip</b>
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
#### Non-False Values (Not a List)
|
|
243
|
+
|
|
244
|
+
When the value is non-false but not a list, the block is rendered **once** with the value used as the context.
|
|
245
|
+
|
|
246
|
+
```mustache
|
|
247
|
+
{{#person?}}
|
|
248
|
+
Hi {{name}}!
|
|
249
|
+
{{/person?}}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
```json
|
|
253
|
+
{ "person?": { "name": "Jon" } }
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Output:
|
|
257
|
+
```
|
|
258
|
+
Hi Jon!
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
#### Section Lambdas
|
|
262
|
+
|
|
263
|
+
When the key value is a callable object (function/lambda), the function is invoked and passed the **literal block text** (unrendered — `{{tags}}` are not expanded). The return value replaces the section content. If the lambda returns a string, it is rendered using the same delimiters as the original section.
|
|
264
|
+
|
|
265
|
+
```mustache
|
|
266
|
+
{{#wrapped}}{{name}} is awesome.{{/wrapped}}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
{
|
|
271
|
+
"name": "Willy",
|
|
272
|
+
"wrapped": "<b>{{name}} is awesome.</b>"
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Output:
|
|
277
|
+
```
|
|
278
|
+
<b>Willy is awesome.</b>
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
### Inverted Sections
|
|
284
|
+
|
|
285
|
+
An inverted section begins with a caret (`^`) and ends with a slash (`/`): `{{^person}}...{{/person}}`. Inverted sections render their content **once** when the key doesn't exist, is `false`, or is an empty list — the inverse of regular sections.
|
|
286
|
+
|
|
287
|
+
```mustache
|
|
288
|
+
{{#repo}}
|
|
289
|
+
<b>{{name}}</b>
|
|
290
|
+
{{/repo}}
|
|
291
|
+
{{^repo}}
|
|
292
|
+
No repos :(
|
|
293
|
+
{{/repo}}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
```json
|
|
297
|
+
{ "repo": [] }
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Output:
|
|
301
|
+
```
|
|
302
|
+
No repos :(
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
### Comments
|
|
308
|
+
|
|
309
|
+
Comments begin with a bang (`!`) and are **ignored** in output. Comments may contain newlines.
|
|
310
|
+
|
|
311
|
+
```mustache
|
|
312
|
+
<h1>Today{{! ignore me }}.</h1>
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Output:
|
|
316
|
+
```
|
|
317
|
+
<h1>Today.</h1>
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
### Partials
|
|
323
|
+
|
|
324
|
+
Partials begin with a greater than sign (`>`): `{{> box}}`. Partials are rendered at **runtime** (not compile time), so recursive partials are possible (just avoid infinite loops).
|
|
325
|
+
|
|
326
|
+
Partials **inherit the calling context**. You don't need to pass data explicitly — any key available in the parent template is also available inside the partial.
|
|
327
|
+
|
|
328
|
+
```
|
|
329
|
+
base.mustache:
|
|
330
|
+
<h2>Names</h2>
|
|
331
|
+
{{#names}}
|
|
332
|
+
{{> user}}
|
|
333
|
+
{{/names}}
|
|
334
|
+
|
|
335
|
+
user.mustache:
|
|
336
|
+
<strong>{{name}}</strong>
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
This can be thought of as a single, expanded template:
|
|
340
|
+
|
|
341
|
+
```mustache
|
|
342
|
+
<h2>Names</h2>
|
|
343
|
+
{{#names}}
|
|
344
|
+
<strong>{{name}}</strong>
|
|
345
|
+
{{/names}}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
#### Dynamic Names
|
|
349
|
+
|
|
350
|
+
Partials can be loaded dynamically at runtime using an asterisk followed by a dotted name: `{{>*dynamic}}`. The dotted name resolves to a string that names the partial to include.
|
|
351
|
+
|
|
352
|
+
```
|
|
353
|
+
main.mustache:
|
|
354
|
+
Hello {{>*dynamic}}
|
|
355
|
+
|
|
356
|
+
world.template:
|
|
357
|
+
everyone!
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
```json
|
|
361
|
+
{ "dynamic": "world" }
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Output:
|
|
365
|
+
```
|
|
366
|
+
Hello everyone!
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
### Blocks and Parents (Template Inheritance)
|
|
372
|
+
|
|
373
|
+
Blocks and parents are part of the **optional inheritance extension**. They enable template inheritance patterns where a base template defines overridable sections.
|
|
374
|
+
|
|
375
|
+
#### Blocks
|
|
376
|
+
|
|
377
|
+
A block begins with a dollar sign (`$`) and ends with a slash: `{{$title}}...{{/title}}`. Blocks mark parts of a template that may be overridden by a parent template. If not overridden, the block's default content is rendered.
|
|
378
|
+
|
|
379
|
+
```
|
|
380
|
+
article.mustache:
|
|
381
|
+
<h1>{{$title}}The News of Today{{/title}}</h1>
|
|
382
|
+
{{$body}}
|
|
383
|
+
<p>Nothing special happened.</p>
|
|
384
|
+
{{/body}}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Rendered directly:
|
|
388
|
+
```
|
|
389
|
+
<h1>The News of Today</h1>
|
|
390
|
+
<p>Nothing special happened.</p>
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
#### Parents
|
|
394
|
+
|
|
395
|
+
A parent begins with a less than sign (`<`) and ends with a slash: `{{<article}}...{{/article}}`. Like a partial, a parent lets you include another template. **Unlike** a partial, a parent also lets you **override blocks** from the included template.
|
|
396
|
+
|
|
397
|
+
Content inside a parent that is not within a block override is ignored (acts like a comment).
|
|
398
|
+
|
|
399
|
+
```mustache
|
|
400
|
+
{{<article}}
|
|
401
|
+
Never shown
|
|
402
|
+
{{$body}}
|
|
403
|
+
{{#headlines}}
|
|
404
|
+
<p>{{.}}</p>
|
|
405
|
+
{{/headlines}}
|
|
406
|
+
{{/body}}
|
|
407
|
+
{{/article}}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
```json
|
|
411
|
+
{
|
|
412
|
+
"headlines": [
|
|
413
|
+
"A pug's handler grew mustaches.",
|
|
414
|
+
"What an exciting day!"
|
|
415
|
+
]
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
Output (using article.mustache from above):
|
|
420
|
+
```
|
|
421
|
+
<h1>The News of Today</h1>
|
|
422
|
+
<p>A pug's handler grew mustaches.</p>
|
|
423
|
+
<p>What an exciting day!</p>
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
#### Dynamic Names in Parents
|
|
427
|
+
|
|
428
|
+
Parent templates can also use dynamic names with `{{<*dynamic}}...{{/*dynamic}}`:
|
|
429
|
+
|
|
430
|
+
```
|
|
431
|
+
{{!normal.mustache}}
|
|
432
|
+
{{$text}}Here goes nothing.{{/text}}
|
|
433
|
+
|
|
434
|
+
{{!bold.mustache}}
|
|
435
|
+
<b>{{$text}}Here also goes nothing but it's bold.{{/text}}</b>
|
|
436
|
+
|
|
437
|
+
{{!dynamic.mustache}}
|
|
438
|
+
{{<*dynamic}}
|
|
439
|
+
{{$text}}Hello World!{{/text}}
|
|
440
|
+
{{/*dynamic}}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
```json
|
|
444
|
+
{ "dynamic": "bold" }
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
Output:
|
|
448
|
+
```
|
|
449
|
+
<b>Hello World!</b>
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
### Set Delimiter
|
|
455
|
+
|
|
456
|
+
Set Delimiter tags start with an equals sign and change the tag delimiters from `{{` and `}}` to custom strings. Custom delimiters **may not contain whitespace or the equals sign**.
|
|
457
|
+
|
|
458
|
+
This is useful for languages like TeX where double-braces may occur in the text and are awkward to use for markup.
|
|
459
|
+
|
|
460
|
+
```mustache
|
|
461
|
+
* {{default_tags}}
|
|
462
|
+
{{=<% %>=}}
|
|
463
|
+
* <% erb_style_tags %>
|
|
464
|
+
<%={{ }}=%>
|
|
465
|
+
* {{ default_tags_again }}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
Output:
|
|
469
|
+
```
|
|
470
|
+
* default_tags_value
|
|
471
|
+
* erb_style_tags_value
|
|
472
|
+
* default_tags_again_value
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
## Lambda Functions Deep Dive
|
|
478
|
+
|
|
479
|
+
Lambdas (callable objects) are an optional extension in the Mustache spec v1.3.0. They behave differently depending on context:
|
|
480
|
+
|
|
481
|
+
| Context | Lambda behavior |
|
|
482
|
+
|---------|----------------|
|
|
483
|
+
| **Variable** `{{lambda}}` | Invoked with zero args. If it returns a string, that string is rendered as a Mustache template (with default delimiters) against the current context. |
|
|
484
|
+
| **Section** `{{#lambda}}...{{/lambda}}` | Invoked with the **literal block text** (unrendered). Return value replaces the section. If a string, rendered with the same delimiters as the section. |
|
|
485
|
+
|
|
486
|
+
**Variable lambda example** — template-generating function:
|
|
487
|
+
|
|
488
|
+
```mustache
|
|
489
|
+
{{#items}}
|
|
490
|
+
<li>{{name}}: {{display}}</li>
|
|
491
|
+
{{/items}}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
```json
|
|
495
|
+
{
|
|
496
|
+
"items": [
|
|
497
|
+
{ "name": "Alice", "value": 5 },
|
|
498
|
+
{ "name": "Bob", "value": 0 }
|
|
499
|
+
],
|
|
500
|
+
"display": "{{#value}}{{.}}{{/value}}{{^value}}N/A{{/value}}"
|
|
501
|
+
}
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
**Section lambda example** — wrapping/filtering:
|
|
505
|
+
|
|
506
|
+
If `wrapped` is a function that takes text and returns `<b>${text}</b>`, then `{{#wrapped}}{{name}}{{/wrapped}}` effectively wraps the name in bold tags.
|
|
507
|
+
|
|
508
|
+
---
|
|
509
|
+
|
|
510
|
+
## Summary: Tag Reference Table
|
|
511
|
+
|
|
512
|
+
| Tag | Syntax | Purpose |
|
|
513
|
+
|-----|--------|---------|
|
|
514
|
+
| Variable (escaped) | `{{name}}` | Interpolate with HTML escaping |
|
|
515
|
+
| Variable (unescaped) | `{{{name}}}` or `{{&name}}` | Interpolate raw, no escaping |
|
|
516
|
+
| Dotted name | `{{a.b.c}}` | Traverse nested objects |
|
|
517
|
+
| Implicit iterator | `{{.}}` | Interpolate current context |
|
|
518
|
+
| Section | `{{#key}}...{{/key}}` | Loop / conditional / context switch |
|
|
519
|
+
| Inverted section | `{{^key}}...{{/key}}` | Render when false/empty/missing |
|
|
520
|
+
| Comment | `{{! text }}` | Ignored, may span lines |
|
|
521
|
+
| Partial | `{{> name}}` | Include another template |
|
|
522
|
+
| Dynamic partial | `{{>*name}}` | Include template by name resolution |
|
|
523
|
+
| Block | `{{$key}}...{{/key}}` | Overridable default content |
|
|
524
|
+
| Parent | `{{<name}}...{{/name}}` | Include template with block overrides |
|
|
525
|
+
| Dynamic parent | `{{<*name}}...{{/*name}}` | Parent by name resolution |
|
|
526
|
+
| Set delimiter | `{{=...=}}` | Change tag delimiters |
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
## Node-RED Template Node Usage
|
|
531
|
+
|
|
532
|
+
In Node-RED, the **template** node supports Mustache as one of its output formats. When the template node's **Format** is set to **Mustache template**, the template is evaluated against the `msg` object as the context hash.
|
|
533
|
+
|
|
534
|
+
### Accessing Message Properties
|
|
535
|
+
|
|
536
|
+
| Mustache expression | Accesses |
|
|
537
|
+
|---------------------|----------|
|
|
538
|
+
| `{{payload}}` | `msg.payload` |
|
|
539
|
+
| `{{topic}}` | `msg.topic` |
|
|
540
|
+
| `{{payload.temperature}}` | `msg.payload.temperature` (nested) |
|
|
541
|
+
| `{{payload.sensor.name}}` | `msg.payload.sensor.name` (deeply nested) |
|
|
542
|
+
| `{{{payload}}}` | `msg.payload` (raw, unescaped) |
|
|
543
|
+
|
|
544
|
+
### Common Patterns
|
|
545
|
+
|
|
546
|
+
**Conditional rendering with sections:**
|
|
547
|
+
```mustache
|
|
548
|
+
{{#payload.active}}
|
|
549
|
+
Sensor is active.
|
|
550
|
+
{{/payload.active}}
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
**Iterating over an array in payload:**
|
|
554
|
+
```mustache
|
|
555
|
+
{{#payload}}
|
|
556
|
+
<li>{{name}}: {{value}}</li>
|
|
557
|
+
{{/payload}}
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
**Fallback with inverted sections:**
|
|
561
|
+
```mustache
|
|
562
|
+
{{#payload}}
|
|
563
|
+
Data: {{.}}
|
|
564
|
+
{{/payload}}
|
|
565
|
+
{{^payload}}
|
|
566
|
+
No data received.
|
|
567
|
+
{{/payload}}
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
**Comments for template documentation:**
|
|
571
|
+
```mustache
|
|
572
|
+
{{! This template formats sensor readings as HTML }}
|
|
573
|
+
<h2>Sensor: {{topic}}</h2>
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
### Relationship to Other Template Formats
|
|
577
|
+
|
|
578
|
+
Node-RED's template node supports multiple formats:
|
|
579
|
+
|
|
580
|
+
| Format | Behavior |
|
|
581
|
+
|--------|----------|
|
|
582
|
+
| **Mustache template** | Evaluated against `msg` as Mustache (this skill) |
|
|
583
|
+
| **Plain text** | Literal text, no substitution |
|
|
584
|
+
| **JSONata** | Evaluated as a JSONata expression against `msg` |
|
|
585
|
+
|
|
586
|
+
When using Mustache format, the entire template is processed by the Mustache engine before being assigned to `msg.payload`. Use Mustache when you need simple variable substitution with HTML escaping and section-based iteration, without the complexity of a full expression language.
|
|
587
|
+
|
|
588
|
+
> **Note:** Mustache is logic-less. For complex data transformations, filtering, or calculations, use the **change** node with JSONata expressions instead.
|