# How to Build Custom TSSLint Plugins Using resolveRules, resolveDiagnostics, and resolveCodeFixes Hooks

> Learn to build custom TSSLint plugins. Explore resolveRules, resolveDiagnostics, and resolveCodeFixes hooks to modify rules, diagnostics, and code fixes for deep linting pipeline customization.

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

---

**TSSLint plugins implement three optional lifecycle hooks—`resolveRules` to modify rule sets before execution, `resolveDiagnostics` to filter or transform linting errors, and `resolveCodeFixes` to inject custom quick-fix actions—enabling deep customization of the linting pipeline.**

TSSLint is a TypeScript linter built on the TypeScript compiler API that emphasizes extensibility through plugins. When you build custom TSSLint plugins, you tap into three powerful hooks defined in the `PluginInstance` interface that let you intercept and modify rules, diagnostics, and code fixes at specific stages of the linting lifecycle.

## Understanding the TSSLint Plugin Architecture

A TSSLint plugin is a function that receives a `LinterContext` and returns a `PluginInstance`. The `PluginInstance` interface, defined in [`packages/types/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/types/index.ts), optionally exposes three methods that the core engine invokes at different stages:

- `resolveRules?`: Intercepts the rule map after initial assembly
- `resolveDiagnostics?`: Processes diagnostics after rule execution  
- `resolveCodeFixes?`: Augments code fixes before presentation

These hooks are declared at lines 30-33 in [`packages/types/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/types/index.ts).

## The Three Core Plugin Hooks

### resolveRules – Modifying Rules Before Execution

The `resolveRules` hook runs after the base rule set for a file is assembled but before any rule executes. It receives the source file name and the current rule map, allowing plugins to inject, replace, or remove rules dynamically.

According to the source code in [`packages/core/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/core/index.ts) (lines 13-16), the engine iterates over each plugin's `resolveRules` method and applies the transformed rule map immediately.

### resolveDiagnostics – Filtering and Transforming Diagnostics

After all rules execute and produce diagnostics, the `resolveDiagnostics` hook allows plugins to filter, merge, or enrich the error array before it reaches the editor or CLI. The hook receives the `SourceFile` and an array of `DiagnosticWithLocation` objects.

The core engine invokes this hook at lines 171-176 in [`packages/core/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/core/index.ts), passing the accumulated diagnostics through each plugin's implementation in sequence.

### resolveCodeFixes – Adding Custom Quick Fixes

When a diagnostic is about to be presented with code-fix suggestions, the `resolveCodeFixes` hook fires. It receives the `SourceFile`, the specific `Diagnostic` being processed, and the array of `CodeFixAction` objects generated by rules. Plugins can append custom fixes, remove unwanted ones, or modify existing suggestions.

This hook is triggered at lines 347-350 in [`packages/core/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/core/index.ts) for every diagnostic that has associated code fixes.

## Step-by-Step Implementation Examples

### Creating a Plugin That Injects Rules (resolveRules)

To dynamically add a custom rule to every file, implement `resolveRules` in your plugin:

```typescript
// plugins/console-plugin.ts
import NoConsoleRule from '../rules/no-console.ts';
import { definePlugin } from '@tsslint/config';

export default definePlugin(() => ({
  resolveRules(fileName, rules) {
    // Inject no-console rule into the rule map
    rules['no-console'] = NoConsoleRule;
    return rules;
  },
}));

```

### Filtering Diagnostics by Message Content (resolveDiagnostics)

Suppress specific diagnostics based on message content using `resolveDiagnostics`:

```typescript
// plugins/ignore-errors.ts
import { definePlugin } from '@tsslint/config';

export default definePlugin(() => ({
  resolveDiagnostics(file, diagnostics) {
    // Remove diagnostics containing "generated"
    return diagnostics.filter(d => 
      !d.messageText.toString().includes('generated')
    );
  },
}));

```

### Adding an Ignore Comment Quick Fix (resolveCodeFixes)

Provide a quick-fix action that inserts an ignore comment:

```typescript
// plugins/quick-ignore.ts
import { definePlugin } from '@tsslint/config';

export default definePlugin(() => ({
  resolveCodeFixes(file, diagnostic, codeFixes) {
    if (diagnostic.source !== 'tsslint' || diagnostic.start === undefined) {
      return codeFixes;
    }

    const line = file.getLineAndCharacterOfPosition(diagnostic.start).line;
    const comment = `// tsslint-ignore ${diagnostic.code}\n`;

    codeFixes.push({
      fixName: 'tsslint-ignore',
      description: 'Add tsslint-ignore comment',
      changes: [{
        fileName: file.fileName,
        textChanges: [{
          newText: comment,
          span: { 
            start: file.getPositionOfLineAndCharacter(line, 0), 
            length: 0 
          },
        }],
      }],
    });

    return codeFixes;
  },
}));

```

### Registering Plugins in tsslint.config.ts

Combine your plugins in the configuration file:

```typescript
// tsslint.config.ts
import { defineConfig } from '@tsslint/config';
import consolePlugin from './plugins/console-plugin.ts';
import ignorePlugin from './plugins/ignore-errors.ts';
import quickIgnore from './plugins/quick-ignore.ts';

export default defineConfig({
  plugins: [
    consolePlugin,   // Injects rules
    ignorePlugin,    // Filters diagnostics
    quickIgnore,     // Adds quick fixes
  ],
});

```

When the above configuration is loaded, the core engine at [`packages/core/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/core/index.ts) will:

