@coderrob/eslint-plugin-zero-tolerance
no-magic-numbers allows arithmetic in named constants, such as const SOMETHING = 10 * 100;.
Behavioral safety contracts document positive and negative inputs, parameter boundaries, state isolation, and cases that require manual migration.
Rule suites require nonempty valid and invalid fixtures, named should cases, explicit diagnostics, and concrete autofix outputs. All 83 rules also run against shared TypeScript, JSX, optional-access, and Jest-chain parsing fixtures. See the contributor guide for validation requirements.
Strict, opinionated ESLint plugin for TypeScript that enforces type safety, code quality, testing standards, and maintainable patterns — with zero exceptions.
Features
- 83 custom ESLint rules across eight categories: type safety, code quality, testing, imports, error handling, bug prevention, naming conventions, and documentation
- Two presets —
recommendedgenerally uses warning severity for gradual adoption, whilestrictgenerally uses error severity; strict-only and opt-in exceptions are identified below - ESLint 8.57+, 9.x, and 10.x — flat config and legacy
.eslintrcboth supported - 99%+ test coverage — every rule is thoroughly tested with both valid and invalid cases
- Built with
@typescript-eslint/utilsfor full TypeScript AST support
Requirements
- Node.js
- 18.18.0+ when using ESLint 8.57.0+ or 9.x
- 20.19.0+, 22.13.0+, or 24.0.0+ when using ESLint 10.x
- CI-tested LTS releases: 18.20.8, 20.20.2, 22.23.4, 24.22.2, and 26.13.0
- ESLint 8.57.0+, 9.x, or 10.x
- CI-tested major releases: 8.57.1, 9.39.5, and 10.14.0
@typescript-eslint/parser8.x- TypeScript 5.x
Installation
npm install --save-dev @coderrob/eslint-plugin-zero-tolerance @typescript-eslint/parser
Quick Start
ESLint 9+ (Flat Config)
// eslint.config.js
import zeroTolerance from '@coderrob/eslint-plugin-zero-tolerance';
export default [zeroTolerance.configs.recommended];
ESLint 8.x (Legacy Config)
// .eslintrc.js
module.exports = {
plugins: ['@coderrob/zero-tolerance'],
extends: ['plugin:@coderrob/zero-tolerance/legacy-recommended'],
};
Legacy ESLint resolves the scoped package through the @coderrob/zero-tolerance shorthand, so
manually selected legacy rule IDs use @coderrob/zero-tolerance/<rule-name>. Flat configs continue
to use the zero-tolerance namespace shown below.
Custom Rule Selection
// eslint.config.js
import zeroTolerance from '@coderrob/eslint-plugin-zero-tolerance';
export default [
{
plugins: {
'zero-tolerance': zeroTolerance,
},
rules: {
'zero-tolerance/require-interface-prefix': 'error',
'zero-tolerance/no-throw-literal': 'error',
'zero-tolerance/max-function-lines': ['warn', { max: 40 }],
},
},
];
Presets
| Preset | Severity | Config Key |
|---|---|---|
| Recommended | warn | configs.recommended |
| Strict | error | configs.strict |
| Legacy Recommended | warn | legacy-recommended |
| Legacy Strict | error | legacy-strict |
Preset severities describe the default for enabled rules. prefer-result-return is strict-only, while require-bdd-spec, require-jsdoc-anonymous-functions, no-fetch-in-tests, no-parent-internal-access, and no-restricted-imports-in-tests remain opt-in in both presets. See the full rule documentation for each rule's preset status.
Rules
Naming Conventions
| Rule | Description |
|---|---|
require-interface-prefix | Enforce that TypeScript interface names start with I followed by an uppercase letter |
Documentation
| Rule | Description |
|---|---|
require-bdd-spec | Enforce that every TypeScript source file has a valid sibling .ts.bdd.json BDD spec |
require-jsdoc-anonymous-functions | Require JSDoc comments on anonymous function-like constructs except test files and known test callbacks |
require-jsdoc-functions | Require JSDoc comments on named functions (except test files) |
require-optional-chaining | Report repeated logical guard access for manual review |
require-readonly-props | Require JSX component props to be typed as readonly |
Testing
| Rule | Description |
|---|---|
require-test-description-style | Enforce that test descriptions start with should |
no-chai-imprecise-spy-assertions | Require exact Chai-style spy call counts and invocation arguments |
no-conditional-test-assertion | Disallow assertions in test branches that may not execute |
no-jest-have-been-called | Require exact call counts and invocation indices in Jest assertions; allow negated zero-call checks |
no-mock-implementation | Prohibit persistent mock methods; use Once variants to prevent test bleeds |
no-sinon-imprecise-spy-assertions | Require exact Sinon spy call counts and invocation arguments |
no-set-timeout-in-tests | Disallow setTimeout usage in test files |
no-set-interval-in-tests | Disallow setInterval usage in test files |
no-fetch-in-tests | Disallow fetch usage in test files |
no-restricted-imports-in-tests | Disallow configured dependency imports in test files |
no-test-interface-declaration | Disallow interface declarations in test files; import production types instead |
no-unawaited-async-assertion | Require asynchronous test assertions to be awaited or returned |
no-vitest-imprecise-spy-assertions | Require exact Vitest spy call counts and invocation indices |
Type Safety
| Rule | Description |
|---|---|
no-type-assertion | Prevent use of TypeScript as and angle-bracket assertions |
no-non-null-assertion | Disallow non-null assertions using the ! postfix operator |
no-explicit-any | Disallow explicit any; require precise modeling or explicit narrowing |
no-indexed-access-types | Disallow TypeScript indexed access types |
no-literal-unions | Report literal unions for manual migration to enums |
no-literal-property-unions | Require property literal unions to use named domain types |
require-union-type-alias | Require inline union types with multiple type references to use named type aliases |
no-inline-type-import | Disallow inline import("...").Type annotations |
no-return-type | Disallow TypeScript ReturnType utility usage |
no-destructured-parameter-type-literal | Disallow inline object type literals on destructured parameters |
require-exported-object-type | Require exported object constants to declare an explicit type annotation |
no-unsafe-json-parse | Disallow treating JSON.parse results as typed data without validation |
Code Quality
| Rule | Description |
|---|---|
max-function-lines | Enforce a maximum number of lines per function body |
max-params | Enforce a maximum number of function parameters |
no-array-mutation | Disallow mutating array methods |
no-date-now | Disallow Date.now() and no-arg new Date() usage |
no-placeholder-implementation | Disallow placeholder, stub, TODO, and not implemented production code |
no-magic-numbers | Disallow magic numbers; use named constants instead |
no-magic-strings | Disallow magic strings in comparisons and switch cases |
no-map-set-mutation | Disallow direct Map and Set mutation methods |
no-object-mutation | Disallow direct object-property mutation |
sort-imports | Report import ordering while preserving runtime dependency order |
sort-functions | Require top-level functions and const function expressions to be sorted alphabetically |
prefer-nullish-coalescing | Prefer nullish coalescing for locally bound identifier guard ternaries |
prefer-object-spread | Report empty-target Object.assign calls for manual review before using object spread |
prefer-readonly-parameters | Prefer readonly typing for object and array-like parameters |
prefer-string-raw | Prefer native String.raw when the constructor is not shadowed |
prefer-structured-clone | Review JSON.parse(JSON.stringify(...)) before considering structuredClone(...) |
Error Handling
| Rule | Description |
|---|---|
no-empty-catch | Disallow empty catch blocks that silently swallow errors |
no-throw-literal | Disallow throwing literals, objects, or templates; always throw a new Error instance |
prefer-result-return | Prefer returning Result-style values instead of throwing |
Imports
no-parent-internal-access remains opt-in and only matches the first concrete directory reached after .. traversal, such as ../src/foo.
| Rule | Description |
|---|---|
require-clean-barrel | Require barrel files (index.*) to contain only module re-exports |
require-barrel-relative-exports | Require barrel re-exports to use ./ descendant paths |
no-barrel-parent-imports | Disallow parent-directory traversal in barrel-file import paths |
no-parent-internal-access | Disallow parent-relative access into protected internal directories such as src |
no-dynamic-import | Ban dynamic import() and require() outside test files |
no-export-alias | Prevent use of aliases in export statements |
no-hardcoded-secrets | Disallow hardcoded secrets, credentials, tokens, and secret env defaults |
no-raw-sql-interpolation | Disallow interpolated raw SQL and unsafe raw query helpers |
no-re-export | Disallow direct or pass-through re-exports from parent/grandparent modules |
no-shell-command-construction | Disallow shell command construction through subprocess APIs |
no-unsafe-code-generation | Disallow eval, Function constructors, string timers, and vm execution APIs |
require-node-protocol | Require Node.js built-in module imports to use the node: protocol prefix |
Bug Prevention
| Rule | Description |
|---|---|
no-identical-expressions | Disallow identical expressions on both sides of a binary or logical operator |
no-identical-branches | Disallow identical conditional branches |
no-boolean-return-trap | Disallow ambiguous boolean-return APIs outside predicate naming |
no-redundant-boolean | Simplify comparisons only when the operand is known to be boolean |
no-for-in | Disallow for..in loops without rewriting inherited-key behavior |
no-labels | Disallow labeled statements |
no-with | Disallow with statements |
no-await-in-loop | Disallow await inside loops; use Promise.all() instead |
no-floating-promises | Check explicit, local async, and type-resolved promises |
no-math-random | Disallow Math.random(); inject a random source instead |
no-eslint-disable | Prevent use of eslint-disable comments |
no-parameter-reassign | Disallow reassigning function parameters |
no-process-env-outside-config | Disallow process.env reads outside configuration modules |
no-flag-argument | Disallow boolean flag parameters in function signatures |
prefer-guard-clauses | Prefer guard clauses by removing else blocks after terminating if branches |
prefer-shortcut-return | Simplify boolean returns while retaining comments |
no-query-side-effects | Disallow side effects in query-style functions |
require-timeout-for-io | Require timeout or cancellation options for external IO calls |
require-exhaustive-switch | Require exhaustive switch statements over finite discriminant types |
Documentation
Full rule documentation with examples is available at:
https://coderrob.github.io/eslint-config-zero-tolerance/
Choose checks
Use the rule reference to choose checks and review examples, options, and limits. Enable require-error-cause individually to preserve original exceptions.
For promise handling, unsafe types, callback returns, and branching limits, see additional code-quality checks.
License
Apache 2.0 Copyright Robert Lindley