@coderrob/eslint-plugin-zero-tolerance
v1.2.6
Published
Strict, opinionated ESLint rules for TypeScript — enforcing type safety, code quality, testing standards, and maintainable patterns with zero exceptions.
Maintainers
Readme
@coderrob/eslint-plugin-zero-tolerance
Strict, opinionated ESLint plugin for TypeScript that enforces type safety, code quality, testing standards, and maintainable patterns — with zero exceptions.
Features
- 77 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.1, and 24.18.0
- ESLint 8.57.0+, 9.x, or 10.x
- CI-tested major releases: 8.57.1, 9.39.5, and 10.7.0
@typescript-eslint/parser8.x- TypeScript 5.x
Installation
npm install --save-dev @coderrob/eslint-plugin-zero-tolerance @typescript-eslint/parserQuick 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 | Require optional chaining instead of repeated guard access |
| 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-jest-have-been-called | Prohibit imprecise call-assertion matchers; use toHaveBeenCalledTimes and toHaveBeenNthCalledWith instead |
| no-mock-implementation | Prohibit persistent mock methods; use Once variants to prevent test bleeds |
| 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 |
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 | Ban literal union types in favour of 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 | Require import declarations to be ordered by group and alphabetically within each group |
| sort-functions | Require top-level functions and const function expressions to be sorted alphabetically |
| prefer-nullish-coalescing | Prefer nullish coalescing instead of repeated nullish guard ternaries |
| prefer-object-spread | Enforce object spread syntax instead of Object.assign with an empty object literal |
| prefer-readonly-parameters | Prefer readonly typing for object and array-like parameters |
| prefer-string-raw | Prefer String.raw for strings containing escaped backslashes |
| prefer-structured-clone | Prefer structuredClone(...) over JSON.parse(JSON.stringify(...)) for deep cloning |
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 | Disallow redundant comparisons to boolean literals |
| no-for-in | Disallow for..in loops |
| 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 | Disallow unhandled promise expressions; require explicit handling |
| 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 | Prefer shortcut boolean returns over if branches that return true/false |
| 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/
License
Apache 2.0 Copyright Robert Lindley
