@@ -15,6 +15,10 @@ var walkers = exports;
1515// if true, `props` will have an integer `typeIndex` field which
1616// represents a node index among all its sibling of the same type
1717//
18+ // - [typeCount]: boolean=false
19+ // if true, `props` will have an integer `typeCount` field which
20+ // is equal to number of siblings sharing the same type with this node
21+ //
1822
1923
2024walkers . topScan = function ( node , nodeIndex , parent , opts ) {
@@ -24,27 +28,22 @@ walkers.topScan = function (node, nodeIndex, parent, opts) {
2428 throw Error ( 'topScan is supposed to be called from the root node' ) ;
2529 }
2630
27- if ( ! opts . typeIndex ) {
31+ if ( ! opts . typeIndex && ! opts . typeCount ) {
2832 opts . iterator ( node , nodeIndex , parent ) ;
2933 }
3034 walkers . descendant . apply ( this , arguments ) ;
3135} ;
3236
3337
3438walkers . descendant = function ( node , nodeIndex , parent , opts ) {
35- if ( ! node . children || ! node . children . length ) {
36- return ;
37- }
39+ var iterator = opts . iterator ;
3840
39- if ( opts . typeIndex ) {
40- var typeIndex = TypeIndex ( ) ;
41- }
41+ opts . iterator = function ( node , nodeIndex , parent ) {
42+ iterator . apply ( this , arguments ) ;
43+ walkers . child ( node , nodeIndex , node , opts ) ;
44+ } ;
4245
43- node . children . forEach ( function ( child , childIndex ) {
44- opts . iterator ( child , childIndex , node ,
45- opts . typeIndex ? { typeIndex : typeIndex ( child ) } : undefined ) ;
46- walkers . descendant ( child , childIndex , node , opts ) ;
47- } ) ;
46+ return walkers . child ( node , nodeIndex , parent , opts ) ;
4847} ;
4948
5049
@@ -53,14 +52,9 @@ walkers.child = function (node, nodeIndex, parent, opts) {
5352 return ;
5453 }
5554
56- if ( opts . typeIndex ) {
57- var typeIndex = TypeIndex ( ) ;
58- }
59-
60- node . children . forEach ( function ( child , childIndex ) {
61- opts . iterator ( child , childIndex , node ,
62- opts . typeIndex ? { typeIndex : typeIndex ( child ) } : undefined ) ;
63- } ) ;
55+ walkIterator ( node , opts )
56+ . each ( )
57+ . finally ( ) ;
6458} ;
6559
6660
@@ -69,20 +63,11 @@ walkers.adjacentSibling = function (node, nodeIndex, parent, opts) {
6963 return ;
7064 }
7165
72- if ( opts . typeIndex ) {
73- var typeIndex = TypeIndex ( ) ;
74-
75- // Prefill type indexes with preceding nodes.
76- for ( var prevIndex = 0 ; prevIndex <= nodeIndex ; ++ prevIndex ) {
77- typeIndex ( parent . children [ prevIndex ] ) ;
78- }
79- }
80-
81- if ( ++ nodeIndex < parent . children . length ) {
82- node = parent . children [ nodeIndex ] ;
83- opts . iterator ( node , nodeIndex , parent ,
84- opts . typeIndex ? { typeIndex : typeIndex ( node ) } : undefined ) ;
85- }
66+ walkIterator ( parent , opts )
67+ . prefillTypeIndex ( 0 , ++ nodeIndex )
68+ . each ( nodeIndex , ++ nodeIndex )
69+ . prefillTypeIndex ( nodeIndex )
70+ . finally ( ) ;
8671} ;
8772
8873
@@ -91,18 +76,75 @@ walkers.generalSibling = function (node, nodeIndex, parent, opts) {
9176 return ;
9277 }
9378
94- if ( opts . typeIndex ) {
95- var typeIndex = TypeIndex ( ) ;
79+ walkIterator ( parent , opts )
80+ . prefillTypeIndex ( 0 , ++ nodeIndex )
81+ . each ( nodeIndex )
82+ . finally ( ) ;
83+ } ;
9684
97- // Prefill type indexes with preceding nodes.
98- for ( var prevIndex = 0 ; prevIndex <= nodeIndex ; ++ prevIndex ) {
99- typeIndex ( parent . children [ prevIndex ] ) ;
100- }
101- }
10285
103- while ( ++ nodeIndex < parent . children . length ) {
104- node = parent . children [ nodeIndex ] ;
105- opts . iterator ( node , nodeIndex , parent ,
106- opts . typeIndex ? { typeIndex : typeIndex ( node ) } : undefined ) ;
107- }
108- } ;
86+ // Handles typeIndex and typeCount properties for every walker.
87+ function walkIterator ( parent , opts ) {
88+ var hasTypeIndex = opts . typeIndex || opts . typeCount ;
89+ var typeIndex = hasTypeIndex ? TypeIndex ( ) : Function . prototype ;
90+ var nodeThunks = [ ] ;
91+
92+ var rangeDefaults = function ( iter ) {
93+ return function ( start , end ) {
94+ if ( start == null || start < 0 ) {
95+ start = 0 ;
96+ }
97+ if ( end == null || end > parent . children . length ) {
98+ end = parent . children . length ;
99+ }
100+ return iter . call ( this , start , end ) ;
101+ } ;
102+ } ;
103+
104+ return {
105+ prefillTypeIndex : rangeDefaults ( function ( start , end ) {
106+ if ( hasTypeIndex ) {
107+ for ( var nodeIndex = start ; nodeIndex < end ; ++ nodeIndex ) {
108+ typeIndex ( parent . children [ nodeIndex ] ) ;
109+ }
110+ }
111+ return this ;
112+ } ) ,
113+
114+ each : rangeDefaults ( function each ( start , end ) {
115+ if ( start >= end ) {
116+ return this ;
117+ }
118+
119+ var nodeIndex = start ;
120+ var node = parent . children [ nodeIndex ] ;
121+ var props = { } ;
122+ var nodeTypeIndex = typeIndex ( node ) ;
123+
124+ if ( opts . typeIndex ) {
125+ props . typeIndex = nodeTypeIndex ;
126+ }
127+
128+ if ( opts . typeCount ) {
129+ nodeThunks . push ( function ( ) {
130+ props . typeCount = typeIndex . count ( node ) ;
131+ pushNode ( ) ;
132+ } ) ;
133+ }
134+ else {
135+ pushNode ( ) ;
136+ }
137+
138+ return each . call ( this , start + 1 , end ) ;
139+
140+ function pushNode ( ) {
141+ opts . iterator ( node , nodeIndex , parent , props ) ;
142+ }
143+ } ) ,
144+
145+ finally : function ( ) {
146+ nodeThunks . forEach ( Function . call . bind ( Function . call ) ) ;
147+ return this ;
148+ }
149+ } ;
150+ }
0 commit comments