easy-template-x 3.2.0 → 3.2.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 CHANGED
@@ -121,7 +121,7 @@ function saveFile(filename, blob) {
121
121
 
122
122
  ## Live Demo
123
123
 
124
- Checkout this [live demo](https://codesandbox.io/s/easy-template-x-demo-x4ppu?fontsize=14&module=%2Findex.ts) on CodeSandbox 😎
124
+ Checkout this [live demo](https://codesandbox.io/p/sandbox/easy-template-x-demo-x4ppu?file=%2Findex.ts) on CodeSandbox 😎
125
125
 
126
126
  ## Plugins
127
127
 
@@ -442,10 +442,11 @@ class XmlDepthTracker {
442
442
  let XmlNodeType = /*#__PURE__*/function (XmlNodeType) {
443
443
  XmlNodeType["Text"] = "Text";
444
444
  XmlNodeType["General"] = "General";
445
+ XmlNodeType["Comment"] = "Comment";
445
446
  return XmlNodeType;
446
447
  }({});
447
448
  const TEXT_NODE_NAME = '#text'; // see: https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeName
448
-
449
+ const COMMENT_NODE_NAME = '#comment';
449
450
  const XmlNode = {
450
451
  //
451
452
  // factories
@@ -464,6 +465,13 @@ const XmlNode = {
464
465
  nodeName: name
465
466
  };
466
467
  },
468
+ createCommentNode(text) {
469
+ return {
470
+ nodeType: XmlNodeType.Comment,
471
+ nodeName: COMMENT_NODE_NAME,
472
+ commentContent: text
473
+ };
474
+ },
467
475
  //
468
476
  // serialization
469
477
  //
@@ -494,6 +502,9 @@ const XmlNode = {
494
502
  },
495
503
  serialize(node) {
496
504
  if (this.isTextNode(node)) return this.encodeValue(node.textContent || '');
505
+ if (this.isCommentNode(node)) {
506
+ return `<!-- ${this.encodeValue(node.commentContent || '')} -->`;
507
+ }
497
508
 
498
509
  // attributes
499
510
  let attributes = '';
@@ -525,25 +536,31 @@ const XmlNode = {
525
536
  * The conversion is always deep.
526
537
  */
527
538
  fromDomNode(domNode) {
539
+ var _domNode$textContent;
528
540
  let xmlNode;
529
541
 
530
542
  // basic properties
531
- if (domNode.nodeType === domNode.TEXT_NODE) {
532
- xmlNode = this.createTextNode(domNode.textContent);
533
- } else {
534
- xmlNode = this.createGeneralNode(domNode.nodeName);
535
-
536
- // attributes
537
- if (domNode.nodeType === domNode.ELEMENT_NODE) {
543
+ switch (domNode.nodeType) {
544
+ case domNode.TEXT_NODE:
545
+ xmlNode = this.createTextNode(domNode.textContent);
546
+ break;
547
+ case domNode.COMMENT_NODE:
548
+ xmlNode = this.createCommentNode((_domNode$textContent = domNode.textContent) === null || _domNode$textContent === void 0 ? void 0 : _domNode$textContent.trim());
549
+ break;
550
+ case domNode.ELEMENT_NODE:
551
+ const generalNode = xmlNode = this.createGeneralNode(domNode.nodeName);
538
552
  const attributes = domNode.attributes;
539
553
  if (attributes) {
540
- xmlNode.attributes = {};
554
+ generalNode.attributes = {};
541
555
  for (let i = 0; i < attributes.length; i++) {
542
556
  const curAttribute = attributes.item(i);
543
- xmlNode.attributes[curAttribute.name] = curAttribute.value;
557
+ generalNode.attributes[curAttribute.name] = curAttribute.value;
544
558
  }
545
559
  }
546
- }
560
+ break;
561
+ default:
562
+ xmlNode = this.createGeneralNode(domNode.nodeName);
563
+ break;
547
564
  }
548
565
 
549
566
  // children
@@ -579,6 +596,15 @@ const XmlNode = {
579
596
  }
580
597
  return false;
581
598
  },
599
+ isCommentNode(node) {
600
+ if (node.nodeType === XmlNodeType.Comment || node.nodeName === COMMENT_NODE_NAME) {
601
+ if (!(node.nodeType === XmlNodeType.Comment && node.nodeName === COMMENT_NODE_NAME)) {
602
+ throw new Error(`Invalid comment node. Type: '${node.nodeType}', Name: '${node.nodeName}'.`);
603
+ }
604
+ return true;
605
+ }
606
+ return false;
607
+ },
582
608
  cloneNode(node, deep) {
583
609
  if (!node) throw new MissingArgumentError("node");
584
610
  if (!deep) {
@@ -1930,7 +1956,8 @@ class Docx {
1930
1956
  // find the last section properties
1931
1957
  // see: http://officeopenxml.com/WPsection.php
1932
1958
  const docRoot = await this.mainDocument.xmlRoot();
1933
- const body = docRoot.childNodes[0];
1959
+ const body = docRoot.childNodes.find(node => node.nodeName == 'w:body');
1960
+ if (body == null) return null;
1934
1961
  const sectionProps = last(body.childNodes.filter(node => node.nodeType === XmlNodeType.General));
1935
1962
  if (sectionProps.nodeName != 'w:sectPr') return null;
1936
1963
 
@@ -2146,7 +2173,10 @@ class DocxParser {
2146
2173
  curWordTextNode = this.firstTextNodeChild(curRunNode);
2147
2174
  }
2148
2175
  while (curWordTextNode) {
2149
- if (curWordTextNode.nodeName !== DocxParser.TEXT_NODE) continue;
2176
+ if (curWordTextNode.nodeName !== DocxParser.TEXT_NODE) {
2177
+ curWordTextNode = curWordTextNode.nextSibling;
2178
+ continue;
2179
+ }
2150
2180
 
2151
2181
  // move text to first node
2152
2182
  const curXmlTextNode = XmlNode.lastTextChild(curWordTextNode);
@@ -3006,7 +3036,7 @@ class TemplateHandler {
3006
3036
  /**
3007
3037
  * Version number of the `easy-template-x` library.
3008
3038
  */
3009
- _defineProperty(this, "version", "3.2.0" );
3039
+ _defineProperty(this, "version", "3.2.1" );
3010
3040
  _defineProperty(this, "xmlParser", new XmlParser());
3011
3041
  _defineProperty(this, "docxParser", void 0);
3012
3042
  _defineProperty(this, "compiler", void 0);
@@ -3156,6 +3186,7 @@ class TemplateHandler {
3156
3186
 
3157
3187
  exports.Base64 = Base64;
3158
3188
  exports.Binary = Binary;
3189
+ exports.COMMENT_NODE_NAME = COMMENT_NODE_NAME;
3159
3190
  exports.ContentPartType = ContentPartType;
3160
3191
  exports.DelimiterSearcher = DelimiterSearcher;
3161
3192
  exports.Delimiters = Delimiters;
@@ -415,10 +415,11 @@ class XmlDepthTracker {
415
415
  let XmlNodeType = /*#__PURE__*/function (XmlNodeType) {
416
416
  XmlNodeType["Text"] = "Text";
417
417
  XmlNodeType["General"] = "General";
418
+ XmlNodeType["Comment"] = "Comment";
418
419
  return XmlNodeType;
419
420
  }({});
420
421
  const TEXT_NODE_NAME = '#text'; // see: https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeName
421
-
422
+ const COMMENT_NODE_NAME = '#comment';
422
423
  const XmlNode = {
423
424
  //
424
425
  // factories
@@ -437,6 +438,13 @@ const XmlNode = {
437
438
  nodeName: name
438
439
  };
439
440
  },
441
+ createCommentNode(text) {
442
+ return {
443
+ nodeType: XmlNodeType.Comment,
444
+ nodeName: COMMENT_NODE_NAME,
445
+ commentContent: text
446
+ };
447
+ },
440
448
  //
441
449
  // serialization
442
450
  //
@@ -467,6 +475,9 @@ const XmlNode = {
467
475
  },
468
476
  serialize(node) {
469
477
  if (this.isTextNode(node)) return this.encodeValue(node.textContent || '');
478
+ if (this.isCommentNode(node)) {
479
+ return `<!-- ${this.encodeValue(node.commentContent || '')} -->`;
480
+ }
470
481
 
471
482
  // attributes
472
483
  let attributes = '';
@@ -498,25 +509,31 @@ const XmlNode = {
498
509
  * The conversion is always deep.
499
510
  */
500
511
  fromDomNode(domNode) {
512
+ var _domNode$textContent;
501
513
  let xmlNode;
502
514
 
503
515
  // 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) {
516
+ switch (domNode.nodeType) {
517
+ case domNode.TEXT_NODE:
518
+ xmlNode = this.createTextNode(domNode.textContent);
519
+ break;
520
+ case domNode.COMMENT_NODE:
521
+ xmlNode = this.createCommentNode((_domNode$textContent = domNode.textContent) === null || _domNode$textContent === void 0 ? void 0 : _domNode$textContent.trim());
522
+ break;
523
+ case domNode.ELEMENT_NODE:
524
+ const generalNode = xmlNode = this.createGeneralNode(domNode.nodeName);
511
525
  const attributes = domNode.attributes;
512
526
  if (attributes) {
513
- xmlNode.attributes = {};
527
+ generalNode.attributes = {};
514
528
  for (let i = 0; i < attributes.length; i++) {
515
529
  const curAttribute = attributes.item(i);
516
- xmlNode.attributes[curAttribute.name] = curAttribute.value;
530
+ generalNode.attributes[curAttribute.name] = curAttribute.value;
517
531
  }
518
532
  }
519
- }
533
+ break;
534
+ default:
535
+ xmlNode = this.createGeneralNode(domNode.nodeName);
536
+ break;
520
537
  }
521
538
 
522
539
  // children
@@ -552,6 +569,15 @@ const XmlNode = {
552
569
  }
553
570
  return false;
554
571
  },
572
+ isCommentNode(node) {
573
+ if (node.nodeType === XmlNodeType.Comment || node.nodeName === COMMENT_NODE_NAME) {
574
+ if (!(node.nodeType === XmlNodeType.Comment && node.nodeName === COMMENT_NODE_NAME)) {
575
+ throw new Error(`Invalid comment node. Type: '${node.nodeType}', Name: '${node.nodeName}'.`);
576
+ }
577
+ return true;
578
+ }
579
+ return false;
580
+ },
555
581
  cloneNode(node, deep) {
556
582
  if (!node) throw new MissingArgumentError("node");
557
583
  if (!deep) {
@@ -1903,7 +1929,8 @@ class Docx {
1903
1929
  // find the last section properties
1904
1930
  // see: http://officeopenxml.com/WPsection.php
1905
1931
  const docRoot = await this.mainDocument.xmlRoot();
1906
- const body = docRoot.childNodes[0];
1932
+ const body = docRoot.childNodes.find(node => node.nodeName == 'w:body');
1933
+ if (body == null) return null;
1907
1934
  const sectionProps = last(body.childNodes.filter(node => node.nodeType === XmlNodeType.General));
1908
1935
  if (sectionProps.nodeName != 'w:sectPr') return null;
1909
1936
 
@@ -2119,7 +2146,10 @@ class DocxParser {
2119
2146
  curWordTextNode = this.firstTextNodeChild(curRunNode);
2120
2147
  }
2121
2148
  while (curWordTextNode) {
2122
- if (curWordTextNode.nodeName !== DocxParser.TEXT_NODE) continue;
2149
+ if (curWordTextNode.nodeName !== DocxParser.TEXT_NODE) {
2150
+ curWordTextNode = curWordTextNode.nextSibling;
2151
+ continue;
2152
+ }
2123
2153
 
2124
2154
  // move text to first node
2125
2155
  const curXmlTextNode = XmlNode.lastTextChild(curWordTextNode);
@@ -2979,7 +3009,7 @@ class TemplateHandler {
2979
3009
  /**
2980
3010
  * Version number of the `easy-template-x` library.
2981
3011
  */
2982
- _defineProperty(this, "version", "3.2.0" );
3012
+ _defineProperty(this, "version", "3.2.1" );
2983
3013
  _defineProperty(this, "xmlParser", new XmlParser());
2984
3014
  _defineProperty(this, "docxParser", void 0);
2985
3015
  _defineProperty(this, "compiler", void 0);
@@ -3127,4 +3157,4 @@ class TemplateHandler {
3127
3157
  }
3128
3158
  }
3129
3159
 
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 };
3160
+ 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, 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 };
@@ -1,9 +1,10 @@
1
1
  import { IMap } from '../types';
2
2
  export declare enum XmlNodeType {
3
3
  Text = "Text",
4
- General = "General"
4
+ General = "General",
5
+ Comment = "Comment"
5
6
  }
6
- export declare type XmlNode = XmlTextNode | XmlGeneralNode;
7
+ export declare type XmlNode = XmlTextNode | XmlGeneralNode | XmlCommentNode;
7
8
  export interface XmlNodeBase {
8
9
  nodeType: XmlNodeType;
9
10
  nodeName: string;
@@ -12,11 +13,17 @@ export interface XmlNodeBase {
12
13
  nextSibling?: XmlNode;
13
14
  }
14
15
  export declare const TEXT_NODE_NAME = "#text";
16
+ export declare const COMMENT_NODE_NAME = "#comment";
15
17
  export interface XmlTextNode extends XmlNodeBase {
16
18
  nodeType: XmlNodeType.Text;
17
19
  nodeName: typeof TEXT_NODE_NAME;
18
20
  textContent: string;
19
21
  }
22
+ export interface XmlCommentNode extends XmlNodeBase {
23
+ nodeType: XmlNodeType.Comment;
24
+ nodeName: typeof COMMENT_NODE_NAME;
25
+ commentContent: string;
26
+ }
20
27
  export interface XmlGeneralNode extends XmlNodeBase {
21
28
  nodeType: XmlNodeType.General;
22
29
  attributes?: IMap<string>;
@@ -24,10 +31,12 @@ export interface XmlGeneralNode extends XmlNodeBase {
24
31
  export declare const XmlNode: {
25
32
  createTextNode(text?: string): XmlTextNode;
26
33
  createGeneralNode(name: string): XmlGeneralNode;
34
+ createCommentNode(text?: string): XmlCommentNode;
27
35
  encodeValue(str: string): string;
28
36
  serialize(node: XmlNode): string;
29
37
  fromDomNode(domNode: Node): XmlNode;
30
38
  isTextNode(node: XmlNode): node is XmlTextNode;
39
+ isCommentNode(node: XmlNode): node is XmlCommentNode;
31
40
  cloneNode<T extends XmlNode>(node: T, deep: boolean): T;
32
41
  insertBefore(newNode: XmlNode, referenceNode: XmlNode): void;
33
42
  insertAfter(newNode: XmlNode, referenceNode: XmlNode): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "easy-template-x",
3
- "version": "3.2.0",
3
+ "version": "3.2.1",
4
4
  "description": "Generate docx documents from templates, in Node or in the browser.",
5
5
  "keywords": [
6
6
  "docx",
@@ -64,6 +64,7 @@
64
64
  "babel-plugin-ts-nameof": "4.2.1",
65
65
  "eslint": "8.19.0",
66
66
  "jest": "28.1.2",
67
+ "jest-html-reporters": "3.1.7",
67
68
  "jest-junit": "14.0.0",
68
69
  "lorem-ipsum": "2.0.8",
69
70
  "rimraf": "3.0.2",
@@ -114,7 +114,10 @@ export class Docx {
114
114
  // find the last section properties
115
115
  // see: http://officeopenxml.com/WPsection.php
116
116
  const docRoot = await this.mainDocument.xmlRoot();
117
- const body = docRoot.childNodes[0];
117
+ const body = docRoot.childNodes.find(node => node.nodeName == 'w:body');
118
+ if (body == null)
119
+ return null;
120
+
118
121
  const sectionProps = last(body.childNodes.filter(node => node.nodeType === XmlNodeType.General));
119
122
  if (sectionProps.nodeName != 'w:sectPr')
120
123
  return null;
@@ -208,8 +208,10 @@ export class DocxParser {
208
208
  }
209
209
  while (curWordTextNode) {
210
210
 
211
- if (curWordTextNode.nodeName !== DocxParser.TEXT_NODE)
211
+ if (curWordTextNode.nodeName !== DocxParser.TEXT_NODE) {
212
+ curWordTextNode = curWordTextNode.nextSibling;
212
213
  continue;
214
+ }
213
215
 
214
216
  // move text to first node
215
217
  const curXmlTextNode = XmlNode.lastTextChild(curWordTextNode);
@@ -4,10 +4,11 @@ import { last } from '../utils';
4
4
 
5
5
  export enum XmlNodeType {
6
6
  Text = "Text",
7
- General = "General"
7
+ General = "General",
8
+ Comment = "Comment",
8
9
  }
9
10
 
10
- export type XmlNode = XmlTextNode | XmlGeneralNode;
11
+ export type XmlNode = XmlTextNode | XmlGeneralNode | XmlCommentNode;
11
12
 
12
13
  export interface XmlNodeBase {
13
14
  nodeType: XmlNodeType;
@@ -18,6 +19,7 @@ export interface XmlNodeBase {
18
19
  }
19
20
 
20
21
  export const TEXT_NODE_NAME = '#text'; // see: https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeName
22
+ export const COMMENT_NODE_NAME = '#comment';
21
23
 
22
24
  export interface XmlTextNode extends XmlNodeBase {
23
25
  nodeType: XmlNodeType.Text;
@@ -25,6 +27,12 @@ export interface XmlTextNode extends XmlNodeBase {
25
27
  textContent: string;
26
28
  }
27
29
 
30
+ export interface XmlCommentNode extends XmlNodeBase {
31
+ nodeType: XmlNodeType.Comment;
32
+ nodeName: typeof COMMENT_NODE_NAME;
33
+ commentContent: string;
34
+ }
35
+
28
36
  export interface XmlGeneralNode extends XmlNodeBase {
29
37
  nodeType: XmlNodeType.General;
30
38
  attributes?: IMap<string>;
@@ -51,6 +59,14 @@ export const XmlNode = {
51
59
  };
52
60
  },
53
61
 
62
+ createCommentNode(text?: string): XmlCommentNode {
63
+ return {
64
+ nodeType: XmlNodeType.Comment,
65
+ nodeName: COMMENT_NODE_NAME,
66
+ commentContent: text
67
+ };
68
+ },
69
+
54
70
  //
55
71
  // serialization
56
72
  //
@@ -82,6 +98,10 @@ export const XmlNode = {
82
98
  if (this.isTextNode(node))
83
99
  return this.encodeValue(node.textContent || '');
84
100
 
101
+ if (this.isCommentNode(node)) {
102
+ return `<!-- ${this.encodeValue(node.commentContent || '')} -->`;
103
+ }
104
+
85
105
  // attributes
86
106
  let attributes = '';
87
107
  if (node.attributes) {
@@ -125,25 +145,27 @@ export const XmlNode = {
125
145
  let xmlNode: XmlNode;
126
146
 
127
147
  // basic properties
128
- if (domNode.nodeType === domNode.TEXT_NODE) {
129
-
130
- xmlNode = this.createTextNode(domNode.textContent);
131
-
132
- } else {
133
-
134
- xmlNode = this.createGeneralNode(domNode.nodeName);
135
-
136
- // attributes
137
- if (domNode.nodeType === domNode.ELEMENT_NODE) {
148
+ switch (domNode.nodeType) {
149
+ case domNode.TEXT_NODE:
150
+ xmlNode = this.createTextNode(domNode.textContent);
151
+ break;
152
+ case domNode.COMMENT_NODE:
153
+ xmlNode = this.createCommentNode(domNode.textContent?.trim());
154
+ break;
155
+ case domNode.ELEMENT_NODE:
156
+ const generalNode = xmlNode = this.createGeneralNode(domNode.nodeName);
138
157
  const attributes = (domNode as Element).attributes;
139
158
  if (attributes) {
140
- (xmlNode as XmlGeneralNode).attributes = {};
159
+ generalNode.attributes = {};
141
160
  for (let i = 0; i < attributes.length; i++) {
142
161
  const curAttribute = attributes.item(i);
143
- (xmlNode as XmlGeneralNode).attributes[curAttribute.name] = curAttribute.value;
162
+ generalNode.attributes[curAttribute.name] = curAttribute.value;
144
163
  }
145
164
  }
146
- }
165
+ break;
166
+ default:
167
+ xmlNode = this.createGeneralNode(domNode.nodeName);
168
+ break;
147
169
  }
148
170
 
149
171
  // children
@@ -183,6 +205,16 @@ export const XmlNode = {
183
205
  return false;
184
206
  },
185
207
 
208
+ isCommentNode(node: XmlNode): node is XmlCommentNode {
209
+ if (node.nodeType === XmlNodeType.Comment || node.nodeName === COMMENT_NODE_NAME) {
210
+ if (!(node.nodeType === XmlNodeType.Comment && node.nodeName === COMMENT_NODE_NAME)) {
211
+ throw new Error(`Invalid comment node. Type: '${node.nodeType}', Name: '${node.nodeName}'.`);
212
+ }
213
+ return true;
214
+ }
215
+ return false;
216
+ },
217
+
186
218
  cloneNode<T extends XmlNode>(node: T, deep: boolean): T {
187
219
  if (!node)
188
220
  throw new MissingArgumentError(nameof(node));