or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

ast-utils.mdeslint-utils.mdindex.mdjson-schema.mdts-eslint.mdts-utils.md

ast-utils.mddocs/

0

# AST Utilities

1

2

The `ASTUtils` namespace provides comprehensive utilities for Abstract Syntax Tree manipulation and analysis in TypeScript ESLint rules.

3

4

## Import

5

6

```typescript { .api }

7

import { ASTUtils } from '@typescript-eslint/utils';

8

```

9

10

## Node Type Predicates

11

12

### Basic Type Checking

13

14

```typescript { .api }

15

// Generic node type checker

16

function isNodeOfType<NodeType extends AST_NODE_TYPES>(

17

nodeType: NodeType

18

): (node: TSESTree.Node | null | undefined) => node is Extract<TSESTree.Node, { type: NodeType }>;

19

20

// Multiple node types checker

21

function isNodeOfTypes<NodeTypes extends readonly AST_NODE_TYPES[]>(

22

nodeTypes: NodeTypes

23

): (node: TSESTree.Node | null | undefined) => node is Extract<TSESTree.Node, { type: NodeTypes[number] }>;

24

25

// Usage examples

26

const isFunctionDeclaration = ASTUtils.isNodeOfType(AST_NODE_TYPES.FunctionDeclaration);

27

const isVariableOrFunction = ASTUtils.isNodeOfTypes([

28

AST_NODE_TYPES.VariableDeclaration,

29

AST_NODE_TYPES.FunctionDeclaration

30

]);

31

32

if (isFunctionDeclaration(node)) {

33

// node is typed as TSESTree.FunctionDeclaration

34

console.log(node.id?.name);

35

}

36

```

37

38

### Conditional Type Checking

39

40

```typescript { .api }

41

// Node type with additional conditions

42

function isNodeOfTypeWithConditions<

43

NodeType extends AST_NODE_TYPES,

44

ExtractedNode extends Extract<TSESTree.Node, { type: NodeType }>,

45

Conditions extends Partial<ExtractedNode>

46

>(

47

nodeType: NodeType,

48

conditions: Conditions

49

): (node: TSESTree.Node | null | undefined) => node is ExtractedNode & Conditions;

50

51

// Usage example

52

const isAsyncFunction = ASTUtils.isNodeOfTypeWithConditions(

53

AST_NODE_TYPES.FunctionDeclaration,

54

{ async: true }

55

);

56

57

if (isAsyncFunction(node)) {

58

// node is TSESTree.FunctionDeclaration with async: true

59

}

60

```

61

62

### Function Predicates

63

64

```typescript { .api }

65

// Check for any function node type

66

function isFunction(node: TSESTree.Node | null | undefined): node is TSESTree.Function;

67

68

// Check for TypeScript function type

69

function isFunctionType(node: TSESTree.Node | null | undefined): node is TSESTree.TSFunctionType;

70

71

// Check for function or function type

72

function isFunctionOrFunctionType(

73

node: TSESTree.Node | null | undefined

74

): node is TSESTree.Function | TSESTree.TSFunctionType;

75

76

// Specific TypeScript function types

77

function isTSFunctionType(node: TSESTree.Node | null | undefined): node is TSESTree.TSFunctionType;

78

function isTSConstructorType(node: TSESTree.Node | null | undefined): node is TSESTree.TSConstructorType;

79

80

// Usage examples

81

if (ASTUtils.isFunction(node)) {

82

// Handle arrow functions, function declarations, function expressions

83

const params = node.params;

84

const body = node.body;

85

}

86

87

if (ASTUtils.isFunctionType(node)) {

88

// Handle TypeScript function type annotations

89

const returnType = node.returnType;

90

}

91

```

92

93

### Expression Predicates

94

95

