Troubleshooting TSSLint Rules Not Firing: Fixing Include, Exclude, and Context Issues

TSSLint rules most commonly fail to fire when include or exclude glob patterns in your configuration filter out target files, or when the language context (TypeScript, Vue, Astro, etc.) isn't properly activated in the CLI.

When a TSSLint rule produces no diagnostics despite being configured, the issue typically traces back to how the core engine filters files. In the johnsoncodehk/tsslint repository, the rule execution flow depends on specific guards in the core package and language plugin registration in the CLI.

Understanding the Core Filtering Mechanism

The primary logic that decides whether a rule runs lives in packages/core/index.ts. Before any rule logic executes, TSSLint evaluates two glob-based guards that short-circuit processing.

How Exclude Patterns Block Execution

According to the source code in packages/core/index.ts (lines 427-429), the engine immediately skips a file if its path matches any exclude pattern:

if (exclude?.some(_minimatch)) {
  return; // File is excluded, rule never fires
}

This check runs before rule invocation. If your file path matches even one exclusion glob, every rule is bypassed for that file.

How Include Patterns Restrict Processing

Similarly, the include guard at line 430 enforces that files must match at least one inclusion pattern when include is defined:

if (include && !include.some(_minimatch)) {
  return; // File not in include list, rule skipped
}

If you define an include array in tsslint.config.ts but your target file doesn't match any entry, the rule's create function never executes.

Verifying Language Context and Plugins

Rules may also fail to fire when the target file uses a language that isn't activated in the CLI. The packages/cli/lib/languagePlugins.ts file (lines 18-30) gates support for Vue, Vue-Vine, MDX, Astro, and other frameworks behind a languages.includes(...) check.

If you're linting .vue files but haven't enabled the Vue language plugin, TSSLint won't process the file context, causing TypeScript-specific rules to never trigger. Ensure your CLI invocation or configuration explicitly includes the required language.

Step-by-Step Troubleshooting Checklist

Follow this sequence to isolate why a rule isn't reporting diagnostics:

  1. Confirm your configuration file explicitly includes the target file.

    In tsslint.config.ts, verify that include covers your file path and exclude doesn't catch it:

    import { defineConfig } from 'tsslint';
    
    export default defineConfig({
      rules: { 'no-console': 'error' },
      include: ['src/**/*.ts'],
      exclude: ['dist/**', '**/*.d.ts'],
    });
  2. Validate glob patterns against the actual file path.

    Use minimatch directly to test your patterns:

    import minimatch from 'minimatch';
    
    const file = '/src/components/Button.ts';
    console.log(minimatch(file, 'src/**/*.ts')); // Should be true
    console.log(minimatch(file, '**/*.d.ts'));   // Should be false
  3. Check language plugin activation.

    Review packages/cli/lib/languagePlugins.ts to ensure your file's language is supported. For Vue files, confirm the CLI includes the Vue plugin in its languages array.

  4. Verify rule registration and metadata.

    Rules must be correctly exported with valid meta categories. Check packages/config/lib/plugins/diagnostics.ts to see how built-in rules define their metadata. If a rule's category is filtered out or the export is malformed, it won't reach the engine.

  5. Run with verbose output.

    Use the --verbose flag to see which files are processed:

    npx tsslint --config ./tsslint.config.ts --verbose ./src

    This reveals "included", "excluded", and "skipped" messages for each file.

  6. Inspect post-execution filtering.

    Even if a rule fires, diagnostics can be filtered out after execution by the same exclude?.some(_minimatch) logic in packages/core/index.ts. Ensure your exclude patterns aren't inadvertently catching the diagnostic output.

Debugging with a Minimal Reproduction Rule

Create a diagnostic rule that logs when activated to determine if the file is reaching the rule engine:

import type { TSSLintRule } from 'tsslint';

export const logRule: TSSLintRule = {
  meta: {
    docs: { description: 'log when rule runs' },
    fixable: false,
    schema: [],
    messages: { executed: 'Rule executed' },
    type: 'suggestion',
  },
  create(context) {
    console.log('logRule CREATE called for', context.getFilename());
    return {
      Program(node) {
        context.report({ node, messageId: 'executed' });
      },
    };
  },
};

Add this to your tsslint.config.ts and run:

npx tsslint --config ./tsslint.config.ts ./src/example.ts

If you don't see the console log, the file is being filtered by include/exclude patterns before reaching the rule. If you see the log but no diagnostic, check post-execution filters or rule metadata in packages/config/lib/plugins/ignore.ts.

Summary

  • Exclude patterns in packages/core/index.ts (lines 427-429) short-circuit rule execution immediately if matched.
  • Include patterns at line 430 skip files that don't match the configured globs.
  • Language plugins in packages/cli/lib/languagePlugins.ts must be enabled for Vue, Astro, MDX, or other non-TypeScript files.
  • Rule metadata and exports in packages/config/lib/plugins/diagnostics.ts determine whether the engine registers the rule.
  • Use verbose logging and a minimal reproduction rule to isolate whether issues stem from file filtering or rule logic.

Frequently Asked Questions

Why does my rule work for .ts files but not .vue files?

TSSLint requires explicit language plugin activation for Vue and other frameworks. As implemented in packages/cli/lib/languagePlugins.ts, the CLI checks languages.includes(...) before loading Vue, Vue-Vine, MDX, or Astro support. Ensure your configuration or CLI flags enable the specific language plugin for your file type.

How do I test if my include/exclude patterns are correct?

Validate your globs against actual file paths using the minimatch library directly in a Node.js REPL. If minimatch(filePath, pattern) returns false for an include pattern or true for an exclude pattern, the core engine in packages/core/index.ts will skip the file before your rule executes.

Can a rule fire but still produce no visible diagnostics?

Yes. The same exclude?.some(_minimatch) filter in packages/core/index.ts that blocks file execution also runs after rule aggregation. A rule might execute and create diagnostics that get filtered out during the final exclusion check, or the rule's meta.category might be filtered by configuration in packages/config/lib/plugins/ignore.ts.

What file paths should I use in my tsslint.config.ts?

Patterns in include and exclude should match the absolute or relative paths passed to the TSSLint CLI. The core engine uses minimatch against the file's resolved path, so ensure your globs account for directory depth (e.g., src/**/*.ts vs *.ts). Check the fixture example in fixtures/define-rule/tsslint.config.ts for valid pattern structure.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →