Skip to content

Commit dc41bb2

Browse files
Lookup the last inclusive descendant
1 parent 023c924 commit dc41bb2

File tree

2 files changed

+48
-12
lines changed

2 files changed

+48
-12
lines changed

lib/SymbolTree.js

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,23 @@ module.exports = class SymbolTree {
111111
}
112112

113113
/**
114+
* Find the inclusive descendant that is last in tree order of the given object.
115+
*
116+
* `O(n)` (worst case)
117+
*
118+
* @method lastInclusiveDescendant
119+
* @param {Object} object
120+
* @return {Object}
121+
*/
122+
lastInclusiveDescendant(object) {
123+
let last;
124+
125+
while ( (last = this._node(object).last) ) {
126+
object = last;
127+
}
128+
129+
return object;
130+
}
114131
* Find the preceding object (A) of the given object (B).
115132
* An object A is preceding an object B if A and B are in the same tree
116133
* and A comes before B in tree order.
@@ -126,15 +143,10 @@ module.exports = class SymbolTree {
126143
return null;
127144
}
128145
129-
// if we have a previous sibling, return the last child of the last child of the ...
130-
if (this._node(object).prev) {
131-
object = this._node(object).prev;
146+
const prev = this._node(object).prev;
132147
133-
while (this._node(object).last) {
134-
object = this._node(object).last;
135-
}
136-
137-
return object;
148+
if (prev) {
149+
return this.lastInclusiveDescendant(prev);
138150
}
139151
140152
// if there is no previous sibling return the parent (might be null)
@@ -154,17 +166,21 @@ module.exports = class SymbolTree {
154166
* @returns {?Object}
155167
*/
156168
following(object, treeRoot, skipChildren) {
157-
if (!skipChildren && this._node(object).first) {
158-
return this._node(object).first;
169+
const first = !skipChildren && this._node(object).first;
170+
171+
if (first) {
172+
return first;
159173
}
160174
161175
do {
162176
if (object === treeRoot) {
163177
return null;
164178
}
165179
166-
if (this._node(object).next) {
167-
return this._node(object).next;
180+
const next = this._node(object).next;
181+
182+
if (next) {
183+
return next;
168184
}
169185
170186
object = this._node(object).parent;

test/SymbolTree.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,26 @@ test('Multiple SymbolTree instances should not conflict', function(t) {
438438
t.end();
439439
});
440440

441+
test('lastInclusiveDescendant', function(t) {
442+
const tree = new SymbolTree();
443+
const a = {};
444+
const aa = {};
445+
const ab = {};
446+
const aba = {};
447+
const abaa = {};
448+
const b = {};
449+
450+
tree.insertLast(aa, a);
451+
tree.insertLast(ab, a);
452+
tree.insertLast(aba, ab);
453+
tree.insertLast(abaa, aba);
454+
tree.insertAfter(b, a);
455+
456+
t.equal(abaa, tree.lastInclusiveDescendant(a));
457+
458+
t.end();
459+
});
460+
441461
test('look up preceding with a previous sibling', function(t) {
442462
const tree = new SymbolTree();
443463
const a = {};

0 commit comments

Comments
 (0)