@xmldom/xmldom 0.8.5 → 0.8.6
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/CHANGELOG.md +9 -0
- package/lib/dom.js +174 -26
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.8.6](https://github.com/xmldom/xmldom/compare/0.8.5...0.8.6)
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Properly check nodes before replacement [`#457`](https://github.com/xmldom/xmldom/pull/457) / [`#455`](https://github.com/xmldom/xmldom/issues/455) / [`#456`](https://github.com/xmldom/xmldom/issues/456)
|
|
12
|
+
|
|
13
|
+
Thank you, [@edemaine](https://github.com/edemaine), [@pedro-l9](https://github.com/pedro-l9), for your contributions
|
|
14
|
+
|
|
15
|
+
|
|
7
16
|
## [0.8.5](https://github.com/xmldom/xmldom/compare/0.8.4...0.8.5)
|
|
8
17
|
|
|
9
18
|
### Fixed
|
package/lib/dom.js
CHANGED
|
@@ -468,7 +468,7 @@ Node.prototype = {
|
|
|
468
468
|
return _insertBefore(this,newChild,refChild);
|
|
469
469
|
},
|
|
470
470
|
replaceChild:function(newChild, oldChild){//raises
|
|
471
|
-
this
|
|
471
|
+
_insertBefore(this, newChild,oldChild, assertPreReplacementValidityInDocument);
|
|
472
472
|
if(oldChild){
|
|
473
473
|
this.removeChild(oldChild);
|
|
474
474
|
}
|
|
@@ -590,6 +590,7 @@ function _visitNode(node,callback){
|
|
|
590
590
|
|
|
591
591
|
|
|
592
592
|
function Document(){
|
|
593
|
+
this.ownerDocument = this;
|
|
593
594
|
}
|
|
594
595
|
|
|
595
596
|
function _onAddAttribute(doc,el,newAttr){
|
|
@@ -747,8 +748,35 @@ function isElementInsertionPossible(doc, child) {
|
|
|
747
748
|
var docTypeNode = find(parentChildNodes, isDocTypeNode);
|
|
748
749
|
return !(child && docTypeNode && parentChildNodes.indexOf(docTypeNode) > parentChildNodes.indexOf(child));
|
|
749
750
|
}
|
|
751
|
+
|
|
750
752
|
/**
|
|
753
|
+
* Check if en element node can be inserted before `child`, or at the end if child is falsy,
|
|
754
|
+
* according to the presence and position of a doctype node on the same level.
|
|
755
|
+
*
|
|
756
|
+
* @param {Node} doc The document node
|
|
757
|
+
* @param {Node} child the node that would become the nextSibling if the element would be inserted
|
|
758
|
+
* @returns {boolean} `true` if an element can be inserted before child
|
|
751
759
|
* @private
|
|
760
|
+
* https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
|
|
761
|
+
*/
|
|
762
|
+
function isElementReplacementPossible(doc, child) {
|
|
763
|
+
var parentChildNodes = doc.childNodes || [];
|
|
764
|
+
|
|
765
|
+
function hasElementChildThatIsNotChild(node) {
|
|
766
|
+
return isElementNode(node) && node !== child;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
if (find(parentChildNodes, hasElementChildThatIsNotChild)) {
|
|
770
|
+
return false;
|
|
771
|
+
}
|
|
772
|
+
var docTypeNode = find(parentChildNodes, isDocTypeNode);
|
|
773
|
+
return !(child && docTypeNode && parentChildNodes.indexOf(docTypeNode) > parentChildNodes.indexOf(child));
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* @private
|
|
778
|
+
* Steps 1-5 of the checks before inserting and before replacing a child are the same.
|
|
779
|
+
*
|
|
752
780
|
* @param {Node} parent the parent node to insert `node` into
|
|
753
781
|
* @param {Node} node the node to insert
|
|
754
782
|
* @param {Node=} child the node that should become the `nextSibling` of `node`
|
|
@@ -756,18 +784,26 @@ function isElementInsertionPossible(doc, child) {
|
|
|
756
784
|
* @throws DOMException for several node combinations that would create a DOM that is not well-formed.
|
|
757
785
|
* @throws DOMException if `child` is provided but is not a child of `parent`.
|
|
758
786
|
* @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
|
|
787
|
+
* @see https://dom.spec.whatwg.org/#concept-node-replace
|
|
759
788
|
*/
|
|
760
|
-
function
|
|
789
|
+
function assertPreInsertionValidity1to5(parent, node, child) {
|
|
790
|
+
// 1. If `parent` is not a Document, DocumentFragment, or Element node, then throw a "HierarchyRequestError" DOMException.
|
|
761
791
|
if (!hasValidParentNodeType(parent)) {
|
|
762
792
|
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Unexpected parent node type ' + parent.nodeType);
|
|
763
793
|
}
|
|
794
|
+
// 2. If `node` is a host-including inclusive ancestor of `parent`, then throw a "HierarchyRequestError" DOMException.
|
|
795
|
+
// not implemented!
|
|
796
|
+
// 3. If `child` is non-null and its parent is not `parent`, then throw a "NotFoundError" DOMException.
|
|
764
797
|
if (child && child.parentNode !== parent) {
|
|
765
798
|
throw new DOMException(NOT_FOUND_ERR, 'child not in parent');
|
|
766
799
|
}
|
|
767
800
|
if (
|
|
801
|
+
// 4. If `node` is not a DocumentFragment, DocumentType, Element, or CharacterData node, then throw a "HierarchyRequestError" DOMException.
|
|
768
802
|
!hasInsertableNodeType(node) ||
|
|
803
|
+
// 5. If either `node` is a Text node and `parent` is a document,
|
|
769
804
|
// the sax parser currently adds top level text nodes, this will be fixed in 0.9.0
|
|
770
805
|
// || (node.nodeType === Node.TEXT_NODE && parent.nodeType === Node.DOCUMENT_NODE)
|
|
806
|
+
// or `node` is a doctype and `parent` is not a document, then throw a "HierarchyRequestError" DOMException.
|
|
771
807
|
(isDocTypeNode(node) && parent.nodeType !== Node.DOCUMENT_NODE)
|
|
772
808
|
) {
|
|
773
809
|
throw new DOMException(
|
|
@@ -775,36 +811,137 @@ function _insertBefore(parent, node, child) {
|
|
|
775
811
|
'Unexpected node type ' + node.nodeType + ' for parent node type ' + parent.nodeType
|
|
776
812
|
);
|
|
777
813
|
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* @private
|
|
818
|
+
* Step 6 of the checks before inserting and before replacing a child are different.
|
|
819
|
+
*
|
|
820
|
+
* @param {Document} parent the parent node to insert `node` into
|
|
821
|
+
* @param {Node} node the node to insert
|
|
822
|
+
* @param {Node | undefined} child the node that should become the `nextSibling` of `node`
|
|
823
|
+
* @returns {Node}
|
|
824
|
+
* @throws DOMException for several node combinations that would create a DOM that is not well-formed.
|
|
825
|
+
* @throws DOMException if `child` is provided but is not a child of `parent`.
|
|
826
|
+
* @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
|
|
827
|
+
* @see https://dom.spec.whatwg.org/#concept-node-replace
|
|
828
|
+
*/
|
|
829
|
+
function assertPreInsertionValidityInDocument(parent, node, child) {
|
|
778
830
|
var parentChildNodes = parent.childNodes || [];
|
|
779
831
|
var nodeChildNodes = node.childNodes || [];
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Element in fragment can not be inserted before doctype');
|
|
788
|
-
}
|
|
832
|
+
|
|
833
|
+
// DocumentFragment
|
|
834
|
+
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
|
835
|
+
var nodeChildElements = nodeChildNodes.filter(isElementNode);
|
|
836
|
+
// If node has more than one element child or has a Text node child.
|
|
837
|
+
if (nodeChildElements.length > 1 || find(nodeChildNodes, isTextNode)) {
|
|
838
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'More than one element or text in fragment');
|
|
789
839
|
}
|
|
790
|
-
if
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
840
|
+
// Otherwise, if `node` has one element child and either `parent` has an element child,
|
|
841
|
+
// `child` is a doctype, or `child` is non-null and a doctype is following `child`.
|
|
842
|
+
if (nodeChildElements.length === 1 && !isElementInsertionPossible(parent, child)) {
|
|
843
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Element in fragment can not be inserted before doctype');
|
|
794
844
|
}
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
845
|
+
}
|
|
846
|
+
// Element
|
|
847
|
+
if (isElementNode(node)) {
|
|
848
|
+
// `parent` has an element child, `child` is a doctype,
|
|
849
|
+
// or `child` is non-null and a doctype is following `child`.
|
|
850
|
+
if (!isElementInsertionPossible(parent, child)) {
|
|
851
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one element can be added and only after doctype');
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
// DocumentType
|
|
855
|
+
if (isDocTypeNode(node)) {
|
|
856
|
+
// `parent` has a doctype child,
|
|
857
|
+
if (find(parentChildNodes, isDocTypeNode)) {
|
|
858
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one doctype is allowed');
|
|
859
|
+
}
|
|
860
|
+
var parentElementChild = find(parentChildNodes, isElementNode);
|
|
861
|
+
// `child` is non-null and an element is preceding `child`,
|
|
862
|
+
if (child && parentChildNodes.indexOf(parentElementChild) < parentChildNodes.indexOf(child)) {
|
|
863
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Doctype can only be inserted before an element');
|
|
864
|
+
}
|
|
865
|
+
// or `child` is null and `parent` has an element child.
|
|
866
|
+
if (!child && parentElementChild) {
|
|
867
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Doctype can not be appended since element is present');
|
|
806
868
|
}
|
|
807
869
|
}
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
/**
|
|
873
|
+
* @private
|
|
874
|
+
* Step 6 of the checks before inserting and before replacing a child are different.
|
|
875
|
+
*
|
|
876
|
+
* @param {Document} parent the parent node to insert `node` into
|
|
877
|
+
* @param {Node} node the node to insert
|
|
878
|
+
* @param {Node | undefined} child the node that should become the `nextSibling` of `node`
|
|
879
|
+
* @returns {Node}
|
|
880
|
+
* @throws DOMException for several node combinations that would create a DOM that is not well-formed.
|
|
881
|
+
* @throws DOMException if `child` is provided but is not a child of `parent`.
|
|
882
|
+
* @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
|
|
883
|
+
* @see https://dom.spec.whatwg.org/#concept-node-replace
|
|
884
|
+
*/
|
|
885
|
+
function assertPreReplacementValidityInDocument(parent, node, child) {
|
|
886
|
+
var parentChildNodes = parent.childNodes || [];
|
|
887
|
+
var nodeChildNodes = node.childNodes || [];
|
|
888
|
+
|
|
889
|
+
// DocumentFragment
|
|
890
|
+
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
|
891
|
+
var nodeChildElements = nodeChildNodes.filter(isElementNode);
|
|
892
|
+
// If `node` has more than one element child or has a Text node child.
|
|
893
|
+
if (nodeChildElements.length > 1 || find(nodeChildNodes, isTextNode)) {
|
|
894
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'More than one element or text in fragment');
|
|
895
|
+
}
|
|
896
|
+
// Otherwise, if `node` has one element child and either `parent` has an element child that is not `child` or a doctype is following `child`.
|
|
897
|
+
if (nodeChildElements.length === 1 && !isElementReplacementPossible(parent, child)) {
|
|
898
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Element in fragment can not be inserted before doctype');
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
// Element
|
|
902
|
+
if (isElementNode(node)) {
|
|
903
|
+
// `parent` has an element child that is not `child` or a doctype is following `child`.
|
|
904
|
+
if (!isElementReplacementPossible(parent, child)) {
|
|
905
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one element can be added and only after doctype');
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
// DocumentType
|
|
909
|
+
if (isDocTypeNode(node)) {
|
|
910
|
+
function hasDoctypeChildThatIsNotChild(node) {
|
|
911
|
+
return isDocTypeNode(node) && node !== child;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
// `parent` has a doctype child that is not `child`,
|
|
915
|
+
if (find(parentChildNodes, hasDoctypeChildThatIsNotChild)) {
|
|
916
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one doctype is allowed');
|
|
917
|
+
}
|
|
918
|
+
var parentElementChild = find(parentChildNodes, isElementNode);
|
|
919
|
+
// or an element is preceding `child`.
|
|
920
|
+
if (child && parentChildNodes.indexOf(parentElementChild) < parentChildNodes.indexOf(child)) {
|
|
921
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Doctype can only be inserted before an element');
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
/**
|
|
927
|
+
* @private
|
|
928
|
+
* @param {Node} parent the parent node to insert `node` into
|
|
929
|
+
* @param {Node} node the node to insert
|
|
930
|
+
* @param {Node=} child the node that should become the `nextSibling` of `node`
|
|
931
|
+
* @returns {Node}
|
|
932
|
+
* @throws DOMException for several node combinations that would create a DOM that is not well-formed.
|
|
933
|
+
* @throws DOMException if `child` is provided but is not a child of `parent`.
|
|
934
|
+
* @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
|
|
935
|
+
*/
|
|
936
|
+
function _insertBefore(parent, node, child, _inDocumentAssertion) {
|
|
937
|
+
// To ensure pre-insertion validity of a node into a parent before a child, run these steps:
|
|
938
|
+
assertPreInsertionValidity1to5(parent, node, child);
|
|
939
|
+
|
|
940
|
+
// If parent is a document, and any of the statements below, switched on the interface node implements,
|
|
941
|
+
// are true, then throw a "HierarchyRequestError" DOMException.
|
|
942
|
+
if (parent.nodeType === Node.DOCUMENT_NODE) {
|
|
943
|
+
(_inDocumentAssertion || assertPreInsertionValidityInDocument)(parent, node, child);
|
|
944
|
+
}
|
|
808
945
|
|
|
809
946
|
var cp = node.parentNode;
|
|
810
947
|
if(cp){
|
|
@@ -912,6 +1049,17 @@ Document.prototype = {
|
|
|
912
1049
|
}
|
|
913
1050
|
return _removeChild(this,oldChild);
|
|
914
1051
|
},
|
|
1052
|
+
replaceChild: function (newChild, oldChild) {
|
|
1053
|
+
//raises
|
|
1054
|
+
_insertBefore(this, newChild, oldChild, assertPreReplacementValidityInDocument);
|
|
1055
|
+
newChild.ownerDocument = this;
|
|
1056
|
+
if (oldChild) {
|
|
1057
|
+
this.removeChild(oldChild);
|
|
1058
|
+
}
|
|
1059
|
+
if (isElementNode(newChild)) {
|
|
1060
|
+
this.documentElement = newChild;
|
|
1061
|
+
}
|
|
1062
|
+
},
|
|
915
1063
|
// Introduced in DOM Level 2:
|
|
916
1064
|
importNode : function(importedNode,deep){
|
|
917
1065
|
return importNode(this,importedNode,deep);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xmldom/xmldom",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.6",
|
|
4
4
|
"description": "A pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"w3c",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"stryker": "stryker run",
|
|
36
36
|
"stryker:dry-run": "stryker run -m '' --reporters progress",
|
|
37
37
|
"test": "jest",
|
|
38
|
-
"testrelease": "npm test &&
|
|
38
|
+
"testrelease": "npm test && eslint lib",
|
|
39
39
|
"version": "./changelog-has-version.sh",
|
|
40
|
-
"release": "np --no-yarn --test-script testrelease"
|
|
40
|
+
"release": "np --no-yarn --test-script testrelease --branch release-0.8.x patch"
|
|
41
41
|
},
|
|
42
42
|
"engines": {
|
|
43
43
|
"node": ">=10.0.0"
|