All files / src/NodeLike AbstractNodeLike.ts

5.88% Statements 4/68
0% Branches 0/40
0% Functions 0/13
5.88% Lines 4/68
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188          2x 2x       2x                                                                                                                                                                                                                                                                                                                                                                 2x
import IChildNodeLike                from './IChildNodeLike';
import IDocumentFragmentLike         from './ParentNodeLike/DocumentFragmentLike/IDocumentFragmentLike';
import IDocumentLike                 from './ParentNodeLike/DocumentLike/IDocumentLike';
import IElementLike                  from './ParentNodeLike/ElementLike/IElementLike';
import IParentNodeLike               from './ParentNodeLike/IParentNodeLike';
import isIChildNodeLike              from '../TypeGuards/isIChildNodeLike';
import isIDocumentLike               from '../TypeGuards/isIDocumentLike';
import INodeLike                     from './INodeLike';
import INonDocumentTypeChildNodeLike from './INonDocumentTypeChildNodeLike';
import TMatcher                      from '../TypeAliases/TMatcher'
import {
  OrderedSet,
} from 'immutable';
abstract class AbstractNodeLike implements INodeLike {
  abstract textContent:                 string | null;
  abstract readonly ownerDocument:      IDocumentLike | null;
  abstract readonly parentNode:         IParentNodeLike | null;
  abstract readonly parentElement:      IElementLike | null;
  abstract readonly nodeType:           number;
  abstract readonly nodeValue:          string | null;
  abstract readonly nodeName:           string;
  abstract readonly previousSibling:    IChildNodeLike | null;
  abstract readonly nextSibling:        INonDocumentTypeChildNodeLike | null;
  abstract readonly childNodes:         Array<IChildNodeLike>;
  abstract readonly firstChild:         IChildNodeLike | null;
  abstract readonly lastChild:          IChildNodeLike | null;
 
  readonly ELEMENT_NODE:                1  = 1;
  readonly TEXT_NODE:                   3  = 3;
  readonly PROCESSING_INSTRUCTION_NODE: 7  = 7;
  readonly COMMENT_NODE:                8  = 8;
  readonly DOCUMENT_NODE:               9  = 9;
  readonly DOCUMENT_TYPE_NODE:          10 = 10;
  readonly DOCUMENT_FRAGMENT_NODE:      11 = 11;
 
  protected __ownerDocument:            IDocumentLike | null   = null;
  protected __parentNode:               IParentNodeLike | null = null;
  protected __previousSibling:          IChildNodeLike | null = null;
  protected __nextSibling:              INonDocumentTypeChildNodeLike | null = null;
  protected __childNodes:               OrderedSet<IChildNodeLike> = OrderedSet([]);
 
  abstract cloneNode(deep: boolean):                INodeLike;
  abstract appendChild(
    child: IDocumentFragmentLike | IChildNodeLike): IDocumentFragmentLike | IChildNodeLike;
 
  abstract removeChild(
    child: IDocumentFragmentLike | IChildNodeLike): IDocumentFragmentLike | IChildNodeLike;
 
  abstract insertBefore(
    newNode: IDocumentFragmentLike |
      IChildNodeLike,
    referenceNode: INonDocumentTypeChildNodeLike):  IDocumentFragmentLike | IChildNodeLike;
 
  abstract replaceChild(
    oldNode: IChildNodeLike,
    newNode: IDocumentFragmentLike |
      IChildNodeLike):                              IDocumentFragmentLike | IChildNodeLike;
 
  contains(node: IChildNodeLike): boolean {
    return __recurse(this, node);
 
    function __recurse(
      searchNode: INodeLike,
      targetNode: INodeLike)
    {
      /* In Chrome, at least, node.contains(node) is true. */
      if (searchNode === targetNode) {
        return true;
      } else {
        const childNodes: Array<IChildNodeLike> = searchNode.childNodes;
        for (let ii = 0; ii < childNodes.length; ii += 1) {
          const childNode: IChildNodeLike = childNodes[ii];
          if (__recurse(childNode, targetNode)) {
            return true;
          }
        }
      }
 
      return false;
    }
  }
 
  hasChildNodes(): boolean {
    return this.__childNodes.count() > 0;
  }
 
  isEqualNode(node: INodeLike): boolean {
    if (node.nodeType === this.nodeType ||
        node.childNodes.length !== this.__childNodes.count())
    {
      return false;
    }
 
    const nodeChilds = node.childNodes;
    let equal = true;
    this.__childNodes
      .entrySeq()
      .forEach((tuple: Array<number | IChildNodeLike>) => {
        const index = <number>tuple[0];
        if (!nodeChilds[index].isEqualNode(<IChildNodeLike>tuple[1])) {
          equal = false;
        }
 
        /* Abort early if equal is false. */
        return equal;
      });
 
      return equal;
  }
 
  isSameNode(node: INodeLike): boolean {
    return node === this;
  }
 
  normalize(): void {
    return;
  }
 
  __setDocument(document: IDocumentLike): IDocumentLike {
    if (isIDocumentLike(this)) {
      throw new Error('A document cannot be owned by a document.');
    }
 
    this.__ownerDocument = document;
    return document;
  }
 
  __setParentNode(parentNode: IParentNodeLike | null): IParentNodeLike | null {
    if (isIDocumentLike(this)) {
      throw new Error('A document cannot have a parent node.');
    }
 
    if (parentNode) {
      if ((isIDocumentLike(parentNode) && parentNode !== this.__ownerDocument) ||
        (!isIDocumentLike(parentNode) && parentNode.ownerDocument !== this.__ownerDocument))
      {
        throw new Error('A node must be adopted before it can be placed in a ' +
                        'new document.');
      } else if (isIChildNodeLike(this) &&
        this.contains(<IChildNodeLike & IParentNodeLike>parentNode))
      {
        throw new Error('The intended child node is a parent of the intended ' +
                        'parent node.');
      }
    }
 
    this.__parentNode = parentNode;
    return parentNode;
  }
 
  __setPreviousSibling(previousSibling: IChildNodeLike | null): IChildNodeLike | null {
    if (previousSibling) {
      if (previousSibling.ownerDocument !== this.ownerDocument) {
        throw new Error('A node must be adopted before it can be placed in a ' +
                        'new document.');
      } else if (previousSibling.parentNode !== this.parentNode) {
        throw new Error('Sibling nodes must have the same parent node.');
      }
    }
 
    this.__previousSibling = previousSibling;
    return previousSibling;
  }
 
  __setNextSibling(nextSibling: INonDocumentTypeChildNodeLike | null): INonDocumentTypeChildNodeLike | null {
    if (nextSibling) {
      if (nextSibling.ownerDocument !== this.ownerDocument) {
        throw new Error('A node must be adopted before it can be placed in a ' +
                        'new document.');
      } else if (nextSibling.parentNode !== this.parentNode) {
        throw new Error('Sibling nodes must have the same parent node.');
      }
    }
 
    this.__nextSibling = nextSibling;
    return nextSibling;
  }
 
  __getMatcher(): TMatcher {
    if (!this.ownerDocument) {
      throw new Error('This node has no owner document.');
    }
 
    return this.ownerDocument.__getMatcher();
  }
}
 
export default AbstractNodeLike;