```typescript { .api }

96

// Optional chaining call expressions

97

function isOptionalCallExpression(node: TSESTree.Node | null | undefined): node is TSESTree.CallExpression & { optional: true };

98

99

// Logical OR expressions

100

function isLogicalOrOperator(node: TSESTree.Node | null | undefined): node is TSESTree.LogicalExpression & { operator: '||' };

101

102

// Type assertions

103

function isTypeAssertion(node: TSESTree.Node | null | undefined): node is TSESTree.TSTypeAssertion | TSESTree.TSAsExpression;

104

105

// Await expressions

106

function isAwaitExpression(node: TSESTree.Node | null | undefined): node is TSESTree.AwaitExpression;

107

108

// Usage examples

109

if (ASTUtils.isOptionalCallExpression(node)) {

110

// Handle obj?.method() calls

111

const callee = node.callee; // has optional property

112

}

113

114

if (ASTUtils.isTypeAssertion(node)) {

115

// Handle both <Type>expr and expr as Type

116

const expression = node.expression;

117

}

118

```

119

120

### Statement and Declaration Predicates

121

122

```typescript { .api }

123

// Variable declarators

124

function isVariableDeclarator(node: TSESTree.Node | null | undefined): node is TSESTree.VariableDeclarator;

125

126

// Loop statements

127

function isLoop(node: TSESTree.Node | null | undefined): node is TSESTree.DoWhileStatement | TSESTree.ForStatement | TSESTree.ForInStatement | TSESTree.ForOfStatement | TSESTree.WhileStatement;

128

129

// Identifiers

130

function isIdentifier(node: TSESTree.Node | null | undefined): node is TSESTree.Identifier;

131

132

// Usage examples

133

if (ASTUtils.isLoop(node)) {

134

// Handle all loop types uniformly

135

const body = node.body;

136

}

137

138

if (ASTUtils.isVariableDeclarator(node)) {

139

// Handle variable declarations

140

const id = node.id;

141

const init = node.init;

142

}

143

```

144

145

### Class and Method Predicates

146

147

```typescript { .api }

148

// Class or type element nodes

149

function isClassOrTypeElement(node: TSESTree.Node | null | undefined): node is TSESTree.ClassElement | TSESTree.TypeElement;

150

151

// Constructor methods

152

function isConstructor(node: TSESTree.Node | null | undefined): node is TSESTree.MethodDefinition & { kind: 'constructor' };

153

154

// Setter methods

155

function isSetter(node: TSESTree.Node | undefined): node is TSESTree.MethodDefinition & { kind: 'set' } | TSESTree.PropertyDefinition & { kind: 'set' };

156

157

// Usage examples

158

if (ASTUtils.isConstructor(node)) {

159

// Handle constructor methods specifically

160

const params = node.value.params;

161

}

162

163

if (ASTUtils.isSetter(node)) {

164

// Handle setter methods

165

const key = node.key;

166

}

167

```

168

169

## Token Predicates

170

171

### Punctuator Tokens

172

173

```typescript { .api }

174

// Optional chaining punctuator (?.)

175

function isOptionalChainPunctuator(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '?.' };

176

function isNotOptionalChainPunctuator(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: '?.' }>;

177

178

// Non-null assertion punctuator (!)

179

function isNonNullAssertionPunctuator(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '!' };

180

function isNotNonNullAssertionPunctuator(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.PunctuatorToken & { value: '!' }>;

181

182

// Common punctuators

183

function isArrowToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '=>' };

184

function isCommaToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: ',' };

185

function isSemicolonToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: ';' };

186

function isColonToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: ':' };

187

188

// Usage examples

189

const tokens = sourceCode.getTokens(node);

190

const arrowToken = tokens.find(ASTUtils.isArrowToken);

191

if (arrowToken) {

192

// Handle arrow function tokens

193

}

194

```

195

196

### Bracket and Brace Tokens

197

198

