@robinpath/template 0.1.0 → 0.1.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/README.md +89 -89
- package/package.json +15 -3
- package/dist/index.d.ts +0 -6
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -12
- package/dist/index.js.map +0 -1
- package/dist/template.d.ts +0 -87
- package/dist/template.d.ts.map +0 -1
- package/dist/template.js +0 -420
- package/dist/template.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
# @robinpath/template
|
|
2
|
-
|
|
3
|
-
> Mustache-like template engine with variable substitution, conditional sections, loops, and simple string interpolation
|
|
4
|
-
|
|
5
|
-
   
|
|
6
|
-
|
|
7
|
-
## Why use this module?
|
|
8
|
-
|
|
9
|
-
The `template` module lets you:
|
|
10
|
-
|
|
11
|
-
- Render a Mustache-like template string with variable substitution, sections, and loops
|
|
12
|
-
- Read a template from a file and render it with the provided data object
|
|
13
|
-
- HTML-escape a string, converting &, <, >, ", and ' to their HTML entity equivalents
|
|
14
|
-
- Validate template syntax, checking for unclosed tags, mismatched sections, and other structural errors
|
|
15
|
-
- Extract all unique variable and section names used in a template
|
|
16
|
-
|
|
17
|
-
All functions are callable directly from RobinPath scripts with a simple, consistent API.
|
|
18
|
-
|
|
19
|
-
## Installation
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npm install @robinpath/template
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Quick Start
|
|
26
|
-
|
|
27
|
-
No credentials needed — start using it right away:
|
|
28
|
-
|
|
29
|
-
```robinpath
|
|
30
|
-
template.renderFile "/tmp/greeting.mustache" { "name": "World" }
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Available Functions
|
|
34
|
-
|
|
35
|
-
| Function | Description |
|
|
36
|
-
|----------|-------------|
|
|
37
|
-
| `template.render` | Render a Mustache-like template string with variable substitution, sections, and loops |
|
|
38
|
-
| `template.renderFile` | Read a template from a file and render it with the provided data object |
|
|
39
|
-
| `template.escape` | HTML-escape a string, converting &, <, >, ", and ' to their HTML entity equivalents |
|
|
40
|
-
| `template.compile` | Validate template syntax, checking for unclosed tags, mismatched sections, and other structural errors |
|
|
41
|
-
| `template.extractVariables` | Extract all unique variable and section names used in a template |
|
|
42
|
-
| `template.renderString` | Simple string interpolation using ${key} placeholders (no sections or loops) |
|
|
43
|
-
|
|
44
|
-
## Examples
|
|
45
|
-
|
|
46
|
-
### Read a template from a file and render it with the provided data object
|
|
47
|
-
|
|
48
|
-
```robinpath
|
|
49
|
-
template.renderFile "/tmp/greeting.mustache" { "name": "World" }
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### HTML-escape a string, converting &, <, >, ", and ' to their HTML entity equivalents
|
|
53
|
-
|
|
54
|
-
```robinpath
|
|
55
|
-
template.escape "<script>alert(1)</script>"
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### Validate template syntax, checking for unclosed tags, mismatched sections, and other structural errors
|
|
59
|
-
|
|
60
|
-
```robinpath
|
|
61
|
-
template.compile "{{#items}}{{name}}{{/items}}"
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
## Integration with RobinPath
|
|
65
|
-
|
|
66
|
-
```typescript
|
|
67
|
-
import { RobinPath } from "@wiredwp/robinpath";
|
|
68
|
-
import Module from "@robinpath/template";
|
|
69
|
-
|
|
70
|
-
const rp = new RobinPath();
|
|
71
|
-
rp.registerModule(Module.name, Module.functions);
|
|
72
|
-
rp.registerModuleMeta(Module.name, Module.functionMetadata);
|
|
73
|
-
|
|
74
|
-
const result = await rp.executeScript(`
|
|
75
|
-
template.renderFile "/tmp/greeting.mustache" { "name": "World" }
|
|
76
|
-
`);
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## Full API Reference
|
|
80
|
-
|
|
81
|
-
See [MODULE.md](./MODULE.md) for complete documentation including all parameters, return types, error handling, and advanced examples.
|
|
82
|
-
|
|
83
|
-
## Related Modules
|
|
84
|
-
|
|
85
|
-
- [`@robinpath/json`](../json) — JSON module for complementary functionality
|
|
86
|
-
|
|
87
|
-
## License
|
|
88
|
-
|
|
89
|
-
MIT
|
|
1
|
+
# @robinpath/template
|
|
2
|
+
|
|
3
|
+
> Mustache-like template engine with variable substitution, conditional sections, loops, and simple string interpolation
|
|
4
|
+
|
|
5
|
+
   
|
|
6
|
+
|
|
7
|
+
## Why use this module?
|
|
8
|
+
|
|
9
|
+
The `template` module lets you:
|
|
10
|
+
|
|
11
|
+
- Render a Mustache-like template string with variable substitution, sections, and loops
|
|
12
|
+
- Read a template from a file and render it with the provided data object
|
|
13
|
+
- HTML-escape a string, converting &, <, >, ", and ' to their HTML entity equivalents
|
|
14
|
+
- Validate template syntax, checking for unclosed tags, mismatched sections, and other structural errors
|
|
15
|
+
- Extract all unique variable and section names used in a template
|
|
16
|
+
|
|
17
|
+
All functions are callable directly from RobinPath scripts with a simple, consistent API.
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @robinpath/template
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
No credentials needed — start using it right away:
|
|
28
|
+
|
|
29
|
+
```robinpath
|
|
30
|
+
template.renderFile "/tmp/greeting.mustache" { "name": "World" }
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Available Functions
|
|
34
|
+
|
|
35
|
+
| Function | Description |
|
|
36
|
+
|----------|-------------|
|
|
37
|
+
| `template.render` | Render a Mustache-like template string with variable substitution, sections, and loops |
|
|
38
|
+
| `template.renderFile` | Read a template from a file and render it with the provided data object |
|
|
39
|
+
| `template.escape` | HTML-escape a string, converting &, <, >, ", and ' to their HTML entity equivalents |
|
|
40
|
+
| `template.compile` | Validate template syntax, checking for unclosed tags, mismatched sections, and other structural errors |
|
|
41
|
+
| `template.extractVariables` | Extract all unique variable and section names used in a template |
|
|
42
|
+
| `template.renderString` | Simple string interpolation using ${key} placeholders (no sections or loops) |
|
|
43
|
+
|
|
44
|
+
## Examples
|
|
45
|
+
|
|
46
|
+
### Read a template from a file and render it with the provided data object
|
|
47
|
+
|
|
48
|
+
```robinpath
|
|
49
|
+
template.renderFile "/tmp/greeting.mustache" { "name": "World" }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### HTML-escape a string, converting &, <, >, ", and ' to their HTML entity equivalents
|
|
53
|
+
|
|
54
|
+
```robinpath
|
|
55
|
+
template.escape "<script>alert(1)</script>"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Validate template syntax, checking for unclosed tags, mismatched sections, and other structural errors
|
|
59
|
+
|
|
60
|
+
```robinpath
|
|
61
|
+
template.compile "{{#items}}{{name}}{{/items}}"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Integration with RobinPath
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { RobinPath } from "@wiredwp/robinpath";
|
|
68
|
+
import Module from "@robinpath/template";
|
|
69
|
+
|
|
70
|
+
const rp = new RobinPath();
|
|
71
|
+
rp.registerModule(Module.name, Module.functions);
|
|
72
|
+
rp.registerModuleMeta(Module.name, Module.functionMetadata);
|
|
73
|
+
|
|
74
|
+
const result = await rp.executeScript(`
|
|
75
|
+
template.renderFile "/tmp/greeting.mustache" { "name": "World" }
|
|
76
|
+
`);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Full API Reference
|
|
80
|
+
|
|
81
|
+
See [MODULE.md](./MODULE.md) for complete documentation including all parameters, return types, error handling, and advanced examples.
|
|
82
|
+
|
|
83
|
+
## Related Modules
|
|
84
|
+
|
|
85
|
+
- [`@robinpath/json`](../json) — JSON module for complementary functionality
|
|
86
|
+
|
|
87
|
+
## License
|
|
88
|
+
|
|
89
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robinpath/template",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -21,11 +21,23 @@
|
|
|
21
21
|
"test": "node --import tsx --test tests/*.test.ts"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
|
-
"@
|
|
24
|
+
"@robinpath/core": ">=0.20.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@
|
|
27
|
+
"@robinpath/core": "^0.30.1",
|
|
28
28
|
"tsx": "^4.19.0",
|
|
29
29
|
"typescript": "^5.6.0"
|
|
30
|
+
},
|
|
31
|
+
"description": "Mustache-like template engine with variable substitution, conditional sections, loops, and simple string interpolation",
|
|
32
|
+
"keywords": [
|
|
33
|
+
"template",
|
|
34
|
+
"utility"
|
|
35
|
+
],
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"robinpath": {
|
|
38
|
+
"category": "utility",
|
|
39
|
+
"type": "utility",
|
|
40
|
+
"auth": "none",
|
|
41
|
+
"functionCount": 6
|
|
30
42
|
}
|
|
31
43
|
}
|
package/dist/index.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { ModuleAdapter } from "@wiredwp/robinpath";
|
|
2
|
-
declare const TemplateModule: ModuleAdapter;
|
|
3
|
-
export default TemplateModule;
|
|
4
|
-
export { TemplateModule };
|
|
5
|
-
export { TemplateFunctions, TemplateFunctionMetadata, TemplateModuleMetadata } from "./template.js";
|
|
6
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD,QAAA,MAAM,cAAc,EAAE,aAMrB,CAAC;AAEF,eAAe,cAAc,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { TemplateFunctions, TemplateFunctionMetadata, TemplateModuleMetadata } from "./template.js";
|
|
2
|
-
const TemplateModule = {
|
|
3
|
-
name: "template",
|
|
4
|
-
functions: TemplateFunctions,
|
|
5
|
-
functionMetadata: TemplateFunctionMetadata,
|
|
6
|
-
moduleMetadata: TemplateModuleMetadata,
|
|
7
|
-
global: false,
|
|
8
|
-
}; // as ModuleAdapter
|
|
9
|
-
export default TemplateModule;
|
|
10
|
-
export { TemplateModule };
|
|
11
|
-
export { TemplateFunctions, TemplateFunctionMetadata, TemplateModuleMetadata } from "./template.js";
|
|
12
|
-
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAEpG,MAAM,cAAc,GAAkB;IACpC,IAAI,EAAE,UAAU;IAChB,SAAS,EAAE,iBAAiB;IAC5B,gBAAgB,EAAE,wBAA+B;IACjD,cAAc,EAAE,sBAA6B;IAC7C,MAAM,EAAE,KAAK;CACd,CAAC,CAAC,mBAAmB;AAEtB,eAAe,cAAc,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/template.d.ts
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import type { BuiltinHandler } from "@wiredwp/robinpath";
|
|
2
|
-
export declare const TemplateFunctions: Record<string, BuiltinHandler>;
|
|
3
|
-
export declare const TemplateFunctionMetadata: {
|
|
4
|
-
render: {
|
|
5
|
-
description: string;
|
|
6
|
-
parameters: {
|
|
7
|
-
name: string;
|
|
8
|
-
dataType: string;
|
|
9
|
-
description: string;
|
|
10
|
-
formInputType: string;
|
|
11
|
-
required: boolean;
|
|
12
|
-
}[];
|
|
13
|
-
returnType: string;
|
|
14
|
-
returnDescription: string;
|
|
15
|
-
example: string;
|
|
16
|
-
};
|
|
17
|
-
renderFile: {
|
|
18
|
-
description: string;
|
|
19
|
-
parameters: {
|
|
20
|
-
name: string;
|
|
21
|
-
dataType: string;
|
|
22
|
-
description: string;
|
|
23
|
-
formInputType: string;
|
|
24
|
-
required: boolean;
|
|
25
|
-
}[];
|
|
26
|
-
returnType: string;
|
|
27
|
-
returnDescription: string;
|
|
28
|
-
example: string;
|
|
29
|
-
};
|
|
30
|
-
escape: {
|
|
31
|
-
description: string;
|
|
32
|
-
parameters: {
|
|
33
|
-
name: string;
|
|
34
|
-
dataType: string;
|
|
35
|
-
description: string;
|
|
36
|
-
formInputType: string;
|
|
37
|
-
required: boolean;
|
|
38
|
-
}[];
|
|
39
|
-
returnType: string;
|
|
40
|
-
returnDescription: string;
|
|
41
|
-
example: string;
|
|
42
|
-
};
|
|
43
|
-
compile: {
|
|
44
|
-
description: string;
|
|
45
|
-
parameters: {
|
|
46
|
-
name: string;
|
|
47
|
-
dataType: string;
|
|
48
|
-
description: string;
|
|
49
|
-
formInputType: string;
|
|
50
|
-
required: boolean;
|
|
51
|
-
}[];
|
|
52
|
-
returnType: string;
|
|
53
|
-
returnDescription: string;
|
|
54
|
-
example: string;
|
|
55
|
-
};
|
|
56
|
-
extractVariables: {
|
|
57
|
-
description: string;
|
|
58
|
-
parameters: {
|
|
59
|
-
name: string;
|
|
60
|
-
dataType: string;
|
|
61
|
-
description: string;
|
|
62
|
-
formInputType: string;
|
|
63
|
-
required: boolean;
|
|
64
|
-
}[];
|
|
65
|
-
returnType: string;
|
|
66
|
-
returnDescription: string;
|
|
67
|
-
example: string;
|
|
68
|
-
};
|
|
69
|
-
renderString: {
|
|
70
|
-
description: string;
|
|
71
|
-
parameters: {
|
|
72
|
-
name: string;
|
|
73
|
-
dataType: string;
|
|
74
|
-
description: string;
|
|
75
|
-
formInputType: string;
|
|
76
|
-
required: boolean;
|
|
77
|
-
}[];
|
|
78
|
-
returnType: string;
|
|
79
|
-
returnDescription: string;
|
|
80
|
-
example: string;
|
|
81
|
-
};
|
|
82
|
-
};
|
|
83
|
-
export declare const TemplateModuleMetadata: {
|
|
84
|
-
description: string;
|
|
85
|
-
methods: string[];
|
|
86
|
-
};
|
|
87
|
-
//# sourceMappingURL=template.d.ts.map
|
package/dist/template.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAA2C,MAAM,oBAAoB,CAAC;AAmWlG,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAO5D,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgHpC,CAAC;AAEF,eAAO,MAAM,sBAAsB;;;CAGlC,CAAC"}
|
package/dist/template.js
DELETED
|
@@ -1,420 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
// ── HTML Escaping ───────────────────────────────────────────────────
|
|
3
|
-
const HTML_ESCAPE_MAP = {
|
|
4
|
-
"&": "&",
|
|
5
|
-
"<": "<",
|
|
6
|
-
">": ">",
|
|
7
|
-
'"': """,
|
|
8
|
-
"'": "'",
|
|
9
|
-
};
|
|
10
|
-
const HTML_ESCAPE_RE = /[&<>"']/g;
|
|
11
|
-
function escapeHtml(str) {
|
|
12
|
-
return str.replace(HTML_ESCAPE_RE, (ch) => HTML_ESCAPE_MAP[ch]);
|
|
13
|
-
}
|
|
14
|
-
// ── Dot-notation property access ────────────────────────────────────
|
|
15
|
-
function resolvePath(obj, path) {
|
|
16
|
-
const parts = path.split(".");
|
|
17
|
-
let current = obj;
|
|
18
|
-
for (const part of parts) {
|
|
19
|
-
if (current == null || typeof current !== "object")
|
|
20
|
-
return undefined;
|
|
21
|
-
current = current[part];
|
|
22
|
-
}
|
|
23
|
-
return current;
|
|
24
|
-
}
|
|
25
|
-
// ── Mustache-like Template Engine ───────────────────────────────────
|
|
26
|
-
/**
|
|
27
|
-
* Render a Mustache-like template string against a data object.
|
|
28
|
-
*
|
|
29
|
-
* Supported syntax:
|
|
30
|
-
* - {{variable}} HTML-escaped variable substitution
|
|
31
|
-
* - {{{variable}}} Unescaped variable substitution
|
|
32
|
-
* - {{#section}}...{{/section}} Conditional / loop block
|
|
33
|
-
* - {{^section}}...{{/section}} Inverted (falsy/empty) block
|
|
34
|
-
* - {{! comment }} Comment (removed from output)
|
|
35
|
-
* - Dot notation: {{a.b.c}}
|
|
36
|
-
*/
|
|
37
|
-
function renderTemplate(template, data) {
|
|
38
|
-
return renderTokens(template, data);
|
|
39
|
-
}
|
|
40
|
-
function renderTokens(template, context) {
|
|
41
|
-
let result = "";
|
|
42
|
-
let pos = 0;
|
|
43
|
-
while (pos < template.length) {
|
|
44
|
-
// Find the next opening tag
|
|
45
|
-
const openIdx = template.indexOf("{{", pos);
|
|
46
|
-
if (openIdx === -1) {
|
|
47
|
-
// No more tags — append the rest as literal text
|
|
48
|
-
result += template.slice(pos);
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
// Append literal text before the tag
|
|
52
|
-
result += template.slice(pos, openIdx);
|
|
53
|
-
// Check for triple-stash {{{...}}}
|
|
54
|
-
if (template[openIdx + 2] === "{") {
|
|
55
|
-
const closeIdx = template.indexOf("}}}", openIdx + 3);
|
|
56
|
-
if (closeIdx === -1) {
|
|
57
|
-
throw new Error(`Unclosed unescaped tag starting at position ${openIdx}`);
|
|
58
|
-
}
|
|
59
|
-
const key = template.slice(openIdx + 3, closeIdx).trim();
|
|
60
|
-
const value = resolvePath(context, key);
|
|
61
|
-
result += value != null ? String(value) : "";
|
|
62
|
-
pos = closeIdx + 3;
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
const closeIdx = template.indexOf("}}", openIdx + 2);
|
|
66
|
-
if (closeIdx === -1) {
|
|
67
|
-
throw new Error(`Unclosed tag starting at position ${openIdx}`);
|
|
68
|
-
}
|
|
69
|
-
const tag = template.slice(openIdx + 2, closeIdx).trim();
|
|
70
|
-
// Comment tag: {{! ... }}
|
|
71
|
-
if (tag.startsWith("!")) {
|
|
72
|
-
pos = closeIdx + 2;
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
// Section opening tag: {{#name}}
|
|
76
|
-
if (tag.startsWith("#")) {
|
|
77
|
-
const name = tag.slice(1).trim();
|
|
78
|
-
const { body, pos: afterClose } = extractSection(template, name, closeIdx + 2);
|
|
79
|
-
const value = resolvePath(context, name);
|
|
80
|
-
if (Array.isArray(value)) {
|
|
81
|
-
// Loop: repeat the body for each item
|
|
82
|
-
for (const item of value) {
|
|
83
|
-
const itemContext = item != null && typeof item === "object" && !Array.isArray(item)
|
|
84
|
-
? { ...context, ...item }
|
|
85
|
-
: { ...context, ".": item };
|
|
86
|
-
result += renderTokens(body, itemContext);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
else if (value) {
|
|
90
|
-
// Truthy: render the body once
|
|
91
|
-
const innerContext = value != null && typeof value === "object" && !Array.isArray(value)
|
|
92
|
-
? { ...context, ...value }
|
|
93
|
-
: context;
|
|
94
|
-
result += renderTokens(body, innerContext);
|
|
95
|
-
}
|
|
96
|
-
// Falsy: skip the body entirely
|
|
97
|
-
pos = afterClose;
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
// Inverted section: {{^name}}
|
|
101
|
-
if (tag.startsWith("^")) {
|
|
102
|
-
const name = tag.slice(1).trim();
|
|
103
|
-
const { body, pos: afterClose } = extractSection(template, name, closeIdx + 2);
|
|
104
|
-
const value = resolvePath(context, name);
|
|
105
|
-
// Render only when falsy or empty array
|
|
106
|
-
const isEmpty = !value || (Array.isArray(value) && value.length === 0);
|
|
107
|
-
if (isEmpty) {
|
|
108
|
-
result += renderTokens(body, context);
|
|
109
|
-
}
|
|
110
|
-
pos = afterClose;
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
// Closing section tag should never appear here at top level
|
|
114
|
-
if (tag.startsWith("/")) {
|
|
115
|
-
throw new Error(`Unexpected closing tag {{/${tag.slice(1).trim()}}} at position ${openIdx}`);
|
|
116
|
-
}
|
|
117
|
-
// Variable tag: {{name}} — HTML-escaped
|
|
118
|
-
const value = resolvePath(context, tag);
|
|
119
|
-
result += value != null ? escapeHtml(String(value)) : "";
|
|
120
|
-
pos = closeIdx + 2;
|
|
121
|
-
}
|
|
122
|
-
return result;
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Extract the body of a section from the template, handling nesting.
|
|
126
|
-
* `startPos` is the position immediately after the opening tag's `}}`.
|
|
127
|
-
* Returns the body text and the position immediately after the closing `{{/name}}`.
|
|
128
|
-
*/
|
|
129
|
-
function extractSection(template, name, startPos) {
|
|
130
|
-
let depth = 1;
|
|
131
|
-
let pos = startPos;
|
|
132
|
-
while (pos < template.length) {
|
|
133
|
-
const nextOpen = template.indexOf("{{", pos);
|
|
134
|
-
if (nextOpen === -1) {
|
|
135
|
-
throw new Error(`Unclosed section "{{#${name}}}": no matching "{{/${name}}}" found`);
|
|
136
|
-
}
|
|
137
|
-
const closeTag = template.indexOf("}}", nextOpen + 2);
|
|
138
|
-
if (closeTag === -1) {
|
|
139
|
-
throw new Error(`Unclosed tag starting at position ${nextOpen}`);
|
|
140
|
-
}
|
|
141
|
-
const inner = template.slice(nextOpen + 2, closeTag).trim();
|
|
142
|
-
if (inner === `#${name}` || inner === `^ ${name}`) {
|
|
143
|
-
depth++;
|
|
144
|
-
}
|
|
145
|
-
else if (inner === `/${name}`) {
|
|
146
|
-
depth--;
|
|
147
|
-
if (depth === 0) {
|
|
148
|
-
const body = template.slice(startPos, nextOpen);
|
|
149
|
-
return { body, pos: closeTag + 2 };
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
pos = closeTag + 2;
|
|
153
|
-
}
|
|
154
|
-
throw new Error(`Unclosed section "{{#${name}}}": no matching "{{/${name}}}" found`);
|
|
155
|
-
}
|
|
156
|
-
// ── Syntax Validation ───────────────────────────────────────────────
|
|
157
|
-
function validateTemplate(template) {
|
|
158
|
-
const sectionStack = [];
|
|
159
|
-
let pos = 0;
|
|
160
|
-
while (pos < template.length) {
|
|
161
|
-
const openIdx = template.indexOf("{{", pos);
|
|
162
|
-
if (openIdx === -1)
|
|
163
|
-
break;
|
|
164
|
-
// Triple stash
|
|
165
|
-
if (template[openIdx + 2] === "{") {
|
|
166
|
-
const closeIdx = template.indexOf("}}}", openIdx + 3);
|
|
167
|
-
if (closeIdx === -1) {
|
|
168
|
-
throw new Error(`Unclosed unescaped tag "{{{" at position ${openIdx}`);
|
|
169
|
-
}
|
|
170
|
-
pos = closeIdx + 3;
|
|
171
|
-
continue;
|
|
172
|
-
}
|
|
173
|
-
const closeIdx = template.indexOf("}}", openIdx + 2);
|
|
174
|
-
if (closeIdx === -1) {
|
|
175
|
-
throw new Error(`Unclosed tag "{{" at position ${openIdx}`);
|
|
176
|
-
}
|
|
177
|
-
const tag = template.slice(openIdx + 2, closeIdx).trim();
|
|
178
|
-
if (tag.startsWith("#") || tag.startsWith("^")) {
|
|
179
|
-
const name = tag.slice(1).trim();
|
|
180
|
-
if (!name) {
|
|
181
|
-
throw new Error(`Empty section name at position ${openIdx}`);
|
|
182
|
-
}
|
|
183
|
-
sectionStack.push({ name, pos: openIdx });
|
|
184
|
-
}
|
|
185
|
-
else if (tag.startsWith("/")) {
|
|
186
|
-
const name = tag.slice(1).trim();
|
|
187
|
-
if (!name) {
|
|
188
|
-
throw new Error(`Empty closing tag at position ${openIdx}`);
|
|
189
|
-
}
|
|
190
|
-
if (sectionStack.length === 0) {
|
|
191
|
-
throw new Error(`Unexpected closing tag "{{/${name}}}" at position ${openIdx} with no matching opening tag`);
|
|
192
|
-
}
|
|
193
|
-
const top = sectionStack.pop();
|
|
194
|
-
if (top.name !== name) {
|
|
195
|
-
throw new Error(`Mismatched section tags: opened "{{#${top.name}}}" at position ${top.pos} but closed with "{{/${name}}}" at position ${openIdx}`);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
// Comments and variables don't need stack tracking
|
|
199
|
-
pos = closeIdx + 2;
|
|
200
|
-
}
|
|
201
|
-
if (sectionStack.length > 0) {
|
|
202
|
-
const unclosed = sectionStack[sectionStack.length - 1];
|
|
203
|
-
throw new Error(`Unclosed section "{{#${unclosed.name}}}" opened at position ${unclosed.pos}`);
|
|
204
|
-
}
|
|
205
|
-
return true;
|
|
206
|
-
}
|
|
207
|
-
// ── Variable Extraction ─────────────────────────────────────────────
|
|
208
|
-
function extractVars(template) {
|
|
209
|
-
const vars = new Set();
|
|
210
|
-
let pos = 0;
|
|
211
|
-
while (pos < template.length) {
|
|
212
|
-
const openIdx = template.indexOf("{{", pos);
|
|
213
|
-
if (openIdx === -1)
|
|
214
|
-
break;
|
|
215
|
-
// Triple stash
|
|
216
|
-
if (template[openIdx + 2] === "{") {
|
|
217
|
-
const closeIdx = template.indexOf("}}}", openIdx + 3);
|
|
218
|
-
if (closeIdx === -1) {
|
|
219
|
-
pos = openIdx + 3;
|
|
220
|
-
continue;
|
|
221
|
-
}
|
|
222
|
-
const key = template.slice(openIdx + 3, closeIdx).trim();
|
|
223
|
-
if (key)
|
|
224
|
-
vars.add(key);
|
|
225
|
-
pos = closeIdx + 3;
|
|
226
|
-
continue;
|
|
227
|
-
}
|
|
228
|
-
const closeIdx = template.indexOf("}}", openIdx + 2);
|
|
229
|
-
if (closeIdx === -1) {
|
|
230
|
-
pos = openIdx + 2;
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
|
-
const tag = template.slice(openIdx + 2, closeIdx).trim();
|
|
234
|
-
if (tag.startsWith("!")) {
|
|
235
|
-
// Comment — skip
|
|
236
|
-
}
|
|
237
|
-
else if (tag.startsWith("#") || tag.startsWith("^")) {
|
|
238
|
-
const name = tag.slice(1).trim();
|
|
239
|
-
if (name)
|
|
240
|
-
vars.add(name);
|
|
241
|
-
}
|
|
242
|
-
else if (tag.startsWith("/")) {
|
|
243
|
-
// Closing tag — skip
|
|
244
|
-
}
|
|
245
|
-
else if (tag) {
|
|
246
|
-
vars.add(tag);
|
|
247
|
-
}
|
|
248
|
-
pos = closeIdx + 2;
|
|
249
|
-
}
|
|
250
|
-
return [...vars];
|
|
251
|
-
}
|
|
252
|
-
// ── Simple ${key} interpolation ─────────────────────────────────────
|
|
253
|
-
function interpolateString(str, data) {
|
|
254
|
-
return str.replace(/\$\{([^}]+)\}/g, (_match, key) => {
|
|
255
|
-
const value = resolvePath(data, key.trim());
|
|
256
|
-
return value != null ? String(value) : "";
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
// ── RobinPath Function Handlers ─────────────────────────────────────
|
|
260
|
-
const render = (args) => {
|
|
261
|
-
const template = String(args[0] ?? "");
|
|
262
|
-
const data = (args[1] != null && typeof args[1] === "object" && !Array.isArray(args[1]))
|
|
263
|
-
? args[1]
|
|
264
|
-
: {};
|
|
265
|
-
return renderTemplate(template, data);
|
|
266
|
-
};
|
|
267
|
-
const renderFile = (args) => {
|
|
268
|
-
const filePath = String(args[0] ?? "");
|
|
269
|
-
const data = (args[1] != null && typeof args[1] === "object" && !Array.isArray(args[1]))
|
|
270
|
-
? args[1]
|
|
271
|
-
: {};
|
|
272
|
-
const template = readFileSync(filePath, "utf-8");
|
|
273
|
-
return renderTemplate(template, data);
|
|
274
|
-
};
|
|
275
|
-
const escape = (args) => {
|
|
276
|
-
const str = String(args[0] ?? "");
|
|
277
|
-
return escapeHtml(str);
|
|
278
|
-
};
|
|
279
|
-
const compile = (args) => {
|
|
280
|
-
const template = String(args[0] ?? "");
|
|
281
|
-
return validateTemplate(template);
|
|
282
|
-
};
|
|
283
|
-
const extractVariables = (args) => {
|
|
284
|
-
const template = String(args[0] ?? "");
|
|
285
|
-
return extractVars(template);
|
|
286
|
-
};
|
|
287
|
-
const renderString = (args) => {
|
|
288
|
-
const str = String(args[0] ?? "");
|
|
289
|
-
const data = (args[1] != null && typeof args[1] === "object" && !Array.isArray(args[1]))
|
|
290
|
-
? args[1]
|
|
291
|
-
: {};
|
|
292
|
-
return interpolateString(str, data);
|
|
293
|
-
};
|
|
294
|
-
// ── Exports ─────────────────────────────────────────────────────────
|
|
295
|
-
export const TemplateFunctions = {
|
|
296
|
-
render,
|
|
297
|
-
renderFile,
|
|
298
|
-
escape,
|
|
299
|
-
compile,
|
|
300
|
-
extractVariables,
|
|
301
|
-
renderString,
|
|
302
|
-
};
|
|
303
|
-
export const TemplateFunctionMetadata = {
|
|
304
|
-
render: {
|
|
305
|
-
description: "Render a Mustache-like template string with variable substitution, sections, and loops",
|
|
306
|
-
parameters: [
|
|
307
|
-
{
|
|
308
|
-
name: "template",
|
|
309
|
-
dataType: "string",
|
|
310
|
-
description: "The template string containing {{variable}}, {{{unescaped}}}, {{#section}}...{{/section}}, {{^inverted}}...{{/inverted}}, and {{! comment }} tags",
|
|
311
|
-
formInputType: "textarea",
|
|
312
|
-
required: true,
|
|
313
|
-
},
|
|
314
|
-
{
|
|
315
|
-
name: "data",
|
|
316
|
-
dataType: "object",
|
|
317
|
-
description: "Key-value data object for variable substitution. Supports nested objects via dot notation.",
|
|
318
|
-
formInputType: "textarea",
|
|
319
|
-
required: true,
|
|
320
|
-
},
|
|
321
|
-
],
|
|
322
|
-
returnType: "string",
|
|
323
|
-
returnDescription: "The rendered template string with all tags resolved",
|
|
324
|
-
example: 'template.render "Hello, {{name}}!" { "name": "World" }',
|
|
325
|
-
},
|
|
326
|
-
renderFile: {
|
|
327
|
-
description: "Read a template from a file and render it with the provided data object",
|
|
328
|
-
parameters: [
|
|
329
|
-
{
|
|
330
|
-
name: "templateFilePath",
|
|
331
|
-
dataType: "string",
|
|
332
|
-
description: "Absolute or relative path to the template file",
|
|
333
|
-
formInputType: "text",
|
|
334
|
-
required: true,
|
|
335
|
-
},
|
|
336
|
-
{
|
|
337
|
-
name: "data",
|
|
338
|
-
dataType: "object",
|
|
339
|
-
description: "Key-value data object for variable substitution. Supports nested objects via dot notation.",
|
|
340
|
-
formInputType: "textarea",
|
|
341
|
-
required: true,
|
|
342
|
-
},
|
|
343
|
-
],
|
|
344
|
-
returnType: "string",
|
|
345
|
-
returnDescription: "The rendered template string with all tags resolved",
|
|
346
|
-
example: 'template.renderFile "/tmp/greeting.mustache" { "name": "World" }',
|
|
347
|
-
},
|
|
348
|
-
escape: {
|
|
349
|
-
description: "HTML-escape a string, converting &, <, >, \", and ' to their HTML entity equivalents",
|
|
350
|
-
parameters: [
|
|
351
|
-
{
|
|
352
|
-
name: "string",
|
|
353
|
-
dataType: "string",
|
|
354
|
-
description: "The string to HTML-escape",
|
|
355
|
-
formInputType: "text",
|
|
356
|
-
required: true,
|
|
357
|
-
},
|
|
358
|
-
],
|
|
359
|
-
returnType: "string",
|
|
360
|
-
returnDescription: "The HTML-escaped string",
|
|
361
|
-
example: 'template.escape "<script>alert(1)</script>"',
|
|
362
|
-
},
|
|
363
|
-
compile: {
|
|
364
|
-
description: "Validate template syntax, checking for unclosed tags, mismatched sections, and other structural errors",
|
|
365
|
-
parameters: [
|
|
366
|
-
{
|
|
367
|
-
name: "template",
|
|
368
|
-
dataType: "string",
|
|
369
|
-
description: "The template string to validate",
|
|
370
|
-
formInputType: "textarea",
|
|
371
|
-
required: true,
|
|
372
|
-
},
|
|
373
|
-
],
|
|
374
|
-
returnType: "boolean",
|
|
375
|
-
returnDescription: "True if the template syntax is valid. Throws an error with details if invalid.",
|
|
376
|
-
example: 'template.compile "{{#items}}{{name}}{{/items}}"',
|
|
377
|
-
},
|
|
378
|
-
extractVariables: {
|
|
379
|
-
description: "Extract all unique variable and section names used in a template",
|
|
380
|
-
parameters: [
|
|
381
|
-
{
|
|
382
|
-
name: "template",
|
|
383
|
-
dataType: "string",
|
|
384
|
-
description: "The template string to analyze",
|
|
385
|
-
formInputType: "textarea",
|
|
386
|
-
required: true,
|
|
387
|
-
},
|
|
388
|
-
],
|
|
389
|
-
returnType: "array",
|
|
390
|
-
returnDescription: "Deduplicated array of all variable and section names found in the template",
|
|
391
|
-
example: 'template.extractVariables "{{greeting}}, {{name}}! {{#show}}Visible{{/show}}"',
|
|
392
|
-
},
|
|
393
|
-
renderString: {
|
|
394
|
-
description: "Simple string interpolation using ${key} placeholders (no sections or loops)",
|
|
395
|
-
parameters: [
|
|
396
|
-
{
|
|
397
|
-
name: "string",
|
|
398
|
-
dataType: "string",
|
|
399
|
-
description: "The string containing ${key} placeholders for substitution",
|
|
400
|
-
formInputType: "textarea",
|
|
401
|
-
required: true,
|
|
402
|
-
},
|
|
403
|
-
{
|
|
404
|
-
name: "data",
|
|
405
|
-
dataType: "object",
|
|
406
|
-
description: "Key-value data object for placeholder substitution. Supports dot notation.",
|
|
407
|
-
formInputType: "textarea",
|
|
408
|
-
required: true,
|
|
409
|
-
},
|
|
410
|
-
],
|
|
411
|
-
returnType: "string",
|
|
412
|
-
returnDescription: "The string with all ${key} placeholders replaced by their values",
|
|
413
|
-
example: 'template.renderString "Hello, ${name}!" { "name": "World" }',
|
|
414
|
-
},
|
|
415
|
-
};
|
|
416
|
-
export const TemplateModuleMetadata = {
|
|
417
|
-
description: "Mustache-like template engine with variable substitution, conditional sections, loops, and simple string interpolation",
|
|
418
|
-
methods: ["render", "renderFile", "escape", "compile", "extractVariables", "renderString"],
|
|
419
|
-
};
|
|
420
|
-
//# sourceMappingURL=template.js.map
|
package/dist/template.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"template.js","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"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"}
|