or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

ast-traversal.mdcode-analysis.mdcontrol-flow.mdindex.mdnode-typeguards.mdtext-processing.mdtype-guards.mdtype-utilities.mdvariable-usage.md

ast-traversal.mddocs/

0

# AST Traversal and Analysis

1

2

Comprehensive utilities for navigating, analyzing, and manipulating TypeScript AST nodes. These functions provide efficient traversal patterns, token iteration, comment processing, position mapping, and node relationship analysis.

3

4

## Capabilities

5

6

### Token Iteration

7

8

Utilities for iterating through tokens and trivia in TypeScript source code.

9

10

```typescript { .api }

11

/**

12

* Iterate through all tokens in a node

13

* @param node - AST node to traverse

14

* @param cb - Callback function called for each token

15

* @param sourceFile - Source file (optional, inferred from node if not provided)

16

*/

17

function forEachToken(node: ts.Node, cb: (node: ts.Node) => void, sourceFile?: ts.SourceFile): void;

18

19

/**

20

* Iterate through all tokens including trivia (whitespace, comments)

21

* @param node - AST node to traverse

22

* @param cb - Callback function called for each token with trivia information

23

* @param sourceFile - Source file (optional, inferred from node if not provided)

24

*/

25

function forEachTokenWithTrivia(node: ts.Node, cb: ForEachTokenCallback, sourceFile?: ts.SourceFile): void;

26

27

/**

28

* Callback type for token iteration with trivia

29

* @param fullText - Full text of the source file

30

* @param kind - Syntax kind of the token

31

* @param range - Text range of the token

32

* @param parent - Parent node of the token

33

*/

34

type ForEachTokenCallback = (fullText: string, kind: ts.SyntaxKind, range: ts.TextRange, parent: ts.Node) => void;

35

```

36

37

### Comment Processing

38

39

Utilities for working with comments in TypeScript source code.

40

41

```typescript { .api }

42

/**

43

* Iterate through all comments in a node

44

* @param node - AST node to search for comments

45

* @param cb - Callback function called for each comment

46

* @param sourceFile - Source file (optional, inferred from node if not provided)

47

*/

48

function forEachComment(node: ts.Node, cb: ForEachCommentCallback, sourceFile?: ts.SourceFile): void;

49

50

/**

51

* Callback type for comment iteration

52

* @param fullText - Full text of the source file

53

* @param comment - Comment range information

54

*/

55

type ForEachCommentCallback = (fullText: string, comment: ts.CommentRange) => void;

56

57

/**

58

* Get comment at specific position

59

* @param sourceFile - Source file to search

60

* @param pos - Position to check for comments

61

* @param parent - Optional parent node to limit search scope

62

* @returns Comment range if found, undefined otherwise

63

*/

64

function getCommentAtPosition(sourceFile: ts.SourceFile, pos: number, parent?: ts.Node): ts.CommentRange | undefined;

65

66

/**

67

* Check if position is inside a comment

68

* @param sourceFile - Source file to check

69

* @param pos - Position to check

70

* @param parent - Optional parent node to limit search scope

71

* @returns true if position is within a comment

72

*/

73

function isPositionInComment(sourceFile: ts.SourceFile, pos: number, parent?: ts.Node): boolean;

74

75

/**

76

* Extract text content from a comment range

77

* @param sourceText - Full source text

78

* @param comment - Comment range to extract

79

* @returns Comment text without comment syntax markers

80

*/

81

function commentText(sourceText: string, comment: ts.CommentRange): string;

82

```

83

84

### Node Navigation

85

86

Utilities for navigating between related AST nodes.

87

88

