easy-template-x 3.2.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/README.md +38 -2
  2. package/dist/cjs/easy-template-x.js +184 -98
  3. package/dist/es/easy-template-x.js +177 -89
  4. package/dist/types/compilation/delimiterMark.d.ts +6 -6
  5. package/dist/types/compilation/delimiterSearcher.d.ts +16 -16
  6. package/dist/types/compilation/index.d.ts +7 -7
  7. package/dist/types/compilation/scopeData.d.ts +21 -21
  8. package/dist/types/compilation/tag.d.ts +14 -12
  9. package/dist/types/compilation/tagParser.d.ts +13 -13
  10. package/dist/types/compilation/templateCompiler.d.ts +25 -25
  11. package/dist/types/compilation/templateContext.d.ts +5 -5
  12. package/dist/types/delimiters.d.ts +10 -8
  13. package/dist/types/errors/index.d.ts +11 -10
  14. package/dist/types/errors/malformedFileError.d.ts +4 -4
  15. package/dist/types/errors/maxXmlDepthError.d.ts +4 -4
  16. package/dist/types/errors/missingArgumentError.d.ts +4 -4
  17. package/dist/types/errors/missingCloseDelimiterError.d.ts +4 -4
  18. package/dist/types/errors/missingStartDelimiterError.d.ts +4 -4
  19. package/dist/types/errors/tagOptionsParseError.d.ts +5 -0
  20. package/dist/types/errors/unclosedTagError.d.ts +4 -4
  21. package/dist/types/errors/unidentifiedFileTypeError.d.ts +3 -3
  22. package/dist/types/errors/unknownContentTypeError.d.ts +6 -6
  23. package/dist/types/errors/unopenedTagError.d.ts +4 -4
  24. package/dist/types/errors/unsupportedFileTypeError.d.ts +4 -4
  25. package/dist/types/extensions/extensionOptions.d.ts +5 -5
  26. package/dist/types/extensions/index.d.ts +2 -2
  27. package/dist/types/extensions/templateExtension.d.ts +14 -14
  28. package/dist/types/index.d.ts +13 -13
  29. package/dist/types/mimeType.d.ts +11 -11
  30. package/dist/types/office/contentPartType.d.ts +9 -9
  31. package/dist/types/office/contentTypesFile.d.ts +16 -16
  32. package/dist/types/office/docx.d.ts +28 -28
  33. package/dist/types/office/docxParser.d.ts +35 -35
  34. package/dist/types/office/index.d.ts +4 -4
  35. package/dist/types/office/mediaFiles.d.ts +14 -14
  36. package/dist/types/office/relationship.d.ts +11 -11
  37. package/dist/types/office/rels.d.ts +20 -20
  38. package/dist/types/office/xmlPart.d.ts +14 -14
  39. package/dist/types/plugins/defaultPlugins.d.ts +2 -2
  40. package/dist/types/plugins/image/imageContent.d.ts +12 -12
  41. package/dist/types/plugins/image/imagePlugin.d.ts +10 -10
  42. package/dist/types/plugins/image/index.d.ts +2 -2
  43. package/dist/types/plugins/index.d.ts +8 -8
  44. package/dist/types/plugins/link/index.d.ts +2 -2
  45. package/dist/types/plugins/link/linkContent.d.ts +7 -7
  46. package/dist/types/plugins/link/linkPlugin.d.ts +9 -9
  47. package/dist/types/plugins/loop/index.d.ts +1 -1
  48. package/dist/types/plugins/loop/loopPlugin.d.ts +13 -13
  49. package/dist/types/plugins/loop/loopTagOptions.d.ts +7 -0
  50. package/dist/types/plugins/loop/strategy/iLoopStrategy.d.ts +14 -14
  51. package/dist/types/plugins/loop/strategy/index.d.ts +4 -4
  52. package/dist/types/plugins/loop/strategy/loopListStrategy.d.ts +11 -11
  53. package/dist/types/plugins/loop/strategy/loopParagraphStrategy.d.ts +11 -11
  54. package/dist/types/plugins/loop/strategy/loopTableStrategy.d.ts +11 -11
  55. package/dist/types/plugins/pluginContent.d.ts +6 -6
  56. package/dist/types/plugins/rawXml/index.d.ts +2 -2
  57. package/dist/types/plugins/rawXml/rawXmlContent.d.ts +6 -6
  58. package/dist/types/plugins/rawXml/rawXmlPlugin.d.ts +6 -6
  59. package/dist/types/plugins/templatePlugin.d.ts +15 -15
  60. package/dist/types/plugins/text/index.d.ts +1 -1
  61. package/dist/types/plugins/text/textPlugin.d.ts +11 -11
  62. package/dist/types/templateData.d.ts +6 -6
  63. package/dist/types/templateHandler.d.ts +20 -20
  64. package/dist/types/templateHandlerOptions.d.ts +15 -15
  65. package/dist/types/types.d.ts +4 -6
  66. package/dist/types/utils/array.d.ts +6 -6
  67. package/dist/types/utils/base64.d.ts +3 -3
  68. package/dist/types/utils/binary.d.ts +11 -12
  69. package/dist/types/utils/index.d.ts +9 -9
  70. package/dist/types/utils/number.d.ts +1 -1
  71. package/dist/types/utils/path.d.ts +5 -5
  72. package/dist/types/utils/regex.d.ts +3 -3
  73. package/dist/types/utils/sha1.d.ts +1 -1
  74. package/dist/types/utils/txt.d.ts +2 -1
  75. package/dist/types/utils/types.d.ts +3 -3
  76. package/dist/types/xml/index.d.ts +3 -3
  77. package/dist/types/xml/xmlDepthTracker.d.ts +7 -7
  78. package/dist/types/xml/xmlNode.d.ts +58 -49
  79. package/dist/types/xml/xmlParser.d.ts +8 -8
  80. package/dist/types/zip/index.d.ts +2 -2
  81. package/dist/types/zip/jsZipHelper.d.ts +7 -7
  82. package/dist/types/zip/zip.d.ts +13 -13
  83. package/dist/types/zip/zipObject.d.ts +13 -13
  84. package/package.json +25 -19
  85. package/src/compilation/tag.ts +4 -2
  86. package/src/compilation/tagParser.ts +32 -13
  87. package/src/delimiters.ts +3 -1
  88. package/src/errors/index.ts +1 -0
  89. package/src/errors/malformedFileError.ts +1 -4
  90. package/src/errors/maxXmlDepthError.ts +1 -4
  91. package/src/errors/missingArgumentError.ts +1 -4
  92. package/src/errors/missingCloseDelimiterError.ts +1 -4
  93. package/src/errors/missingStartDelimiterError.ts +1 -4
  94. package/src/errors/tagOptionsParseError.ts +12 -0
  95. package/src/errors/unclosedTagError.ts +1 -4
  96. package/src/errors/unidentifiedFileTypeError.ts +1 -4
  97. package/src/errors/unknownContentTypeError.ts +1 -4
  98. package/src/errors/unopenedTagError.ts +1 -4
  99. package/src/errors/unsupportedFileTypeError.ts +1 -4
  100. package/src/office/docx.ts +4 -1
  101. package/src/office/docxParser.ts +3 -1
  102. package/src/plugins/loop/loopPlugin.ts +1 -1
  103. package/src/plugins/loop/loopTagOptions.ts +14 -0
  104. package/src/plugins/loop/strategy/loopTableStrategy.ts +22 -3
  105. package/src/plugins/templatePlugin.ts +0 -2
  106. package/src/types.ts +1 -3
  107. package/src/utils/txt.ts +29 -1
  108. package/src/xml/xmlNode.ts +50 -14
