@@ -54,7 +54,7 @@ namespace ts {
54
54
public jsDoc : JSDoc [ ] ;
55
55
public original : Node ;
56
56
public transformFlags : TransformFlags ;
57
- private _children : Node [ ] ;
57
+ private _children : Node [ ] | undefined ;
58
58
59
59
constructor ( kind : SyntaxKind , pos : number , end : number ) {
60
60
this . pos = pos ;
@@ -117,106 +117,17 @@ namespace ts {
117
117
return sourceFile . text . substring ( this . getStart ( sourceFile ) , this . getEnd ( ) ) ;
118
118
}
119
119
120
- private addSyntheticNodes ( nodes : Push < Node > , pos : number , end : number ) : number {
121
- scanner . setTextPos ( pos ) ;
122
- while ( pos < end ) {
123
- const token = scanner . scan ( ) ;
124
- const textPos = scanner . getTextPos ( ) ;
125
- if ( textPos <= end ) {
126
- if ( token === SyntaxKind . Identifier ) {
127
- Debug . fail ( `Did not expect ${ Debug . showSyntaxKind ( this ) } to have an Identifier in its trivia` ) ;
128
- }
129
- nodes . push ( createNode ( token , pos , textPos , this ) ) ;
130
- }
131
- pos = textPos ;
132
- if ( token === SyntaxKind . EndOfFileToken ) {
133
- break ;
134
- }
135
- }
136
- return pos ;
137
- }
138
-
139
- private createSyntaxList ( nodes : NodeArray < Node > ) : Node {
140
- const list = < NodeObject > createNode ( SyntaxKind . SyntaxList , nodes . pos , nodes . end , this ) ;
141
- list . _children = [ ] ;
142
- let pos = nodes . pos ;
143
-
144
- for ( const node of nodes ) {
145
- if ( pos < node . pos ) {
146
- pos = this . addSyntheticNodes ( list . _children , pos , node . pos ) ;
147
- }
148
- list . _children . push ( node ) ;
149
- pos = node . end ;
150
- }
151
- if ( pos < nodes . end ) {
152
- this . addSyntheticNodes ( list . _children , pos , nodes . end ) ;
153
- }
154
- return list ;
155
- }
156
-
157
- private createChildren ( sourceFile ?: SourceFileLike ) {
158
- if ( ! isNodeKind ( this . kind ) ) {
159
- this . _children = emptyArray ;
160
- return ;
161
- }
162
-
163
- if ( isJSDocCommentContainingNode ( this ) ) {
164
- /** Don't add trivia for "tokens" since this is in a comment. */
165
- const children : Node [ ] = [ ] ;
166
- this . forEachChild ( child => { children . push ( child ) ; } ) ;
167
- this . _children = children ;
168
- return ;
169
- }
170
-
171
- const children : Node [ ] = [ ] ;
172
- scanner . setText ( ( sourceFile || this . getSourceFile ( ) ) . text ) ;
173
- let pos = this . pos ;
174
- const processNode = ( node : Node ) => {
175
- pos = this . addSyntheticNodes ( children , pos , node . pos ) ;
176
- children . push ( node ) ;
177
- pos = node . end ;
178
- } ;
179
- const processNodes = ( nodes : NodeArray < Node > ) => {
180
- if ( pos < nodes . pos ) {
181
- pos = this . addSyntheticNodes ( children , pos , nodes . pos ) ;
182
- }
183
- children . push ( this . createSyntaxList ( nodes ) ) ;
184
- pos = nodes . end ;
185
- } ;
186
- // jsDocComments need to be the first children
187
- if ( this . jsDoc ) {
188
- for ( const jsDocComment of this . jsDoc ) {
189
- processNode ( jsDocComment ) ;
190
- }
191
- }
192
- // For syntactic classifications, all trivia are classcified together, including jsdoc comments.
193
- // For that to work, the jsdoc comments should still be the leading trivia of the first child.
194
- // Restoring the scanner position ensures that.
195
- pos = this . pos ;
196
- forEachChild ( this , processNode , processNodes ) ;
197
- if ( pos < this . end ) {
198
- this . addSyntheticNodes ( children , pos , this . end ) ;
199
- }
200
- scanner . setText ( undefined ) ;
201
- this . _children = children ;
202
- }
203
-
204
120
public getChildCount ( sourceFile ?: SourceFile ) : number {
205
- this . assertHasRealPosition ( ) ;
206
- if ( ! this . _children ) this . createChildren ( sourceFile ) ;
207
- return this . _children . length ;
121
+ return this . getChildren ( sourceFile ) . length ;
208
122
}
209
123
210
124
public getChildAt ( index : number , sourceFile ?: SourceFile ) : Node {
211
- this . assertHasRealPosition ( ) ;
212
- if ( ! this . _children ) this . createChildren ( sourceFile ) ;
213
- return this . _children [ index ] ;
125
+ return this . getChildren ( sourceFile ) [ index ] ;
214
126
}
215
127
216
128
public getChildren ( sourceFile ?: SourceFileLike ) : Node [ ] {
217
129
this . assertHasRealPosition ( "Node without a real position cannot be scanned and thus has no token nodes - use forEachChild and collect the result if that's fine" ) ;
218
- if ( ! this . _children ) this . createChildren ( sourceFile ) ;
219
- return this . _children ;
130
+ return this . _children || ( this . _children = createChildren ( this , sourceFile ) ) ;
220
131
}
221
132
222
133
public getFirstToken ( sourceFile ?: SourceFile ) : Node {
@@ -249,6 +160,74 @@ namespace ts {
249
160
}
250
161
}
251
162
163
+ function createChildren ( node : Node , sourceFile : SourceFileLike | undefined ) : Node [ ] {
164
+ if ( ! isNodeKind ( node . kind ) ) {
165
+ return emptyArray ;
166
+ }
167
+
168
+ const children : Node [ ] = [ ] ;
169
+
170
+ if ( isJSDocCommentContainingNode ( node ) ) {
171
+ /** Don't add trivia for "tokens" since this is in a comment. */
172
+ node . forEachChild ( child => { children . push ( child ) ; } ) ;
173
+ return children ;
174
+ }
175
+
176
+ scanner . setText ( ( sourceFile || node . getSourceFile ( ) ) . text ) ;
177
+ let pos = node . pos ;
178
+ const processNode = ( child : Node ) => {
179
+ addSyntheticNodes ( children , pos , child . pos , node ) ;
180
+ children . push ( child ) ;
181
+ pos = child . end ;
182
+ } ;
183
+ const processNodes = ( nodes : NodeArray < Node > ) => {
184
+ addSyntheticNodes ( children , pos , nodes . pos , node ) ;
185
+ children . push ( createSyntaxList ( nodes , node ) ) ;
186
+ pos = nodes . end ;
187
+ } ;
188
+ // jsDocComments need to be the first children
189
+ forEach ( ( node as JSDocContainer ) . jsDoc , processNode ) ;
190
+ // For syntactic classifications, all trivia are classified together, including jsdoc comments.
191
+ // For that to work, the jsdoc comments should still be the leading trivia of the first child.
192
+ // Restoring the scanner position ensures that.
193
+ pos = node . pos ;
194
+ node . forEachChild ( processNode , processNodes ) ;
195
+ addSyntheticNodes ( children , pos , node . end , node ) ;
196
+ scanner . setText ( undefined ) ;
197
+ return children ;
198
+ }
199
+
200
+ function addSyntheticNodes ( nodes : Push < Node > , pos : number , end : number , parent : Node ) : void {
201
+ scanner . setTextPos ( pos ) ;
202
+ while ( pos < end ) {
203
+ const token = scanner . scan ( ) ;
204
+ const textPos = scanner . getTextPos ( ) ;
205
+ if ( textPos <= end ) {
206
+ if ( token === SyntaxKind . Identifier ) {
207
+ Debug . fail ( `Did not expect ${ Debug . showSyntaxKind ( parent ) } to have an Identifier in its trivia` ) ;
208
+ }
209
+ nodes . push ( createNode ( token , pos , textPos , parent ) ) ;
210
+ }
211
+ pos = textPos ;
212
+ if ( token === SyntaxKind . EndOfFileToken ) {
213
+ break ;
214
+ }
215
+ }
216
+ }
217
+
218
+ function createSyntaxList ( nodes : NodeArray < Node > , parent : Node ) : Node {
219
+ const list = createNode ( SyntaxKind . SyntaxList , nodes . pos , nodes . end , parent ) as any as SyntaxList ;
220
+ list . _children = [ ] ;
221
+ let pos = nodes . pos ;
222
+ for ( const node of nodes ) {
223
+ addSyntheticNodes ( list . _children , pos , node . pos , parent ) ;
224
+ list . _children . push ( node ) ;
225
+ pos = node . end ;
226
+ }
227
+ addSyntheticNodes ( list . _children , pos , nodes . end , parent ) ;
228
+ return list ;
229
+ }
230
+
252
231
class TokenOrIdentifierObject implements Node {
253
232
public kind : SyntaxKind ;
254
233
public pos : number ;
0 commit comments