4
4
"github.com/microsoft/typescript-go/shim/ast"
5
5
"github.com/microsoft/typescript-go/shim/checker"
6
6
"github.com/microsoft/typescript-go/shim/core"
7
+ "github.com/microsoft/typescript-go/shim/scanner"
7
8
)
8
9
9
10
func UnionTypeParts (t * checker.Type ) []* checker.Type {
@@ -157,30 +158,54 @@ func GetWellKnownSymbolPropertyOfType(t *checker.Type, name string, typeChecker
157
158
return checker .Checker_getPropertyOfType (typeChecker , t , checker .Checker_getPropertyNameForKnownSymbolName (typeChecker , name ))
158
159
}
159
160
160
- /**
161
- * Checks if a given compiler option is enabled, accounting for whether all flags
162
- * (except `strictPropertyInitialization`) have been enabled by `strict: true`.
163
- * @category Compiler Options
164
- * @example
165
- * ```ts
166
- * const optionsLenient = {
167
- * noImplicitAny: true,
168
- * };
169
- *
170
- * isStrictCompilerOptionEnabled(optionsLenient, "noImplicitAny"); // true
171
- * isStrictCompilerOptionEnabled(optionsLenient, "noImplicitThis"); // false
172
- * ```
173
- * @example
174
- * ```ts
175
- * const optionsStrict = {
176
- * noImplicitThis: false,
177
- * strict: true,
178
- * };
179
- *
180
- * isStrictCompilerOptionEnabled(optionsStrict, "noImplicitAny"); // true
181
- * isStrictCompilerOptionEnabled(optionsStrict, "noImplicitThis"); // false
182
- * ```
183
- */
161
+ func GetChildren (node * ast.Node , sourceFile * ast.SourceFile ) []* ast.Node {
162
+ children := make ([]* ast.Node , 0 )
163
+
164
+ pos := node .Pos ()
165
+ node .ForEachChild (func (child * ast.Node ) bool {
166
+ childPos := child .Pos ()
167
+ if pos < childPos {
168
+ scanner := scanner .GetScannerForSourceFile (sourceFile , pos )
169
+ for pos < childPos {
170
+ token := scanner .Token ()
171
+ tokenFullStart := scanner .TokenFullStart ()
172
+ tokenEnd := scanner .TokenEnd ()
173
+ children = append (children , sourceFile .GetOrCreateToken (token , tokenFullStart , tokenEnd , node ))
174
+ pos = tokenEnd
175
+ scanner .Scan ()
176
+ }
177
+ }
178
+
179
+ children = append (children , child )
180
+ pos = child .End ()
181
+ return false
182
+ })
183
+ return children
184
+ }
185
+
186
+ // Checks if a given compiler option is enabled, accounting for whether all flags
187
+ // (except `strictPropertyInitialization`) have been enabled by `strict: true`.
188
+ //
189
+ // @category Compiler Options
190
+ //
191
+ // @example
192
+ //
193
+ // const optionsLenient = {
194
+ // noImplicitAny: true,
195
+ // };
196
+ //
197
+ // isStrictCompilerOptionEnabled(optionsLenient, "noImplicitAny"); // true
198
+ // isStrictCompilerOptionEnabled(optionsLenient, "noImplicitThis"); // false
199
+ //
200
+ // @example
201
+ //
202
+ // const optionsStrict = {
203
+ // noImplicitThis: false,
204
+ // strict: true,
205
+ // };
206
+ //
207
+ // isStrictCompilerOptionEnabled(optionsStrict, "noImplicitAny"); // true
208
+ // isStrictCompilerOptionEnabled(optionsStrict, "noImplicitThis"); // false
184
209
func IsStrictCompilerOptionEnabled (
185
210
options * core.CompilerOptions ,
186
211
option core.Tristate ,
@@ -195,3 +220,125 @@ func IsStrictCompilerOptionEnabled(
195
220
// isStrictCompilerOptionEnabled(options, "strictNullChecks"))
196
221
// );
197
222
}
223
+
224
+ // Port https://github.com/JoshuaKGoldberg/ts-api-utils/blob/491c0374725a5dd64632405efea101f20ed5451f/src/tokens.ts#L34
225
+ //
226
+ // Iterates over all tokens of `node`
227
+ //
228
+ // @category Nodes - Other Utilities
229
+ //
230
+ // @example
231
+ //
232
+ // declare const node: ts.Node;
233
+ //
234
+ // forEachToken(node, (token) => {
235
+ // console.log("Found token:", token.getText());
236
+ // });
237
+ //
238
+ // @param node The node whose tokens should be visited
239
+ // @param callback Is called for every token contained in `node`
240
+ func ForEachToken (node * ast.Node , callback func (token * ast.Node ), sourceFile * ast.SourceFile ) {
241
+ queue := make ([]* ast.Node , 0 )
242
+
243
+ for {
244
+ if ast .IsTokenKind (node .Kind ) {
245
+ callback (node )
246
+ } else {
247
+ children := GetChildren (node , sourceFile )
248
+ for i := len (children ) - 1 ; i >= 0 ; i -- {
249
+ queue = append (queue , children [i ])
250
+ }
251
+ }
252
+
253
+ if len (queue ) == 0 {
254
+ break
255
+ }
256
+
257
+ node = queue [len (queue )- 1 ]
258
+ queue = queue [:len (queue )- 1 ]
259
+ }
260
+ }
261
+
262
+ // Port https://github.com/JoshuaKGoldberg/ts-api-utils/blob/491c0374725a5dd64632405efea101f20ed5451f/src/comments.ts#L37C17-L37C31
263
+ //
264
+ // Iterates over all comments owned by `node` or its children.
265
+ //
266
+ // @category Nodes - Other Utilities
267
+ //
268
+ // @example
269
+ //
270
+ // declare const node: ts.Node;
271
+ //
272
+ // forEachComment(node, (fullText, comment) => {
273
+ // console.log(`Found comment at position ${comment.pos}: '${fullText}'.`);
274
+ // });
275
+ func ForEachComment (node * ast.Node , callback func (comment * ast.CommentRange ), sourceFile * ast.SourceFile ) {
276
+ fullText := sourceFile .Text ()
277
+ notJsx := sourceFile .LanguageVariant != core .LanguageVariantJSX
278
+
279
+ ForEachToken (
280
+ node ,
281
+ func (token * ast.Node ) {
282
+ if token .Pos () == token .End () {
283
+ return
284
+ }
285
+
286
+ if token .Kind != ast .KindJsxText {
287
+ pos := token .Pos ()
288
+ if pos == 0 {
289
+ pos = len (scanner .GetShebang (fullText ))
290
+ }
291
+
292
+ for comment := range scanner .GetLeadingCommentRanges (& ast.NodeFactory {}, fullText , pos ) {
293
+ callback (& comment )
294
+ }
295
+ }
296
+
297
+ if notJsx || canHaveTrailingTrivia (token ) {
298
+ for comment := range scanner .GetTrailingCommentRanges (& ast.NodeFactory {}, fullText , token .End ()) {
299
+ callback (& comment )
300
+ }
301
+ return
302
+ }
303
+ },
304
+ sourceFile ,
305
+ )
306
+ }
307
+
308
+ // Port https://github.com/JoshuaKGoldberg/ts-api-utils/blob/491c0374725a5dd64632405efea101f20ed5451f/src/comments.ts#L84
309
+ //
310
+ // Exclude trailing positions that would lead to scanning for trivia inside `JsxText`.
311
+ // @internal
312
+ func canHaveTrailingTrivia (token * ast.Node ) bool {
313
+ switch token .Kind {
314
+ case ast .KindCloseBraceToken :
315
+ // after a JsxExpression inside a JsxElement's body can only be other JsxChild, but no trivia
316
+ return token .Parent .Kind != ast .KindJsxExpression || ! isJsxElementOrFragment (token .Parent .Parent )
317
+ case ast .KindGreaterThanToken :
318
+ switch token .Parent .Kind {
319
+ case ast .KindJsxClosingElement :
320
+ case ast .KindJsxClosingFragment :
321
+ // there's only trailing trivia if it's the end of the top element
322
+ return ! isJsxElementOrFragment (token .Parent .Parent .Parent )
323
+ case ast .KindJsxOpeningElement :
324
+ // if end is not equal, this is part of the type arguments list. in all other cases it would be inside the element body
325
+ return token .End () != token .Parent .End ()
326
+ case ast .KindJsxOpeningFragment :
327
+ return false // would be inside the fragment
328
+ case ast .KindJsxSelfClosingElement :
329
+ // if end is not equal, this is part of the type arguments list
330
+ // there's only trailing trivia if it's the end of the top element
331
+ return token .End () != token .Parent .End () || ! isJsxElementOrFragment (token .Parent .Parent )
332
+ }
333
+ }
334
+
335
+ return true
336
+ }
337
+
338
+ // Port https://github.com/JoshuaKGoldberg/ts-api-utils/blob/491c0374725a5dd64632405efea101f20ed5451f/src/comments.ts#L118
339
+ //
340
+ // Test if a node is a `JsxElement` or `JsxFragment`.
341
+ // @internal
342
+ func isJsxElementOrFragment (node * ast.Node ) bool {
343
+ return node .Kind == ast .KindJsxElement || node .Kind == ast .KindJsxFragment
344
+ }
0 commit comments