@dogsbay/minja 0.2.0-beta.93 → 0.2.0-beta.99

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/dist/index.umd.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * minja v0.2.0-beta.93
2
+ * minja v0.2.0-beta.99
3
3
  * Minimal, secure Jinja2/Nunjucks subset for documentation preprocessing
4
4
  * @license MIT
5
5
  */
@@ -29,10 +29,16 @@ var minja = (() => {
29
29
  Context: () => Context,
30
30
  FetchLoader: () => FetchLoader,
31
31
  MemoryLoader: () => MemoryLoader,
32
+ commentRe: () => commentRe,
33
+ directiveTagRe: () => directiveTagRe,
32
34
  evaluateExpression: () => evaluateExpression,
35
+ includeDirectiveRe: () => includeDirectiveRe,
33
36
  parse: () => parse,
34
37
  parseExpression: () => parseExpression,
35
- render: () => render
38
+ rawBlockRe: () => rawBlockRe,
39
+ render: () => render,
40
+ scanIncludes: () => scanIncludes,
41
+ variableRe: () => variableRe
36
42
  });
37
43
 
38
44
  // src/evaluator.ts
@@ -195,6 +201,24 @@ var minja = (() => {
195
201
  }
196
202
 
197
203
  // src/parser.ts
204
+ var KNOWN_TAG_KEYWORDS = /* @__PURE__ */ new Set([
205
+ "set",
206
+ "if",
207
+ "include",
208
+ "switch",
209
+ "leveloffset",
210
+ "raw",
211
+ "endif",
212
+ "elif",
213
+ "else",
214
+ "endswitch",
215
+ "case",
216
+ "endleveloffset",
217
+ "endraw"
218
+ ]);
219
+ function stripBodyForEndTag(body, endTag) {
220
+ return endTag.startsWith("{%-") ? body.replace(/[ \t]*\n[ \t\n]*$/, "") : body;
221
+ }
198
222
  function parse(template) {
199
223
  const errors = [];
200
224
  const ast = [];
@@ -277,12 +301,57 @@ var minja = (() => {
277
301
  }
278
302
  }
279
303
  } else if (nearest.type === "tag") {
304
+ const tagStart2 = position;
280
305
  advance(2);
281
306
  const endPos = findNext("%}", position);
282
307
  if (endPos === -1) {
283
308
  errors.push(createError("Unclosed statement tag"));
284
309
  break;
285
310
  }
311
+ const peeked = template.substring(position, endPos).trim();
312
+ const peekKeyword = peeked.replace(/^-\s*/, "").replace(/\s*-$/, "").split(/\s+/)[0] ?? "";
313
+ if (peekKeyword === "raw") {
314
+ const openerLeftStrip = peeked.startsWith("-");
315
+ const openerRightStrip = peeked.endsWith("-");
316
+ if (openerLeftStrip && ast.length > 0 && ast[ast.length - 1].type === "text") {
317
+ const lastNode = ast[ast.length - 1];
318
+ lastNode.value = lastNode.value.replace(/[ \t]*\n[ \t\n]*$/, "");
319
+ }
320
+ extractTo(endPos);
321
+ advance(2);
322
+ if (openerRightStrip) {
323
+ while (position < template.length && /[ \t\n]/.test(template[position])) {
324
+ advance(1);
325
+ }
326
+ }
327
+ const endrawMatch = /\{%-?\s*endraw\s*-?%\}/.exec(template.substring(position));
328
+ if (!endrawMatch) {
329
+ errors.push(createError("Unclosed raw block"));
330
+ break;
331
+ }
332
+ const endrawAbs = position + endrawMatch.index;
333
+ let content = extractTo(endrawAbs);
334
+ const endrawTag = endrawMatch[0];
335
+ if (endrawTag.startsWith("{%-")) {
336
+ content = content.replace(/[ \t]*\n[ \t\n]*$/, "");
337
+ }
338
+ advance(endrawTag.length);
339
+ if (endrawTag.endsWith("-%}")) {
340
+ while (position < template.length && /[ \t\n]/.test(template[position])) {
341
+ advance(1);
342
+ }
343
+ }
344
+ if (content) {
345
+ ast.push({ type: "text", value: content });
346
+ }
347
+ continue;
348
+ }
349
+ if (!KNOWN_TAG_KEYWORDS.has(peekKeyword)) {
350
+ extractTo(endPos);
351
+ advance(2);
352
+ ast.push({ type: "text", value: template.substring(tagStart2, endPos + 2) });
353
+ continue;
354
+ }
286
355
  let statement = extractTo(endPos).trim();
287
356
  const hasLeftStrip = statement.startsWith("-");
288
357
  const hasRightStrip = statement.endsWith("-");
@@ -416,12 +485,13 @@ var minja = (() => {
416
485
  }
417
486
  return { ast, errors };
418
487
  function findEndTag(tagName) {
419
- const pattern = new RegExp(`{%\\s*${tagName}\\s*%}`);
488
+ const pattern = new RegExp(`{%-?\\s*${tagName}\\s*-?%}`);
420
489
  const match = pattern.exec(template.substring(position));
421
490
  if (match) {
422
491
  return {
423
492
  start: position + match.index,
424
- length: match[0].length
493
+ length: match[0].length,
494
+ tag: match[0]
425
495
  };
426
496
  }
427
497
  return null;
@@ -453,8 +523,12 @@ var minja = (() => {
453
523
  searchPos = nearest.pos + nearest.match[0].length;
454
524
  } else if (nearest.type === "endif") {
455
525
  if (depth === 0) {
456
- const bodyTemplate = extractTo(nearest.pos);
526
+ const bodyTemplate = stripBodyForEndTag(extractTo(nearest.pos), nearest.match[0]);
457
527
  advance(nearest.match[0].length);
528
+ if (nearest.match[0].endsWith("-%}")) {
529
+ while (position < template.length && /[ \t\n]/.test(template[position]))
530
+ advance(1);
531
+ }
458
532
  const bodyResult = parse(bodyTemplate);
459
533
  parseErrors.push(...bodyResult.errors);
460
534
  return {
@@ -468,7 +542,7 @@ var minja = (() => {
468
542
  searchPos = nearest.pos + nearest.match[0].length;
469
543
  }
470
544
  } else if (depth === 0 && (nearest.type === "elif" || nearest.type === "else")) {
471
- const bodyTemplate = extractTo(nearest.pos);
545
+ const bodyTemplate = stripBodyForEndTag(extractTo(nearest.pos), nearest.match[0]);
472
546
  const bodyResult = parse(bodyTemplate);
473
547
  if (elifBranches.length === 0 && elseBranch.length === 0) {
474
548
  parseErrors.push(...bodyResult.errors);
@@ -505,7 +579,10 @@ var minja = (() => {
505
579
  if (!endifMatch2) {
506
580
  parseErrors.push(createError("Missing endif after else"));
507
581
  } else {
508
- const elseBodyTemplate = extractTo(endifMatch2.start);
582
+ const elseBodyTemplate = stripBodyForEndTag(
583
+ extractTo(endifMatch2.start),
584
+ endifMatch2.tag
585
+ );
509
586
  advance(endifMatch2.length);
510
587
  const elseBodyResult = parse(elseBodyTemplate);
511
588
  parseErrors.push(...elseBodyResult.errors);
@@ -691,12 +768,14 @@ var minja = (() => {
691
768
  };
692
769
 
693
770
  // src/renderer.ts
694
- function transformHeadings(text, offset) {
771
+ function transformHeadings(text, offset, initialFence = null, fenceOut) {
695
772
  if (offset === 0) {
773
+ if (fenceOut)
774
+ fenceOut.fence = initialFence;
696
775
  return text;
697
776
  }
698
777
  const lines = text.split("\n");
699
- let fence = null;
778
+ let fence = initialFence;
700
779
  for (let i = 0; i < lines.length; i++) {
701
780
  const line = lines[i];
702
781
  const fenceMatch = line.match(/^\s*(`{3,}|~{3,})/);
@@ -718,6 +797,8 @@ var minja = (() => {
718
797
  lines[i] = "#".repeat(newLevel) + line.slice(m[1].length);
719
798
  }
720
799
  }
800
+ if (fenceOut)
801
+ fenceOut.fence = fence;
721
802
  return lines.join("\n");
722
803
  }
723
804
  function resolvePath(path, basePath) {
@@ -789,7 +870,14 @@ var minja = (() => {
789
870
  async function renderNodes(nodes, options) {
790
871
  const parts = [];
791
872
  for (const node of nodes) {
792
- parts.push(await renderNode(node, options));
873
+ let rendered = await renderNode(node, options);
874
+ if (node.type === "include" && rendered && parts.length > 0) {
875
+ const tail = /(?:^|\n)([ \t]+)$/.exec(parts[parts.length - 1]);
876
+ if (tail) {
877
+ rendered = rendered.replace(/\n(?=[^\n])/g, "\n" + tail[1]);
878
+ }
879
+ }
880
+ parts.push(rendered);
793
881
  }
794
882
  return parts.join("");
795
883
  }
@@ -801,7 +889,15 @@ var minja = (() => {
801
889
  if (currentOffset === 0) {
802
890
  return node.value;
803
891
  }
804
- return transformHeadings(node.value, currentOffset);
892
+ const fenceOut = { fence: null };
893
+ const out = transformHeadings(
894
+ node.value,
895
+ currentOffset,
896
+ context.get("_levelOffsetFence") ?? null,
897
+ fenceOut
898
+ );
899
+ context.set("_levelOffsetFence", fenceOut.fence);
900
+ return out;
805
901
  }
806
902
  case "variable": {
807
903
  const value = context.get(node.name);
@@ -811,6 +907,8 @@ var minja = (() => {
811
907
  throw new Error(`Undefined variable: ${node.name}`);
812
908
  case "preserve":
813
909
  return `{{ ${node.name} }}`;
910
+ case "asciidoc-literal":
911
+ return `{${node.name}}`;
814
912
  case "empty":
815
913
  default:
816
914
  return "";
@@ -830,7 +928,7 @@ var minja = (() => {
830
928
  case "comment":
831
929
  return "";
832
930
  case "if": {
833
- if (options.undefinedBehavior === "preserve" && options.undefinedConditions !== "falsy") {
931
+ if ((options.undefinedBehavior === "preserve" || options.undefinedBehavior === "asciidoc-literal") && options.undefinedConditions !== "falsy") {
834
932
  const undefinedRefs = findUndefinedRefs(node.condition, context);
835
933
  if (undefinedRefs.length > 0) {
836
934
  return ifNodeToSource(node);
@@ -890,7 +988,10 @@ var minja = (() => {
890
988
  undefinedConditions: options.undefinedConditions
891
989
  });
892
990
  } catch (error) {
893
- if (options.undefinedBehavior === "preserve") {
991
+ if (error instanceof Error && error.name === "IncludeContainmentError") {
992
+ throw error;
993
+ }
994
+ if (options.undefinedBehavior === "preserve" || options.undefinedBehavior === "asciidoc-literal") {
894
995
  return `{% include "${node.path}" %}`;
895
996
  }
896
997
  const message = error instanceof Error ? error.message : String(error);
@@ -913,11 +1014,14 @@ var minja = (() => {
913
1014
  const newOffset = node.isRelative ? parentOffset + node.offset : node.offset;
914
1015
  const previousOffset = parentOffset;
915
1016
  context.set("_levelOffset", newOffset);
1017
+ const previousFence = context.get("_levelOffsetFence") ?? null;
1018
+ context.set("_levelOffsetFence", null);
916
1019
  try {
917
1020
  const result = await renderNodes(node.body, options);
918
1021
  return result;
919
1022
  } finally {
920
1023
  context.set("_levelOffset", previousOffset);
1024
+ context.set("_levelOffsetFence", previousFence);
921
1025
  }
922
1026
  }
923
1027
  default:
@@ -1043,6 +1147,14 @@ var minja = (() => {
1043
1147
  return content;
1044
1148
  }
1045
1149
  };
1150
+
1151
+ // src/scan.ts
1152
+ var includeDirectiveRe = () => /\{%-?\s*include\s+["']([^"']+)["']\s*-?%\}/g;
1153
+ var scanIncludes = (text) => [...text.matchAll(includeDirectiveRe())].map((match) => match[1]);
1154
+ var variableRe = () => /\{\{-?([\s\S]*?)-?\}\}/g;
1155
+ var directiveTagRe = () => /\{%-?\s*([A-Za-z_][A-Za-z0-9_]*)([\s\S]*?)-?%\}/g;
1156
+ var commentRe = () => /\{#[\s\S]*?#\}/g;
1157
+ var rawBlockRe = () => /\{%-?\s*raw\s*-?%\}([\s\S]*?)\{%-?\s*endraw\s*-?%\}/g;
1046
1158
  return __toCommonJS(browser_exports);
1047
1159
  })();
1048
1160
  //# sourceMappingURL=index.umd.js.map