@@ -1,34 +1,29 @@
1
1
  import { DOMParser } from '@xmldom/xmldom';
2
2
  import getProp from 'lodash.get';
3
+ import * as JSON5 from 'json5';
3
4
  import * as JSZip from 'jszip';
4
5
 
5
- function _defineProperty(obj, key, value) {
6
- key = _toPropertyKey(key);
7
- if (key in obj) {
8
- Object.defineProperty(obj, key, {
9
- value: value,
10
- enumerable: true,
11
- configurable: true,
12
- writable: true
13
- });
14
- } else {
15
- obj[key] = value;
16
- }
17
- return obj;
6
+ function _defineProperty(e, r, t) {
7
+ return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
8
+ value: t,
9
+ enumerable: !0,
10
+ configurable: !0,
11
+ writable: !0
12
+ }) : e[r] = t, e;
18
13
  }
19
- function _toPrimitive(input, hint) {
20
- if (typeof input !== "object" || input === null) return input;
21
- var prim = input[Symbol.toPrimitive];
22
- if (prim !== undefined) {
23
- var res = prim.call(input, hint || "default");
24
- if (typeof res !== "object") return res;
14
+ function _toPrimitive(t, r) {
15
+ if ("object" != typeof t || !t) return t;
16
+ var e = t[Symbol.toPrimitive];
17
+ if (void 0 !== e) {
18
+ var i = e.call(t, r || "default");
19
+ if ("object" != typeof i) return i;
25
20
  throw new TypeError("@@toPrimitive must return a primitive value.");
26
21
  }
27
- return (hint === "string" ? String : Number)(input);
22
+ return ("string" === r ? String : Number)(t);
28
23
  }
29
- function _toPropertyKey(arg) {
30
- var key = _toPrimitive(arg, "string");
31
- return typeof key === "symbol" ? key : String(key);
24
+ function _toPropertyKey(t) {
25
+ var i = _toPrimitive(t, "string");
26
+ return "symbol" == typeof i ? i : i + "";
32
27
  }
33
28
 
34
29
  class MalformedFileError extends Error {
@@ -36,9 +31,6 @@ class MalformedFileError extends Error {
36
31
  super(`Malformed file detected. Make sure the file is a valid ${expectedFileType} file.`);
37
32
  _defineProperty(this, "expectedFileType", void 0);
38
33
  this.expectedFileType = expectedFileType;
39
-
40
- // typescript hack: https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
41
- Object.setPrototypeOf(this, MalformedFileError.prototype);
42
34
  }
43
35
  }
44
36
 
@@ -47,9 +39,6 @@ class MaxXmlDepthError extends Error {
47
39
  super(`XML maximum depth reached (max depth: ${maxDepth}).`);
48
40
  _defineProperty(this, "maxDepth", void 0);
49
41
  this.maxDepth = maxDepth;
50
-
51
- // typescript hack: https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
52
- Object.setPrototypeOf(this, MaxXmlDepthError.prototype);
53
42
  }
54
43
  }
55
44
 
@@ -58,9 +47,6 @@ class MissingArgumentError extends Error {
58
47
  super(`Argument '${argName}' is missing.`);
59
48
  _defineProperty(this, "argName", void 0);
60
49
  this.argName = argName;
61
-
62
- // typescript hack: https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
63
- Object.setPrototypeOf(this, MissingArgumentError.prototype);
64
50
  }
65
51
  }
66
52
 
@@ -69,9 +55,6 @@ class MissingCloseDelimiterError extends Error {
69
55
  super(`Close delimiter is missing from '${openDelimiterText}'.`);
70
56
  _defineProperty(this, "openDelimiterText", void 0);
71
57
  this.openDelimiterText = openDelimiterText;
72
-
73
- // typescript hack: https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
74
- Object.setPrototypeOf(this, MissingCloseDelimiterError.prototype);
75
58
  }
76
59
  }
