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 +1 -1
- package/dist/cjs/easy-template-x.js +45 -14
- package/dist/es/easy-template-x.js +45 -15
- package/dist/types/xml/xmlNode.d.ts +11 -2
- package/package.json +2 -1
- package/src/office/docx.ts +4 -1
- package/src/office/docxParser.ts +3 -1
- package/src/xml/xmlNode.ts +47 -15
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/
|
|
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
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
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
|
-
|
|
554
|
+
generalNode.attributes = {};
|
|
541
555
|
for (let i = 0; i < attributes.length; i++) {
|
|
542
556
|
const curAttribute = attributes.item(i);
|
|
543
|
-
|
|
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
|
|
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)
|
|
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.
|
|
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
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
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
|
-
|
|
527
|
+
generalNode.attributes = {};
|
|
514
528
|
for (let i = 0; i < attributes.length; i++) {
|
|
515
529
|
const curAttribute = attributes.item(i);
|
|
516
|
-
|
|
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
|
|
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)
|
|
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.
|
|
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.
|
|
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",
|
package/src/office/docx.ts
CHANGED
|
@@ -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
|
|
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;
|
package/src/office/docxParser.ts
CHANGED
|
@@ -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);
|
package/src/xml/xmlNode.ts
CHANGED
|
@@ -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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
159
|
+
generalNode.attributes = {};
|
|
141
160
|
for (let i = 0; i < attributes.length; i++) {
|
|
142
161
|
const curAttribute = attributes.item(i);
|
|
143
|
-
|
|
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));
|