# How to Access SourceFile and Program Objects in TSSLint RuleContext for AST Traversal

> Access TSSLint SourceFile and Program objects in RuleContext for deep AST traversal and type-aware analysis. Discover how TSSLint empowers advanced linting.

- Repository: [Johnson Chu/tsslint](https://github.com/johnsoncodehk/tsslint)
- Tags: how-to-guide
- Published: 2026-03-04

---

**TSSLint exposes TypeScript's `SourceFile` and `Program` objects directly through the `RuleContext` parameter, allowing rules to perform deep AST traversal and type-aware analysis without external imports.**

TSSLint is a TypeScript-first linter built on top of the official compiler API in the `johnsoncodehk/tsslint` repository. When you define custom lint rules, the framework automatically injects a **RuleContext** object that contains everything needed for sophisticated code analysis, including the current source file and entire program instance for accessing the type checker.

## RuleContext Properties for TypeScript API Access

The `RuleContext` interface bundles four essential properties for rule authors. These are defined in [[`packages/types/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/types/index.ts)](https://github.com/johnsoncodehk/tsslint/blob/master/packages/types/index.ts#L44-L48):

- **`typescript`**: The full TypeScript namespace (`typeof import('typescript')`), giving you access to all utility functions like `ts.forEachChild` and `ts.isIdentifier`.
- **`file`**: The `ts.SourceFile` instance representing the current file being linted.
- **`program`**: The `ts.Program` instance containing the entire project context, type checker, and compiler options.
- **`report`**: A helper function to emit diagnostics with optional quick fixes.

This design eliminates the need to manually import TypeScript or create program instances in your rules.

## Traversing the AST with SourceFile

The `file` property serves as the entry point for AST traversal. Since it is a standard `ts.SourceFile`, you can use TypeScript's built-in visitor functions to walk the node tree.

Here is a complete example demonstrating how to traverse the AST and flag specific identifiers:

```typescript
import { defineRule } from '@tsslint/config';

export default defineRule(({ typescript: ts, file, program, report }) => {
  // Walk the AST of the current file
  ts.forEachChild(file, function walk(node) {
    // Example: flag any use of `eval`
    if (ts.isIdentifier(node) && node.text === 'eval') {
      report('Avoid using eval()', node.getStart(file), node.getEnd())
        .withFix('Remove eval', () => [{
          fileName: file.fileName,
          textChanges: [{ 
            newText: '', 
            span: { 
              start: node.getStart(file), 
              length: node.getWidth(file) 
            } 
          }],
        }]);
    }

    // Continue walking deeper
    ts.forEachChild(node, walk);
  });
});

```

This pattern is demonstrated in the repository's built-in example at [[`fixtures/noConsoleRule.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/fixtures/noConsoleRule.ts)](https://github.com/johnsoncodehk/tsslint/blob/master/fixtures/noConsoleRule.ts#L3-L14), which shows how to destructure the context and access these objects for AST inspection.

## Accessing Type Information via Program

While `file` provides the syntax tree, the `program` property enables **semantic analysis**. By calling `program.getTypeChecker()`, you gain access to type information, symbol resolution, and compiler diagnostics.

```typescript
export default defineRule(({ typescript: ts, file, program, report }) => {
  const checker = program.getTypeChecker();
  
  ts.forEachChild(file, function walk(node) {
    if (ts.isCallExpression(node)) {
      const signature = checker.getResolvedSignature(node);
      const returnType = checker.getReturnTypeOfSignature(signature);
      
      // Perform type-level checks here
      if (checker.typeToString(returnType) === 'any') {
        report('Avoid implicit any return type', node.getStart(file), node.getEnd());
      }
    }
    ts.forEachChild(node, walk);
  });
});

```

The `program` object also exposes `getCompilerOptions()`, allowing rules to adapt behavior based on project configuration such as strict mode settings or path mappings.

## How the Context is Constructed

Understanding the internal construction of `RuleContext` helps when debugging complex rules. The context object is assembled in two key locations:

1. **Context Builder**: [[`packages/config/lib/tsl.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/config/lib/tsl.ts)](https://github.com/johnsoncodehk/tsslint/blob/master/packages/config/lib/tsl.ts) constructs the base context object, injecting `program`, `file`, and the `typescript` namespace.
2. **Rule Execution**: [[`packages/core/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/core/index.ts)](https://github.com/johnsoncodehk/tsslint/blob/master/packages/core/index.ts) obtains the `Program` from the TypeScript language service and creates the final `RuleContext` for each file being analyzed.

The `defineRule` function exported from [[`packages/config/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/config/index.ts)](https://github.com/johnsoncodehk/tsslint/blob/master/packages/config/index.ts) wraps your rule function and ensures these parameters are passed correctly at runtime.

## Summary

- **RuleContext** exposes `file` (SourceFile), `program` (Program), `typescript` (TS namespace), and `report` (diagnostic emitter) to every rule.
- Use `file` with `ts.forEachChild()` to traverse the AST and inspect syntax nodes.
- Access `program.getTypeChecker()` for semantic analysis, type resolution, and symbol information.
- The context is type-defined in [`packages/types/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/types/index.ts) and instantiated in [`packages/config/lib/tsl.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/config/lib/tsl.ts) and [`packages/core/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/core/index.ts).

## Frequently Asked Questions

### How do I access the TypeScript type checker in a TSSLint rule?

Access the type checker by calling `program.getTypeChecker()` on the `program` object destructured from the `RuleContext`. This returns a `TypeChecker` instance that can resolve types, symbols, and signatures for any node in the `file` being analyzed.

### What is the difference between file and program in RuleContext?

The `file` property is the specific `ts.SourceFile` currently being linted, used for AST traversal and obtaining node positions. The `program` property represents the entire TypeScript project context, containing all source files, the type checker, and compiler options.

### Where is the RuleContext interface defined in TSSLint?

The `RuleContext` interface is defined in [[`packages/types/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/types/index.ts)](https://github.com/johnsoncodehk/tsslint/blob/master/packages/types/index.ts#L44-L48). This file specifies the exact types for `typescript`, `program`, `file`, and `report` properties available to every rule.

### Can I use Program to access compiler options within a rule?

Yes. Call `program.getCompilerOptions()` to access the resolved compiler options for the project. This allows rules to adapt their behavior based on configuration flags like `strict`, `noImplicitAny`, or custom path mappings defined in [`tsconfig.json`](https://github.com/johnsoncodehk/tsslint/blob/main/tsconfig.json).