77
60
 
@@ -80,9 +63,16 @@ class MissingStartDelimiterError extends Error {
80
63
  super(`Open delimiter is missing from '${closeDelimiterText}'.`);
81
64
  _defineProperty(this, "closeDelimiterText", void 0);
82
65
  this.closeDelimiterText = closeDelimiterText;
66
+ }
67
+ }
83
68
 
84
- // typescript hack: https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
85
- Object.setPrototypeOf(this, MissingStartDelimiterError.prototype);
69
+ class TagOptionsParseError extends Error {
70
+ constructor(tagRawText, parseError) {
71
+ super(`Failed to parse tag options of '${tagRawText}': ${parseError.message}.`);
72
+ _defineProperty(this, "tagRawText", void 0);
73
+ _defineProperty(this, "parseError", void 0);
74
+ this.tagRawText = tagRawText;
75
+ this.parseError = parseError;
86
76
  }
87
77
  }
88
78
 
@@ -91,18 +81,12 @@ class UnclosedTagError extends Error {
91
81
  super(`Tag '${tagName}' is never closed.`);
92
82
  _defineProperty(this, "tagName", void 0);
93
83
  this.tagName = tagName;
94
-
95
- // typescript hack: https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
96
- Object.setPrototypeOf(this, UnclosedTagError.prototype);
97
84
  }
98
85
  }
99
86
 
100
87
  class UnidentifiedFileTypeError extends Error {
101
88
  constructor() {
102
89
  super(`The filetype for this file could not be identified, is this file corrupted?`);
103
-
104
- // typescript hack: https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
105
- Object.setPrototypeOf(this, UnidentifiedFileTypeError.prototype);
106
90
  }
107
91
  }
108
92
 
@@ -115,9 +99,6 @@ class UnknownContentTypeError extends Error {
115
99
  this.contentType = contentType;
116
100
  this.tagRawText = tagRawText;
117
101
  this.path = path;
118
-
119
- // typescript hack: https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
120
- Object.setPrototypeOf(this, UnknownContentTypeError.prototype);
121
102
  }
122
103
  }
123
104
 
@@ -126,9 +107,6 @@ class UnopenedTagError extends Error {
126
107
  super(`Tag '${tagName}' is closed but was never opened.`);
127
108
  _defineProperty(this, "tagName", void 0);
128
109
  this.tagName = tagName;
129
-
130
- // typescript hack: https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
131
- Object.setPrototypeOf(this, UnopenedTagError.prototype);
132
110
  }
133
111
  }
134
112
 
@@ -137,9 +115,6 @@ class UnsupportedFileTypeError extends Error {
137
115
  super(`Filetype "${fileType}" is not supported.`);
138
116
  _defineProperty(this, "fileType", void 0);
139
117
  this.fileType = fileType;
140
-
141
- // typescript hack: https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
142
- Object.setPrototypeOf(this, UnsupportedFileTypeError.prototype);
143
118
  }
144
119
  }
145
120
 
@@ -389,12 +364,48 @@ function utf8Encode(str) {
389
364
  return utfStr;
390
365
  }
391
366
 
367
+ // Copied from: https://gist.github.com/thanpolas/244d9a13151caf5a12e42208b6111aa6
368
+ // And see: https://unicode-table.com/en/sets/quotation-marks/
369
+ const nonStandardDoubleQuotes = ['“',
370
+ // U+201c
371
+ '”',
372
+ // U+201d
373
+ '«',
374
+ // U+00AB
375
+ '»',
376
+ // U+00BB
377
+ '„',
378
+ // U+201E
379
+ '“',
380
+ // U+201C
381
+ '‟',
382
+ // U+201F
383
+ '”',
384
+ // U+201D
385
+ '❝',
386
+ // U+275D
387
+ '❞',
388
+ // U+275E
389
+ '〝',
390
+ // U+301D
391
+ '〞',
392
+ // U+301E
393
+ '〟',
394
+ // U+301F
395
+ '"' // U+FF02
396
+ ];
397
+ const standardDoubleQuotes = '"'; // U+0022
398
+
399
+ const nonStandardDoubleQuotesRegex = new RegExp(nonStandardDoubleQuotes.join('|'), 'g');
392
400
  function stringValue(val) {
393
401
  if (val === null || val === undefined) {
394
402
  return '';
395
403
  }
396
404
  return val.toString();
397
405
  }
406
+ function normalizeDoubleQuotes(text) {
407
+ return text.replace(nonStandardDoubleQuotesRegex, standardDoubleQuotes);
408
+ }
398
409
 
