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.
Background
@exadev/eslint-configwas bumped from2.1.2to2.12.1in #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-commentsbanning Stryker suppression comments, andmax-linescapping 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 owneslint.config.ts, with the specific rule names listed there -- seePackageLintOptionsineslint.shared.tsfor the exact mechanism (preferReadonlyParams,magicNumbers,maxLines,newRuleDebt).Measured scope, at the time of the bump
@typescript-eslint/no-magic-numbers(enabled in2.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-levelconst NAME = valuefully 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 in2.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/TS2339from mutation methods and property assignments no longer existing on the now-readonly type,TS4104/TS2345/TS2322from 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 in2.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.newRuleDebtarray:@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-commentsneeded no exception: its 6 real hits were all astryker.config.tscomment 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.tsexceptions, 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 innewRuleDebt), then delete that package's own line disabling it (or that rule's name out of itsnewRuleDebtarray). Land it as its own PR per package/rule pair rather than one enormous change -- each is independently reviewable and revertable that way.