How to Access SourceFile and Program Objects in TSSLint RuleContext for AST Traversal
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/master/packages/types/index.ts#L44-L48):
typescript: The full TypeScript namespace (typeof import('typescript')), giving you access to all utility functions likets.forEachChildandts.isIdentifier.file: Thets.SourceFileinstance representing the current file being linted.program: Thets.Programinstance 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:
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/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.
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:
- Context Builder: [
packages/config/lib/tsl.ts](https://github.com/johnsoncodehk/tsslint/blob/master/packages/config/lib/tsl.ts) constructs the base context object, injectingprogram,file, and thetypescriptnamespace. - Rule Execution: [
packages/core/index.ts](https://github.com/johnsoncodehk/tsslint/blob/master/packages/core/index.ts) obtains theProgramfrom the TypeScript language service and creates the finalRuleContextfor each file being analyzed.
The defineRule function exported from [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), andreport(diagnostic emitter) to every rule. - Use
filewithts.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.tsand instantiated inpackages/config/lib/tsl.tsandpackages/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/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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →