@ttoss/eslint-config
@ttoss/eslint-config is a set of rules for ESLint to use on ttoss ecosystem. It uses the new ESLint flat configuration format.
Installation
pnpm add -D @ttoss/eslint-config
Usage
Add the following to your eslint.config.mjs file:
import ttossEslintConfig from '@ttoss/eslint-config';
export default [...ttossEslintConfig];
Relay projects
Relay rules are not in the base config: every one of them operates on
graphql\...`` tagged template literals, so a project without them pays to load
the plugin on every file and gets nothing back. Applications that do use Relay
compose the extra config on top:
import ttossEslintConfig from '@ttoss/eslint-config';
import ttossEslintConfigRelay from '@ttoss/eslint-config/relay';
export default [...ttossEslintConfig, ...ttossEslintConfigRelay];
Rules
Complexity, module sizes, and duplication
To keep code understandable and testable, this config limits cyclomatic complexity, cognitive complexity, and module size, and rejects duplicated branches, identical functions, and assignments that are never read. The rationale is explained in Cognitive Complexity — because testability, understandability, and changeability matter.
For the current rule values, see config.js. Test files (*.spec.ts, *.test.ts, *.spec.tsx, *.test.tsx) get thresholds calibrated for suites rather than a blanket opt-out: file length, callback nesting and cyclomatic complexity are all still enforced, just at limits picked so only genuine outliers report. Depth, parameter count and cognitive complexity apply unchanged. Only two rules are off there — max-lines-per-function, which counts a whole describe block as one function, and no-identical-functions, since repetitive arrange/assert blocks are how a suite stays readable.
Untranslated JSX text
formatjs/no-literal-string-in-jsx applies to packages/*/src/**/*.tsx only — what a package ships. Tests, Storybook stories and the docs sites are allowed hardcoded copy, and scoping it there is what makes it enforceable: repo-wide it reported 2216 times, every one of them hidden by eslint --quiet.
What this config cannot enforce
ESLint reads one file at a time and has no coverage or runtime data, so these quality gates need separate tooling: Halstead metrics (an escomplex-based reporter), test coverage and CRAP (Jest coverageThreshold), surviving mutants (Stryker), cross-file duplication (jscpd), and unused exports or modules (Knip).
any is rejected via @typescript-eslint/no-explicit-any. unknown is deliberately allowed — it is the safe counterpart to any, and TypeScript has no alternative for as unknown as T double assertions, Record<string, unknown>, or generic defaults.