@xmldom/xmldom 0.7.8 → 0.7.9
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 +183 -36
- package/package.json +2 -2
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.7.9](https://github.com/xmldom/xmldom/compare/0.7.8...0.7.9)
|
|
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.7.8](https://github.com/xmldom/xmldom/compare/0.7.7...0.7.8)
|
|
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
|
}
|
|
@@ -592,6 +592,7 @@ function _visitNode(node,callback){
|
|
|
592
592
|
|
|
593
593
|
|
|
594
594
|
function Document(){
|
|
595
|
+
this.ownerDocument = this;
|
|
595
596
|
}
|
|
596
597
|
|
|
597
598
|
function _onAddAttribute(doc,el,newAttr){
|
|
@@ -628,6 +629,7 @@ function _onUpdateChild(doc,el,newChild){
|
|
|
628
629
|
child =child.nextSibling;
|
|
629
630
|
}
|
|
630
631
|
cs.length = i;
|
|
632
|
+
delete cs[cs.length];
|
|
631
633
|
}
|
|
632
634
|
}
|
|
633
635
|
}
|
|
@@ -653,6 +655,9 @@ function _removeChild(parentNode,child){
|
|
|
653
655
|
}else{
|
|
654
656
|
parentNode.lastChild = previous;
|
|
655
657
|
}
|
|
658
|
+
child.parentNode = null;
|
|
659
|
+
child.previousSibling = null;
|
|
660
|
+
child.nextSibling = null;
|
|
656
661
|
_onUpdateChild(parentNode.ownerDocument,parentNode);
|
|
657
662
|
return child;
|
|
658
663
|
}
|
|
@@ -730,8 +735,35 @@ function isElementInsertionPossible(doc, child) {
|
|
|
730
735
|
var docTypeNode = find(parentChildNodes, isDocTypeNode);
|
|
731
736
|
return !(child && docTypeNode && parentChildNodes.indexOf(docTypeNode) > parentChildNodes.indexOf(child));
|
|
732
737
|
}
|
|
738
|
+
|
|
733
739
|
/**
|
|
740
|
+
* Check if en element node can be inserted before `child`, or at the end if child is falsy,
|
|
741
|
+
* according to the presence and position of a doctype node on the same level.
|
|
742
|
+
*
|
|
743
|
+
* @param {Node} doc The document node
|
|
744
|
+
* @param {Node} child the node that would become the nextSibling if the element would be inserted
|
|
745
|
+
* @returns {boolean} `true` if an element can be inserted before child
|
|
734
746
|
* @private
|
|
747
|
+
* https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
|
|
748
|
+
*/
|
|
749
|
+
function isElementReplacementPossible(doc, child) {
|
|
750
|
+
var parentChildNodes = doc.childNodes || [];
|
|
751
|
+
|
|
752
|
+
function hasElementChildThatIsNotChild(node) {
|
|
753
|
+
return isElementNode(node) && node !== child;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
if (find(parentChildNodes, hasElementChildThatIsNotChild)) {
|
|
757
|
+
return false;
|
|
758
|
+
}
|
|
759
|
+
var docTypeNode = find(parentChildNodes, isDocTypeNode);
|
|
760
|
+
return !(child && docTypeNode && parentChildNodes.indexOf(docTypeNode) > parentChildNodes.indexOf(child));
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/**
|
|
764
|
+
* @private
|
|
765
|
+
* Steps 1-5 of the checks before inserting and before replacing a child are the same.
|
|
766
|
+
*
|
|
735
767
|
* @param {Node} parent the parent node to insert `node` into
|
|
736
768
|
* @param {Node} node the node to insert
|
|
737
769
|
* @param {Node=} child the node that should become the `nextSibling` of `node`
|
|
@@ -739,18 +771,26 @@ function isElementInsertionPossible(doc, child) {
|
|
|
739
771
|
* @throws DOMException for several node combinations that would create a DOM that is not well-formed.
|
|
740
772
|
* @throws DOMException if `child` is provided but is not a child of `parent`.
|
|
741
773
|
* @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
|
|
774
|
+
* @see https://dom.spec.whatwg.org/#concept-node-replace
|
|
742
775
|
*/
|
|
743
|
-
function
|
|
776
|
+
function assertPreInsertionValidity1to5(parent, node, child) {
|
|
777
|
+
// 1. If `parent` is not a Document, DocumentFragment, or Element node, then throw a "HierarchyRequestError" DOMException.
|
|
744
778
|
if (!hasValidParentNodeType(parent)) {
|
|
745
779
|
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Unexpected parent node type ' + parent.nodeType);
|
|
746
780
|
}
|
|
781
|
+
// 2. If `node` is a host-including inclusive ancestor of `parent`, then throw a "HierarchyRequestError" DOMException.
|
|
782
|
+
// not implemented!
|
|
783
|
+
// 3. If `child` is non-null and its parent is not `parent`, then throw a "NotFoundError" DOMException.
|
|
747
784
|
if (child && child.parentNode !== parent) {
|
|
748
785
|
throw new DOMException(NOT_FOUND_ERR, 'child not in parent');
|
|
749
786
|
}
|
|
750
787
|
if (
|
|
788
|
+
// 4. If `node` is not a DocumentFragment, DocumentType, Element, or CharacterData node, then throw a "HierarchyRequestError" DOMException.
|
|
751
789
|
!hasInsertableNodeType(node) ||
|
|
790
|
+
// 5. If either `node` is a Text node and `parent` is a document,
|
|
752
791
|
// the sax parser currently adds top level text nodes, this will be fixed in 0.9.0
|
|
753
792
|
// || (node.nodeType === Node.TEXT_NODE && parent.nodeType === Node.DOCUMENT_NODE)
|
|
793
|
+
// or `node` is a doctype and `parent` is not a document, then throw a "HierarchyRequestError" DOMException.
|
|
754
794
|
(isDocTypeNode(node) && parent.nodeType !== Node.DOCUMENT_NODE)
|
|
755
795
|
) {
|
|
756
796
|
throw new DOMException(
|
|
@@ -758,36 +798,137 @@ function _insertBefore(parent, node, child) {
|
|
|
758
798
|
'Unexpected node type ' + node.nodeType + ' for parent node type ' + parent.nodeType
|
|
759
799
|
);
|
|
760
800
|
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/**
|
|
804
|
+
* @private
|
|
805
|
+
* Step 6 of the checks before inserting and before replacing a child are different.
|
|
806
|
+
*
|
|
807
|
+
* @param {Document} parent the parent node to insert `node` into
|
|
808
|
+
* @param {Node} node the node to insert
|
|
809
|
+
* @param {Node | undefined} child the node that should become the `nextSibling` of `node`
|
|
810
|
+
* @returns {Node}
|
|
811
|
+
* @throws DOMException for several node combinations that would create a DOM that is not well-formed.
|
|
812
|
+
* @throws DOMException if `child` is provided but is not a child of `parent`.
|
|
813
|
+
* @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
|
|
814
|
+
* @see https://dom.spec.whatwg.org/#concept-node-replace
|
|
815
|
+
*/
|
|
816
|
+
function assertPreInsertionValidityInDocument(parent, node, child) {
|
|
761
817
|
var parentChildNodes = parent.childNodes || [];
|
|
762
818
|
var nodeChildNodes = node.childNodes || [];
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Element in fragment can not be inserted before doctype');
|
|
771
|
-
}
|
|
819
|
+
|
|
820
|
+
// DocumentFragment
|
|
821
|
+
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
|
822
|
+
var nodeChildElements = nodeChildNodes.filter(isElementNode);
|
|
823
|
+
// If node has more than one element child or has a Text node child.
|
|
824
|
+
if (nodeChildElements.length > 1 || find(nodeChildNodes, isTextNode)) {
|
|
825
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'More than one element or text in fragment');
|
|
772
826
|
}
|
|
773
|
-
if
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
827
|
+
// Otherwise, if `node` has one element child and either `parent` has an element child,
|
|
828
|
+
// `child` is a doctype, or `child` is non-null and a doctype is following `child`.
|
|
829
|
+
if (nodeChildElements.length === 1 && !isElementInsertionPossible(parent, child)) {
|
|
830
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Element in fragment can not be inserted before doctype');
|
|
777
831
|
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
832
|
+
}
|
|
833
|
+
// Element
|
|
834
|
+
if (isElementNode(node)) {
|
|
835
|
+
// `parent` has an element child, `child` is a doctype,
|
|
836
|
+
// or `child` is non-null and a doctype is following `child`.
|
|
837
|
+
if (!isElementInsertionPossible(parent, child)) {
|
|
838
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one element can be added and only after doctype');
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
// DocumentType
|
|
842
|
+
if (isDocTypeNode(node)) {
|
|
843
|
+
// `parent` has a doctype child,
|
|
844
|
+
if (find(parentChildNodes, isDocTypeNode)) {
|
|
845
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one doctype is allowed');
|
|
846
|
+
}
|
|
847
|
+
var parentElementChild = find(parentChildNodes, isElementNode);
|
|
848
|
+
// `child` is non-null and an element is preceding `child`,
|
|
849
|
+
if (child && parentChildNodes.indexOf(parentElementChild) < parentChildNodes.indexOf(child)) {
|
|
850
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Doctype can only be inserted before an element');
|
|
851
|
+
}
|
|
852
|
+
// or `child` is null and `parent` has an element child.
|
|
853
|
+
if (!child && parentElementChild) {
|
|
854
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Doctype can not be appended since element is present');
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
/**
|
|
860
|
+
* @private
|
|
861
|
+
* Step 6 of the checks before inserting and before replacing a child are different.
|
|
862
|
+
*
|
|
863
|
+
* @param {Document} parent the parent node to insert `node` into
|
|
864
|
+
* @param {Node} node the node to insert
|
|
865
|
+
* @param {Node | undefined} child the node that should become the `nextSibling` of `node`
|
|
866
|
+
* @returns {Node}
|
|
867
|
+
* @throws DOMException for several node combinations that would create a DOM that is not well-formed.
|
|
868
|
+
* @throws DOMException if `child` is provided but is not a child of `parent`.
|
|
869
|
+
* @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
|
|
870
|
+
* @see https://dom.spec.whatwg.org/#concept-node-replace
|
|
871
|
+
*/
|
|
872
|
+
function assertPreReplacementValidityInDocument(parent, node, child) {
|
|
873
|
+
var parentChildNodes = parent.childNodes || [];
|
|
874
|
+
var nodeChildNodes = node.childNodes || [];
|
|
875
|
+
|
|
876
|
+
// DocumentFragment
|
|
877
|
+
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
|
878
|
+
var nodeChildElements = nodeChildNodes.filter(isElementNode);
|
|
879
|
+
// If `node` has more than one element child or has a Text node child.
|
|
880
|
+
if (nodeChildElements.length > 1 || find(nodeChildNodes, isTextNode)) {
|
|
881
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'More than one element or text in fragment');
|
|
882
|
+
}
|
|
883
|
+
// Otherwise, if `node` has one element child and either `parent` has an element child that is not `child` or a doctype is following `child`.
|
|
884
|
+
if (nodeChildElements.length === 1 && !isElementReplacementPossible(parent, child)) {
|
|
885
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Element in fragment can not be inserted before doctype');
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
// Element
|
|
889
|
+
if (isElementNode(node)) {
|
|
890
|
+
// `parent` has an element child that is not `child` or a doctype is following `child`.
|
|
891
|
+
if (!isElementReplacementPossible(parent, child)) {
|
|
892
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one element can be added and only after doctype');
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
// DocumentType
|
|
896
|
+
if (isDocTypeNode(node)) {
|
|
897
|
+
function hasDoctypeChildThatIsNotChild(node) {
|
|
898
|
+
return isDocTypeNode(node) && node !== child;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
// `parent` has a doctype child that is not `child`,
|
|
902
|
+
if (find(parentChildNodes, hasDoctypeChildThatIsNotChild)) {
|
|
903
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one doctype is allowed');
|
|
904
|
+
}
|
|
905
|
+
var parentElementChild = find(parentChildNodes, isElementNode);
|
|
906
|
+
// or an element is preceding `child`.
|
|
907
|
+
if (child && parentChildNodes.indexOf(parentElementChild) < parentChildNodes.indexOf(child)) {
|
|
908
|
+
throw new DOMException(HIERARCHY_REQUEST_ERR, 'Doctype can only be inserted before an element');
|
|
789
909
|
}
|
|
790
910
|
}
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
/**
|
|
914
|
+
* @private
|
|
915
|
+
* @param {Node} parent the parent node to insert `node` into
|
|
916
|
+
* @param {Node} node the node to insert
|
|
917
|
+
* @param {Node=} child the node that should become the `nextSibling` of `node`
|
|
918
|
+
* @returns {Node}
|
|
919
|
+
* @throws DOMException for several node combinations that would create a DOM that is not well-formed.
|
|
920
|
+
* @throws DOMException if `child` is provided but is not a child of `parent`.
|
|
921
|
+
* @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
|
|
922
|
+
*/
|
|
923
|
+
function _insertBefore(parent, node, child, _inDocumentAssertion) {
|
|
924
|
+
// To ensure pre-insertion validity of a node into a parent before a child, run these steps:
|
|
925
|
+
assertPreInsertionValidity1to5(parent, node, child);
|
|
926
|
+
|
|
927
|
+
// If parent is a document, and any of the statements below, switched on the interface node implements,
|
|
928
|
+
// are true, then throw a "HierarchyRequestError" DOMException.
|
|
929
|
+
if (parent.nodeType === Node.DOCUMENT_NODE) {
|
|
930
|
+
(_inDocumentAssertion || assertPreInsertionValidityInDocument)(parent, node, child);
|
|
931
|
+
}
|
|
791
932
|
|
|
792
933
|
var cp = node.parentNode;
|
|
793
934
|
if(cp){
|
|
@@ -829,25 +970,20 @@ function _insertBefore(parent, node, child) {
|
|
|
829
970
|
return node;
|
|
830
971
|
}
|
|
831
972
|
function _appendSingleChild(parentNode,newChild){
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
var pre = parentNode.lastChild;
|
|
835
|
-
cp.removeChild(newChild);//remove and update
|
|
836
|
-
var pre = parentNode.lastChild;
|
|
973
|
+
if (newChild.parentNode) {
|
|
974
|
+
newChild.parentNode.removeChild(newChild);
|
|
837
975
|
}
|
|
838
|
-
var pre = parentNode.lastChild;
|
|
839
976
|
newChild.parentNode = parentNode;
|
|
840
|
-
newChild.previousSibling =
|
|
977
|
+
newChild.previousSibling = parentNode.lastChild;
|
|
841
978
|
newChild.nextSibling = null;
|
|
842
|
-
if(
|
|
843
|
-
|
|
979
|
+
if (newChild.previousSibling) {
|
|
980
|
+
newChild.previousSibling.nextSibling = newChild;
|
|
844
981
|
}else{
|
|
845
982
|
parentNode.firstChild = newChild;
|
|
846
983
|
}
|
|
847
984
|
parentNode.lastChild = newChild;
|
|
848
985
|
_onUpdateChild(parentNode.ownerDocument,parentNode,newChild);
|
|
849
986
|
return newChild;
|
|
850
|
-
//console.log("__aa",parentNode.lastChild.nextSibling == null)
|
|
851
987
|
}
|
|
852
988
|
|
|
853
989
|
Document.prototype = {
|
|
@@ -888,6 +1024,17 @@ Document.prototype = {
|
|
|
888
1024
|
}
|
|
889
1025
|
return _removeChild(this,oldChild);
|
|
890
1026
|
},
|
|
1027
|
+
replaceChild: function (newChild, oldChild) {
|
|
1028
|
+
//raises
|
|
1029
|
+
_insertBefore(this, newChild, oldChild, assertPreReplacementValidityInDocument);
|
|
1030
|
+
newChild.ownerDocument = this;
|
|
1031
|
+
if (oldChild) {
|
|
1032
|
+
this.removeChild(oldChild);
|
|
1033
|
+
}
|
|
1034
|
+
if (isElementNode(newChild)) {
|
|
1035
|
+
this.documentElement = newChild;
|
|
1036
|
+
}
|
|
1037
|
+
},
|
|
891
1038
|
// Introduced in DOM Level 2:
|
|
892
1039
|
importNode : function(importedNode,deep){
|
|
893
1040
|
return importNode(this,importedNode,deep);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xmldom/xmldom",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.9",
|
|
4
4
|
"description": "A pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"w3c",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"stryker:dry-run": "stryker run -m '' --reporters progress",
|
|
34
34
|
"test": "jest",
|
|
35
35
|
"testrelease": "npm test && eslint lib",
|
|
36
|
-
"release": "np --no-yarn --test-script testrelease --branch release-0.7.x --tag lts"
|
|
36
|
+
"release": "np --no-yarn --test-script testrelease --branch release-0.7.x --tag lts patch"
|
|
37
37
|
},
|
|
38
38
|
"engines": {
|
|
39
39
|
"node": ">=10.0.0"
|