@dogsbay/minja 0.2.0-beta.92 → 0.2.0-beta.98
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 +20 -0
- package/bin/minja.js +179 -19
- package/dist/browser.d.ts +1 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +1 -0
- package/dist/browser.js.map +1 -1
- package/dist/cli.js +2 -1
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +148 -17
- package/dist/index.umd.js.map +4 -4
- package/dist/index.umd.min.js +7 -4
- package/dist/index.umd.min.js.map +4 -4
- package/dist/loader.d.ts +20 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +69 -1
- package/dist/loader.js.map +1 -1
- package/dist/parser.d.ts +0 -5
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +112 -4
- package/dist/parser.js.map +1 -1
- package/dist/renderer.d.ts.map +1 -1
- package/dist/renderer.js +84 -12
- package/dist/renderer.js.map +1 -1
- package/dist/scan.d.ts +46 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +46 -0
- package/dist/scan.js.map +1 -0
- package/dist/types.d.ts +12 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +17 -7
package/README.md
CHANGED
|
@@ -101,6 +101,8 @@ Options:
|
|
|
101
101
|
-d, --max-depth <number> Maximum include depth (default: 10)
|
|
102
102
|
-t, --timeout <ms> Rendering timeout in milliseconds (default: 5000)
|
|
103
103
|
-v, --vars <json> Inline context variables as JSON
|
|
104
|
+
-r, --include-root <dir> Refuse {% include %} targets that resolve
|
|
105
|
+
(after symlinks) outside this directory
|
|
104
106
|
-h, --help display help for command
|
|
105
107
|
```
|
|
106
108
|
|
|
@@ -129,6 +131,24 @@ minja README.md --context vars.json
|
|
|
129
131
|
minja document.md --output docs/index.html
|
|
130
132
|
```
|
|
131
133
|
|
|
134
|
+
**Untrusted input — contain includes to a directory:**
|
|
135
|
+
```bash
|
|
136
|
+
# Any {% include %} resolving (after symlink resolution) outside docs/
|
|
137
|
+
# is REFUSED and the render fails — without this, an include like
|
|
138
|
+
# "../secrets.txt" or "/etc/hostname" splices any readable file into
|
|
139
|
+
# the output. `..` and absolute paths that stay inside the root are fine.
|
|
140
|
+
minja docs/page.md --include-root docs/
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Programmatic equivalent:
|
|
144
|
+
```ts
|
|
145
|
+
import { render, FileSystemLoader } from '@dogsbay/minja'
|
|
146
|
+
const out = await render(template, {
|
|
147
|
+
basePath: 'docs/',
|
|
148
|
+
loader: new FileSystemLoader('docs/', { root: 'docs/' }),
|
|
149
|
+
})
|
|
150
|
+
```
|
|
151
|
+
|
|
132
152
|
**Pipeline usage:**
|
|
133
153
|
```bash
|
|
134
154
|
# Generate docs from multiple sources
|
package/bin/minja.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* minja v0.2.0-beta.
|
|
3
|
+
* minja v0.2.0-beta.98
|
|
4
4
|
* Minimal, secure Jinja2/Nunjucks subset for documentation preprocessing
|
|
5
5
|
* @license MIT
|
|
6
6
|
*/
|
|
@@ -171,6 +171,24 @@ function isTruthy(value) {
|
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
// src/parser.ts
|
|
174
|
+
var KNOWN_TAG_KEYWORDS = /* @__PURE__ */ new Set([
|
|
175
|
+
"set",
|
|
176
|
+
"if",
|
|
177
|
+
"include",
|
|
178
|
+
"switch",
|
|
179
|
+
"leveloffset",
|
|
180
|
+
"raw",
|
|
181
|
+
"endif",
|
|
182
|
+
"elif",
|
|
183
|
+
"else",
|
|
184
|
+
"endswitch",
|
|
185
|
+
"case",
|
|
186
|
+
"endleveloffset",
|
|
187
|
+
"endraw"
|
|
188
|
+
]);
|
|
189
|
+
function stripBodyForEndTag(body, endTag) {
|
|
190
|
+
return endTag.startsWith("{%-") ? body.replace(/[ \t]*\n[ \t\n]*$/, "") : body;
|
|
191
|
+
}
|
|
174
192
|
function parse(template) {
|
|
175
193
|
const errors = [];
|
|
176
194
|
const ast = [];
|
|
@@ -253,12 +271,57 @@ function parse(template) {
|
|
|
253
271
|
}
|
|
254
272
|
}
|
|
255
273
|
} else if (nearest.type === "tag") {
|
|
274
|
+
const tagStart2 = position;
|
|
256
275
|
advance(2);
|
|
257
276
|
const endPos = findNext("%}", position);
|
|
258
277
|
if (endPos === -1) {
|
|
259
278
|
errors.push(createError("Unclosed statement tag"));
|
|
260
279
|
break;
|
|
261
280
|
}
|
|
281
|
+
const peeked = template.substring(position, endPos).trim();
|
|
282
|
+
const peekKeyword = peeked.replace(/^-\s*/, "").replace(/\s*-$/, "").split(/\s+/)[0] ?? "";
|
|
283
|
+
if (peekKeyword === "raw") {
|
|
284
|
+
const openerLeftStrip = peeked.startsWith("-");
|
|
285
|
+
const openerRightStrip = peeked.endsWith("-");
|
|
286
|
+
if (openerLeftStrip && ast.length > 0 && ast[ast.length - 1].type === "text") {
|
|
287
|
+
const lastNode = ast[ast.length - 1];
|
|
288
|
+
lastNode.value = lastNode.value.replace(/[ \t]*\n[ \t\n]*$/, "");
|
|
289
|
+
}
|
|
290
|
+
extractTo(endPos);
|
|
291
|
+
advance(2);
|
|
292
|
+
if (openerRightStrip) {
|
|
293
|
+
while (position < template.length && /[ \t\n]/.test(template[position])) {
|
|
294
|
+
advance(1);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const endrawMatch = /\{%-?\s*endraw\s*-?%\}/.exec(template.substring(position));
|
|
298
|
+
if (!endrawMatch) {
|
|
299
|
+
errors.push(createError("Unclosed raw block"));
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
const endrawAbs = position + endrawMatch.index;
|
|
303
|
+
let content = extractTo(endrawAbs);
|
|
304
|
+
const endrawTag = endrawMatch[0];
|
|
305
|
+
if (endrawTag.startsWith("{%-")) {
|
|
306
|
+
content = content.replace(/[ \t]*\n[ \t\n]*$/, "");
|
|
307
|
+
}
|
|
308
|
+
advance(endrawTag.length);
|
|
309
|
+
if (endrawTag.endsWith("-%}")) {
|
|
310
|
+
while (position < template.length && /[ \t\n]/.test(template[position])) {
|
|
311
|
+
advance(1);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
if (content) {
|
|
315
|
+
ast.push({ type: "text", value: content });
|
|
316
|
+
}
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
if (!KNOWN_TAG_KEYWORDS.has(peekKeyword)) {
|
|
320
|
+
extractTo(endPos);
|
|
321
|
+
advance(2);
|
|
322
|
+
ast.push({ type: "text", value: template.substring(tagStart2, endPos + 2) });
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
262
325
|
let statement = extractTo(endPos).trim();
|
|
263
326
|
const hasLeftStrip = statement.startsWith("-");
|
|
264
327
|
const hasRightStrip = statement.endsWith("-");
|
|
@@ -392,12 +455,13 @@ function parse(template) {
|
|
|
392
455
|
}
|
|
393
456
|
return { ast, errors };
|
|
394
457
|
function findEndTag(tagName) {
|
|
395
|
-
const pattern = new RegExp(`{
|
|
458
|
+
const pattern = new RegExp(`{%-?\\s*${tagName}\\s*-?%}`);
|
|
396
459
|
const match = pattern.exec(template.substring(position));
|
|
397
460
|
if (match) {
|
|
398
461
|
return {
|
|
399
462
|
start: position + match.index,
|
|
400
|
-
length: match[0].length
|
|
463
|
+
length: match[0].length,
|
|
464
|
+
tag: match[0]
|
|
401
465
|
};
|
|
402
466
|
}
|
|
403
467
|
return null;
|
|
@@ -429,8 +493,12 @@ function parse(template) {
|
|
|
429
493
|
searchPos = nearest.pos + nearest.match[0].length;
|
|
430
494
|
} else if (nearest.type === "endif") {
|
|
431
495
|
if (depth === 0) {
|
|
432
|
-
const bodyTemplate = extractTo(nearest.pos);
|
|
496
|
+
const bodyTemplate = stripBodyForEndTag(extractTo(nearest.pos), nearest.match[0]);
|
|
433
497
|
advance(nearest.match[0].length);
|
|
498
|
+
if (nearest.match[0].endsWith("-%}")) {
|
|
499
|
+
while (position < template.length && /[ \t\n]/.test(template[position]))
|
|
500
|
+
advance(1);
|
|
501
|
+
}
|
|
434
502
|
const bodyResult = parse(bodyTemplate);
|
|
435
503
|
parseErrors.push(...bodyResult.errors);
|
|
436
504
|
return {
|
|
@@ -444,7 +512,7 @@ function parse(template) {
|
|
|
444
512
|
searchPos = nearest.pos + nearest.match[0].length;
|
|
445
513
|
}
|
|
446
514
|
} else if (depth === 0 && (nearest.type === "elif" || nearest.type === "else")) {
|
|
447
|
-
const bodyTemplate = extractTo(nearest.pos);
|
|
515
|
+
const bodyTemplate = stripBodyForEndTag(extractTo(nearest.pos), nearest.match[0]);
|
|
448
516
|
const bodyResult = parse(bodyTemplate);
|
|
449
517
|
if (elifBranches.length === 0 && elseBranch.length === 0) {
|
|
450
518
|
parseErrors.push(...bodyResult.errors);
|
|
@@ -481,7 +549,10 @@ function parse(template) {
|
|
|
481
549
|
if (!endifMatch2) {
|
|
482
550
|
parseErrors.push(createError("Missing endif after else"));
|
|
483
551
|
} else {
|
|
484
|
-
const elseBodyTemplate =
|
|
552
|
+
const elseBodyTemplate = stripBodyForEndTag(
|
|
553
|
+
extractTo(endifMatch2.start),
|
|
554
|
+
endifMatch2.tag
|
|
555
|
+
);
|
|
485
556
|
advance(endifMatch2.length);
|
|
486
557
|
const elseBodyResult = parse(elseBodyTemplate);
|
|
487
558
|
parseErrors.push(...elseBodyResult.errors);
|
|
@@ -667,15 +738,38 @@ var FetchLoader = class {
|
|
|
667
738
|
};
|
|
668
739
|
|
|
669
740
|
// src/renderer.ts
|
|
670
|
-
function transformHeadings(text, offset) {
|
|
741
|
+
function transformHeadings(text, offset, initialFence = null, fenceOut) {
|
|
671
742
|
if (offset === 0) {
|
|
743
|
+
if (fenceOut)
|
|
744
|
+
fenceOut.fence = initialFence;
|
|
672
745
|
return text;
|
|
673
746
|
}
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
747
|
+
const lines = text.split("\n");
|
|
748
|
+
let fence = initialFence;
|
|
749
|
+
for (let i = 0; i < lines.length; i++) {
|
|
750
|
+
const line = lines[i];
|
|
751
|
+
const fenceMatch = line.match(/^\s*(`{3,}|~{3,})/);
|
|
752
|
+
if (fenceMatch) {
|
|
753
|
+
const run = fenceMatch[1];
|
|
754
|
+
if (fence === null) {
|
|
755
|
+
fence = run;
|
|
756
|
+
} else if (run[0] === fence[0] && run.length >= fence.length && line.trim() === run) {
|
|
757
|
+
fence = null;
|
|
758
|
+
}
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
if (fence !== null) {
|
|
762
|
+
continue;
|
|
763
|
+
}
|
|
764
|
+
const m = line.match(/^(#{1,6})(\s+)/);
|
|
765
|
+
if (m) {
|
|
766
|
+
const newLevel = Math.max(1, Math.min(6, m[1].length + offset));
|
|
767
|
+
lines[i] = "#".repeat(newLevel) + line.slice(m[1].length);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
if (fenceOut)
|
|
771
|
+
fenceOut.fence = fence;
|
|
772
|
+
return lines.join("\n");
|
|
679
773
|
}
|
|
680
774
|
function resolvePath(path, basePath) {
|
|
681
775
|
if (path.startsWith("/")) {
|
|
@@ -746,7 +840,14 @@ async function renderInternal(template, options) {
|
|
|
746
840
|
async function renderNodes(nodes, options) {
|
|
747
841
|
const parts = [];
|
|
748
842
|
for (const node of nodes) {
|
|
749
|
-
|
|
843
|
+
let rendered = await renderNode(node, options);
|
|
844
|
+
if (node.type === "include" && rendered && parts.length > 0) {
|
|
845
|
+
const tail = /(?:^|\n)([ \t]+)$/.exec(parts[parts.length - 1]);
|
|
846
|
+
if (tail) {
|
|
847
|
+
rendered = rendered.replace(/\n(?=[^\n])/g, "\n" + tail[1]);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
parts.push(rendered);
|
|
750
851
|
}
|
|
751
852
|
return parts.join("");
|
|
752
853
|
}
|
|
@@ -758,7 +859,15 @@ async function renderNode(node, options) {
|
|
|
758
859
|
if (currentOffset === 0) {
|
|
759
860
|
return node.value;
|
|
760
861
|
}
|
|
761
|
-
|
|
862
|
+
const fenceOut = { fence: null };
|
|
863
|
+
const out = transformHeadings(
|
|
864
|
+
node.value,
|
|
865
|
+
currentOffset,
|
|
866
|
+
context.get("_levelOffsetFence") ?? null,
|
|
867
|
+
fenceOut
|
|
868
|
+
);
|
|
869
|
+
context.set("_levelOffsetFence", fenceOut.fence);
|
|
870
|
+
return out;
|
|
762
871
|
}
|
|
763
872
|
case "variable": {
|
|
764
873
|
const value = context.get(node.name);
|
|
@@ -768,6 +877,8 @@ async function renderNode(node, options) {
|
|
|
768
877
|
throw new Error(`Undefined variable: ${node.name}`);
|
|
769
878
|
case "preserve":
|
|
770
879
|
return `{{ ${node.name} }}`;
|
|
880
|
+
case "asciidoc-literal":
|
|
881
|
+
return `{${node.name}}`;
|
|
771
882
|
case "empty":
|
|
772
883
|
default:
|
|
773
884
|
return "";
|
|
@@ -787,7 +898,7 @@ async function renderNode(node, options) {
|
|
|
787
898
|
case "comment":
|
|
788
899
|
return "";
|
|
789
900
|
case "if": {
|
|
790
|
-
if (options.undefinedBehavior === "preserve" && options.undefinedConditions !== "falsy") {
|
|
901
|
+
if ((options.undefinedBehavior === "preserve" || options.undefinedBehavior === "asciidoc-literal") && options.undefinedConditions !== "falsy") {
|
|
791
902
|
const undefinedRefs = findUndefinedRefs(node.condition, context);
|
|
792
903
|
if (undefinedRefs.length > 0) {
|
|
793
904
|
return ifNodeToSource(node);
|
|
@@ -847,7 +958,10 @@ async function renderNode(node, options) {
|
|
|
847
958
|
undefinedConditions: options.undefinedConditions
|
|
848
959
|
});
|
|
849
960
|
} catch (error) {
|
|
850
|
-
if (
|
|
961
|
+
if (error instanceof Error && error.name === "IncludeContainmentError") {
|
|
962
|
+
throw error;
|
|
963
|
+
}
|
|
964
|
+
if (options.undefinedBehavior === "preserve" || options.undefinedBehavior === "asciidoc-literal") {
|
|
851
965
|
return `{% include "${node.path}" %}`;
|
|
852
966
|
}
|
|
853
967
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -870,11 +984,14 @@ async function renderNode(node, options) {
|
|
|
870
984
|
const newOffset = node.isRelative ? parentOffset + node.offset : node.offset;
|
|
871
985
|
const previousOffset = parentOffset;
|
|
872
986
|
context.set("_levelOffset", newOffset);
|
|
987
|
+
const previousFence = context.get("_levelOffsetFence") ?? null;
|
|
988
|
+
context.set("_levelOffsetFence", null);
|
|
873
989
|
try {
|
|
874
990
|
const result = await renderNodes(node.body, options);
|
|
875
991
|
return result;
|
|
876
992
|
} finally {
|
|
877
993
|
context.set("_levelOffset", previousOffset);
|
|
994
|
+
context.set("_levelOffsetFence", previousFence);
|
|
878
995
|
}
|
|
879
996
|
}
|
|
880
997
|
default:
|
|
@@ -975,9 +1092,11 @@ var FileSystemLoader = class {
|
|
|
975
1092
|
/**
|
|
976
1093
|
* Create a filesystem loader
|
|
977
1094
|
* @param basePath - Base directory for resolving relative paths
|
|
1095
|
+
* @param options - See {@link FileSystemLoaderOptions}
|
|
978
1096
|
*/
|
|
979
|
-
constructor(basePath = process.cwd()) {
|
|
1097
|
+
constructor(basePath = process.cwd(), options = {}) {
|
|
980
1098
|
this.basePath = basePath;
|
|
1099
|
+
this.root = options.root;
|
|
981
1100
|
}
|
|
982
1101
|
/**
|
|
983
1102
|
* Load a file from the filesystem
|
|
@@ -990,6 +1109,41 @@ var FileSystemLoader = class {
|
|
|
990
1109
|
const pathModule = await import("path");
|
|
991
1110
|
const resolvedBasePath = basePath || this.basePath;
|
|
992
1111
|
const resolvedPath = pathModule.isAbsolute(path) ? path : pathModule.resolve(resolvedBasePath, path);
|
|
1112
|
+
if (this.root !== void 0) {
|
|
1113
|
+
const refuse = (detail) => {
|
|
1114
|
+
const err = new Error(`Refusing include outside the include root: ${detail}`);
|
|
1115
|
+
err.name = "IncludeContainmentError";
|
|
1116
|
+
throw err;
|
|
1117
|
+
};
|
|
1118
|
+
if (this.realRoot === void 0) {
|
|
1119
|
+
try {
|
|
1120
|
+
this.realRoot = await fs.realpath(this.root);
|
|
1121
|
+
} catch (error) {
|
|
1122
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1123
|
+
refuse(`include root ${this.root} does not resolve (${message})`);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
const lexical = pathModule.resolve(resolvedPath);
|
|
1127
|
+
if (lexical !== this.realRoot && !lexical.startsWith(this.realRoot + pathModule.sep) && lexical !== this.root && !lexical.startsWith(pathModule.resolve(this.root) + pathModule.sep)) {
|
|
1128
|
+
refuse(`"${path}" resolves to ${lexical}, which is not inside ${this.realRoot}`);
|
|
1129
|
+
}
|
|
1130
|
+
let realTarget;
|
|
1131
|
+
try {
|
|
1132
|
+
realTarget = await fs.realpath(resolvedPath);
|
|
1133
|
+
} catch (error) {
|
|
1134
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1135
|
+
throw new Error(`Failed to load ${resolvedPath}: ${message}`);
|
|
1136
|
+
}
|
|
1137
|
+
if (realTarget !== this.realRoot && !realTarget.startsWith(this.realRoot + pathModule.sep)) {
|
|
1138
|
+
refuse(`"${path}" resolves to ${realTarget}, which is not inside ${this.realRoot}`);
|
|
1139
|
+
}
|
|
1140
|
+
try {
|
|
1141
|
+
return await fs.readFile(realTarget, "utf-8");
|
|
1142
|
+
} catch (error) {
|
|
1143
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1144
|
+
throw new Error(`Failed to load ${resolvedPath}: ${message}`);
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
993
1147
|
try {
|
|
994
1148
|
return await fs.readFile(resolvedPath, "utf-8");
|
|
995
1149
|
} catch (error) {
|
|
@@ -1001,7 +1155,10 @@ var FileSystemLoader = class {
|
|
|
1001
1155
|
|
|
1002
1156
|
// src/cli.ts
|
|
1003
1157
|
var program = new Command();
|
|
1004
|
-
program.name("minja").description("Minimal, secure Jinja2/Nunjucks subset for documentation preprocessing").version("0.1.0").argument("[template]", "Template file to render (or read from stdin)").option("-c, --context <file>", "Context file (JSON or YAML)").option("-o, --output <file>", "Output file (default: stdout)").option("-d, --max-depth <number>", "Maximum include depth", "10").option("-t, --timeout <ms>", "Rendering timeout in milliseconds", "5000").option("-v, --vars <json>", "Inline context variables as JSON").
|
|
1158
|
+
program.name("minja").description("Minimal, secure Jinja2/Nunjucks subset for documentation preprocessing").version("0.1.0").argument("[template]", "Template file to render (or read from stdin)").option("-c, --context <file>", "Context file (JSON or YAML)").option("-o, --output <file>", "Output file (default: stdout)").option("-d, --max-depth <number>", "Maximum include depth", "10").option("-t, --timeout <ms>", "Rendering timeout in milliseconds", "5000").option("-v, --vars <json>", "Inline context variables as JSON").option(
|
|
1159
|
+
"-r, --include-root <dir>",
|
|
1160
|
+
"Refuse {% include %} targets that resolve (after symlinks) outside this directory"
|
|
1161
|
+
).action(async (templatePath, options) => {
|
|
1005
1162
|
try {
|
|
1006
1163
|
let template;
|
|
1007
1164
|
let baseDir = process.cwd();
|
|
@@ -1028,7 +1185,10 @@ program.name("minja").description("Minimal, secure Jinja2/Nunjucks subset for do
|
|
|
1028
1185
|
const inlineVars = JSON.parse(options.vars);
|
|
1029
1186
|
context = { ...context, ...inlineVars };
|
|
1030
1187
|
}
|
|
1031
|
-
const loader = new FileSystemLoader(
|
|
1188
|
+
const loader = new FileSystemLoader(
|
|
1189
|
+
baseDir,
|
|
1190
|
+
options.includeRoot ? { root: resolve(options.includeRoot) } : {}
|
|
1191
|
+
);
|
|
1032
1192
|
const result = await render(template, {
|
|
1033
1193
|
loader,
|
|
1034
1194
|
basePath: baseDir,
|
package/dist/browser.d.ts
CHANGED
|
@@ -8,4 +8,5 @@ export { Context } from './context.js';
|
|
|
8
8
|
export { FetchLoader } from './loader-fetch.js';
|
|
9
9
|
export { MemoryLoader } from './loader-memory.js';
|
|
10
10
|
export type { ASTNode, TextNode, VariableNode, SetNode, IfNode, IncludeNode, CommentNode, Expression, LiteralExpression, VariableExpression, BinaryExpression, UnaryExpression, RenderOptions, Loader, IContext, ParseResult, ParseError, } from './types.js';
|
|
11
|
+
export { includeDirectiveRe, scanIncludes, variableRe, directiveTagRe, commentRe, rawBlockRe } from './scan.js';
|
|
11
12
|
//# sourceMappingURL=browser.d.ts.map
|
package/dist/browser.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,YAAY,EAEV,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,OAAO,EACP,MAAM,EACN,WAAW,EACX,WAAW,EAGX,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EAGf,aAAa,EACb,MAAM,EACN,QAAQ,EACR,WAAW,EACX,UAAU,GACX,MAAM,YAAY,CAAA"}
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,YAAY,EAEV,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,OAAO,EACP,MAAM,EACN,WAAW,EACX,WAAW,EAGX,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EAGf,aAAa,EACb,MAAM,EACN,QAAQ,EACR,WAAW,EACX,UAAU,GACX,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA"}
|
package/dist/browser.js
CHANGED
|
@@ -7,4 +7,5 @@ export { parseExpression, evaluateExpression } from './evaluator.js';
|
|
|
7
7
|
export { Context } from './context.js';
|
|
8
8
|
export { FetchLoader } from './loader-fetch.js';
|
|
9
9
|
export { MemoryLoader } from './loader-memory.js';
|
|
10
|
+
export { includeDirectiveRe, scanIncludes, variableRe, directiveTagRe, commentRe, rawBlockRe } from './scan.js';
|
|
10
11
|
//# sourceMappingURL=browser.js.map
|
package/dist/browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA"}
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AA0BjD,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA"}
|
package/dist/cli.js
CHANGED
|
@@ -18,6 +18,7 @@ program
|
|
|
18
18
|
.option('-d, --max-depth <number>', 'Maximum include depth', '10')
|
|
19
19
|
.option('-t, --timeout <ms>', 'Rendering timeout in milliseconds', '5000')
|
|
20
20
|
.option('-v, --vars <json>', 'Inline context variables as JSON')
|
|
21
|
+
.option('-r, --include-root <dir>', 'Refuse {% include %} targets that resolve (after symlinks) outside this directory')
|
|
21
22
|
.action(async (templatePath, options) => {
|
|
22
23
|
try {
|
|
23
24
|
// Read template from file or stdin
|
|
@@ -53,7 +54,7 @@ program
|
|
|
53
54
|
context = { ...context, ...inlineVars };
|
|
54
55
|
}
|
|
55
56
|
// Render template
|
|
56
|
-
const loader = new FileSystemLoader(baseDir);
|
|
57
|
+
const loader = new FileSystemLoader(baseDir, options.includeRoot ? { root: resolve(options.includeRoot) } : {});
|
|
57
58
|
const result = await render(template, {
|
|
58
59
|
loader,
|
|
59
60
|
basePath: baseDir,
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAA;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAE9C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;AAE7B,OAAO;KACJ,IAAI,CAAC,OAAO,CAAC;KACb,WAAW,CAAC,wEAAwE,CAAC;KACrF,OAAO,CAAC,OAAO,CAAC;KAChB,QAAQ,CAAC,YAAY,EAAE,8CAA8C,CAAC;KACtE,MAAM,CAAC,sBAAsB,EAAE,6BAA6B,CAAC;KAC7D,MAAM,CAAC,qBAAqB,EAAE,+BAA+B,CAAC;KAC9D,MAAM,CAAC,0BAA0B,EAAE,uBAAuB,EAAE,IAAI,CAAC;KACjE,MAAM,CAAC,oBAAoB,EAAE,mCAAmC,EAAE,MAAM,CAAC;KACzE,MAAM,CAAC,mBAAmB,EAAE,kCAAkC,CAAC;KAC/D,MAAM,CAAC,KAAK,EAAE,YAAgC,EAAE,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -14,5 +14,7 @@ export { parse } from './parser.js';
|
|
|
14
14
|
export { parseExpression, evaluateExpression } from './evaluator.js';
|
|
15
15
|
export { Context, type ContextOptions } from './context.js';
|
|
16
16
|
export { FetchLoader, FileSystemLoader, MemoryLoader } from './loader.js';
|
|
17
|
+
export type { FileSystemLoaderOptions } from './loader.js';
|
|
18
|
+
export { includeDirectiveRe, scanIncludes, variableRe, directiveTagRe, commentRe, rawBlockRe } from './scan.js';
|
|
17
19
|
export type { ASTNode, TextNode, VariableNode, SetNode, IfNode, IncludeNode, CommentNode, Expression, LiteralExpression, VariableExpression, BinaryExpression, UnaryExpression, RenderOptions, Loader, IContext, ParseResult, ParseError, } from './types.js';
|
|
18
20
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACpE,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACpE,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACzE,YAAY,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAC1D,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE/G,YAAY,EAEV,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,OAAO,EACP,MAAM,EACN,WAAW,EACX,WAAW,EAGX,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EAGf,aAAa,EACb,MAAM,EACN,QAAQ,EACR,WAAW,EACX,UAAU,GACX,MAAM,YAAY,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -14,4 +14,5 @@ export { parse } from './parser.js';
|
|
|
14
14
|
export { parseExpression, evaluateExpression } from './evaluator.js';
|
|
15
15
|
export { Context } from './context.js';
|
|
16
16
|
export { FetchLoader, FileSystemLoader, MemoryLoader } from './loader.js';
|
|
17
|
+
export { includeDirectiveRe, scanIncludes, variableRe, directiveTagRe, commentRe, rawBlockRe } from './scan.js';
|
|
17
18
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACpE,OAAO,EAAE,OAAO,EAAuB,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACpE,OAAO,EAAE,OAAO,EAAuB,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAEzE,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA"}
|