```typescript { .api }

199

// Opening tokens

200

function isOpeningBraceToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '{' };

201

function isOpeningBracketToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '[' };

202

function isOpeningParenToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '(' };

203

204

// Closing tokens

205

function isClosingBraceToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: '}' };

206

function isClosingBracketToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: ']' };

207

function isClosingParenToken(token: TSESTree.Token | null | undefined): token is TSESTree.PunctuatorToken & { value: ')' };

208

209

// Negated versions available for all punctuators

210

function isNotOpeningBraceToken(token: TSESTree.Token | null | undefined): boolean;

211

function isNotClosingParenToken(token: TSESTree.Token | null | undefined): boolean;

212

// ... (similar pattern for all punctuators)

213

214

// Usage examples

215

const openBrace = sourceCode.getTokenAfter(node, ASTUtils.isOpeningBraceToken);

216

const closeBrace = sourceCode.getTokenAfter(node, ASTUtils.isClosingBraceToken);

217

```

218

219

### Keyword Tokens

220

221

```typescript { .api }

222

// Keyword token predicates

223

function isAwaitKeyword(token: TSESTree.Token | null | undefined): token is TSESTree.KeywordToken & { value: 'await' };

224

function isTypeKeyword(token: TSESTree.Token | null | undefined): token is TSESTree.KeywordToken & { value: 'type' };

225

function isImportKeyword(token: TSESTree.Token | null | undefined): token is TSESTree.KeywordToken & { value: 'import' };

226

227

// Usage examples

228

const awaitToken = sourceCode.getFirstToken(node, ASTUtils.isAwaitKeyword);

229

if (awaitToken) {

230

// Handle await keyword positioning

231

}

232

```

233

234

### Comment Tokens

235

236

```typescript { .api }

237

// Comment token predicates

238

function isCommentToken(token: TSESTree.Token | null | undefined): token is TSESTree.Comment;

239

function isNotCommentToken(token: TSESTree.Token | null | undefined): token is Exclude<TSESTree.Token, TSESTree.Comment>;

240

241

// Usage examples

242

const nonCommentTokens = sourceCode.getTokens(node).filter(ASTUtils.isNotCommentToken);

243

```

244

245

## Token Conditions

246

247

### Advanced Token Filtering

248

249

```typescript { .api }

250

// Token type with conditions

251

function isTokenOfTypeWithConditions<

252

TokenType extends AST_TOKEN_TYPES,

253

ExtractedToken extends Extract<TSESTree.Token, { type: TokenType }>,

254

Conditions extends Partial<ExtractedToken>

255

>(

256

tokenType: TokenType,

257

conditions: Conditions

258

): (token: TSESTree.Token | null | undefined) => token is ExtractedToken & Conditions;

259

260

// Negated token conditions

261

function isNotTokenOfTypeWithConditions<

262

TokenType extends AST_TOKEN_TYPES,

263

ExtractedToken extends Extract<TSESTree.Token, { type: TokenType }>,

264

Conditions extends Partial<ExtractedToken>

265

>(

266

tokenType: TokenType,

267

conditions: Conditions

268

): (token: TSESTree.Token | null | undefined) => token is Exclude<TSESTree.Token, ExtractedToken & Conditions>;

269

270

// Usage examples

271

const isSpecificPunctuator = ASTUtils.isTokenOfTypeWithConditions(

272

AST_TOKEN_TYPES.Punctuator,

273

{ value: '=>' as const }

274

);

275

276

const isNotArrowFunction = ASTUtils.isNotTokenOfTypeWithConditions(

277

AST_TOKEN_TYPES.Punctuator,

278

{ value: '=>' as const }

279

);

280

```

281

282

## Utility Functions

283

284

### Line Analysis

285

286

```typescript { .api }

287

// Check if tokens are on the same line

288

function isTokenOnSameLine(

289

left: TSESTree.Node | TSESTree.Token,

290

right: TSESTree.Node | TSESTree.Token

291

): boolean;

292

293

// Line break matcher regex

294

const LINEBREAK_MATCHER: RegExp; // /\r\n|[\r\n\u2028\u2029]/

295

296

// Usage examples

297

if (ASTUtils.isTokenOnSameLine(node, nextToken)) {

298

// Tokens are on the same line

299

}

300

301

const hasLineBreak = ASTUtils.LINEBREAK_MATCHER.test(sourceCode.getText(node));

302

```

303

304

## ESLint Integration Utilities

305

306

### Function Analysis

307

308

```typescript { .api }

309

// Get function head location for reporting

310

function getFunctionHeadLocation(

311

node: TSESTree.Function,

312

sourceCode: TSESLint.SourceCode

313

): TSESTree.SourceLocation;

314

315

// Get function name with kind description

316

function getFunctionNameWithKind(

317

node: TSESTree.Function,

318

sourceCode?: TSESLint.SourceCode

319

): string;

320

321

// Usage examples

322

const location = ASTUtils.getFunctionHeadLocation(node, context.getSourceCode());

323

context.report({

324

loc: location,

325

messageId: 'error'

326

});

327

328

const functionDescription = ASTUtils.getFunctionNameWithKind(node);

329

// Returns strings like "function 'myFunc'", "arrow function", "method 'myMethod'"

330

```

331

332

### Property Analysis

333

334

```typescript { .api }

335

// Get property name from property-like nodes

336

function getPropertyName(

337

node: TSESTree.Property | TSESTree.MethodDefinition | TSESTree.PropertyDefinition,

338

initialScope?: TSESLint.Scope.Scope

339

): string | null;

340

341

// Usage examples

342

const propName = ASTUtils.getPropertyName(node);

343

if (propName) {

344

// Handle known property names

345

}

346

```

347

348

### Static Value Analysis

349

350

```typescript { .api }

351

// Get static value if determinable

352

function getStaticValue(

353

node: TSESTree.Node,

354

initialScope?: TSESLint.Scope.Scope

355

): { value: unknown } | null;

356

357

// Get string value if constant

358

function getStringIfConstant(

359

node: TSESTree.Node,

360

initialScope?: TSESLint.Scope.Scope

361

): string | null;

362

363

// Usage examples

364

const staticValue = ASTUtils.getStaticValue(node);

365

if (staticValue) {

366

console.log('Static value:', staticValue.value);

367

}

368

369

const stringValue = ASTUtils.getStringIfConstant(node);

370

if (stringValue) {

371

// Handle constant string values

372

}

373

```

374

375

### Side Effect Analysis

376

377

```typescript { .api }

378

// Check if node has side effects

379

function hasSideEffect(

380

node: TSESTree.Node,

381

sourceCode: TSESLint.SourceCode,

382

options?: { considerGetters?: boolean; considerImplicitTypeConversion?: boolean }

383

): boolean;

384

385

// Usage examples

386

if (!ASTUtils.hasSideEffect(node, context.getSourceCode())) {

387

// Safe to remove or reorder this node

388

}

389

```

390

391

### Parentheses Analysis

392

393

```typescript { .api }

394

// Check if node is parenthesized (overloaded)

395

function isParenthesized(node: TSESTree.Node, sourceCode: TSESLint.SourceCode): boolean;

396

function isParenthesized(times: number, node: TSESTree.Node, sourceCode: TSESLint.SourceCode): boolean;

397

398

// Usage examples

399

if (ASTUtils.isParenthesized(node, sourceCode)) {

400

// Node has parentheses around it

401

}

402

403

if (ASTUtils.isParenthesized(2, node, sourceCode)) {

404

// Node has at least 2 levels of parentheses: ((node))

405

}

406

```

407

408

## Pattern Matching

409

410

### PatternMatcher Class

411

412

```typescript { .api }

413

class PatternMatcher {

414

constructor(pattern: RegExp, options?: { escaped?: boolean });

415

416

// Execute pattern matching

417

execAll(str: string): IterableIterator<RegExpExecArray>;

418

419

// Test if pattern matches

420

test(str: string): boolean;

421

422

// Replace matches in string

423

[Symbol.replace](str: string, replacer: string | ((match: string, ...args: any[]) => string)): string;

424

}

425

426

// Usage examples

427

const matcher = new ASTUtils.PatternMatcher(/function\s+(\w+)/g);

428

429

for (const match of matcher.execAll(sourceCode.getText())) {

430

console.log('Found function:', match[1]);

431

}

432

```

433

434

## Reference Tracking

435

436

### ReferenceTracker Class

437

438