```typescript { .api }

89

/**

90

* Get the previous token before a node

91

* @param node - Starting node

92

* @param sourceFile - Source file (optional, inferred from node if not provided)

93

* @returns Previous token or undefined if none exists

94

*/

95

function getPreviousToken(node: ts.Node, sourceFile?: ts.SourceFile): ts.Node | undefined;

96

97

/**

98

* Get the next token after a node

99

* @param node - Starting node

100

* @param sourceFile - Source file (optional, inferred from node if not provided)

101

* @returns Next token or undefined if none exists

102

*/

103

function getNextToken(node: ts.Node, sourceFile?: ts.SourceFile): ts.Node | undefined;

104

105

/**

106

* Get token at or following a specific position

107

* @param parent - Parent node to search within

108

* @param pos - Position to find token at

109

* @param sourceFile - Source file (optional, inferred from parent if not provided)

110

* @param allowJsDoc - Whether to include JSDoc comments in search

111

* @returns Token at position or undefined if none found

112

*/

113

function getTokenAtPosition(parent: ts.Node, pos: number, sourceFile?: ts.SourceFile, allowJsDoc?: boolean): ts.Node | undefined;

114

115

/**

116

* Find child node of specific syntax kind

117

* @param node - Parent node to search

118

* @param kind - Syntax kind to find

119

* @param sourceFile - Source file (optional, inferred from node if not provided)

120

* @returns Child token of specified kind or undefined

121

*/

122

function getChildOfKind<T extends ts.SyntaxKind>(node: ts.Node, kind: T, sourceFile?: ts.SourceFile): ts.Token<T> | undefined;

123

```

124

125

### Statement Navigation

126

127

Utilities for navigating between statements in block-like structures.

128

129

```typescript { .api }

130

/**

131

* Get the previous statement in a block

132

* @param statement - Current statement

133

* @returns Previous statement or undefined if first statement

134

*/

135

function getPreviousStatement(statement: ts.Statement): ts.Statement | undefined;

136

137

/**

138

* Get the next statement in a block

139

* @param statement - Current statement

140

* @returns Next statement or undefined if last statement

141

*/

142

function getNextStatement(statement: ts.Statement): ts.Statement | undefined;

143

```

144

145

### Position-based Analysis

146

147

Utilities for finding nodes and analyzing positions within source code.

148

149

```typescript { .api }

150

/**

151

* Get the deepest AST node at a specific position

152

* @param node - Root node to search from

153

* @param pos - Position to find node at

154

* @returns Deepest node at position or undefined if position is outside node range

155

*/

156

function getAstNodeAtPosition(node: ts.Node, pos: number): ts.Node | undefined;

157

158

/**

159

* Get wrapped node at position (for converted AST)

160

* @param wrap - Wrapped node to search

161

* @param pos - Position to find node at

162

* @returns Wrapped node at position or undefined

163

*/

164

function getWrappedNodeAtPosition(wrap: NodeWrap, pos: number): NodeWrap | undefined;

165

```

166

167

### Syntax Kind Utilities

168

169

Utilities for checking and categorizing syntax kinds.

170

171

```typescript { .api }

172

/**

173

* Check if syntax kind represents a token

174

* @param kind - Syntax kind to check

175

* @returns true if kind is a token

176

*/

177

function isTokenKind(kind: ts.SyntaxKind): boolean;

178

179

/**

180

* Check if syntax kind represents a node

181

* @param kind - Syntax kind to check

182

* @returns true if kind is a node

183

*/

184

function isNodeKind(kind: ts.SyntaxKind): boolean;

185

186

/**

187

* Check if syntax kind represents an assignment operator

188

* @param kind - Syntax kind to check

189

* @returns true if kind is an assignment operator

190

*/

191

function isAssignmentKind(kind: ts.SyntaxKind): boolean;

192

193

/**

194

* Check if syntax kind represents a type node

195

* @param kind - Syntax kind to check

196

* @returns true if kind is a type node

197

*/

198

function isTypeNodeKind(kind: ts.SyntaxKind): boolean;

199

200

/**

201

* Check if syntax kind represents a JSDoc node

202

* @param kind - Syntax kind to check

203

* @returns true if kind is a JSDoc node

204

*/

205

function isJsDocKind(kind: ts.SyntaxKind): boolean;

206

207

/**

208

* Check if syntax kind represents a keyword

209

* @param kind - Syntax kind to check

210

* @returns true if kind is a keyword

211

*/

212

function isKeywordKind(kind: ts.SyntaxKind): boolean;

213

```