399
410
  class XmlDepthTracker {
400
411
  constructor(maxDepth) {
@@ -415,10 +426,11 @@ class XmlDepthTracker {
415
426
  let XmlNodeType = /*#__PURE__*/function (XmlNodeType) {
416
427
  XmlNodeType["Text"] = "Text";
417
428
  XmlNodeType["General"] = "General";
429
+ XmlNodeType["Comment"] = "Comment";
418
430
  return XmlNodeType;
419
431
  }({});
420
432
  const TEXT_NODE_NAME = '#text'; // see: https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeName
421
-
433
+ const COMMENT_NODE_NAME = '#comment';
422
434
  const XmlNode = {
423
435
  //
424
436
  // factories
@@ -437,6 +449,13 @@ const XmlNode = {
437
449
  nodeName: name
438
450
  };
439
451
  },
452
+ createCommentNode(text) {
453
+ return {
454
+ nodeType: XmlNodeType.Comment,
455
+ nodeName: COMMENT_NODE_NAME,
456
+ commentContent: text
457
+ };
458
+ },
440
459
  //
441
460
  // serialization
442
461
  //
@@ -467,6 +486,9 @@ const XmlNode = {
467
486
  },
468
487
  serialize(node) {
469
488
  if (this.isTextNode(node)) return this.encodeValue(node.textContent || '');
489
+ if (this.isCommentNode(node)) {
490
+ return `<!-- ${this.encodeValue(node.commentContent || '')} -->`;
491
+ }
470
492
 
471
493
  // attributes
472
494
  let attributes = '';
@@ -501,22 +523,36 @@ const XmlNode = {
501
523
  let xmlNode;
502
524
 
503
525
  // basic properties
504
- if (domNode.nodeType === domNode.TEXT_NODE) {
505
- xmlNode = this.createTextNode(domNode.textContent);
506
- } else {
507
- xmlNode = this.createGeneralNode(domNode.nodeName);
508
-
509
- // attributes
510
- if (domNode.nodeType === domNode.ELEMENT_NODE) {
511
- const attributes = domNode.attributes;
512
- if (attributes) {
513
- xmlNode.attributes = {};
514
- for (let i = 0; i < attributes.length; i++) {
515
- const curAttribute = attributes.item(i);
516
- xmlNode.attributes[curAttribute.name] = curAttribute.value;
526
+ switch (domNode.nodeType) {
527
+ case domNode.TEXT_NODE:
528
+ {
529
+ xmlNode = this.createTextNode(domNode.textContent);
530
+ break;
531
+ }
532
+ case domNode.COMMENT_NODE:
533
+ {
534
+ var _domNode$textContent;
535
+ xmlNode = this.createCommentNode((_domNode$textContent = domNode.textContent) === null || _domNode$textContent === void 0 ? void 0 : _domNode$textContent.trim());
536
+ break;
537
+ }
538
+ case domNode.ELEMENT_NODE:
539
+ {
540
+ const generalNode = xmlNode = this.createGeneralNode(domNode.nodeName);
541
+ const attributes = domNode.attributes;
542
+ if (attributes) {
543
+ generalNode.attributes = {};
544
+ for (let i = 0; i < attributes.length; i++) {
545
+ const curAttribute = attributes.item(i);
546
+ generalNode.attributes[curAttribute.name] = curAttribute.value;
547
+ }
517
548
  }
549
+ break;
550
+ }
551
+ default:
552
+ {
553
+ xmlNode = this.createGeneralNode(domNode.nodeName);
554
+ break;
518
555
  }
519
- }
520
556
  }
521
557
 
522
558
  // children
@@ -552,6 +588,15 @@ const XmlNode = {
552
588
  }
553
589
  return false;
554
590
  },
591
+ isCommentNode(node) {
592
+ if (node.nodeType === XmlNodeType.Comment || node.nodeName === COMMENT_NODE_NAME) {
593
+ if (!(node.nodeType === XmlNodeType.Comment && node.nodeName === COMMENT_NODE_NAME)) {
594
+ throw new Error(`Invalid comment node. Type: '${node.nodeType}', Name: '${node.nodeName}'.`);
595
+ }
596
+ return true;
597
+ }
598
+ return false;
599
+ },
555
600
  cloneNode(node, deep) {
556
601
  if (!node) throw new MissingArgumentError("node");
557
602
  if (!deep) {
@@ -783,9 +828,11 @@ const XmlNode = {
783
828
  *
784
829
  * * **Note:** Prefer calling with explicit index.
785
830
  */
831
+
786
832
  /**
787
833
  * Remove a child node from it's parent. Returns the removed child.
788
834
  */
835
+
789
836
  function removeChild(parent, childOrIndex) {
790
837
  if (!parent) throw new MissingArgumentError("parent");
791
838
  if (childOrIndex === null || childOrIndex === undefined) throw new MissingArgumentError("childOrIndex");
@@ -1112,7 +1159,8 @@ class TagParser {
1112
1159
  _defineProperty(this, "tagRegex", void 0);
1113
1160
  if (!docParser) throw new MissingArgumentError("docParser");
1114
1161
  if (!delimiters) throw new MissingArgumentError("delimiters");
1115
- this.tagRegex = new RegExp(`^${Regex.escape(delimiters.tagStart)}(.*?)${Regex.escape(delimiters.tagEnd)}`, 'm');
1162
+ const tagOptionsRegex = `${Regex.escape(delimiters.tagOptionsStart)}(?<tagOptions>.*?)${Regex.escape(delimiters.tagOptionsEnd)}`;
1163
+ this.tagRegex = new RegExp(`^${Regex.escape(delimiters.tagStart)}(?<tagName>.*?)(${tagOptionsRegex})?${Regex.escape(delimiters.tagEnd)}`, 'm');
1116
1164
  }
1117
1165
  parse(delimiters) {
1118
1166
  const tags = [];
@@ -1211,23 +1259,44 @@ class TagParser {
1211
1259
  closeDelimiter.xmlTextNode = endTextNode;
1212
1260
  }
1213
1261
  processTag(tag) {
1262
+ var _tagParts$groups, _tagParts$groups2;
1214
1263
  tag.rawText = tag.xmlTextNode.textContent;
1215
1264
  const tagParts = this.tagRegex.exec(tag.rawText);
1216
- const tagContent = (tagParts[1] || '').trim();
1217
- if (!tagContent || !tagContent.length) {
1265
+ const tagName = (((_tagParts$groups = tagParts.groups) === null || _tagParts$groups === void 0 ? void 0 : _tagParts$groups["tagName"]) || '').trim();
1266
+
1267
+ // Ignoring empty tags.
1268
+ if (!(tagName !== null && tagName !== void 0 && tagName.length)) {
1218
1269
  tag.disposition = TagDisposition.SelfClosed;
1219
1270
  return;
1220
1271
  }
1221
- if (tagContent.startsWith(this.delimiters.containerTagOpen)) {
1272
+
1273
+ // Tag options.
1274
+ const tagOptionsText = (((_tagParts$groups2 = tagParts.groups) === null || _tagParts$groups2 === void 0 ? void 0 : _tagParts$groups2["tagOptions"]) || '').trim();
1275
+ if (tagOptionsText) {
1276
+ try {
1277
+ tag.options = JSON5.parse("{" + normalizeDoubleQuotes(tagOptionsText) + "}");
1278
+ } catch (e) {
1279
+ throw new TagOptionsParseError(tag.rawText, e);
1280
+ }
1281
+ }
1282
+
1283
+ // Container open tag.
1284
+ if (tagName.startsWith(this.delimiters.containerTagOpen)) {
1222
1285
  tag.disposition = TagDisposition.Open;
1223
- tag.name = tagContent.slice(this.delimiters.containerTagOpen.length).trim();
1224
- } else if (tagContent.startsWith(this.delimiters.containerTagClose)) {
1286
+ tag.name = tagName.slice(this.delimiters.containerTagOpen.length).trim();
1287
+ return;
1288
+ }
1289
+
1290
+ // Container close tag.
1291
+ if (tagName.startsWith(this.delimiters.containerTagClose)) {
1225
1292
  tag.disposition = TagDisposition.Close;
1226
- tag.name = tagContent.slice(this.delimiters.containerTagClose.length).trim();
1227
- } else {
1228
- tag.disposition = TagDisposition.SelfClosed;
1229
- tag.name = tagContent;
1293
+ tag.name = tagName.slice(this.delimiters.containerTagClose.length).trim();
1294
+ return;
1230
1295
  }
1296
+
1297
+ // Self-closed tag.
1298
+ tag.disposition = TagDisposition.SelfClosed;
1299
+ tag.name = tagName;
1231
1300
  }
1232
1301
  }
1233
1302
 
@@ -1270,8 +1339,6 @@ class MimeTypeHelper {
1270
1339
  }
1271
1340
  }
1272
1341
 
1273
- /* eslint-disable @typescript-eslint/member-ordering */
1274
-
1275
1342
  class TemplatePlugin {
1276
1343
  constructor() {
1277
1344
  /**
@@ -1824,6 +1891,7 @@ class Docx {
1824
1891
  //
1825
1892
  // static methods
1826
1893
  //
1894
+
1827
1895
  static async open(zip, xmlParser) {
1828
1896
  const mainDocumentPath = await Docx.getMainDocumentPath(zip, xmlParser);
1829
1897
  if (!mainDocumentPath) throw new MalformedFileError('docx');
@@ -1903,7 +1971,8 @@ class Docx {
1903
1971
  // find the last section properties
1904
1972
  // see: http://officeopenxml.com/WPsection.php
1905
1973
  const docRoot = await this.mainDocument.xmlRoot();
1906
- const body = docRoot.childNodes[0];
1974
+ const body = docRoot.childNodes.find(node => node.nodeName == 'w:body');
1975
+ if (body == null) return null;
1907
1976
  const sectionProps = last(body.childNodes.filter(node => node.nodeType === XmlNodeType.General));
1908
1977
  if (sectionProps.nodeName != 'w:sectPr') return null;
1909
1978
 
@@ -1969,6 +2038,7 @@ class DocxParser {
1969
2038
  //
1970
2039
  // constructor
1971
2040
  //
2041
+
1972
2042
  constructor(xmlParser) {
1973
2043
  this.xmlParser = xmlParser;
1974
2044
  }
@@ -2119,7 +2189,10 @@ class DocxParser {
2119
2189
  curWordTextNode = this.firstTextNodeChild(curRunNode);
2120
2190
  }
2121
2191
  while (curWordTextNode) {
2122
- if (curWordTextNode.nodeName !== DocxParser.TEXT_NODE) continue;
2192
+ if (curWordTextNode.nodeName !== DocxParser.TEXT_NODE) {
2193
+ curWordTextNode = curWordTextNode.nextSibling;
2194
+ continue;
2195
+ }
2123
2196
 
2124
2197
  // move text to first node
2125
2198
  const curXmlTextNode = XmlNode.lastTextChild(curWordTextNode);
@@ -2490,6 +2563,12 @@ class LoopParagraphStrategy {
2490
2563
  }
2491
2564
  }
2492
2565
 
2566
+ let LoopOver = /*#__PURE__*/function (LoopOver) {
2567
+ LoopOver["Row"] = "row";
2568
+ LoopOver["Content"] = "content";
2569
+ return LoopOver;
2570
+ }({});
2571
+
2493
2572
  class LoopTableStrategy {
2494
2573
  constructor() {
2495
2574
  _defineProperty(this, "utilities", void 0);
@@ -2498,9 +2577,18 @@ class LoopTableStrategy {
2498
2577
  this.utilities = utilities;
2499
2578
  }
2500
2579
  isApplicable(openTag, closeTag) {
2501
- const containingParagraph = this.utilities.docxParser.containingParagraphNode(openTag.xmlTextNode);
2502
- if (!containingParagraph.parentNode) return false;
2503
- return this.utilities.docxParser.isTableCellNode(containingParagraph.parentNode);
2580
+ const openParagraph = this.utilities.docxParser.containingParagraphNode(openTag.xmlTextNode);
2581
+ if (!openParagraph.parentNode) return false;
2582
+ if (!this.utilities.docxParser.isTableCellNode(openParagraph.parentNode)) return false;
2583
+ const closeParagraph = this.utilities.docxParser.containingParagraphNode(closeTag.xmlTextNode);
2584
+ if (!closeParagraph.parentNode) return false;
2585
+ if (!this.utilities.docxParser.isTableCellNode(closeParagraph.parentNode)) return false;
2586
+ const options = openTag.options;
2587
+ const forceRowLoop = (options === null || options === void 0 ? void 0 : options.loopOver) === LoopOver.Row;
2588
+
2589
+ // If both tags are in the same cell, assume it's a paragraph loop (iterate content, not rows).
2590
+ if (!forceRowLoop && openParagraph.parentNode === closeParagraph.parentNode) return false;
2591
+ return true;
2504
2592
  }
2505
2593
  splitBefore(openTag, closeTag) {
2506
2594
  const firstRow = this.utilities.docxParser.containingTableRowNode(openTag.xmlTextNode);
@@ -2539,7 +2627,6 @@ class LoopPlugin extends TemplatePlugin {
2539
2627
  _defineProperty(this, "loopStrategies", [new LoopTableStrategy(), new LoopListStrategy(), new LoopParagraphStrategy() // the default strategy
2540
2628
  ]);
2541
2629
  }
2542
-
2543
2630
  setUtilities(utilities) {
2544
2631
  this.utilities = utilities;
2545
2632
  this.loopStrategies.forEach(strategy => strategy.setUtilities(utilities));
@@ -2550,7 +2637,7 @@ class LoopPlugin extends TemplatePlugin {
2550
2637
  // Non array value - treat as a boolean condition.
2551
2638
  const isCondition = !Array.isArray(value);
2552
2639
  if (isCondition) {
2553
- if (!!value) {
2640
+ if (value) {
2554
2641
  value = [{}];
2555
2642
  } else {
2556
2643
  value = [];
@@ -2921,7 +3008,6 @@ class Zip {
2921
3008
  level: 6 // between 1 (best speed) and 9 (best compression)
2922
3009
  }
2923
3010
  });
2924
-
2925
3011
  return output;
2926
3012
  }
2927
3013
  }
@@ -2932,6 +3018,8 @@ class Delimiters {
2932
3018
  _defineProperty(this, "tagEnd", "}");
2933
3019
  _defineProperty(this, "containerTagOpen", "#");
2934
3020
  _defineProperty(this, "containerTagClose", "/");
3021
+ _defineProperty(this, "tagOptionsStart", "[");
3022
+ _defineProperty(this, "tagOptionsEnd", "]");
2935
3023
  Object.assign(this, initial);
2936
3024
  this.encodeAndValidate();
2937
3025
  if (this.containerTagOpen === this.containerTagClose) throw new Error(`${"containerTagOpen"} can not be equal to ${"containerTagClose"}`);
@@ -2979,7 +3067,7 @@ class TemplateHandler {
2979
3067
  /**
2980
3068
  * Version number of the `easy-template-x` library.
2981
3069
  */
2982
- _defineProperty(this, "version", "3.2.0" );
3070
+ _defineProperty(this, "version", "3.2.1" );
2983
3071
  _defineProperty(this, "xmlParser", new XmlParser());
2984
3072
  _defineProperty(this, "docxParser", void 0);
2985
3073
  _defineProperty(this, "compiler", void 0);
@@ -3127,4 +3215,4 @@ class TemplateHandler {
3127
3215
  }
3128
3216
  }
3129
3217
 
3130
- export { Base64, Binary, ContentPartType, DelimiterSearcher, Delimiters, Docx, DocxParser, ImagePlugin, LOOP_CONTENT_TYPE, LinkPlugin, LoopPlugin, MalformedFileError, MaxXmlDepthError, MimeType, MimeTypeHelper, MissingArgumentError, MissingCloseDelimiterError, MissingStartDelimiterError, Path, PluginContent, RawXmlPlugin, Regex, ScopeData, TEXT_CONTENT_TYPE, TEXT_NODE_NAME, TagDisposition, TagParser, TemplateCompiler, TemplateExtension, TemplateHandler, TemplateHandlerOptions, TemplatePlugin, TextPlugin, UnclosedTagError, UnidentifiedFileTypeError, UnknownContentTypeError, UnopenedTagError, UnsupportedFileTypeError, XmlDepthTracker, XmlNode, XmlNodeType, XmlParser, XmlPart, Zip, ZipObject, createDefaultPlugins, first, inheritsFrom, isNumber, isPromiseLike, last, pushMany, sha1, stringValue, toDictionary };
3218
+ export { Base64, Binary, COMMENT_NODE_NAME, ContentPartType, DelimiterSearcher, Delimiters, Docx, DocxParser, ImagePlugin, LOOP_CONTENT_TYPE, LinkPlugin, LoopPlugin, MalformedFileError, MaxXmlDepthError, MimeType, MimeTypeHelper, MissingArgumentError, MissingCloseDelimiterError, MissingStartDelimiterError, Path, PluginContent, RawXmlPlugin, Regex, ScopeData, TEXT_CONTENT_TYPE, TEXT_NODE_NAME, TagDisposition, TagOptionsParseError, TagParser, TemplateCompiler, TemplateExtension, TemplateHandler, TemplateHandlerOptions, TemplatePlugin, TextPlugin, UnclosedTagError, UnidentifiedFileTypeError, UnknownContentTypeError, UnopenedTagError, UnsupportedFileTypeError, XmlDepthTracker, XmlNode, XmlNodeType, XmlParser, XmlPart, Zip, ZipObject, createDefaultPlugins, first, inheritsFrom, isNumber, isPromiseLike, last, normalizeDoubleQuotes, pushMany, sha1, stringValue, toDictionary };
@@ -1,6 +1,6 @@
1
- import { XmlTextNode } from "../xml";
2
- export interface DelimiterMark {
3
- xmlTextNode: XmlTextNode;
4
- index: number;
5
- isOpen: boolean;
6
- }
1
+ import { XmlTextNode } from "../xml";
2
+ export interface DelimiterMark {
3
+ xmlTextNode: XmlTextNode;
4
+ index: number;
5
+ isOpen: boolean;
6
+ }
@@ -1,16 +1,16 @@
1
- import { DocxParser } from '../office';
2
- import { XmlNode } from '../xml';
3
- import { DelimiterMark } from './delimiterMark';
4
- export declare class DelimiterSearcher {
5
- private readonly docxParser;
6
- maxXmlDepth: number;
7
- startDelimiter: string;
8
- endDelimiter: string;
9
- constructor(docxParser: DocxParser);
10
- findDelimiters(node: XmlNode): DelimiterMark[];
11
- private noMatch;
12
- private fullMatch;
13
- private shouldSearchNode;
14
- private findNextNode;
15
- private createDelimiterMark;
16
- }
1
+ import { DocxParser } from '../office';
2
+ import { XmlNode } from '../xml';
3
+ import { DelimiterMark } from './delimiterMark';
4
+ export declare class DelimiterSearcher {
5
+ private readonly docxParser;
6
+ maxXmlDepth: number;
7
+ startDelimiter: string;
8
+ endDelimiter: string;
9
+ constructor(docxParser: DocxParser);
10
+ findDelimiters(node: XmlNode): DelimiterMark[];
11
+ private noMatch;
12
+ private fullMatch;
13
+ private shouldSearchNode;
14
+ private findNextNode;
15
+ private createDelimiterMark;
16
+ }
@@ -1,7 +1,7 @@
1
- export * from './delimiterMark';
2
- export * from './delimiterSearcher';
3
- export * from './scopeData';
4
- export * from './tag';
5
- export * from './tagParser';
6
- export * from './templateCompiler';
7
- export * from './templateContext';
1
+ export * from './delimiterMark';
2
+ export * from './delimiterSearcher';
3
+ export * from './scopeData';
4
+ export * from './tag';
5
+ export * from './tagParser';
6
+ export * from './templateCompiler';
7
+ export * from './templateContext';
@@ -1,21 +1,21 @@
1
- import { TemplateContent, TemplateData } from '../templateData';
2
- import { Tag } from './tag';
3
- export declare type PathPart = Tag | number;
4
- export interface ScopeDataArgs {
5
- path: PathPart[];
6
- strPath: string[];
7
- data: TemplateData;
8
- }
9
- export declare type ScopeDataResolver = (args: ScopeDataArgs) => TemplateContent | TemplateData[];
10
- export declare class ScopeData {
11
- static defaultResolver(args: ScopeDataArgs): TemplateContent | TemplateData[];
12
- scopeDataResolver: ScopeDataResolver;
13
- allData: TemplateData;
14
- private readonly path;
15
- private readonly strPath;
16
- constructor(data: TemplateData);
17
- pathPush(pathPart: PathPart): void;
18
- pathPop(): Tag | number;
19
- pathString(): string;
20
- getScopeData<T extends TemplateContent | TemplateData[]>(): T;
21
- }
1
+ import { TemplateContent, TemplateData } from '../templateData';
2
+ import { Tag } from './tag';
3
+ export type PathPart = Tag | number;
4
+ export interface ScopeDataArgs {
5
+ path: PathPart[];
6
+ strPath: string[];
7
+ data: TemplateData;
8
+ }
9
+ export type ScopeDataResolver = (args: ScopeDataArgs) => TemplateContent | TemplateData[];
10
+ export declare class ScopeData {
11
+ static defaultResolver(args: ScopeDataArgs): TemplateContent | TemplateData[];
12
+ scopeDataResolver: ScopeDataResolver;
13
+ allData: TemplateData;
14
+ private readonly path;
15
+ private readonly strPath;
16
+ constructor(data: TemplateData);
17
+ pathPush(pathPart: PathPart): void;
18
+ pathPop(): Tag | number;
19
+ pathString(): string;
20
+ getScopeData<T extends TemplateContent | TemplateData[]>(): T;
21
+ }
@@ -1,12 +1,14 @@
1
- import { XmlTextNode } from '../xml';
2
- export declare enum TagDisposition {
3
- Open = "Open",
4
- Close = "Close",
5
- SelfClosed = "SelfClosed"
6
- }
7
- export interface Tag {
8
- name: string;
9
- rawText: string;
10
- disposition: TagDisposition;
11
- xmlTextNode: XmlTextNode;
12
- }
1
+ import { IMap } from '../types';
2
+ import { XmlTextNode } from '../xml';
3
+ export declare enum TagDisposition {
4
+ Open = "Open",
5
+ Close = "Close",
6
+ SelfClosed = "SelfClosed"
7
+ }
8
+ export interface Tag {
9
+ name: string;
10
+ options?: IMap<any>;
11
+ rawText: string;
12
+ disposition: TagDisposition;
13
+ xmlTextNode: XmlTextNode;
14
+ }
@@ -1,13 +1,13 @@
1
- import { Delimiters } from '../delimiters';
2
- import { DocxParser } from '../office';
3
- import { DelimiterMark } from './delimiterMark';
4
- import { Tag } from './tag';
5
- export declare class TagParser {
6
- private readonly docParser;
7
- private readonly delimiters;
8
- private readonly tagRegex;
9
- constructor(docParser: DocxParser, delimiters: Delimiters);
10
- parse(delimiters: DelimiterMark[]): Tag[];
11
- private normalizeTagNodes;
12
- private processTag;
13
- }
1
+ import { Delimiters } from '../delimiters';
2
+ import { DocxParser } from '../office';
3
+ import { DelimiterMark } from './delimiterMark';
4
+ import { Tag } from './tag';
5
+ export declare class TagParser {
6
+ private readonly docParser;
7
+ private readonly delimiters;
8
+ private readonly tagRegex;
9
+ constructor(docParser: DocxParser, delimiters: Delimiters);
10
+ parse(delimiters: DelimiterMark[]): Tag[];
11
+ private normalizeTagNodes;
12
+ private processTag;
13
+ }