# TSSLint `.at()` Method: Advanced Rule Debugging and Stack Trace Customization

> Discover how TSSLint's.at() method enhances rule debugging and stack trace customization by attaching detailed debug info to diagnostics for precise error tracing.

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

---

**The `.at()` method captures error objects and stack frame indices to attach detailed debug information to diagnostics, enabling precise tracing of rule failures back to their source code location.**

The `tsslint` repository provides a flexible linting framework that prioritizes developer experience when debugging complex rules. The `.at()` method on the Reporter object allows rule authors to preserve execution context and customize how stack traces appear in diagnostic output, making it an essential tool for advanced rule debugging.

## How the `.at()` Method Works in TSSLint Core

The `.at()` method is a chainable modifier available on the **Reporter** object that every rule receives via the `report()` helper in [`packages/core/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/core/index.ts). When invoked, it stores an error reference and stack depth index that the framework uses to generate rich diagnostic information.

### The Reporter Chain Architecture

When a rule reports a diagnostic, the `report(message, start, end)` function returns a Reporter instance that supports method chaining. The `.at(err, stackIndex)` modifier accepts two parameters:

- **`err`**: An `Error` object (either the original thrown error or a newly created one) whose stack trace will be preserved
- **`stackIndex`**: A number indicating which frame in the stack trace should be treated as the entry point for the diagnostic

This design enables fluent API usage:

```typescript
report('Avoid using eval()', evalPos, evalPos + 4)
  .at(err, 0)
  .asError()
  .withFix('Remove eval', () => [{ /* edits */ }]);

```

### Internal Storage and Lazy Evaluation

Internally, the Reporter stores the error and stack index as a tuple `[Error, number]` in a private variable called `location`. When the diagnostic's `relatedInformation` property is accessed, it lazily invokes the repository-provided `getRelatedInformations(location[0], location[1])` function.

This lazy evaluation, implemented in [`packages/core/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/core/index.ts), ensures that stack processing only occurs when diagnostics are actually rendered, optimizing performance for rules that may generate many reports. The resulting `ts.DiagnosticRelatedInformation[]` objects are then attached to the diagnostic, surfacing the stack trace in editors and CLI output.

## Advanced Debugging Scenarios

The `.at()` method enables several critical debugging workflows that distinguish TSSLint from simpler linting frameworks.

### Capturing Rule Execution Failures

When a rule throws an exception during execution, the core framework catches the error and uses `.at()` to preserve the original stack trace. In the execution wrapper found in the core implementation:

```typescript
try {
  rule(rulesContext);
} catch (err) {
  if (err instanceof Error) {
    report(err.stack ?? err.message, 0, 0).at(err, 0);
  }
}

```

This pattern ensures that developers see exactly where a rule failed, rather than receiving a generic error message.

### Handling Non-Type-Aware Mode Errors

When rules execute without type information and encounter errors, the framework uses a specific technique to capture full diagnostic context:

```typescript
report(String(err), 0, 0).at(new Error(), Number.MAX_VALUE);

```

By passing `Number.MAX_VALUE` as the `stackIndex`, the core forces `getRelatedInformations` to include the complete stack trace. This aids in debugging configuration issues or plugin compatibility problems that only surface in specific execution modes.

### TSLint Compatibility Layer Integration

The compatibility shim in [`packages/config/lib/tslint.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/config/lib/tslint.ts) also leverages `.at()` to handle failures from legacy TSLint rules:

```typescript
// In packages/config/lib/tslint.ts
report(failureMessage, 0, 0).at(new Error(), Number.MAX_VALUE);

```

This ensures consistent stack trace handling across both native TSSLint rules and migrated TSLint codebases.

## Key Implementation Files

The `.at()` functionality spans several packages in the monorepo:

- **[`packages/core/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/core/index.ts)** – Defines the Reporter class and the `.at()` method implementation
- **[`packages/types/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/types/index.ts)** – Declares the Reporter interface and type signatures
- **[`packages/typescript-plugin/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/typescript-plugin/index.ts)** – Creates the linter instance and forwards `getRelatedInformations` callbacks
- **[`packages/cli/lib/worker.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/cli/lib/worker.ts)** – Provides the concrete `getRelatedInformations` implementation that parses stack frames into diagnostic objects
- **[`packages/config/lib/tslint.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/config/lib/tslint.ts)** – Uses `.at()` for error handling in the TSLint compatibility layer

## Practical Code Examples

### Creating Diagnostics with Custom Stack Context

Rule authors can manually create error objects to provide specific debugging context:

```typescript
export default (ctx: RuleContext) => {
  const { report } = ctx;
  const source = ctx.file.getFullText();
  const evalPos = source.indexOf('eval(');
  
  if (evalPos !== -1) {
    const err = new Error('Avoid eval');
    
    report('Avoid using eval()', evalPos, evalPos + 4)
      .at(err, 0)
      .asError()
      .withFix('Remove eval', () => [{
        span: { start: evalPos, length: 4 },
        newText: '',
      }]);
  }
};

```

### Processing Stack Frames for Display

The `getRelatedInformations` callback, typically implemented in the CLI worker, transforms captured errors into diagnostic-related information:

```typescript
function getRelatedInformations(err: Error, stackIndex: number) {
  const frames = err.stack?.split('\n').slice(stackIndex + 1) ?? [];
  return frames.map(frame => ({
    messageText: frame.trim(),
    file: { /* file location extraction logic */ },
    start: 0,
    length: 0,
  }));
}

```

This function extracts frames starting from the specified index, allowing editors to display a clean breadcrumb trail back to the rule's source.

## Summary

- The `.at(err, stackIndex)` method modifies Reporter instances to capture error objects and specific stack frame indices
- Error data is stored as a `[Error, number]` tuple and processed lazily when `relatedInformation` is accessed
- The method enables chaining with other modifiers like `asError()` and `withFix()` for fluent diagnostic construction
- `Number.MAX_VALUE` as a `stackIndex` forces inclusion of the complete stack trace for deep debugging scenarios
- Core implementation resides in [`packages/core/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/core/index.ts) with platform-specific `getRelatedInformations` handling in [`packages/cli/lib/worker.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/cli/lib/worker.ts)

## Frequently Asked Questions

### What parameters does the `.at()` method accept?

The `.at()` method accepts two parameters: an `Error` object containing the stack trace to preserve, and a `stackIndex` number indicating which frame represents the diagnostic entry point. When the stack index is `0`, the error's capture point is used; when set to `Number.MAX_VALUE`, the entire stack trace is included.

### How does `.at()` interact with `relatedInformation`?

The `.at()` method stores the error and stack index internally, but the actual `ts.DiagnosticRelatedInformation` objects are generated lazily. When an IDE or CLI accesses the diagnostic's `relatedInformation` property, the core invokes the `getRelatedInformations` callback with the stored error and index, transforming raw stack frames into structured diagnostic objects.

### Can `.at()` be chained with other Reporter methods?

Yes, `.at()` returns the same Reporter instance, enabling method chaining with other modifiers like `asError()`, `asWarning()`, and `withFix()`. This fluent API allows concise construction of complex diagnostics: `report(msg, start, end).at(err, 0).asError().withFix(title, edits)`.

### When should rule authors use `Number.MAX_VALUE` as the stack index?

Use `Number.MAX_VALUE` when you need to capture the complete stack trace without filtering specific frames. This is particularly useful when reporting errors from unexpected exceptions where the exact failure point is unknown, or when debugging configuration issues where every frame provides valuable context for tracing the execution path.