1. Call `consolePlugin.resolveRules` (lines 13-16) to modify the rule map
2. Execute rules and collect diagnostics
3. Pass diagnostics through `ignorePlugin.resolveDiagnostics` (lines 171-176)
4. For each remaining diagnostic, invoke `quickIgnore.resolveCodeFixes` (lines 347-350) to augment available fixes

## Using Built-in Helpers for Common Patterns

For the common use case of adding ignore comments, TSSLint provides a built-in helper that encapsulates the `resolveDiagnostics` and `resolveCodeFixes` logic:

```typescript
import { defineConfig, createIgnorePlugin } from '@tsslint/config';

export default defineConfig({
  plugins: [
    // Automatically adds // @tsslint-ignore comments
    createIgnorePlugin(/\/\/\s*@tsslint-ignore/g, true),
  ],
});

```

The `createIgnorePlugin` implementation, located in [`packages/config/lib/plugins/ignore.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/config/lib/plugins/ignore.ts) (lines 48-72), demonstrates production-grade usage of both `resolveDiagnostics` and `resolveCodeFixes` hooks to suppress diagnostics and generate the corresponding ignore comments.

## Summary

- **TSSLint plugins** are functions returning a `PluginInstance` that can implement three optional hooks to intercept the linting pipeline.
- **`resolveRules`** (invoked at [`packages/core/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/core/index.ts) lines 13-16) allows dynamic injection or modification of rules before execution.
- **`resolveDiagnostics`** (invoked at lines 171-176) enables filtering, merging, or enriching diagnostic messages after rule execution.
- **`resolveCodeFixes`** (invoked at lines 347-350) permits customization of quick-fix actions presented to users.
- Plugins are registered via the `plugins` array in [`tsslint.config.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/tsslint.config.ts) using `defineConfig` from `@tsslint/config`.

## Frequently Asked Questions

### What is the execution order of TSSLint plugin hooks?

The hooks execute sequentially as the linting pipeline progresses. First, `resolveRules` runs after the base rule set is assembled but before any rules execute. Next, `resolveDiagnostics` processes the results after all rules have finished. Finally, `resolveCodeFixes` runs on-demand when the editor or CLI requests fixes for specific diagnostics.

### Can a plugin modify diagnostics generated by other plugins?

Yes. Because `resolveDiagnostics` receives the accumulated diagnostic array after all rules have executed, your plugin can filter, modify, or remove diagnostics regardless of which rule or plugin produced them. The same applies to `resolveCodeFixes`, where you can augment or replace fixes provided by other plugins.

### How do I access the TypeScript compiler API inside a plugin?

The `LinterContext` passed to your plugin function contains the `typescript` object (the TypeScript module) and the current `program`. You can destructure these from the context parameter to access the full compiler API for advanced type checking or AST manipulation.

### Is it possible to suppress specific diagnostics using the built-in helpers?

Yes. The `@tsslint/config` package exports `createIgnorePlugin`, which encapsulates the logic for both suppressing diagnostics matching a specific pattern and generating the corresponding ignore comments. This helper uses the `resolveDiagnostics` and `resolveCodeFixes` hooks internally, as shown in [`packages/config/lib/plugins/ignore.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/config/lib/plugins/ignore.ts).