214

215

### AST Conversion

216

217

Utilities for converting AST to wrapped format for advanced analysis.

218

219

```typescript { .api }

220

/**

221

* Convert TypeScript AST to wrapped format with navigation aids

222

* @param sourceFile - Source file to convert

223

* @returns Converted AST with wrapped nodes and flat array

224

*/

225

function convertAst(sourceFile: ts.SourceFile): ConvertedAst;

226

227

/**

228

* Wrapped node with navigation properties

229

*/

230

interface NodeWrap {

231

node: ts.Node;

232

kind: ts.SyntaxKind;

233

children: NodeWrap[];

234

next?: NodeWrap;

235

skip?: NodeWrap;

236

parent?: NodeWrap;

237

}

238

239

/**

240

* Wrapped AST root node

241

*/

242

interface WrappedAst extends NodeWrap {

243

node: ts.SourceFile;

244

next: NodeWrap;

245

skip: undefined;

246

parent: undefined;

247

}

248

249

/**

250

* Result of AST conversion

251

*/

252

interface ConvertedAst {

253

wrapped: WrappedAst;

254

flat: ReadonlyArray<ts.Node>;

255

}

256

```

257

258

**Usage Examples:**

259

260

```typescript

261

import * as ts from "typescript";

262

import {

263

forEachToken,

264

forEachComment,

265

getPreviousToken,

266

getAstNodeAtPosition,

267

convertAst

268

} from "tsutils/util";

269

270

// Token iteration example

271

function analyzeTokens(sourceFile: ts.SourceFile) {

272

forEachToken(sourceFile, (token) => {

273

console.log(`Token: ${ts.SyntaxKind[token.kind]} at ${token.pos}-${token.end}`);

274

275

if (token.kind === ts.SyntaxKind.Identifier) {

276

const identifier = token as ts.Identifier;

277

console.log(` Identifier text: ${identifier.text}`);

278

}

279

});

280

}

281

282

// Comment analysis example

283

function analyzeComments(sourceFile: ts.SourceFile) {

284

forEachComment(sourceFile, (fullText, comment) => {

285

const commentText = fullText.substring(comment.pos, comment.end);

286

console.log(`Comment: ${commentText}`);

287

console.log(` Type: ${comment.kind === ts.SyntaxKind.SingleLineCommentTrivia ? 'single-line' : 'multi-line'}`);

288

});

289

}

290

291

// Navigation example

292

function analyzeNodeContext(node: ts.Node, sourceFile: ts.SourceFile) {

293

const previousToken = getPreviousToken(node, sourceFile);

294

const nextToken = getNextToken(node, sourceFile);

295

296

console.log(`Node: ${ts.SyntaxKind[node.kind]}`);

297

console.log(` Previous token: ${previousToken ? ts.SyntaxKind[previousToken.kind] : 'none'}`);

298

console.log(` Next token: ${nextToken ? ts.SyntaxKind[nextToken.kind] : 'none'}`);

299

}

300

301

// Position-based analysis example

302

function findNodeAtCursor(sourceFile: ts.SourceFile, cursorPosition: number) {

303

const nodeAtPosition = getAstNodeAtPosition(sourceFile, cursorPosition);

304

305

if (nodeAtPosition) {

306

console.log(`Node at cursor: ${ts.SyntaxKind[nodeAtPosition.kind]}`);

307

console.log(` Text: ${nodeAtPosition.getText(sourceFile)}`);

308

console.log(` Range: ${nodeAtPosition.pos}-${nodeAtPosition.end}`);

309

}

310

}

311

312

// AST conversion example

313

function analyzeWithWrappedAst(sourceFile: ts.SourceFile) {

314

const { wrapped, flat } = convertAst(sourceFile);

315

316

console.log(`Total nodes: ${flat.length}`);

317

318

// Navigate using wrapped structure

319

let current = wrapped.next;

320

while (current) {

321

console.log(`Node: ${ts.SyntaxKind[current.kind]}`);

322

current = current.next;

323

}

324

}

325

```