```typescript { .api }

439

class ReferenceTracker {

440

constructor(globalScope: TSESLint.Scope.Scope, options?: {

441

mode?: 'strict' | 'legacy';

442

globalObjectNames?: readonly string[];

443

});

444

445

// Iterate over global references

446

iterateGlobalReferences<T>(

447

traceMap: ReferenceTracker.TraceMap<T>

448

): IterableIterator<ReferenceTracker.FoundReference<T>>;

449

450

// Iterate over CommonJS references

451

iterateCjsReferences<T>(

452

traceMap: ReferenceTracker.TraceMap<T>

453

): IterableIterator<ReferenceTracker.FoundReference<T>>;

454

455

// Iterate over ES module references

456

iterateEsModuleReferences<T>(

457

traceMap: ReferenceTracker.TraceMap<T>

458

): IterableIterator<ReferenceTracker.FoundReference<T>>;

459

}

460

461

// Usage examples

462

const tracker = new ASTUtils.ReferenceTracker(context.getScope());

463

464

const traceMap = {

465

React: {

466

createElement: { [ASTUtils.ReferenceTracker.READ]: true }

467

}

468

};

469

470

for (const { node, path } of tracker.iterateGlobalReferences(traceMap)) {

471

// Handle React.createElement references

472

}

473

```

474

475

## Scope Analysis

476

477

### Variable and Scope Utilities

478

479

```typescript { .api }

480

// Find variable by name or node

481

function findVariable(

482

initialScope: TSESLint.Scope.Scope,

483

nameOrNode: string | TSESTree.Identifier

484

): TSESLint.Scope.Variable | null;

485

486

// Get innermost scope containing node

487

function getInnermostScope(

488

initialScope: TSESLint.Scope.Scope,

489

node: TSESTree.Node

490

): TSESLint.Scope.Scope;

491

492

// Usage examples

493

const variable = ASTUtils.findVariable(context.getScope(), 'myVar');

494

if (variable) {

495

// Check variable references and definitions

496

const refs = variable.references;

497

const defs = variable.defs;

498

}

499

500

const innerScope = ASTUtils.getInnermostScope(context.getScope(), node);

501

// Get scope that directly contains the node

502

```

503

504

## Complete Usage Example

505

506

```typescript { .api }

507

import { ESLintUtils, ASTUtils, TSESTree } from '@typescript-eslint/utils';

508

509

const createRule = ESLintUtils.RuleCreator(name => `https://example.com/${name}`);

510

511

export default createRule({

512

name: 'comprehensive-ast-example',

513

meta: {

514

type: 'suggestion',

515

docs: { description: 'Comprehensive AST utilities example' },

516

messages: {

517

optionalCall: 'Consider using optional chaining',

518

parenthesized: 'Unnecessary parentheses detected',

519

sideEffect: 'Expression has side effects'

520

},

521

schema: []

522

},

523

defaultOptions: [],

524

create(context) {

525

const sourceCode = context.getSourceCode();

526

527

return {

528

CallExpression(node) {

529

// Check for optional calls

530

if (ASTUtils.isOptionalCallExpression(node)) {

531

context.report({

532

node,

533

messageId: 'optionalCall'

534

});

535

}

536

537

// Check if parenthesized

538

if (ASTUtils.isParenthesized(node, sourceCode)) {

539

context.report({

540

node,

541

messageId: 'parenthesized'

542

});

543

}

544

545

// Check for side effects

546

if (ASTUtils.hasSideEffect(node, sourceCode)) {

547

context.report({

548

node,

549

messageId: 'sideEffect'

550

});

551

}

552

},

553

554

'Program:exit'() {

555

// Use reference tracker

556

const tracker = new ASTUtils.ReferenceTracker(context.getScope());

557

const traceMap = {

558

console: {

559

log: { [ASTUtils.ReferenceTracker.READ]: true }

560

}

561

};

562

563

for (const { node } of tracker.iterateGlobalReferences(traceMap)) {

564

// Handle console.log references

565

}

566

}

567

};

568

}

569

});

570

```