6
6
*/
7
7
8
8
const SymbolTreeNode = require ( './SymbolTreeNode' ) ;
9
+ const TreePosition = require ( './TreePosition' ) ;
9
10
10
11
function returnTrue ( ) {
11
12
return true ;
12
13
}
13
14
15
+ function reverseArrayIndex ( array , reverseIndex ) {
16
+ return array [ array . length - 1 - reverseIndex ] ; // no need to check `index >= 0`
17
+ }
18
+
14
19
class SymbolTree {
15
20
16
21
/**
@@ -528,7 +533,7 @@ class SymbolTree {
528
533
*
529
534
* @method childrenCount
530
535
* @memberOf module:symbol-tree#
531
- * @param parent
536
+ * @param { Object } parent
532
537
* @return {Number }
533
538
*/
534
539
childrenCount ( parent ) {
@@ -541,6 +546,98 @@ class SymbolTree {
541
546
return this . index ( parentNode . last ) + 1 ;
542
547
}
543
548
549
+ /**
550
+ * Compare the position of an object relative to another object. A bit set is returned:
551
+ *
552
+ * <ul>
553
+ * <li>DISCONNECTED : 1</li>
554
+ * <li>PRECEDING : 2</li>
555
+ * <li>FOLLOWING : 4</li>
556
+ * <li>CONTAINS : 8</li>
557
+ * <li>CONTAINED_BY : 16</li>
558
+ * </ul>
559
+ *
560
+ * The semantics are the same as compareDocumentPosition in DOM, with the exception that
561
+ * DISCONNECTED never occurs with any other bit.
562
+ *
563
+ * `O(n)` (worst case)
564
+ *
565
+ * @method childrenCount
566
+ * @memberOf module:symbol-tree#
567
+ * @param {Object } left
568
+ * @param {Object } right
569
+ * @return {Number }
570
+ */
571
+ compareTreePosition ( left , right ) {
572
+ // In DOM terms:
573
+ // left = reference / context object
574
+ // right = other
575
+
576
+ if ( left === right ) {
577
+ return 0 ;
578
+ }
579
+
580
+ /* jshint -W016 */
581
+
582
+ const leftAncestors = [ ] ; { // inclusive
583
+ let leftAncestor = left ;
584
+
585
+ while ( leftAncestor ) {
586
+ if ( leftAncestor === right ) {
587
+ return TreePosition . CONTAINS | TreePosition . PRECEDING ;
588
+ // other is ancestor of reference
589
+ }
590
+
591
+ leftAncestors . push ( leftAncestor ) ;
592
+ leftAncestor = this . parent ( leftAncestor ) ;
593
+ }
594
+ }
595
+
596
+
597
+ const rightAncestors = [ ] ; {
598
+ let rightAncestor = right ;
599
+
600
+ while ( rightAncestor ) {
601
+ if ( rightAncestor === left ) {
602
+ return TreePosition . CONTAINED_BY | TreePosition . FOLLOWING ;
603
+ }
604
+
605
+ rightAncestors . push ( rightAncestor ) ;
606
+ rightAncestor = this . parent ( rightAncestor ) ;
607
+ }
608
+ }
609
+
610
+
611
+ const root = reverseArrayIndex ( leftAncestors , 0 ) ;
612
+
613
+ if ( ! root || root !== reverseArrayIndex ( rightAncestors , 0 ) ) {
614
+ // note: unlike DOM, preceding / following is not set here
615
+ return TreePosition . DISCONNECTED ;
616
+ }
617
+
618
+ let commonAncestorIndex = 0 ;
619
+ const ancestorsMinLength = Math . min ( leftAncestors . length , rightAncestors . length ) ;
620
+
621
+ for ( let i = 0 ; i < ancestorsMinLength ; ++ i ) {
622
+ const leftAncestor = reverseArrayIndex ( leftAncestors , i ) ;
623
+ const rightAncestor = reverseArrayIndex ( rightAncestors , i ) ;
624
+
625
+ if ( leftAncestor !== rightAncestor ) {
626
+ break ;
627
+ }
628
+
629
+ commonAncestorIndex = i ;
630
+ }
631
+
632
+ // indexes within the common ancestor
633
+ const leftIndex = this . index ( reverseArrayIndex ( leftAncestors , commonAncestorIndex + 1 ) ) ;
634
+ const rightIndex = this . index ( reverseArrayIndex ( rightAncestors , commonAncestorIndex + 1 ) ) ;
635
+
636
+ return rightIndex < leftIndex
637
+ ? TreePosition . PRECEDING
638
+ : TreePosition . FOLLOWING ;
639
+ }
640
+
544
641
/**
545
642
* Remove the object from this tree.
546
643
* Has no effect if already removed.
0 commit comments