Skip to content

Burn down eslint-config 2.1.2->2.12.1 rule debt (magic numbers, readonly params, max-lines, and 17 others) #1275

Description

@Mearman

Background

@exadev/eslint-config was bumped from 2.1.2 to 2.12.1 in #TBD. That pin had never moved across roughly ten minor releases of the shared config, several of which enabled new rules this workspace has real, pre-existing violations of. Adopting the version bump itself (and the two rules its own release notes call out -- no-warning-comments banning Stryker suppression comments, and max-lines capping a file at 800 real lines) was in scope for that PR; fixing every violation the intervening releases also newly surface was not, given the measured scale below. Each rule stays enforced everywhere it already reports clean, and every package that needed an exception carries it in its own eslint.config.ts, with the specific rule names listed there -- see PackageLintOptions in eslint.shared.ts for the exact mechanism (preferReadonlyParams, magicNumbers, maxLines, newRuleDebt).

Measured scope, at the time of the bump

  • @typescript-eslint/no-magic-numbers (enabled in 2.4.0, never previously enforced here) -- 30,748 sites across 864 files, in every one of the 22 published packages (smallest: document-operations, 8; largest: pdf-codec, 6,040). The rule's own configuration already exempts array indexes, enum members, readonly class properties, default values, and -1/0/1/2 -- every remaining site is a literal that needs a real name from someone who understands what it means (a format code, a byte offset, a boundary value in a test fixture). A plain top-level const NAME = value fully satisfies the rule, confirmed directly, so the fix is mechanical type-wise but not mechanical content-wise.
  • exadev/prefer-readonly-array-param / exadev/prefer-readonly-object-param (enabled in 2.6.0) -- both mark every array/tuple or "flat" object parameter readonly unconditionally, with no check for whether the function body mutates it in place. Running the autofix against this workspace produced 443 real compile errors across 18 of the 22 packages (TS2540/TS2542/TS2551/TS2339 from mutation methods and property assignments no longer existing on the now-readonly type, TS4104/TS2345/TS2322 from the readonly value then failing to satisfy a mutable field elsewhere) -- not stray exceptions, but the majority shape of how this workspace's binary/format-codec packages are written (a bounds tracker, a glyph/operand stack, a byte cursor genuinely owned and mutated by the function that receives it). Two packages (byte-codec, excel-number-format) are already clean and keep both rules enforced.
  • max-lines (enabled in 2.12.0, 800 real lines, blank/comments excluded) -- 93 files exceed it, from a handful of files in smaller packages up to several files over 2,000 real lines each. Splitting one properly means a real per-file design decision (which exports move where, which tests follow which module), not a cut at an arbitrary line count.
  • Everything else -- 781 sites across 17 further rules enabled somewhere in the same version gap, measured per package and listed exactly in each package's own newRuleDebt array: @typescript-eslint/strict-void-return (239), method-signature-style (133), consistent-return (119), no-use-before-define (60), promise-function-async (55), no-shadow (45), tsdoc/syntax (39), strict-boolean-expressions (38), switch-exhaustiveness-check (31), consistent-type-exports (5), prefer-readonly (4), exadev/no-object-assign (3), exadev/no-mutable-union-array-param (3), require-array-sort-compare (3), jsdoc/escape-inline-tags (2), jsdoc/no-multi-asterisks (1), exadev/prefer-numeric-sort-compare (1).

no-warning-comments needed no exception: its 6 real hits were all a stryker.config.ts comment explaining that a package carries no Stryker suppression comments, which itself contained the banned phrase -- reworded, not suppressed.

Burn-down

Pick a package and a rule from its own eslint.config.ts exceptions, fix every site that rule reports there (a real name for each magic number, a real restructure for a mutated parameter, a real split for an oversized file, a real fix for everything in newRuleDebt), then delete that package's own line disabling it (or that rule's name out of its newRuleDebt array). Land it as its own PR per package/rule pair rather than one enormous change -- each is independently reviewable and revertable that way.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions